if_run.c revision 288646
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 288646 2015-10-04 04:25:56Z 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),
249209918Sthompsa    RUN_DEV(OVISLINK,		RT3072),
250209918Sthompsa    RUN_DEV(PARA,		RT3070),
251209918Sthompsa    RUN_DEV(PEGATRON,		RT2870),
252209918Sthompsa    RUN_DEV(PEGATRON,		RT3070),
253209918Sthompsa    RUN_DEV(PEGATRON,		RT3070_2),
254209918Sthompsa    RUN_DEV(PEGATRON,		RT3070_3),
255209918Sthompsa    RUN_DEV(PHILIPS,		RT2870),
256209918Sthompsa    RUN_DEV(PLANEX2,		GWUS300MINIS),
257209918Sthompsa    RUN_DEV(PLANEX2,		GWUSMICRON),
258209918Sthompsa    RUN_DEV(PLANEX2,		RT2870),
259209918Sthompsa    RUN_DEV(PLANEX2,		RT3070),
260209918Sthompsa    RUN_DEV(QCOM,		RT2870),
261209918Sthompsa    RUN_DEV(QUANTA,		RT3070),
262209918Sthompsa    RUN_DEV(RALINK,		RT2070),
263209918Sthompsa    RUN_DEV(RALINK,		RT2770),
264209918Sthompsa    RUN_DEV(RALINK,		RT2870),
265209918Sthompsa    RUN_DEV(RALINK,		RT3070),
266209918Sthompsa    RUN_DEV(RALINK,		RT3071),
267209918Sthompsa    RUN_DEV(RALINK,		RT3072),
268209918Sthompsa    RUN_DEV(RALINK,		RT3370),
269209918Sthompsa    RUN_DEV(RALINK,		RT3572),
270260219Skevlo    RUN_DEV(RALINK,		RT3573),
271257955Skevlo    RUN_DEV(RALINK,		RT5370),
272259032Skevlo    RUN_DEV(RALINK,		RT5572),
273209918Sthompsa    RUN_DEV(RALINK,		RT8070),
274226534Shselasky    RUN_DEV(SAMSUNG,		WIS09ABGN),
275209918Sthompsa    RUN_DEV(SAMSUNG2,		RT2870_1),
276209918Sthompsa    RUN_DEV(SENAO,		RT2870_1),
277209918Sthompsa    RUN_DEV(SENAO,		RT2870_2),
278209918Sthompsa    RUN_DEV(SENAO,		RT2870_3),
279209918Sthompsa    RUN_DEV(SENAO,		RT2870_4),
280209918Sthompsa    RUN_DEV(SENAO,		RT3070),
281209918Sthompsa    RUN_DEV(SENAO,		RT3071),
282209918Sthompsa    RUN_DEV(SENAO,		RT3072_1),
283209918Sthompsa    RUN_DEV(SENAO,		RT3072_2),
284209918Sthompsa    RUN_DEV(SENAO,		RT3072_3),
285209918Sthompsa    RUN_DEV(SENAO,		RT3072_4),
286209918Sthompsa    RUN_DEV(SENAO,		RT3072_5),
287209918Sthompsa    RUN_DEV(SITECOMEU,		RT2770),
288209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_1),
289209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_2),
290209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_3),
291209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_4),
292209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070),
293209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070_2),
294209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070_3),
295209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070_4),
296209918Sthompsa    RUN_DEV(SITECOMEU,		RT3071),
297209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_1),
298209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_2),
299209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_3),
300209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_4),
301209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_5),
302209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_6),
303209918Sthompsa    RUN_DEV(SITECOMEU,		WL608),
304209918Sthompsa    RUN_DEV(SPARKLAN,		RT2870_1),
305209918Sthompsa    RUN_DEV(SPARKLAN,		RT3070),
306209918Sthompsa    RUN_DEV(SWEEX2,		LW153),
307209918Sthompsa    RUN_DEV(SWEEX2,		LW303),
308209918Sthompsa    RUN_DEV(SWEEX2,		LW313),
309209918Sthompsa    RUN_DEV(TOSHIBA,		RT3070),
310209918Sthompsa    RUN_DEV(UMEDIA,		RT2870_1),
311209918Sthompsa    RUN_DEV(ZCOM,		RT2870_1),
312209918Sthompsa    RUN_DEV(ZCOM,		RT2870_2),
313209918Sthompsa    RUN_DEV(ZINWELL,		RT2870_1),
314209918Sthompsa    RUN_DEV(ZINWELL,		RT2870_2),
315209918Sthompsa    RUN_DEV(ZINWELL,		RT3070),
316209918Sthompsa    RUN_DEV(ZINWELL,		RT3072_1),
317209918Sthompsa    RUN_DEV(ZINWELL,		RT3072_2),
318209918Sthompsa    RUN_DEV(ZYXEL,		RT2870_1),
319209918Sthompsa    RUN_DEV(ZYXEL,		RT2870_2),
320263985Shselasky    RUN_DEV(ZYXEL,		RT3070),
321262465Skevlo    RUN_DEV_EJECT(ZYXEL,	NWD2705),
322259812Skevlo    RUN_DEV_EJECT(RALINK,	RT_STOR),
323259812Skevlo#undef RUN_DEV_EJECT
324209918Sthompsa#undef RUN_DEV
325203134Sthompsa};
326203134Sthompsa
327203134Sthompsastatic device_probe_t	run_match;
328203134Sthompsastatic device_attach_t	run_attach;
329203134Sthompsastatic device_detach_t	run_detach;
330203134Sthompsa
331203134Sthompsastatic usb_callback_t	run_bulk_rx_callback;
332203134Sthompsastatic usb_callback_t	run_bulk_tx_callback0;
333203134Sthompsastatic usb_callback_t	run_bulk_tx_callback1;
334203134Sthompsastatic usb_callback_t	run_bulk_tx_callback2;
335203134Sthompsastatic usb_callback_t	run_bulk_tx_callback3;
336203134Sthompsastatic usb_callback_t	run_bulk_tx_callback4;
337203134Sthompsastatic usb_callback_t	run_bulk_tx_callback5;
338203134Sthompsa
339259812Skevlostatic void	run_autoinst(void *, struct usb_device *,
340259812Skevlo		    struct usb_attach_arg *);
341259812Skevlostatic int	run_driver_loaded(struct module *, int, void *);
342203134Sthompsastatic void	run_bulk_tx_callbackN(struct usb_xfer *xfer,
343257429Shselasky		    usb_error_t error, u_int index);
344203134Sthompsastatic struct ieee80211vap *run_vap_create(struct ieee80211com *,
345228621Sbschmidt		    const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
346228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN],
347228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN]);
348203134Sthompsastatic void	run_vap_delete(struct ieee80211vap *);
349208019Sthompsastatic void	run_cmdq_cb(void *, int);
350203134Sthompsastatic void	run_setup_tx_list(struct run_softc *,
351203134Sthompsa		    struct run_endpoint_queue *);
352203134Sthompsastatic void	run_unsetup_tx_list(struct run_softc *,
353203134Sthompsa		    struct run_endpoint_queue *);
354203134Sthompsastatic int	run_load_microcode(struct run_softc *);
355203134Sthompsastatic int	run_reset(struct run_softc *);
356203134Sthompsastatic usb_error_t run_do_request(struct run_softc *,
357203134Sthompsa		    struct usb_device_request *, void *);
358203134Sthompsastatic int	run_read(struct run_softc *, uint16_t, uint32_t *);
359203134Sthompsastatic int	run_read_region_1(struct run_softc *, uint16_t, uint8_t *, int);
360203134Sthompsastatic int	run_write_2(struct run_softc *, uint16_t, uint16_t);
361203134Sthompsastatic int	run_write(struct run_softc *, uint16_t, uint32_t);
362203134Sthompsastatic int	run_write_region_1(struct run_softc *, uint16_t,
363203134Sthompsa		    const uint8_t *, int);
364203134Sthompsastatic int	run_set_region_4(struct run_softc *, uint16_t, uint32_t, int);
365259544Skevlostatic int	run_efuse_read(struct run_softc *, uint16_t, uint16_t *, int);
366203134Sthompsastatic int	run_efuse_read_2(struct run_softc *, uint16_t, uint16_t *);
367203134Sthompsastatic int	run_eeprom_read_2(struct run_softc *, uint16_t, uint16_t *);
368258733Skevlostatic int	run_rt2870_rf_write(struct run_softc *, uint32_t);
369203134Sthompsastatic int	run_rt3070_rf_read(struct run_softc *, uint8_t, uint8_t *);
370203134Sthompsastatic int	run_rt3070_rf_write(struct run_softc *, uint8_t, uint8_t);
371203134Sthompsastatic int	run_bbp_read(struct run_softc *, uint8_t, uint8_t *);
372203134Sthompsastatic int	run_bbp_write(struct run_softc *, uint8_t, uint8_t);
373203134Sthompsastatic int	run_mcu_cmd(struct run_softc *, uint8_t, uint16_t);
374257955Skevlostatic const char *run_get_rf(uint16_t);
375260219Skevlostatic void	run_rt3593_get_txpower(struct run_softc *);
376260219Skevlostatic void	run_get_txpower(struct run_softc *);
377203134Sthompsastatic int	run_read_eeprom(struct run_softc *);
378203134Sthompsastatic struct ieee80211_node *run_node_alloc(struct ieee80211vap *,
379203134Sthompsa			    const uint8_t mac[IEEE80211_ADDR_LEN]);
380203134Sthompsastatic int	run_media_change(struct ifnet *);
381203134Sthompsastatic int	run_newstate(struct ieee80211vap *, enum ieee80211_state, int);
382203134Sthompsastatic int	run_wme_update(struct ieee80211com *);
383208019Sthompsastatic void	run_wme_update_cb(void *);
384208019Sthompsastatic void	run_key_set_cb(void *);
385288635Sadrianstatic int	run_key_set(struct ieee80211vap *, struct ieee80211_key *);
386208019Sthompsastatic void	run_key_delete_cb(void *);
387208019Sthompsastatic int	run_key_delete(struct ieee80211vap *, struct ieee80211_key *);
388206358Srpaulostatic void	run_ratectl_to(void *);
389206358Srpaulostatic void	run_ratectl_cb(void *, int);
390208019Sthompsastatic void	run_drain_fifo(void *);
391203134Sthompsastatic void	run_iter_func(void *, struct ieee80211_node *);
392208019Sthompsastatic void	run_newassoc_cb(void *);
393203134Sthompsastatic void	run_newassoc(struct ieee80211_node *, int);
394288603Sadrianstatic void	run_recv_mgmt(struct ieee80211_node *, struct mbuf *, int,
395288603Sadrian		    const struct ieee80211_rx_stats *, int, int);
396203134Sthompsastatic void	run_rx_frame(struct run_softc *, struct mbuf *, uint32_t);
397203134Sthompsastatic void	run_tx_free(struct run_endpoint_queue *pq,
398203134Sthompsa		    struct run_tx_data *, int);
399208019Sthompsastatic void	run_set_tx_desc(struct run_softc *, struct run_tx_data *);
400203134Sthompsastatic int	run_tx(struct run_softc *, struct mbuf *,
401203134Sthompsa		    struct ieee80211_node *);
402203134Sthompsastatic int	run_tx_mgt(struct run_softc *, struct mbuf *,
403203134Sthompsa		    struct ieee80211_node *);
404203134Sthompsastatic int	run_sendprot(struct run_softc *, const struct mbuf *,
405203134Sthompsa		    struct ieee80211_node *, int, int);
406203134Sthompsastatic int	run_tx_param(struct run_softc *, struct mbuf *,
407203134Sthompsa		    struct ieee80211_node *,
408203134Sthompsa		    const struct ieee80211_bpf_params *);
409203134Sthompsastatic int	run_raw_xmit(struct ieee80211_node *, struct mbuf *,
410203134Sthompsa		    const struct ieee80211_bpf_params *);
411287197Sglebiusstatic int	run_transmit(struct ieee80211com *, struct mbuf *);
412287197Sglebiusstatic void	run_start(struct run_softc *);
413287197Sglebiusstatic void	run_parent(struct ieee80211com *);
414259544Skevlostatic void	run_iq_calib(struct run_softc *, u_int);
415205042Sthompsastatic void	run_set_agc(struct run_softc *, uint8_t);
416203134Sthompsastatic void	run_select_chan_group(struct run_softc *, int);
417203134Sthompsastatic void	run_set_rx_antenna(struct run_softc *, int);
418203134Sthompsastatic void	run_rt2870_set_chan(struct run_softc *, u_int);
419203134Sthompsastatic void	run_rt3070_set_chan(struct run_softc *, u_int);
420205042Sthompsastatic void	run_rt3572_set_chan(struct run_softc *, u_int);
421260219Skevlostatic void	run_rt3593_set_chan(struct run_softc *, u_int);
422257955Skevlostatic void	run_rt5390_set_chan(struct run_softc *, u_int);
423259032Skevlostatic void	run_rt5592_set_chan(struct run_softc *, u_int);
424203134Sthompsastatic int	run_set_chan(struct run_softc *, struct ieee80211_channel *);
425203134Sthompsastatic void	run_set_channel(struct ieee80211com *);
426203134Sthompsastatic void	run_scan_start(struct ieee80211com *);
427203134Sthompsastatic void	run_scan_end(struct ieee80211com *);
428203134Sthompsastatic void	run_update_beacon(struct ieee80211vap *, int);
429208019Sthompsastatic void	run_update_beacon_cb(void *);
430203134Sthompsastatic void	run_updateprot(struct ieee80211com *);
431218492Sbschmidtstatic void	run_updateprot_cb(void *);
432208019Sthompsastatic void	run_usb_timeout_cb(void *);
433203134Sthompsastatic void	run_reset_livelock(struct run_softc *);
434203134Sthompsastatic void	run_enable_tsf_sync(struct run_softc *);
435287555Skevlostatic void	run_enable_tsf(struct run_softc *);
436287554Skevlostatic void	run_get_tsf(struct run_softc *, uint64_t *);
437203134Sthompsastatic void	run_enable_mrr(struct run_softc *);
438203134Sthompsastatic void	run_set_txpreamble(struct run_softc *);
439203134Sthompsastatic void	run_set_basicrates(struct run_softc *);
440203134Sthompsastatic void	run_set_leds(struct run_softc *, uint16_t);
441203134Sthompsastatic void	run_set_bssid(struct run_softc *, const uint8_t *);
442203134Sthompsastatic void	run_set_macaddr(struct run_softc *, const uint8_t *);
443283540Sglebiusstatic void	run_updateslot(struct ieee80211com *);
444218492Sbschmidtstatic void	run_updateslot_cb(void *);
445283540Sglebiusstatic void	run_update_mcast(struct ieee80211com *);
446203134Sthompsastatic int8_t	run_rssi2dbm(struct run_softc *, uint8_t, uint8_t);
447283540Sglebiusstatic void	run_update_promisc_locked(struct run_softc *);
448283540Sglebiusstatic void	run_update_promisc(struct ieee80211com *);
449257955Skevlostatic void	run_rt5390_bbp_init(struct run_softc *);
450203134Sthompsastatic int	run_bbp_init(struct run_softc *);
451203134Sthompsastatic int	run_rt3070_rf_init(struct run_softc *);
452260219Skevlostatic void	run_rt3593_rf_init(struct run_softc *);
453257955Skevlostatic void	run_rt5390_rf_init(struct run_softc *);
454203134Sthompsastatic int	run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t,
455203134Sthompsa		    uint8_t *);
456205042Sthompsastatic void	run_rt3070_rf_setup(struct run_softc *);
457260219Skevlostatic void	run_rt3593_rf_setup(struct run_softc *);
458260219Skevlostatic void	run_rt5390_rf_setup(struct run_softc *);
459203134Sthompsastatic int	run_txrx_enable(struct run_softc *);
460257955Skevlostatic void	run_adjust_freq_offset(struct run_softc *);
461203134Sthompsastatic void	run_init_locked(struct run_softc *);
462203134Sthompsastatic void	run_stop(void *);
463257429Shselaskystatic void	run_delay(struct run_softc *, u_int);
464203134Sthompsa
465259812Skevlostatic eventhandler_tag run_etag;
466259812Skevlo
467259544Skevlostatic const struct rt2860_rate {
468259544Skevlo	uint8_t		rate;
469259544Skevlo	uint8_t		mcs;
470259544Skevlo	enum		ieee80211_phytype phy;
471259544Skevlo	uint8_t		ctl_ridx;
472259544Skevlo	uint16_t	sp_ack_dur;
473259544Skevlo	uint16_t	lp_ack_dur;
474259544Skevlo} rt2860_rates[] = {
475259544Skevlo	{   2, 0, IEEE80211_T_DS,   0, 314, 314 },
476259544Skevlo	{   4, 1, IEEE80211_T_DS,   1, 258, 162 },
477259544Skevlo	{  11, 2, IEEE80211_T_DS,   2, 223, 127 },
478259544Skevlo	{  22, 3, IEEE80211_T_DS,   3, 213, 117 },
479259544Skevlo	{  12, 0, IEEE80211_T_OFDM, 4,  60,  60 },
480259544Skevlo	{  18, 1, IEEE80211_T_OFDM, 4,  52,  52 },
481259544Skevlo	{  24, 2, IEEE80211_T_OFDM, 6,  48,  48 },
482259544Skevlo	{  36, 3, IEEE80211_T_OFDM, 6,  44,  44 },
483259544Skevlo	{  48, 4, IEEE80211_T_OFDM, 8,  44,  44 },
484259544Skevlo	{  72, 5, IEEE80211_T_OFDM, 8,  40,  40 },
485259544Skevlo	{  96, 6, IEEE80211_T_OFDM, 8,  40,  40 },
486259544Skevlo	{ 108, 7, IEEE80211_T_OFDM, 8,  40,  40 }
487259544Skevlo};
488259544Skevlo
489203134Sthompsastatic const struct {
490208019Sthompsa	uint16_t	reg;
491203134Sthompsa	uint32_t	val;
492203134Sthompsa} rt2870_def_mac[] = {
493203134Sthompsa	RT2870_DEF_MAC
494203134Sthompsa};
495203134Sthompsa
496203134Sthompsastatic const struct {
497203134Sthompsa	uint8_t	reg;
498203134Sthompsa	uint8_t	val;
499203134Sthompsa} rt2860_def_bbp[] = {
500203134Sthompsa	RT2860_DEF_BBP
501257955Skevlo},rt5390_def_bbp[] = {
502257955Skevlo	RT5390_DEF_BBP
503259032Skevlo},rt5592_def_bbp[] = {
504259032Skevlo	RT5592_DEF_BBP
505203134Sthompsa};
506203134Sthompsa
507259032Skevlo/*
508259032Skevlo * Default values for BBP register R196 for RT5592.
509259032Skevlo */
510259032Skevlostatic const uint8_t rt5592_bbp_r196[] = {
511259032Skevlo	0xe0, 0x1f, 0x38, 0x32, 0x08, 0x28, 0x19, 0x0a, 0xff, 0x00,
512259032Skevlo	0x16, 0x10, 0x10, 0x0b, 0x36, 0x2c, 0x26, 0x24, 0x42, 0x36,
513259032Skevlo	0x30, 0x2d, 0x4c, 0x46, 0x3d, 0x40, 0x3e, 0x42, 0x3d, 0x40,
514259032Skevlo	0x3c, 0x34, 0x2c, 0x2f, 0x3c, 0x35, 0x2e, 0x2a, 0x49, 0x41,
515259032Skevlo	0x36, 0x31, 0x30, 0x30, 0x0e, 0x0d, 0x28, 0x21, 0x1c, 0x16,
516259032Skevlo	0x50, 0x4a, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00,
517259032Skevlo	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
518259032Skevlo	0x00, 0x00, 0x7d, 0x14, 0x32, 0x2c, 0x36, 0x4c, 0x43, 0x2c,
519259032Skevlo	0x2e, 0x36, 0x30, 0x6e
520259032Skevlo};
521259032Skevlo
522203134Sthompsastatic const struct rfprog {
523203134Sthompsa	uint8_t		chan;
524203134Sthompsa	uint32_t	r1, r2, r3, r4;
525203134Sthompsa} rt2860_rf2850[] = {
526203134Sthompsa	RT2860_RF2850
527203134Sthompsa};
528203134Sthompsa
529203134Sthompsastruct {
530203134Sthompsa	uint8_t	n, r, k;
531205042Sthompsa} rt3070_freqs[] = {
532205042Sthompsa	RT3070_RF3052
533203134Sthompsa};
534203134Sthompsa
535259032Skevlostatic const struct rt5592_freqs {
536259032Skevlo	uint16_t	n;
537259032Skevlo	uint8_t		k, m, r;
538259032Skevlo} rt5592_freqs_20mhz[] = {
539259032Skevlo	RT5592_RF5592_20MHZ
540259032Skevlo},rt5592_freqs_40mhz[] = {
541259032Skevlo	RT5592_RF5592_40MHZ
542259032Skevlo};
543259032Skevlo
544203134Sthompsastatic const struct {
545203134Sthompsa	uint8_t	reg;
546203134Sthompsa	uint8_t	val;
547203134Sthompsa} rt3070_def_rf[] = {
548203134Sthompsa	RT3070_DEF_RF
549205042Sthompsa},rt3572_def_rf[] = {
550205042Sthompsa	RT3572_DEF_RF
551260219Skevlo},rt3593_def_rf[] = {
552260219Skevlo	RT3593_DEF_RF
553257955Skevlo},rt5390_def_rf[] = {
554257955Skevlo	RT5390_DEF_RF
555257955Skevlo},rt5392_def_rf[] = {
556257955Skevlo	RT5392_DEF_RF
557259032Skevlo},rt5592_def_rf[] = {
558259032Skevlo	RT5592_DEF_RF
559259032Skevlo},rt5592_2ghz_def_rf[] = {
560259032Skevlo	RT5592_2GHZ_DEF_RF
561259032Skevlo},rt5592_5ghz_def_rf[] = {
562259032Skevlo	RT5592_5GHZ_DEF_RF
563203134Sthompsa};
564203134Sthompsa
565259032Skevlostatic const struct {
566259032Skevlo	u_int	firstchan;
567259032Skevlo	u_int	lastchan;
568259032Skevlo	uint8_t	reg;
569259032Skevlo	uint8_t	val;
570259032Skevlo} rt5592_chan_5ghz[] = {
571259032Skevlo	RT5592_CHAN_5GHZ
572259032Skevlo};
573259032Skevlo
574203134Sthompsastatic const struct usb_config run_config[RUN_N_XFER] = {
575203134Sthompsa    [RUN_BULK_TX_BE] = {
576203134Sthompsa	.type = UE_BULK,
577203134Sthompsa	.endpoint = UE_ADDR_ANY,
578203134Sthompsa	.ep_index = 0,
579203134Sthompsa	.direction = UE_DIR_OUT,
580203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
581203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
582203134Sthompsa	.callback = run_bulk_tx_callback0,
583203134Sthompsa	.timeout = 5000,	/* ms */
584203134Sthompsa    },
585203134Sthompsa    [RUN_BULK_TX_BK] = {
586203134Sthompsa	.type = UE_BULK,
587203134Sthompsa	.endpoint = UE_ADDR_ANY,
588203134Sthompsa	.direction = UE_DIR_OUT,
589203134Sthompsa	.ep_index = 1,
590203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
591203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
592203134Sthompsa	.callback = run_bulk_tx_callback1,
593203134Sthompsa	.timeout = 5000,	/* ms */
594203134Sthompsa    },
595203134Sthompsa    [RUN_BULK_TX_VI] = {
596203134Sthompsa	.type = UE_BULK,
597203134Sthompsa	.endpoint = UE_ADDR_ANY,
598203134Sthompsa	.direction = UE_DIR_OUT,
599203134Sthompsa	.ep_index = 2,
600203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
601203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
602203134Sthompsa	.callback = run_bulk_tx_callback2,
603203134Sthompsa	.timeout = 5000,	/* ms */
604203134Sthompsa    },
605203134Sthompsa    [RUN_BULK_TX_VO] = {
606203134Sthompsa	.type = UE_BULK,
607203134Sthompsa	.endpoint = UE_ADDR_ANY,
608203134Sthompsa	.direction = UE_DIR_OUT,
609203134Sthompsa	.ep_index = 3,
610203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
611203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
612203134Sthompsa	.callback = run_bulk_tx_callback3,
613203134Sthompsa	.timeout = 5000,	/* ms */
614203134Sthompsa    },
615203134Sthompsa    [RUN_BULK_TX_HCCA] = {
616203134Sthompsa	.type = UE_BULK,
617203134Sthompsa	.endpoint = UE_ADDR_ANY,
618203134Sthompsa	.direction = UE_DIR_OUT,
619203134Sthompsa	.ep_index = 4,
620203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
621203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
622203134Sthompsa	.callback = run_bulk_tx_callback4,
623203134Sthompsa	.timeout = 5000,	/* ms */
624203134Sthompsa    },
625203134Sthompsa    [RUN_BULK_TX_PRIO] = {
626203134Sthompsa	.type = UE_BULK,
627203134Sthompsa	.endpoint = UE_ADDR_ANY,
628203134Sthompsa	.direction = UE_DIR_OUT,
629203134Sthompsa	.ep_index = 5,
630203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
631203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
632203134Sthompsa	.callback = run_bulk_tx_callback5,
633203134Sthompsa	.timeout = 5000,	/* ms */
634203134Sthompsa    },
635203134Sthompsa    [RUN_BULK_RX] = {
636203134Sthompsa	.type = UE_BULK,
637203134Sthompsa	.endpoint = UE_ADDR_ANY,
638203134Sthompsa	.direction = UE_DIR_IN,
639203134Sthompsa	.bufsize = RUN_MAX_RXSZ,
640203134Sthompsa	.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
641203134Sthompsa	.callback = run_bulk_rx_callback,
642203134Sthompsa    }
643203134Sthompsa};
644203134Sthompsa
645259812Skevlostatic void
646259812Skevlorun_autoinst(void *arg, struct usb_device *udev,
647259812Skevlo    struct usb_attach_arg *uaa)
648259812Skevlo{
649259812Skevlo	struct usb_interface *iface;
650259812Skevlo	struct usb_interface_descriptor *id;
651259812Skevlo
652259812Skevlo	if (uaa->dev_state != UAA_DEV_READY)
653259812Skevlo		return;
654259812Skevlo
655259812Skevlo	iface = usbd_get_iface(udev, 0);
656259812Skevlo	if (iface == NULL)
657259812Skevlo		return;
658259812Skevlo	id = iface->idesc;
659259812Skevlo	if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
660259812Skevlo		return;
661259812Skevlo	if (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa))
662259812Skevlo		return;
663259812Skevlo
664259812Skevlo	if (usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT) == 0)
665259812Skevlo		uaa->dev_state = UAA_DEV_EJECTING;
666259812Skevlo}
667259812Skevlo
668220235Skevlostatic int
669259812Skevlorun_driver_loaded(struct module *mod, int what, void *arg)
670259812Skevlo{
671259812Skevlo	switch (what) {
672259812Skevlo	case MOD_LOAD:
673259812Skevlo		run_etag = EVENTHANDLER_REGISTER(usb_dev_configured,
674259812Skevlo		    run_autoinst, NULL, EVENTHANDLER_PRI_ANY);
675259812Skevlo		break;
676259812Skevlo	case MOD_UNLOAD:
677259812Skevlo		EVENTHANDLER_DEREGISTER(usb_dev_configured, run_etag);
678259812Skevlo		break;
679259812Skevlo	default:
680259812Skevlo		return (EOPNOTSUPP);
681259812Skevlo	}
682259812Skevlo	return (0);
683259812Skevlo}
684259812Skevlo
685259812Skevlostatic int
686203134Sthompsarun_match(device_t self)
687203134Sthompsa{
688203134Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(self);
689203134Sthompsa
690203134Sthompsa	if (uaa->usb_mode != USB_MODE_HOST)
691203134Sthompsa		return (ENXIO);
692203134Sthompsa	if (uaa->info.bConfigIndex != 0)
693203134Sthompsa		return (ENXIO);
694203134Sthompsa	if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX)
695203134Sthompsa		return (ENXIO);
696203134Sthompsa
697203134Sthompsa	return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa));
698203134Sthompsa}
699203134Sthompsa
700203134Sthompsastatic int
701203134Sthompsarun_attach(device_t self)
702203134Sthompsa{
703203134Sthompsa	struct run_softc *sc = device_get_softc(self);
704203134Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(self);
705287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
706205042Sthompsa	uint32_t ver;
707258082Skevlo	int ntries, error;
708203134Sthompsa	uint8_t iface_index, bands;
709203134Sthompsa
710203134Sthompsa	device_set_usb_desc(self);
711203134Sthompsa	sc->sc_udev = uaa->device;
712203134Sthompsa	sc->sc_dev = self;
713262465Skevlo	if (USB_GET_DRIVER_INFO(uaa) != RUN_EJECT)
714262465Skevlo		sc->sc_flags |= RUN_FLAG_FWLOAD_NEEDED;
715203134Sthompsa
716203134Sthompsa	mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev),
717203134Sthompsa	    MTX_NETWORK_LOCK, MTX_DEF);
718287197Sglebius	mbufq_init(&sc->sc_snd, ifqmaxlen);
719203134Sthompsa
720203134Sthompsa	iface_index = RT2860_IFACE_INDEX;
721208019Sthompsa
722203134Sthompsa	error = usbd_transfer_setup(uaa->device, &iface_index,
723203134Sthompsa	    sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx);
724203134Sthompsa	if (error) {
725205042Sthompsa		device_printf(self, "could not allocate USB transfers, "
726203134Sthompsa		    "err=%s\n", usbd_errstr(error));
727203134Sthompsa		goto detach;
728203134Sthompsa	}
729203134Sthompsa
730203134Sthompsa	RUN_LOCK(sc);
731203134Sthompsa
732203134Sthompsa	/* wait for the chip to settle */
733203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
734209917Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0) {
735203134Sthompsa			RUN_UNLOCK(sc);
736203134Sthompsa			goto detach;
737203134Sthompsa		}
738205042Sthompsa		if (ver != 0 && ver != 0xffffffff)
739203134Sthompsa			break;
740203134Sthompsa		run_delay(sc, 10);
741203134Sthompsa	}
742203134Sthompsa	if (ntries == 100) {
743203138Sthompsa		device_printf(sc->sc_dev,
744203138Sthompsa		    "timeout waiting for NIC to initialize\n");
745203134Sthompsa		RUN_UNLOCK(sc);
746203134Sthompsa		goto detach;
747203134Sthompsa	}
748205042Sthompsa	sc->mac_ver = ver >> 16;
749205042Sthompsa	sc->mac_rev = ver & 0xffff;
750203134Sthompsa
751203134Sthompsa	/* retrieve RF rev. no and various other things from EEPROM */
752203134Sthompsa	run_read_eeprom(sc);
753203134Sthompsa
754203138Sthompsa	device_printf(sc->sc_dev,
755203138Sthompsa	    "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n",
756205042Sthompsa	    sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev),
757287197Sglebius	    sc->ntxchains, sc->nrxchains, ether_sprintf(ic->ic_macaddr));
758203134Sthompsa
759203134Sthompsa	RUN_UNLOCK(sc);
760203134Sthompsa
761283537Sglebius	ic->ic_softc = sc;
762283527Sglebius	ic->ic_name = device_get_nameunit(self);
763203134Sthompsa	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
764203134Sthompsa	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
765208019Sthompsa
766203134Sthompsa	/* set device capabilities */
767203134Sthompsa	ic->ic_caps =
768203134Sthompsa	    IEEE80211_C_STA |		/* station mode supported */
769203134Sthompsa	    IEEE80211_C_MONITOR |	/* monitor mode supported */
770203134Sthompsa	    IEEE80211_C_IBSS |
771203134Sthompsa	    IEEE80211_C_HOSTAP |
772208019Sthompsa	    IEEE80211_C_WDS |		/* 4-address traffic works */
773208019Sthompsa	    IEEE80211_C_MBSS |
774203134Sthompsa	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
775203134Sthompsa	    IEEE80211_C_SHSLOT |	/* short slot time supported */
776203134Sthompsa	    IEEE80211_C_WME |		/* WME */
777214894Sbschmidt	    IEEE80211_C_WPA;		/* WPA1|WPA2(RSN) */
778203134Sthompsa
779203134Sthompsa	ic->ic_cryptocaps =
780203134Sthompsa	    IEEE80211_CRYPTO_WEP |
781203134Sthompsa	    IEEE80211_CRYPTO_AES_CCM |
782203134Sthompsa	    IEEE80211_CRYPTO_TKIPMIC |
783203134Sthompsa	    IEEE80211_CRYPTO_TKIP;
784203134Sthompsa
785203134Sthompsa	ic->ic_flags |= IEEE80211_F_DATAPAD;
786203134Sthompsa	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;
787203134Sthompsa
788203134Sthompsa	bands = 0;
789203134Sthompsa	setbit(&bands, IEEE80211_MODE_11B);
790203134Sthompsa	setbit(&bands, IEEE80211_MODE_11G);
791258082Skevlo	if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850 ||
792260219Skevlo	    sc->rf_rev == RT3070_RF_3052 || sc->rf_rev == RT3593_RF_3053 ||
793260219Skevlo	    sc->rf_rev == RT5592_RF_5592)
794258082Skevlo		setbit(&bands, IEEE80211_MODE_11A);
795203134Sthompsa	ieee80211_init_channels(ic, NULL, &bands);
796203134Sthompsa
797287197Sglebius	ieee80211_ifattach(ic);
798203134Sthompsa
799203134Sthompsa	ic->ic_scan_start = run_scan_start;
800203134Sthompsa	ic->ic_scan_end = run_scan_end;
801203134Sthompsa	ic->ic_set_channel = run_set_channel;
802203134Sthompsa	ic->ic_node_alloc = run_node_alloc;
803203134Sthompsa	ic->ic_newassoc = run_newassoc;
804218492Sbschmidt	ic->ic_updateslot = run_updateslot;
805208019Sthompsa	ic->ic_update_mcast = run_update_mcast;
806203134Sthompsa	ic->ic_wme.wme_update = run_wme_update;
807203134Sthompsa	ic->ic_raw_xmit = run_raw_xmit;
808203134Sthompsa	ic->ic_update_promisc = run_update_promisc;
809203134Sthompsa	ic->ic_vap_create = run_vap_create;
810203134Sthompsa	ic->ic_vap_delete = run_vap_delete;
811287197Sglebius	ic->ic_transmit = run_transmit;
812287197Sglebius	ic->ic_parent = run_parent;
813203134Sthompsa
814203134Sthompsa	ieee80211_radiotap_attach(ic,
815203134Sthompsa	    &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
816203134Sthompsa		RUN_TX_RADIOTAP_PRESENT,
817203134Sthompsa	    &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
818203134Sthompsa		RUN_RX_RADIOTAP_PRESENT);
819203134Sthompsa
820208019Sthompsa	TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc);
821208019Sthompsa	TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc);
822257712Shselasky	usb_callout_init_mtx(&sc->ratectl_ch, &sc->sc_mtx, 0);
823208019Sthompsa
824203134Sthompsa	if (bootverbose)
825203134Sthompsa		ieee80211_announce(ic);
826203134Sthompsa
827209917Sthompsa	return (0);
828203134Sthompsa
829203134Sthompsadetach:
830203134Sthompsa	run_detach(self);
831209917Sthompsa	return (ENXIO);
832203134Sthompsa}
833203134Sthompsa
834203134Sthompsastatic int
835203134Sthompsarun_detach(device_t self)
836203134Sthompsa{
837203134Sthompsa	struct run_softc *sc = device_get_softc(self);
838287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
839203134Sthompsa	int i;
840203134Sthompsa
841246614Shselasky	RUN_LOCK(sc);
842246614Shselasky	sc->sc_detached = 1;
843246614Shselasky	RUN_UNLOCK(sc);
844246614Shselasky
845203134Sthompsa	/* stop all USB transfers */
846203134Sthompsa	usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER);
847203134Sthompsa
848203134Sthompsa	RUN_LOCK(sc);
849209144Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
850209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set = RUN_CMDQ_ABORT;
851209144Sthompsa
852203134Sthompsa	/* free TX list, if any */
853203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
854203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
855203134Sthompsa	RUN_UNLOCK(sc);
856203134Sthompsa
857287197Sglebius	if (sc->sc_ic.ic_softc == sc) {
858208019Sthompsa		/* drain tasks */
859208019Sthompsa		usb_callout_drain(&sc->ratectl_ch);
860208019Sthompsa		ieee80211_draintask(ic, &sc->cmdq_task);
861208019Sthompsa		ieee80211_draintask(ic, &sc->ratectl_task);
862203134Sthompsa		ieee80211_ifdetach(ic);
863203134Sthompsa	}
864203134Sthompsa
865287197Sglebius	mbufq_drain(&sc->sc_snd);
866203134Sthompsa	mtx_destroy(&sc->sc_mtx);
867203134Sthompsa
868203134Sthompsa	return (0);
869203134Sthompsa}
870203134Sthompsa
871203134Sthompsastatic struct ieee80211vap *
872228621Sbschmidtrun_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
873228621Sbschmidt    enum ieee80211_opmode opmode, int flags,
874203134Sthompsa    const uint8_t bssid[IEEE80211_ADDR_LEN],
875203134Sthompsa    const uint8_t mac[IEEE80211_ADDR_LEN])
876203134Sthompsa{
877286950Sadrian	struct run_softc *sc = ic->ic_softc;
878203134Sthompsa	struct run_vap *rvp;
879203134Sthompsa	struct ieee80211vap *vap;
880208019Sthompsa	int i;
881203134Sthompsa
882209917Sthompsa	if (sc->rvp_cnt >= RUN_VAP_MAX) {
883287197Sglebius		device_printf(sc->sc_dev, "number of VAPs maxed out\n");
884209917Sthompsa		return (NULL);
885208019Sthompsa	}
886208019Sthompsa
887208019Sthompsa	switch (opmode) {
888208019Sthompsa	case IEEE80211_M_STA:
889208019Sthompsa		/* enable s/w bmiss handling for sta mode */
890208019Sthompsa		flags |= IEEE80211_CLONE_NOBEACONS;
891208019Sthompsa		/* fall though */
892208019Sthompsa	case IEEE80211_M_IBSS:
893208019Sthompsa	case IEEE80211_M_MONITOR:
894208019Sthompsa	case IEEE80211_M_HOSTAP:
895208019Sthompsa	case IEEE80211_M_MBSS:
896208019Sthompsa		/* other than WDS vaps, only one at a time */
897208019Sthompsa		if (!TAILQ_EMPTY(&ic->ic_vaps))
898209917Sthompsa			return (NULL);
899208019Sthompsa		break;
900208019Sthompsa	case IEEE80211_M_WDS:
901208019Sthompsa		TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next){
902208019Sthompsa			if(vap->iv_opmode != IEEE80211_M_HOSTAP)
903208019Sthompsa				continue;
904208019Sthompsa			/* WDS vap's always share the local mac address. */
905208019Sthompsa			flags &= ~IEEE80211_CLONE_BSSID;
906208019Sthompsa			break;
907208019Sthompsa		}
908209917Sthompsa		if (vap == NULL) {
909287197Sglebius			device_printf(sc->sc_dev,
910287197Sglebius			    "wds only supported in ap mode\n");
911209917Sthompsa			return (NULL);
912208019Sthompsa		}
913208019Sthompsa		break;
914208019Sthompsa	default:
915287197Sglebius		device_printf(sc->sc_dev, "unknown opmode %d\n", opmode);
916209917Sthompsa		return (NULL);
917208019Sthompsa	}
918208019Sthompsa
919287197Sglebius	rvp = malloc(sizeof(struct run_vap), M_80211_VAP, M_WAITOK | M_ZERO);
920203134Sthompsa	vap = &rvp->vap;
921203134Sthompsa
922287197Sglebius	if (ieee80211_vap_setup(ic, vap, name, unit, opmode, flags,
923287197Sglebius	    bssid) != 0) {
924257743Shselasky		/* out of memory */
925257743Shselasky		free(rvp, M_80211_VAP);
926257743Shselasky		return (NULL);
927257743Shselasky	}
928257743Shselasky
929203134Sthompsa	vap->iv_update_beacon = run_update_beacon;
930208019Sthompsa	vap->iv_max_aid = RT2870_WCID_MAX;
931208019Sthompsa	/*
932208019Sthompsa	 * To delete the right key from h/w, we need wcid.
933208019Sthompsa	 * Luckily, there is unused space in ieee80211_key{}, wk_pad,
934208019Sthompsa	 * and matching wcid will be written into there. So, cast
935208019Sthompsa	 * some spells to remove 'const' from ieee80211_key{}
936208019Sthompsa	 */
937208019Sthompsa	vap->iv_key_delete = (void *)run_key_delete;
938208019Sthompsa	vap->iv_key_set = (void *)run_key_set;
939203134Sthompsa
940203134Sthompsa	/* override state transition machine */
941203134Sthompsa	rvp->newstate = vap->iv_newstate;
942203134Sthompsa	vap->iv_newstate = run_newstate;
943288603Sadrian	if (opmode == IEEE80211_M_IBSS) {
944288603Sadrian		rvp->recv_mgmt = vap->iv_recv_mgmt;
945288603Sadrian		vap->iv_recv_mgmt = run_recv_mgmt;
946288603Sadrian	}
947203134Sthompsa
948206358Srpaulo	ieee80211_ratectl_init(vap);
949206358Srpaulo	ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */);
950203134Sthompsa
951203134Sthompsa	/* complete setup */
952287197Sglebius	ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status,
953287197Sglebius	    mac);
954208019Sthompsa
955208019Sthompsa	/* make sure id is always unique */
956209917Sthompsa	for (i = 0; i < RUN_VAP_MAX; i++) {
957208019Sthompsa		if((sc->rvp_bmap & 1 << i) == 0){
958208019Sthompsa			sc->rvp_bmap |= 1 << i;
959208019Sthompsa			rvp->rvp_id = i;
960208019Sthompsa			break;
961208019Sthompsa		}
962208019Sthompsa	}
963209917Sthompsa	if (sc->rvp_cnt++ == 0)
964208019Sthompsa		ic->ic_opmode = opmode;
965208019Sthompsa
966209917Sthompsa	if (opmode == IEEE80211_M_HOSTAP)
967209144Sthompsa		sc->cmdq_run = RUN_CMDQ_GO;
968209144Sthompsa
969208019Sthompsa	DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n",
970208019Sthompsa	    rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt);
971208019Sthompsa
972209917Sthompsa	return (vap);
973203134Sthompsa}
974203134Sthompsa
975203134Sthompsastatic void
976203134Sthompsarun_vap_delete(struct ieee80211vap *vap)
977203134Sthompsa{
978203134Sthompsa	struct run_vap *rvp = RUN_VAP(vap);
979203134Sthompsa	struct ieee80211com *ic;
980203134Sthompsa	struct run_softc *sc;
981208019Sthompsa	uint8_t rvp_id;
982203134Sthompsa
983209917Sthompsa	if (vap == NULL)
984203134Sthompsa		return;
985203134Sthompsa
986203134Sthompsa	ic = vap->iv_ic;
987286950Sadrian	sc = ic->ic_softc;
988203134Sthompsa
989205042Sthompsa	RUN_LOCK(sc);
990208019Sthompsa
991218492Sbschmidt	m_freem(rvp->beacon_mbuf);
992218492Sbschmidt	rvp->beacon_mbuf = NULL;
993218492Sbschmidt
994208019Sthompsa	rvp_id = rvp->rvp_id;
995208019Sthompsa	sc->ratectl_run &= ~(1 << rvp_id);
996208019Sthompsa	sc->rvp_bmap &= ~(1 << rvp_id);
997208019Sthompsa	run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128);
998208019Sthompsa	run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512);
999208019Sthompsa	--sc->rvp_cnt;
1000208019Sthompsa
1001208019Sthompsa	DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n",
1002208019Sthompsa	    vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt);
1003208019Sthompsa
1004205042Sthompsa	RUN_UNLOCK(sc);
1005203134Sthompsa
1006206358Srpaulo	ieee80211_ratectl_deinit(vap);
1007203134Sthompsa	ieee80211_vap_detach(vap);
1008203134Sthompsa	free(rvp, M_80211_VAP);
1009203134Sthompsa}
1010203134Sthompsa
1011208019Sthompsa/*
1012208019Sthompsa * There are numbers of functions need to be called in context thread.
1013208019Sthompsa * Rather than creating taskqueue event for each of those functions,
1014208019Sthompsa * here is all-for-one taskqueue callback function. This function
1015208019Sthompsa * gurantees deferred functions are executed in the same order they
1016208019Sthompsa * were enqueued.
1017208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[].
1018208019Sthompsa */
1019203134Sthompsastatic void
1020208019Sthompsarun_cmdq_cb(void *arg, int pending)
1021208019Sthompsa{
1022208019Sthompsa	struct run_softc *sc = arg;
1023208019Sthompsa	uint8_t i;
1024208019Sthompsa
1025208019Sthompsa	/* call cmdq[].func locked */
1026208019Sthompsa	RUN_LOCK(sc);
1027209917Sthompsa	for (i = sc->cmdq_exec; sc->cmdq[i].func && pending;
1028209917Sthompsa	    i = sc->cmdq_exec, pending--) {
1029208019Sthompsa		DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending);
1030209917Sthompsa		if (sc->cmdq_run == RUN_CMDQ_GO) {
1031208019Sthompsa			/*
1032208019Sthompsa			 * If arg0 is NULL, callback func needs more
1033208019Sthompsa			 * than one arg. So, pass ptr to cmdq struct.
1034208019Sthompsa			 */
1035209917Sthompsa			if (sc->cmdq[i].arg0)
1036208019Sthompsa				sc->cmdq[i].func(sc->cmdq[i].arg0);
1037208019Sthompsa			else
1038208019Sthompsa				sc->cmdq[i].func(&sc->cmdq[i]);
1039208019Sthompsa		}
1040208019Sthompsa		sc->cmdq[i].arg0 = NULL;
1041208019Sthompsa		sc->cmdq[i].func = NULL;
1042208019Sthompsa		sc->cmdq_exec++;
1043208019Sthompsa		sc->cmdq_exec &= RUN_CMDQ_MASQ;
1044208019Sthompsa	}
1045208019Sthompsa	RUN_UNLOCK(sc);
1046208019Sthompsa}
1047208019Sthompsa
1048208019Sthompsastatic void
1049203134Sthompsarun_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
1050203134Sthompsa{
1051203134Sthompsa	struct run_tx_data *data;
1052203134Sthompsa
1053203134Sthompsa	memset(pq, 0, sizeof(*pq));
1054203134Sthompsa
1055203134Sthompsa	STAILQ_INIT(&pq->tx_qh);
1056203134Sthompsa	STAILQ_INIT(&pq->tx_fh);
1057203134Sthompsa
1058203134Sthompsa	for (data = &pq->tx_data[0];
1059203134Sthompsa	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
1060203134Sthompsa		data->sc = sc;
1061203134Sthompsa		STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
1062203134Sthompsa	}
1063203134Sthompsa	pq->tx_nfree = RUN_TX_RING_COUNT;
1064203134Sthompsa}
1065203134Sthompsa
1066203134Sthompsastatic void
1067203134Sthompsarun_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
1068203134Sthompsa{
1069203134Sthompsa	struct run_tx_data *data;
1070203134Sthompsa
1071203134Sthompsa	/* make sure any subsequent use of the queues will fail */
1072203134Sthompsa	pq->tx_nfree = 0;
1073203134Sthompsa	STAILQ_INIT(&pq->tx_fh);
1074203134Sthompsa	STAILQ_INIT(&pq->tx_qh);
1075203134Sthompsa
1076203134Sthompsa	/* free up all node references and mbufs */
1077203134Sthompsa	for (data = &pq->tx_data[0];
1078209917Sthompsa	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
1079203134Sthompsa		if (data->m != NULL) {
1080203134Sthompsa			m_freem(data->m);
1081203134Sthompsa			data->m = NULL;
1082203134Sthompsa		}
1083203134Sthompsa		if (data->ni != NULL) {
1084203134Sthompsa			ieee80211_free_node(data->ni);
1085203134Sthompsa			data->ni = NULL;
1086203134Sthompsa		}
1087203134Sthompsa	}
1088203134Sthompsa}
1089203134Sthompsa
1090220235Skevlostatic int
1091203134Sthompsarun_load_microcode(struct run_softc *sc)
1092203134Sthompsa{
1093203134Sthompsa	usb_device_request_t req;
1094203137Sthompsa	const struct firmware *fw;
1095203134Sthompsa	const u_char *base;
1096203134Sthompsa	uint32_t tmp;
1097203134Sthompsa	int ntries, error;
1098203134Sthompsa	const uint64_t *temp;
1099203134Sthompsa	uint64_t bytes;
1100203134Sthompsa
1101205042Sthompsa	RUN_UNLOCK(sc);
1102203137Sthompsa	fw = firmware_get("runfw");
1103205042Sthompsa	RUN_LOCK(sc);
1104209917Sthompsa	if (fw == NULL) {
1105203138Sthompsa		device_printf(sc->sc_dev,
1106203138Sthompsa		    "failed loadfirmware of file %s\n", "runfw");
1107203134Sthompsa		return ENOENT;
1108203134Sthompsa	}
1109203134Sthompsa
1110203137Sthompsa	if (fw->datasize != 8192) {
1111203138Sthompsa		device_printf(sc->sc_dev,
1112203138Sthompsa		    "invalid firmware size (should be 8KB)\n");
1113203137Sthompsa		error = EINVAL;
1114203137Sthompsa		goto fail;
1115203134Sthompsa	}
1116203134Sthompsa
1117203134Sthompsa	/*
1118203134Sthompsa	 * RT3071/RT3072 use a different firmware
1119203134Sthompsa	 * run-rt2870 (8KB) contains both,
1120203134Sthompsa	 * first half (4KB) is for rt2870,
1121203134Sthompsa	 * last half is for rt3071.
1122203134Sthompsa	 */
1123203137Sthompsa	base = fw->data;
1124205042Sthompsa	if ((sc->mac_ver) != 0x2860 &&
1125205042Sthompsa	    (sc->mac_ver) != 0x2872 &&
1126209917Sthompsa	    (sc->mac_ver) != 0x3070) {
1127203134Sthompsa		base += 4096;
1128205042Sthompsa	}
1129203134Sthompsa
1130203134Sthompsa	/* cheap sanity check */
1131203137Sthompsa	temp = fw->data;
1132203134Sthompsa	bytes = *temp;
1133257712Shselasky	if (bytes != be64toh(0xffffff0210280210ULL)) {
1134203138Sthompsa		device_printf(sc->sc_dev, "firmware checksum failed\n");
1135203137Sthompsa		error = EINVAL;
1136203137Sthompsa		goto fail;
1137203137Sthompsa	}
1138203134Sthompsa
1139203134Sthompsa	/* write microcode image */
1140262465Skevlo	if (sc->sc_flags & RUN_FLAG_FWLOAD_NEEDED) {
1141260219Skevlo		run_write_region_1(sc, RT2870_FW_BASE, base, 4096);
1142260219Skevlo		run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff);
1143260219Skevlo		run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff);
1144260219Skevlo	}
1145203134Sthompsa
1146203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1147203134Sthompsa	req.bRequest = RT2870_RESET;
1148203134Sthompsa	USETW(req.wValue, 8);
1149203134Sthompsa	USETW(req.wIndex, 0);
1150203134Sthompsa	USETW(req.wLength, 0);
1151220235Skevlo	if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL))
1152220235Skevlo	    != 0) {
1153203138Sthompsa		device_printf(sc->sc_dev, "firmware reset failed\n");
1154203137Sthompsa		goto fail;
1155203137Sthompsa	}
1156203134Sthompsa
1157203134Sthompsa	run_delay(sc, 10);
1158203134Sthompsa
1159260219Skevlo	run_write(sc, RT2860_H2M_BBPAGENT, 0);
1160203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
1161260219Skevlo	run_write(sc, RT2860_H2M_INTSRC, 0);
1162205042Sthompsa	if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0)
1163203137Sthompsa		goto fail;
1164203134Sthompsa
1165203134Sthompsa	/* wait until microcontroller is ready */
1166203134Sthompsa	for (ntries = 0; ntries < 1000; ntries++) {
1167260219Skevlo		if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0)
1168203137Sthompsa			goto fail;
1169203134Sthompsa		if (tmp & RT2860_MCU_READY)
1170203134Sthompsa			break;
1171203134Sthompsa		run_delay(sc, 10);
1172203134Sthompsa	}
1173203134Sthompsa	if (ntries == 1000) {
1174203138Sthompsa		device_printf(sc->sc_dev,
1175203138Sthompsa		    "timeout waiting for MCU to initialize\n");
1176203137Sthompsa		error = ETIMEDOUT;
1177203137Sthompsa		goto fail;
1178203134Sthompsa	}
1179233283Sbschmidt	device_printf(sc->sc_dev, "firmware %s ver. %u.%u loaded\n",
1180233283Sbschmidt	    (base == fw->data) ? "RT2870" : "RT3071",
1181233283Sbschmidt	    *(base + 4092), *(base + 4093));
1182203134Sthompsa
1183203137Sthompsafail:
1184203137Sthompsa	firmware_put(fw, FIRMWARE_UNLOAD);
1185203137Sthompsa	return (error);
1186203134Sthompsa}
1187203134Sthompsa
1188258641Shselaskystatic int
1189203134Sthompsarun_reset(struct run_softc *sc)
1190203134Sthompsa{
1191203134Sthompsa	usb_device_request_t req;
1192203134Sthompsa
1193203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1194203134Sthompsa	req.bRequest = RT2870_RESET;
1195203134Sthompsa	USETW(req.wValue, 1);
1196203134Sthompsa	USETW(req.wIndex, 0);
1197203134Sthompsa	USETW(req.wLength, 0);
1198209917Sthompsa	return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL));
1199203134Sthompsa}
1200203134Sthompsa
1201203134Sthompsastatic usb_error_t
1202203134Sthompsarun_do_request(struct run_softc *sc,
1203203134Sthompsa    struct usb_device_request *req, void *data)
1204203134Sthompsa{
1205203134Sthompsa	usb_error_t err;
1206203134Sthompsa	int ntries = 10;
1207203134Sthompsa
1208203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
1209203134Sthompsa
1210203134Sthompsa	while (ntries--) {
1211203134Sthompsa		err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx,
1212203134Sthompsa		    req, data, 0, NULL, 250 /* ms */);
1213203134Sthompsa		if (err == 0)
1214203134Sthompsa			break;
1215203134Sthompsa		DPRINTFN(1, "Control request failed, %s (retrying)\n",
1216203134Sthompsa		    usbd_errstr(err));
1217203134Sthompsa		run_delay(sc, 10);
1218203134Sthompsa	}
1219203134Sthompsa	return (err);
1220203134Sthompsa}
1221203134Sthompsa
1222203134Sthompsastatic int
1223203134Sthompsarun_read(struct run_softc *sc, uint16_t reg, uint32_t *val)
1224203134Sthompsa{
1225203134Sthompsa	uint32_t tmp;
1226203134Sthompsa	int error;
1227203134Sthompsa
1228203134Sthompsa	error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp);
1229203134Sthompsa	if (error == 0)
1230203134Sthompsa		*val = le32toh(tmp);
1231203134Sthompsa	else
1232203134Sthompsa		*val = 0xffffffff;
1233209917Sthompsa	return (error);
1234203134Sthompsa}
1235203134Sthompsa
1236203134Sthompsastatic int
1237203134Sthompsarun_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len)
1238203134Sthompsa{
1239203134Sthompsa	usb_device_request_t req;
1240203134Sthompsa
1241203134Sthompsa	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1242203134Sthompsa	req.bRequest = RT2870_READ_REGION_1;
1243203134Sthompsa	USETW(req.wValue, 0);
1244203134Sthompsa	USETW(req.wIndex, reg);
1245203134Sthompsa	USETW(req.wLength, len);
1246203134Sthompsa
1247209917Sthompsa	return (run_do_request(sc, &req, buf));
1248203134Sthompsa}
1249203134Sthompsa
1250203134Sthompsastatic int
1251203134Sthompsarun_write_2(struct run_softc *sc, uint16_t reg, uint16_t val)
1252203134Sthompsa{
1253203134Sthompsa	usb_device_request_t req;
1254203134Sthompsa
1255203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1256203134Sthompsa	req.bRequest = RT2870_WRITE_2;
1257203134Sthompsa	USETW(req.wValue, val);
1258203134Sthompsa	USETW(req.wIndex, reg);
1259203134Sthompsa	USETW(req.wLength, 0);
1260203134Sthompsa
1261209917Sthompsa	return (run_do_request(sc, &req, NULL));
1262203134Sthompsa}
1263203134Sthompsa
1264203134Sthompsastatic int
1265203134Sthompsarun_write(struct run_softc *sc, uint16_t reg, uint32_t val)
1266203134Sthompsa{
1267203134Sthompsa	int error;
1268203134Sthompsa
1269203134Sthompsa	if ((error = run_write_2(sc, reg, val & 0xffff)) == 0)
1270203134Sthompsa		error = run_write_2(sc, reg + 2, val >> 16);
1271209917Sthompsa	return (error);
1272203134Sthompsa}
1273203134Sthompsa
1274203134Sthompsastatic int
1275203134Sthompsarun_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf,
1276203134Sthompsa    int len)
1277203134Sthompsa{
1278203134Sthompsa#if 1
1279203134Sthompsa	int i, error = 0;
1280203134Sthompsa	/*
1281203134Sthompsa	 * NB: the WRITE_REGION_1 command is not stable on RT2860.
1282203134Sthompsa	 * We thus issue multiple WRITE_2 commands instead.
1283203134Sthompsa	 */
1284203134Sthompsa	KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n"));
1285203134Sthompsa	for (i = 0; i < len && error == 0; i += 2)
1286203134Sthompsa		error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8);
1287209917Sthompsa	return (error);
1288203134Sthompsa#else
1289203134Sthompsa	usb_device_request_t req;
1290257958Skevlo	int error = 0;
1291203134Sthompsa
1292257958Skevlo	/*
1293257958Skevlo	 * NOTE: It appears the WRITE_REGION_1 command cannot be
1294257958Skevlo	 * passed a huge amount of data, which will crash the
1295257958Skevlo	 * firmware. Limit amount of data passed to 64-bytes at a
1296257958Skevlo	 * time.
1297257958Skevlo	 */
1298257958Skevlo	while (len > 0) {
1299257958Skevlo		int delta = 64;
1300257958Skevlo		if (delta > len)
1301257958Skevlo			delta = len;
1302257958Skevlo
1303257958Skevlo		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1304257958Skevlo		req.bRequest = RT2870_WRITE_REGION_1;
1305257958Skevlo		USETW(req.wValue, 0);
1306257958Skevlo		USETW(req.wIndex, reg);
1307257958Skevlo		USETW(req.wLength, delta);
1308257958Skevlo		error = run_do_request(sc, &req, __DECONST(uint8_t *, buf));
1309257958Skevlo		if (error != 0)
1310257958Skevlo			break;
1311257958Skevlo		reg += delta;
1312257958Skevlo		buf += delta;
1313257958Skevlo		len -= delta;
1314257958Skevlo	}
1315257958Skevlo	return (error);
1316203134Sthompsa#endif
1317203134Sthompsa}
1318203134Sthompsa
1319203134Sthompsastatic int
1320203134Sthompsarun_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len)
1321203134Sthompsa{
1322203134Sthompsa	int i, error = 0;
1323203134Sthompsa
1324203134Sthompsa	KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n"));
1325203134Sthompsa	for (i = 0; i < len && error == 0; i += 4)
1326203134Sthompsa		error = run_write(sc, reg + i, val);
1327209917Sthompsa	return (error);
1328203134Sthompsa}
1329203134Sthompsa
1330203134Sthompsastatic int
1331259544Skevlorun_efuse_read(struct run_softc *sc, uint16_t addr, uint16_t *val, int count)
1332203134Sthompsa{
1333203134Sthompsa	uint32_t tmp;
1334203134Sthompsa	uint16_t reg;
1335203134Sthompsa	int error, ntries;
1336203134Sthompsa
1337203134Sthompsa	if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1338209917Sthompsa		return (error);
1339203134Sthompsa
1340261076Shselasky	if (count == 2)
1341261076Shselasky		addr *= 2;
1342203134Sthompsa	/*-
1343203134Sthompsa	 * Read one 16-byte block into registers EFUSE_DATA[0-3]:
1344203134Sthompsa	 * DATA0: F E D C
1345203134Sthompsa	 * DATA1: B A 9 8
1346203134Sthompsa	 * DATA2: 7 6 5 4
1347203134Sthompsa	 * DATA3: 3 2 1 0
1348203134Sthompsa	 */
1349203134Sthompsa	tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK);
1350203134Sthompsa	tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK;
1351203134Sthompsa	run_write(sc, RT3070_EFUSE_CTRL, tmp);
1352203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1353203134Sthompsa		if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1354209917Sthompsa			return (error);
1355203134Sthompsa		if (!(tmp & RT3070_EFSROM_KICK))
1356203134Sthompsa			break;
1357203134Sthompsa		run_delay(sc, 2);
1358203134Sthompsa	}
1359203134Sthompsa	if (ntries == 100)
1360209917Sthompsa		return (ETIMEDOUT);
1361203134Sthompsa
1362261076Shselasky	if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) {
1363261076Shselasky		*val = 0xffff;	/* address not found */
1364209917Sthompsa		return (0);
1365261076Shselasky	}
1366203134Sthompsa	/* determine to which 32-bit register our 16-bit word belongs */
1367203134Sthompsa	reg = RT3070_EFUSE_DATA3 - (addr & 0xc);
1368203134Sthompsa	if ((error = run_read(sc, reg, &tmp)) != 0)
1369209917Sthompsa		return (error);
1370203134Sthompsa
1371261118Skevlo	tmp >>= (8 * (addr & 0x3));
1372261118Skevlo	*val = (addr & 1) ? tmp >> 16 : tmp & 0xffff;
1373261118Skevlo
1374209917Sthompsa	return (0);
1375203134Sthompsa}
1376203134Sthompsa
1377261124Skevlo/* Read 16-bit from eFUSE ROM for RT3xxx. */
1378203134Sthompsastatic int
1379259544Skevlorun_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1380259544Skevlo{
1381259544Skevlo	return (run_efuse_read(sc, addr, val, 2));
1382259544Skevlo}
1383259544Skevlo
1384259544Skevlostatic int
1385203134Sthompsarun_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1386203134Sthompsa{
1387203134Sthompsa	usb_device_request_t req;
1388203134Sthompsa	uint16_t tmp;
1389203134Sthompsa	int error;
1390203134Sthompsa
1391203134Sthompsa	addr *= 2;
1392203134Sthompsa	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1393203134Sthompsa	req.bRequest = RT2870_EEPROM_READ;
1394203134Sthompsa	USETW(req.wValue, 0);
1395203134Sthompsa	USETW(req.wIndex, addr);
1396260219Skevlo	USETW(req.wLength, sizeof(tmp));
1397203134Sthompsa
1398203134Sthompsa	error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp);
1399203134Sthompsa	if (error == 0)
1400203134Sthompsa		*val = le16toh(tmp);
1401203134Sthompsa	else
1402203134Sthompsa		*val = 0xffff;
1403209917Sthompsa	return (error);
1404203134Sthompsa}
1405203134Sthompsa
1406203134Sthompsastatic __inline int
1407203134Sthompsarun_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val)
1408203134Sthompsa{
1409203134Sthompsa	/* either eFUSE ROM or EEPROM */
1410203134Sthompsa	return sc->sc_srom_read(sc, addr, val);
1411203134Sthompsa}
1412203134Sthompsa
1413203134Sthompsastatic int
1414258733Skevlorun_rt2870_rf_write(struct run_softc *sc, uint32_t val)
1415203134Sthompsa{
1416203134Sthompsa	uint32_t tmp;
1417203134Sthompsa	int error, ntries;
1418203134Sthompsa
1419203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1420203134Sthompsa		if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0)
1421209917Sthompsa			return (error);
1422203134Sthompsa		if (!(tmp & RT2860_RF_REG_CTRL))
1423203134Sthompsa			break;
1424203134Sthompsa	}
1425203134Sthompsa	if (ntries == 10)
1426209917Sthompsa		return (ETIMEDOUT);
1427203134Sthompsa
1428258732Skevlo	return (run_write(sc, RT2860_RF_CSR_CFG0, val));
1429203134Sthompsa}
1430203134Sthompsa
1431203134Sthompsastatic int
1432203134Sthompsarun_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1433203134Sthompsa{
1434203134Sthompsa	uint32_t tmp;
1435203134Sthompsa	int error, ntries;
1436203134Sthompsa
1437203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1438203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1439209917Sthompsa			return (error);
1440203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1441203134Sthompsa			break;
1442203134Sthompsa	}
1443203134Sthompsa	if (ntries == 100)
1444209917Sthompsa		return (ETIMEDOUT);
1445203134Sthompsa
1446203134Sthompsa	tmp = RT3070_RF_KICK | reg << 8;
1447203134Sthompsa	if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0)
1448209917Sthompsa		return (error);
1449203134Sthompsa
1450203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1451203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1452209917Sthompsa			return (error);
1453203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1454203134Sthompsa			break;
1455203134Sthompsa	}
1456203134Sthompsa	if (ntries == 100)
1457209917Sthompsa		return (ETIMEDOUT);
1458203134Sthompsa
1459203134Sthompsa	*val = tmp & 0xff;
1460209917Sthompsa	return (0);
1461203134Sthompsa}
1462203134Sthompsa
1463203134Sthompsastatic int
1464203134Sthompsarun_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1465203134Sthompsa{
1466203134Sthompsa	uint32_t tmp;
1467203134Sthompsa	int error, ntries;
1468203134Sthompsa
1469203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1470203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1471209917Sthompsa			return (error);
1472203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1473203134Sthompsa			break;
1474203134Sthompsa	}
1475203134Sthompsa	if (ntries == 10)
1476209917Sthompsa		return (ETIMEDOUT);
1477203134Sthompsa
1478203134Sthompsa	tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val;
1479209917Sthompsa	return (run_write(sc, RT3070_RF_CSR_CFG, tmp));
1480203134Sthompsa}
1481203134Sthompsa
1482203134Sthompsastatic int
1483203134Sthompsarun_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1484203134Sthompsa{
1485203134Sthompsa	uint32_t tmp;
1486203134Sthompsa	int ntries, error;
1487203134Sthompsa
1488203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1489203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1490209917Sthompsa			return (error);
1491203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1492203134Sthompsa			break;
1493203134Sthompsa	}
1494203134Sthompsa	if (ntries == 10)
1495209917Sthompsa		return (ETIMEDOUT);
1496203134Sthompsa
1497203134Sthompsa	tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8;
1498203134Sthompsa	if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0)
1499209917Sthompsa		return (error);
1500203134Sthompsa
1501203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1502203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1503209917Sthompsa			return (error);
1504203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1505203134Sthompsa			break;
1506203134Sthompsa	}
1507203134Sthompsa	if (ntries == 10)
1508209917Sthompsa		return (ETIMEDOUT);
1509203134Sthompsa
1510203134Sthompsa	*val = tmp & 0xff;
1511209917Sthompsa	return (0);
1512203134Sthompsa}
1513203134Sthompsa
1514203134Sthompsastatic int
1515203134Sthompsarun_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1516203134Sthompsa{
1517203134Sthompsa	uint32_t tmp;
1518203134Sthompsa	int ntries, error;
1519203134Sthompsa
1520203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1521203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1522209917Sthompsa			return (error);
1523203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1524203134Sthompsa			break;
1525203134Sthompsa	}
1526203134Sthompsa	if (ntries == 10)
1527209917Sthompsa		return (ETIMEDOUT);
1528203134Sthompsa
1529203134Sthompsa	tmp = RT2860_BBP_CSR_KICK | reg << 8 | val;
1530209917Sthompsa	return (run_write(sc, RT2860_BBP_CSR_CFG, tmp));
1531203134Sthompsa}
1532203134Sthompsa
1533203134Sthompsa/*
1534203134Sthompsa * Send a command to the 8051 microcontroller unit.
1535203134Sthompsa */
1536203134Sthompsastatic int
1537203134Sthompsarun_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg)
1538203134Sthompsa{
1539203134Sthompsa	uint32_t tmp;
1540203134Sthompsa	int error, ntries;
1541203134Sthompsa
1542203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1543203134Sthompsa		if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0)
1544203134Sthompsa			return error;
1545203134Sthompsa		if (!(tmp & RT2860_H2M_BUSY))
1546203134Sthompsa			break;
1547203134Sthompsa	}
1548203134Sthompsa	if (ntries == 100)
1549203134Sthompsa		return ETIMEDOUT;
1550203134Sthompsa
1551203134Sthompsa	tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg;
1552203134Sthompsa	if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0)
1553203134Sthompsa		error = run_write(sc, RT2860_HOST_CMD, cmd);
1554209917Sthompsa	return (error);
1555203134Sthompsa}
1556203134Sthompsa
1557203134Sthompsa/*
1558203134Sthompsa * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word.
1559203134Sthompsa * Used to adjust per-rate Tx power registers.
1560203134Sthompsa */
1561203134Sthompsastatic __inline uint32_t
1562203134Sthompsab4inc(uint32_t b32, int8_t delta)
1563203134Sthompsa{
1564203134Sthompsa	int8_t i, b4;
1565203134Sthompsa
1566203134Sthompsa	for (i = 0; i < 8; i++) {
1567203134Sthompsa		b4 = b32 & 0xf;
1568203134Sthompsa		b4 += delta;
1569203134Sthompsa		if (b4 < 0)
1570203134Sthompsa			b4 = 0;
1571203134Sthompsa		else if (b4 > 0xf)
1572203134Sthompsa			b4 = 0xf;
1573203134Sthompsa		b32 = b32 >> 4 | b4 << 28;
1574203134Sthompsa	}
1575209917Sthompsa	return (b32);
1576203134Sthompsa}
1577203134Sthompsa
1578203134Sthompsastatic const char *
1579257955Skevlorun_get_rf(uint16_t rev)
1580203134Sthompsa{
1581203134Sthompsa	switch (rev) {
1582203134Sthompsa	case RT2860_RF_2820:	return "RT2820";
1583203134Sthompsa	case RT2860_RF_2850:	return "RT2850";
1584203134Sthompsa	case RT2860_RF_2720:	return "RT2720";
1585203134Sthompsa	case RT2860_RF_2750:	return "RT2750";
1586203134Sthompsa	case RT3070_RF_3020:	return "RT3020";
1587203134Sthompsa	case RT3070_RF_2020:	return "RT2020";
1588203134Sthompsa	case RT3070_RF_3021:	return "RT3021";
1589203134Sthompsa	case RT3070_RF_3022:	return "RT3022";
1590203134Sthompsa	case RT3070_RF_3052:	return "RT3052";
1591260219Skevlo	case RT3593_RF_3053:	return "RT3053";
1592259032Skevlo	case RT5592_RF_5592:	return "RT5592";
1593257955Skevlo	case RT5390_RF_5370:	return "RT5370";
1594257955Skevlo	case RT5390_RF_5372:	return "RT5372";
1595203134Sthompsa	}
1596209917Sthompsa	return ("unknown");
1597203134Sthompsa}
1598203134Sthompsa
1599260219Skevlostatic void
1600260219Skevlorun_rt3593_get_txpower(struct run_softc *sc)
1601260219Skevlo{
1602260219Skevlo	uint16_t addr, val;
1603260219Skevlo	int i;
1604260219Skevlo
1605260219Skevlo	/* Read power settings for 2GHz channels. */
1606260219Skevlo	for (i = 0; i < 14; i += 2) {
1607260219Skevlo		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE1 :
1608260219Skevlo		    RT2860_EEPROM_PWR2GHZ_BASE1;
1609260219Skevlo		run_srom_read(sc, addr + i / 2, &val);
1610260219Skevlo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1611260219Skevlo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1612260219Skevlo
1613260219Skevlo		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE2 :
1614260219Skevlo		    RT2860_EEPROM_PWR2GHZ_BASE2;
1615260219Skevlo		run_srom_read(sc, addr + i / 2, &val);
1616260219Skevlo		sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1617260219Skevlo		sc->txpow2[i + 1] = (int8_t)(val >> 8);
1618260219Skevlo
1619260219Skevlo		if (sc->ntxchains == 3) {
1620260219Skevlo			run_srom_read(sc, RT3593_EEPROM_PWR2GHZ_BASE3 + i / 2,
1621260219Skevlo			    &val);
1622260219Skevlo			sc->txpow3[i + 0] = (int8_t)(val & 0xff);
1623260219Skevlo			sc->txpow3[i + 1] = (int8_t)(val >> 8);
1624260219Skevlo		}
1625260219Skevlo	}
1626260219Skevlo	/* Fix broken Tx power entries. */
1627260219Skevlo	for (i = 0; i < 14; i++) {
1628260542Skevlo		if (sc->txpow1[i] > 31)
1629260219Skevlo			sc->txpow1[i] = 5;
1630260542Skevlo		if (sc->txpow2[i] > 31)
1631260219Skevlo			sc->txpow2[i] = 5;
1632260219Skevlo		if (sc->ntxchains == 3) {
1633260542Skevlo			if (sc->txpow3[i] > 31)
1634260219Skevlo				sc->txpow3[i] = 5;
1635260219Skevlo		}
1636260219Skevlo	}
1637260219Skevlo	/* Read power settings for 5GHz channels. */
1638260219Skevlo	for (i = 0; i < 40; i += 2) {
1639260219Skevlo		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1640260219Skevlo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1641260219Skevlo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1642260219Skevlo
1643260219Skevlo		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1644260219Skevlo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1645260219Skevlo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1646260219Skevlo
1647260219Skevlo		if (sc->ntxchains == 3) {
1648260219Skevlo			run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE3 + i / 2,
1649260219Skevlo			    &val);
1650260219Skevlo			sc->txpow3[i + 14] = (int8_t)(val & 0xff);
1651260219Skevlo			sc->txpow3[i + 15] = (int8_t)(val >> 8);
1652260219Skevlo		}
1653260219Skevlo	}
1654260219Skevlo}
1655260219Skevlo
1656260219Skevlostatic void
1657260219Skevlorun_get_txpower(struct run_softc *sc)
1658260219Skevlo{
1659260219Skevlo	uint16_t val;
1660260219Skevlo	int i;
1661260219Skevlo
1662260219Skevlo	/* Read power settings for 2GHz channels. */
1663260219Skevlo	for (i = 0; i < 14; i += 2) {
1664260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val);
1665260219Skevlo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1666260219Skevlo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1667260219Skevlo
1668260219Skevlo		if (sc->mac_ver != 0x5390) {
1669260219Skevlo			run_srom_read(sc,
1670260219Skevlo			    RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val);
1671260219Skevlo			sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1672260219Skevlo			sc->txpow2[i + 1] = (int8_t)(val >> 8);
1673260219Skevlo		}
1674260219Skevlo	}
1675260219Skevlo	/* Fix broken Tx power entries. */
1676260219Skevlo	for (i = 0; i < 14; i++) {
1677260219Skevlo		if (sc->mac_ver >= 0x5390) {
1678260219Skevlo			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 27)
1679260219Skevlo				sc->txpow1[i] = 5;
1680260219Skevlo		} else {
1681260219Skevlo			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31)
1682260219Skevlo				sc->txpow1[i] = 5;
1683260219Skevlo		}
1684260219Skevlo		if (sc->mac_ver > 0x5390) {
1685260219Skevlo			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 27)
1686260219Skevlo				sc->txpow2[i] = 5;
1687260219Skevlo		} else if (sc->mac_ver < 0x5390) {
1688260219Skevlo			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31)
1689260219Skevlo				sc->txpow2[i] = 5;
1690260219Skevlo		}
1691260219Skevlo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1692260219Skevlo		    rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]);
1693260219Skevlo	}
1694260219Skevlo	/* Read power settings for 5GHz channels. */
1695260219Skevlo	for (i = 0; i < 40; i += 2) {
1696260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1697260219Skevlo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1698260219Skevlo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1699260219Skevlo
1700260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1701260219Skevlo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1702260219Skevlo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1703260219Skevlo	}
1704260219Skevlo	/* Fix broken Tx power entries. */
1705260219Skevlo	for (i = 0; i < 40; i++ ) {
1706260219Skevlo		if (sc->mac_ver != 0x5592) {
1707260219Skevlo			if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15)
1708260219Skevlo				sc->txpow1[14 + i] = 5;
1709260219Skevlo			if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15)
1710260219Skevlo				sc->txpow2[14 + i] = 5;
1711260219Skevlo		}
1712260219Skevlo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1713260219Skevlo		    rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i],
1714260219Skevlo		    sc->txpow2[14 + i]);
1715260219Skevlo	}
1716260219Skevlo}
1717260219Skevlo
1718258641Shselaskystatic int
1719203134Sthompsarun_read_eeprom(struct run_softc *sc)
1720203134Sthompsa{
1721287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
1722203134Sthompsa	int8_t delta_2ghz, delta_5ghz;
1723203134Sthompsa	uint32_t tmp;
1724203134Sthompsa	uint16_t val;
1725203134Sthompsa	int ridx, ant, i;
1726203134Sthompsa
1727203134Sthompsa	/* check whether the ROM is eFUSE ROM or EEPROM */
1728203134Sthompsa	sc->sc_srom_read = run_eeprom_read_2;
1729205042Sthompsa	if (sc->mac_ver >= 0x3070) {
1730203134Sthompsa		run_read(sc, RT3070_EFUSE_CTRL, &tmp);
1731203134Sthompsa		DPRINTF("EFUSE_CTRL=0x%08x\n", tmp);
1732261118Skevlo		if ((tmp & RT3070_SEL_EFUSE) || sc->mac_ver == 0x3593)
1733203134Sthompsa			sc->sc_srom_read = run_efuse_read_2;
1734203134Sthompsa	}
1735203134Sthompsa
1736203134Sthompsa	/* read ROM version */
1737203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_VERSION, &val);
1738287853Skevlo	DPRINTF("EEPROM rev=%d, FAE=%d\n", val >> 8, val & 0xff);
1739203134Sthompsa
1740203134Sthompsa	/* read MAC address */
1741203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC01, &val);
1742287197Sglebius	ic->ic_macaddr[0] = val & 0xff;
1743287197Sglebius	ic->ic_macaddr[1] = val >> 8;
1744203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC23, &val);
1745287197Sglebius	ic->ic_macaddr[2] = val & 0xff;
1746287197Sglebius	ic->ic_macaddr[3] = val >> 8;
1747203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC45, &val);
1748287197Sglebius	ic->ic_macaddr[4] = val & 0xff;
1749287197Sglebius	ic->ic_macaddr[5] = val >> 8;
1750203134Sthompsa
1751260219Skevlo	if (sc->mac_ver < 0x3593) {
1752257955Skevlo		/* read vender BBP settings */
1753205042Sthompsa		for (i = 0; i < 10; i++) {
1754257955Skevlo			run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val);
1755257955Skevlo			sc->bbp[i].val = val & 0xff;
1756257955Skevlo			sc->bbp[i].reg = val >> 8;
1757257955Skevlo			DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg,
1758257955Skevlo			    sc->bbp[i].val);
1759205042Sthompsa		}
1760257955Skevlo		if (sc->mac_ver >= 0x3071) {
1761257955Skevlo			/* read vendor RF settings */
1762257955Skevlo			for (i = 0; i < 10; i++) {
1763257955Skevlo				run_srom_read(sc, RT3071_EEPROM_RF_BASE + i,
1764257955Skevlo				   &val);
1765257955Skevlo				sc->rf[i].val = val & 0xff;
1766257955Skevlo				sc->rf[i].reg = val >> 8;
1767257955Skevlo				DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg,
1768257955Skevlo				    sc->rf[i].val);
1769257955Skevlo			}
1770257955Skevlo		}
1771205042Sthompsa	}
1772203134Sthompsa
1773203134Sthompsa	/* read RF frequency offset from EEPROM */
1774260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1775260219Skevlo	    RT3593_EEPROM_FREQ, &val);
1776203134Sthompsa	sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0;
1777203134Sthompsa	DPRINTF("EEPROM freq offset %d\n", sc->freq & 0xff);
1778203134Sthompsa
1779260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1780260219Skevlo	    RT3593_EEPROM_FREQ_LEDS, &val);
1781205042Sthompsa	if (val >> 8 != 0xff) {
1782203134Sthompsa		/* read LEDs operating mode */
1783205042Sthompsa		sc->leds = val >> 8;
1784260219Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED1 :
1785260219Skevlo		    RT3593_EEPROM_LED1, &sc->led[0]);
1786260219Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED2 :
1787260219Skevlo		    RT3593_EEPROM_LED2, &sc->led[1]);
1788260219Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED3 :
1789260219Skevlo		    RT3593_EEPROM_LED3, &sc->led[2]);
1790203134Sthompsa	} else {
1791203134Sthompsa		/* broken EEPROM, use default settings */
1792203134Sthompsa		sc->leds = 0x01;
1793203134Sthompsa		sc->led[0] = 0x5555;
1794203134Sthompsa		sc->led[1] = 0x2221;
1795203134Sthompsa		sc->led[2] = 0x5627;	/* differs from RT2860 */
1796203134Sthompsa	}
1797203134Sthompsa	DPRINTF("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n",
1798203134Sthompsa	    sc->leds, sc->led[0], sc->led[1], sc->led[2]);
1799203134Sthompsa
1800203134Sthompsa	/* read RF information */
1801259032Skevlo	if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392)
1802257955Skevlo		run_srom_read(sc, 0x00, &val);
1803257955Skevlo	else
1804257955Skevlo		run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1805257955Skevlo
1806203134Sthompsa	if (val == 0xffff) {
1807260219Skevlo		device_printf(sc->sc_dev,
1808260219Skevlo		    "invalid EEPROM antenna info, using default\n");
1809203134Sthompsa		DPRINTF("invalid EEPROM antenna info, using default\n");
1810205042Sthompsa		if (sc->mac_ver == 0x3572) {
1811205042Sthompsa			/* default to RF3052 2T2R */
1812205042Sthompsa			sc->rf_rev = RT3070_RF_3052;
1813205042Sthompsa			sc->ntxchains = 2;
1814205042Sthompsa			sc->nrxchains = 2;
1815205042Sthompsa		} else if (sc->mac_ver >= 0x3070) {
1816203134Sthompsa			/* default to RF3020 1T1R */
1817203134Sthompsa			sc->rf_rev = RT3070_RF_3020;
1818203134Sthompsa			sc->ntxchains = 1;
1819203134Sthompsa			sc->nrxchains = 1;
1820203134Sthompsa		} else {
1821203134Sthompsa			/* default to RF2820 1T2R */
1822203134Sthompsa			sc->rf_rev = RT2860_RF_2820;
1823203134Sthompsa			sc->ntxchains = 1;
1824203134Sthompsa			sc->nrxchains = 2;
1825203134Sthompsa		}
1826203134Sthompsa	} else {
1827259032Skevlo		if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) {
1828257955Skevlo			sc->rf_rev = val;
1829257955Skevlo			run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1830257955Skevlo		} else
1831257955Skevlo			sc->rf_rev = (val >> 8) & 0xf;
1832203134Sthompsa		sc->ntxchains = (val >> 4) & 0xf;
1833203134Sthompsa		sc->nrxchains = val & 0xf;
1834203134Sthompsa	}
1835257955Skevlo	DPRINTF("EEPROM RF rev=0x%04x chains=%dT%dR\n",
1836203134Sthompsa	    sc->rf_rev, sc->ntxchains, sc->nrxchains);
1837203134Sthompsa
1838208019Sthompsa	/* check if RF supports automatic Tx access gain control */
1839203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_CONFIG, &val);
1840203134Sthompsa	DPRINTF("EEPROM CFG 0x%04x\n", val);
1841205042Sthompsa	/* check if driver should patch the DAC issue */
1842205042Sthompsa	if ((val >> 8) != 0xff)
1843205042Sthompsa		sc->patch_dac = (val >> 15) & 1;
1844203134Sthompsa	if ((val & 0xff) != 0xff) {
1845203134Sthompsa		sc->ext_5ghz_lna = (val >> 3) & 1;
1846203134Sthompsa		sc->ext_2ghz_lna = (val >> 2) & 1;
1847205042Sthompsa		/* check if RF supports automatic Tx access gain control */
1848203134Sthompsa		sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1;
1849205042Sthompsa		/* check if we have a hardware radio switch */
1850205042Sthompsa		sc->rfswitch = val & 1;
1851203134Sthompsa	}
1852203134Sthompsa
1853260219Skevlo	/* Read Tx power settings. */
1854260219Skevlo	if (sc->mac_ver == 0x3593)
1855260219Skevlo		run_rt3593_get_txpower(sc);
1856260219Skevlo	else
1857260219Skevlo		run_get_txpower(sc);
1858203134Sthompsa
1859203134Sthompsa	/* read Tx power compensation for each Tx rate */
1860203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val);
1861203134Sthompsa	delta_2ghz = delta_5ghz = 0;
1862203134Sthompsa	if ((val & 0xff) != 0xff && (val & 0x80)) {
1863203134Sthompsa		delta_2ghz = val & 0xf;
1864203134Sthompsa		if (!(val & 0x40))	/* negative number */
1865203134Sthompsa			delta_2ghz = -delta_2ghz;
1866203134Sthompsa	}
1867203134Sthompsa	val >>= 8;
1868203134Sthompsa	if ((val & 0xff) != 0xff && (val & 0x80)) {
1869203134Sthompsa		delta_5ghz = val & 0xf;
1870203134Sthompsa		if (!(val & 0x40))	/* negative number */
1871203134Sthompsa			delta_5ghz = -delta_5ghz;
1872203134Sthompsa	}
1873203134Sthompsa	DPRINTF("power compensation=%d (2GHz), %d (5GHz)\n",
1874203134Sthompsa	    delta_2ghz, delta_5ghz);
1875203134Sthompsa
1876203134Sthompsa	for (ridx = 0; ridx < 5; ridx++) {
1877203134Sthompsa		uint32_t reg;
1878203134Sthompsa
1879208019Sthompsa		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val);
1880208019Sthompsa		reg = val;
1881208019Sthompsa		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val);
1882208019Sthompsa		reg |= (uint32_t)val << 16;
1883203134Sthompsa
1884203134Sthompsa		sc->txpow20mhz[ridx] = reg;
1885203134Sthompsa		sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz);
1886203134Sthompsa		sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz);
1887203134Sthompsa
1888203134Sthompsa		DPRINTF("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, "
1889203134Sthompsa		    "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx],
1890203134Sthompsa		    sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]);
1891203134Sthompsa	}
1892203134Sthompsa
1893260219Skevlo	/* Read RSSI offsets and LNA gains from EEPROM. */
1894260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_2GHZ :
1895260219Skevlo	    RT3593_EEPROM_RSSI1_2GHZ, &val);
1896203134Sthompsa	sc->rssi_2ghz[0] = val & 0xff;	/* Ant A */
1897203134Sthompsa	sc->rssi_2ghz[1] = val >> 8;	/* Ant B */
1898260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_2GHZ :
1899260219Skevlo	    RT3593_EEPROM_RSSI2_2GHZ, &val);
1900205042Sthompsa	if (sc->mac_ver >= 0x3070) {
1901260219Skevlo		if (sc->mac_ver == 0x3593) {
1902260219Skevlo			sc->txmixgain_2ghz = 0;
1903260219Skevlo			sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1904260219Skevlo		} else {
1905260219Skevlo			/*
1906260219Skevlo			 * On RT3070 chips (limited to 2 Rx chains), this ROM
1907260219Skevlo			 * field contains the Tx mixer gain for the 2GHz band.
1908260219Skevlo			 */
1909260219Skevlo			if ((val & 0xff) != 0xff)
1910260219Skevlo				sc->txmixgain_2ghz = val & 0x7;
1911260219Skevlo		}
1912205042Sthompsa		DPRINTF("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz);
1913205042Sthompsa	} else
1914205042Sthompsa		sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1915260219Skevlo	if (sc->mac_ver == 0x3593)
1916260219Skevlo		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
1917203134Sthompsa	sc->lna[2] = val >> 8;		/* channel group 2 */
1918203134Sthompsa
1919260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_5GHZ :
1920260219Skevlo	    RT3593_EEPROM_RSSI1_5GHZ, &val);
1921203134Sthompsa	sc->rssi_5ghz[0] = val & 0xff;	/* Ant A */
1922203134Sthompsa	sc->rssi_5ghz[1] = val >> 8;	/* Ant B */
1923260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_5GHZ :
1924260219Skevlo	    RT3593_EEPROM_RSSI2_5GHZ, &val);
1925205042Sthompsa	if (sc->mac_ver == 0x3572) {
1926205042Sthompsa		/*
1927205042Sthompsa		 * On RT3572 chips (limited to 2 Rx chains), this ROM
1928205042Sthompsa		 * field contains the Tx mixer gain for the 5GHz band.
1929205042Sthompsa		 */
1930205042Sthompsa		if ((val & 0xff) != 0xff)
1931205042Sthompsa			sc->txmixgain_5ghz = val & 0x7;
1932205042Sthompsa		DPRINTF("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz);
1933205042Sthompsa	} else
1934205042Sthompsa		sc->rssi_5ghz[2] = val & 0xff;	/* Ant C */
1935260219Skevlo	if (sc->mac_ver == 0x3593) {
1936260219Skevlo		sc->txmixgain_5ghz = 0;
1937260219Skevlo		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
1938260219Skevlo	}
1939203134Sthompsa	sc->lna[3] = val >> 8;		/* channel group 3 */
1940203134Sthompsa
1941260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LNA :
1942260219Skevlo	    RT3593_EEPROM_LNA, &val);
1943203134Sthompsa	sc->lna[0] = val & 0xff;	/* channel group 0 */
1944203134Sthompsa	sc->lna[1] = val >> 8;		/* channel group 1 */
1945203134Sthompsa
1946203134Sthompsa	/* fix broken 5GHz LNA entries */
1947203134Sthompsa	if (sc->lna[2] == 0 || sc->lna[2] == 0xff) {
1948203134Sthompsa		DPRINTF("invalid LNA for channel group %d\n", 2);
1949203134Sthompsa		sc->lna[2] = sc->lna[1];
1950203134Sthompsa	}
1951203134Sthompsa	if (sc->lna[3] == 0 || sc->lna[3] == 0xff) {
1952203134Sthompsa		DPRINTF("invalid LNA for channel group %d\n", 3);
1953203134Sthompsa		sc->lna[3] = sc->lna[1];
1954203134Sthompsa	}
1955203134Sthompsa
1956203134Sthompsa	/* fix broken RSSI offset entries */
1957203134Sthompsa	for (ant = 0; ant < 3; ant++) {
1958203134Sthompsa		if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) {
1959203134Sthompsa			DPRINTF("invalid RSSI%d offset: %d (2GHz)\n",
1960203134Sthompsa			    ant + 1, sc->rssi_2ghz[ant]);
1961203134Sthompsa			sc->rssi_2ghz[ant] = 0;
1962203134Sthompsa		}
1963203134Sthompsa		if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) {
1964203134Sthompsa			DPRINTF("invalid RSSI%d offset: %d (5GHz)\n",
1965203134Sthompsa			    ant + 1, sc->rssi_5ghz[ant]);
1966203134Sthompsa			sc->rssi_5ghz[ant] = 0;
1967203134Sthompsa		}
1968203134Sthompsa	}
1969209917Sthompsa	return (0);
1970203134Sthompsa}
1971203134Sthompsa
1972218676Shselaskystatic struct ieee80211_node *
1973203134Sthompsarun_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
1974203134Sthompsa{
1975203134Sthompsa	return malloc(sizeof (struct run_node), M_DEVBUF, M_NOWAIT | M_ZERO);
1976203134Sthompsa}
1977203134Sthompsa
1978203134Sthompsastatic int
1979203134Sthompsarun_media_change(struct ifnet *ifp)
1980203134Sthompsa{
1981208019Sthompsa	struct ieee80211vap *vap = ifp->if_softc;
1982208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
1983203134Sthompsa	const struct ieee80211_txparam *tp;
1984286950Sadrian	struct run_softc *sc = ic->ic_softc;
1985203134Sthompsa	uint8_t rate, ridx;
1986203134Sthompsa	int error;
1987203134Sthompsa
1988203134Sthompsa	RUN_LOCK(sc);
1989203134Sthompsa
1990203134Sthompsa	error = ieee80211_media_change(ifp);
1991209917Sthompsa	if (error != ENETRESET) {
1992203134Sthompsa		RUN_UNLOCK(sc);
1993209917Sthompsa		return (error);
1994208019Sthompsa	}
1995203134Sthompsa
1996203134Sthompsa	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
1997203134Sthompsa	if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
1998212127Sthompsa		struct ieee80211_node *ni;
1999212127Sthompsa		struct run_node	*rn;
2000212127Sthompsa
2001203134Sthompsa		rate = ic->ic_sup_rates[ic->ic_curmode].
2002203134Sthompsa		    rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL;
2003203134Sthompsa		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2004203134Sthompsa			if (rt2860_rates[ridx].rate == rate)
2005203134Sthompsa				break;
2006212127Sthompsa		ni = ieee80211_ref_node(vap->iv_bss);
2007287552Skevlo		rn = RUN_NODE(ni);
2008208019Sthompsa		rn->fix_ridx = ridx;
2009208019Sthompsa		DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx);
2010212127Sthompsa		ieee80211_free_node(ni);
2011203134Sthompsa	}
2012203134Sthompsa
2013208019Sthompsa#if 0
2014203134Sthompsa	if ((ifp->if_flags & IFF_UP) &&
2015287197Sglebius	    (ifp->if_drv_flags &  RUN_RUNNING)){
2016203134Sthompsa		run_init_locked(sc);
2017203134Sthompsa	}
2018208019Sthompsa#endif
2019203134Sthompsa
2020203134Sthompsa	RUN_UNLOCK(sc);
2021203134Sthompsa
2022209917Sthompsa	return (0);
2023203134Sthompsa}
2024203134Sthompsa
2025203134Sthompsastatic int
2026203134Sthompsarun_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
2027203134Sthompsa{
2028203134Sthompsa	const struct ieee80211_txparam *tp;
2029203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2030286950Sadrian	struct run_softc *sc = ic->ic_softc;
2031203134Sthompsa	struct run_vap *rvp = RUN_VAP(vap);
2032203134Sthompsa	enum ieee80211_state ostate;
2033208019Sthompsa	uint32_t sta[3];
2034203134Sthompsa	uint32_t tmp;
2035208019Sthompsa	uint8_t ratectl;
2036208019Sthompsa	uint8_t restart_ratectl = 0;
2037208019Sthompsa	uint8_t bid = 1 << rvp->rvp_id;
2038203134Sthompsa
2039203134Sthompsa	ostate = vap->iv_state;
2040203134Sthompsa	DPRINTF("%s -> %s\n",
2041203134Sthompsa		ieee80211_state_name[ostate],
2042203134Sthompsa		ieee80211_state_name[nstate]);
2043203134Sthompsa
2044203134Sthompsa	IEEE80211_UNLOCK(ic);
2045203134Sthompsa	RUN_LOCK(sc);
2046203134Sthompsa
2047208019Sthompsa	ratectl = sc->ratectl_run; /* remember current state */
2048208019Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
2049208019Sthompsa	usb_callout_stop(&sc->ratectl_ch);
2050203134Sthompsa
2051203134Sthompsa	if (ostate == IEEE80211_S_RUN) {
2052203134Sthompsa		/* turn link LED off */
2053203134Sthompsa		run_set_leds(sc, RT2860_LED_RADIO);
2054203134Sthompsa	}
2055203134Sthompsa
2056203134Sthompsa	switch (nstate) {
2057203134Sthompsa	case IEEE80211_S_INIT:
2058208019Sthompsa		restart_ratectl = 1;
2059208019Sthompsa
2060208019Sthompsa		if (ostate != IEEE80211_S_RUN)
2061208019Sthompsa			break;
2062208019Sthompsa
2063208019Sthompsa		ratectl &= ~bid;
2064208019Sthompsa		sc->runbmap &= ~bid;
2065208019Sthompsa
2066208019Sthompsa		/* abort TSF synchronization if there is no vap running */
2067209917Sthompsa		if (--sc->running == 0) {
2068203134Sthompsa			run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
2069203134Sthompsa			run_write(sc, RT2860_BCN_TIME_CFG,
2070203134Sthompsa			    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
2071203134Sthompsa			    RT2860_TBTT_TIMER_EN));
2072203134Sthompsa		}
2073203134Sthompsa		break;
2074203134Sthompsa
2075203134Sthompsa	case IEEE80211_S_RUN:
2076209917Sthompsa		if (!(sc->runbmap & bid)) {
2077208019Sthompsa			if(sc->running++)
2078208019Sthompsa				restart_ratectl = 1;
2079208019Sthompsa			sc->runbmap |= bid;
2080208019Sthompsa		}
2081203134Sthompsa
2082218492Sbschmidt		m_freem(rvp->beacon_mbuf);
2083218492Sbschmidt		rvp->beacon_mbuf = NULL;
2084218492Sbschmidt
2085209917Sthompsa		switch (vap->iv_opmode) {
2086208019Sthompsa		case IEEE80211_M_HOSTAP:
2087208019Sthompsa		case IEEE80211_M_MBSS:
2088208019Sthompsa			sc->ap_running |= bid;
2089208019Sthompsa			ic->ic_opmode = vap->iv_opmode;
2090208019Sthompsa			run_update_beacon_cb(vap);
2091208019Sthompsa			break;
2092208019Sthompsa		case IEEE80211_M_IBSS:
2093208019Sthompsa			sc->adhoc_running |= bid;
2094209917Sthompsa			if (!sc->ap_running)
2095208019Sthompsa				ic->ic_opmode = vap->iv_opmode;
2096208019Sthompsa			run_update_beacon_cb(vap);
2097208019Sthompsa			break;
2098208019Sthompsa		case IEEE80211_M_STA:
2099208019Sthompsa			sc->sta_running |= bid;
2100209917Sthompsa			if (!sc->ap_running && !sc->adhoc_running)
2101208019Sthompsa				ic->ic_opmode = vap->iv_opmode;
2102208019Sthompsa
2103208019Sthompsa			/* read statistic counters (clear on read) */
2104208019Sthompsa			run_read_region_1(sc, RT2860_TX_STA_CNT0,
2105208019Sthompsa			    (uint8_t *)sta, sizeof sta);
2106208019Sthompsa
2107208019Sthompsa			break;
2108208019Sthompsa		default:
2109208019Sthompsa			ic->ic_opmode = vap->iv_opmode;
2110208019Sthompsa			break;
2111208019Sthompsa		}
2112208019Sthompsa
2113203134Sthompsa		if (vap->iv_opmode != IEEE80211_M_MONITOR) {
2114212127Sthompsa			struct ieee80211_node *ni;
2115212127Sthompsa
2116236439Shselasky			if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) {
2117236439Shselasky				RUN_UNLOCK(sc);
2118236439Shselasky				IEEE80211_LOCK(ic);
2119236439Shselasky				return (-1);
2120236439Shselasky			}
2121283540Sglebius			run_updateslot(ic);
2122203134Sthompsa			run_enable_mrr(sc);
2123203134Sthompsa			run_set_txpreamble(sc);
2124203134Sthompsa			run_set_basicrates(sc);
2125212127Sthompsa			ni = ieee80211_ref_node(vap->iv_bss);
2126287197Sglebius			IEEE80211_ADDR_COPY(ic->ic_macaddr, ni->ni_bssid);
2127203134Sthompsa			run_set_bssid(sc, ni->ni_bssid);
2128212127Sthompsa			ieee80211_free_node(ni);
2129208019Sthompsa			run_enable_tsf_sync(sc);
2130203134Sthompsa
2131208019Sthompsa			/* enable automatic rate adaptation */
2132208019Sthompsa			tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
2133208019Sthompsa			if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
2134208019Sthompsa				ratectl |= bid;
2135287555Skevlo		} else
2136287555Skevlo			run_enable_tsf(sc);
2137203134Sthompsa
2138203134Sthompsa		/* turn link LED on */
2139203134Sthompsa		run_set_leds(sc, RT2860_LED_RADIO |
2140208019Sthompsa		    (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ?
2141203134Sthompsa		     RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ));
2142203134Sthompsa
2143203134Sthompsa		break;
2144203134Sthompsa	default:
2145203134Sthompsa		DPRINTFN(6, "undefined case\n");
2146203134Sthompsa		break;
2147203134Sthompsa	}
2148203134Sthompsa
2149208019Sthompsa	/* restart amrr for running VAPs */
2150209917Sthompsa	if ((sc->ratectl_run = ratectl) && restart_ratectl)
2151208019Sthompsa		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2152208019Sthompsa
2153203134Sthompsa	RUN_UNLOCK(sc);
2154203134Sthompsa	IEEE80211_LOCK(ic);
2155203134Sthompsa
2156203134Sthompsa	return(rvp->newstate(vap, nstate, arg));
2157203134Sthompsa}
2158203134Sthompsa
2159203134Sthompsa/* ARGSUSED */
2160203134Sthompsastatic void
2161208019Sthompsarun_wme_update_cb(void *arg)
2162203134Sthompsa{
2163203134Sthompsa	struct ieee80211com *ic = arg;
2164286950Sadrian	struct run_softc *sc = ic->ic_softc;
2165288646Sadrian	const struct wmeParams *ac =
2166288646Sadrian	    ic->ic_wme.wme_chanParams.cap_wmeParams;
2167203134Sthompsa	int aci, error = 0;
2168203134Sthompsa
2169208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2170203134Sthompsa
2171203134Sthompsa	/* update MAC TX configuration registers */
2172203134Sthompsa	for (aci = 0; aci < WME_NUM_AC; aci++) {
2173203134Sthompsa		error = run_write(sc, RT2860_EDCA_AC_CFG(aci),
2174288646Sadrian		    ac[aci].wmep_logcwmax << 16 |
2175288646Sadrian		    ac[aci].wmep_logcwmin << 12 |
2176288646Sadrian		    ac[aci].wmep_aifsn    <<  8 |
2177288646Sadrian		    ac[aci].wmep_txopLimit);
2178209917Sthompsa		if (error) goto err;
2179203134Sthompsa	}
2180203134Sthompsa
2181203134Sthompsa	/* update SCH/DMA registers too */
2182203134Sthompsa	error = run_write(sc, RT2860_WMM_AIFSN_CFG,
2183288646Sadrian	    ac[WME_AC_VO].wmep_aifsn  << 12 |
2184288646Sadrian	    ac[WME_AC_VI].wmep_aifsn  <<  8 |
2185288646Sadrian	    ac[WME_AC_BK].wmep_aifsn  <<  4 |
2186288646Sadrian	    ac[WME_AC_BE].wmep_aifsn);
2187209917Sthompsa	if (error) goto err;
2188203134Sthompsa	error = run_write(sc, RT2860_WMM_CWMIN_CFG,
2189288646Sadrian	    ac[WME_AC_VO].wmep_logcwmin << 12 |
2190288646Sadrian	    ac[WME_AC_VI].wmep_logcwmin <<  8 |
2191288646Sadrian	    ac[WME_AC_BK].wmep_logcwmin <<  4 |
2192288646Sadrian	    ac[WME_AC_BE].wmep_logcwmin);
2193209917Sthompsa	if (error) goto err;
2194203134Sthompsa	error = run_write(sc, RT2860_WMM_CWMAX_CFG,
2195288646Sadrian	    ac[WME_AC_VO].wmep_logcwmax << 12 |
2196288646Sadrian	    ac[WME_AC_VI].wmep_logcwmax <<  8 |
2197288646Sadrian	    ac[WME_AC_BK].wmep_logcwmax <<  4 |
2198288646Sadrian	    ac[WME_AC_BE].wmep_logcwmax);
2199209917Sthompsa	if (error) goto err;
2200203134Sthompsa	error = run_write(sc, RT2860_WMM_TXOP0_CFG,
2201288646Sadrian	    ac[WME_AC_BK].wmep_txopLimit << 16 |
2202288646Sadrian	    ac[WME_AC_BE].wmep_txopLimit);
2203209917Sthompsa	if (error) goto err;
2204203134Sthompsa	error = run_write(sc, RT2860_WMM_TXOP1_CFG,
2205288646Sadrian	    ac[WME_AC_VO].wmep_txopLimit << 16 |
2206288646Sadrian	    ac[WME_AC_VI].wmep_txopLimit);
2207203134Sthompsa
2208203134Sthompsaerr:
2209209917Sthompsa	if (error)
2210203134Sthompsa		DPRINTF("WME update failed\n");
2211203134Sthompsa
2212203134Sthompsa	return;
2213203134Sthompsa}
2214203134Sthompsa
2215208019Sthompsastatic int
2216208019Sthompsarun_wme_update(struct ieee80211com *ic)
2217208019Sthompsa{
2218286950Sadrian	struct run_softc *sc = ic->ic_softc;
2219208019Sthompsa
2220208019Sthompsa	/* sometime called wothout lock */
2221209917Sthompsa	if (mtx_owned(&ic->ic_comlock.mtx)) {
2222208019Sthompsa		uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
2223208019Sthompsa		DPRINTF("cmdq_store=%d\n", i);
2224208019Sthompsa		sc->cmdq[i].func = run_wme_update_cb;
2225208019Sthompsa		sc->cmdq[i].arg0 = ic;
2226208019Sthompsa		ieee80211_runtask(ic, &sc->cmdq_task);
2227209918Sthompsa		return (0);
2228208019Sthompsa	}
2229208019Sthompsa
2230208019Sthompsa	RUN_LOCK(sc);
2231208019Sthompsa	run_wme_update_cb(ic);
2232208019Sthompsa	RUN_UNLOCK(sc);
2233208019Sthompsa
2234287552Skevlo	/* return whatever, upper layer doesn't care anyway */
2235208019Sthompsa	return (0);
2236208019Sthompsa}
2237208019Sthompsa
2238203134Sthompsastatic void
2239208019Sthompsarun_key_set_cb(void *arg)
2240203134Sthompsa{
2241208019Sthompsa	struct run_cmdq *cmdq = arg;
2242208019Sthompsa	struct ieee80211vap *vap = cmdq->arg1;
2243208019Sthompsa	struct ieee80211_key *k = cmdq->k;
2244203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2245286950Sadrian	struct run_softc *sc = ic->ic_softc;
2246203134Sthompsa	struct ieee80211_node *ni;
2247287553Skevlo	u_int cipher = k->wk_cipher->ic_cipher;
2248203134Sthompsa	uint32_t attr;
2249203134Sthompsa	uint16_t base, associd;
2250209144Sthompsa	uint8_t mode, wcid, iv[8];
2251203134Sthompsa
2252208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2253203134Sthompsa
2254209917Sthompsa	if (vap->iv_opmode == IEEE80211_M_HOSTAP)
2255208019Sthompsa		ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac);
2256209144Sthompsa	else
2257203134Sthompsa		ni = vap->iv_bss;
2258208019Sthompsa	associd = (ni != NULL) ? ni->ni_associd : 0;
2259203134Sthompsa
2260203134Sthompsa	/* map net80211 cipher to RT2860 security mode */
2261287553Skevlo	switch (cipher) {
2262203134Sthompsa	case IEEE80211_CIPHER_WEP:
2263203134Sthompsa		if(k->wk_keylen < 8)
2264203134Sthompsa			mode = RT2860_MODE_WEP40;
2265203134Sthompsa		else
2266203134Sthompsa			mode = RT2860_MODE_WEP104;
2267203134Sthompsa		break;
2268203134Sthompsa	case IEEE80211_CIPHER_TKIP:
2269203134Sthompsa		mode = RT2860_MODE_TKIP;
2270203134Sthompsa		break;
2271203134Sthompsa	case IEEE80211_CIPHER_AES_CCM:
2272203134Sthompsa		mode = RT2860_MODE_AES_CCMP;
2273203134Sthompsa		break;
2274203134Sthompsa	default:
2275203134Sthompsa		DPRINTF("undefined case\n");
2276208019Sthompsa		return;
2277203134Sthompsa	}
2278203134Sthompsa
2279208019Sthompsa	DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n",
2280203134Sthompsa	    associd, k->wk_keyix, mode,
2281208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise",
2282208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off",
2283208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off");
2284203134Sthompsa
2285203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2286203134Sthompsa		wcid = 0;	/* NB: update WCID0 for group keys */
2287208019Sthompsa		base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix);
2288203134Sthompsa	} else {
2289245047Shselasky		wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2290245047Shselasky		    1 : RUN_AID2WCID(associd);
2291203134Sthompsa		base = RT2860_PKEY(wcid);
2292203134Sthompsa	}
2293203134Sthompsa
2294287553Skevlo	if (cipher == IEEE80211_CIPHER_TKIP) {
2295203134Sthompsa		if(run_write_region_1(sc, base, k->wk_key, 16))
2296208019Sthompsa			return;
2297209144Sthompsa		if(run_write_region_1(sc, base + 16, &k->wk_key[16], 8))	/* wk_txmic */
2298208019Sthompsa			return;
2299209144Sthompsa		if(run_write_region_1(sc, base + 24, &k->wk_key[24], 8))	/* wk_rxmic */
2300208019Sthompsa			return;
2301203134Sthompsa	} else {
2302203134Sthompsa		/* roundup len to 16-bit: XXX fix write_region_1() instead */
2303203134Sthompsa		if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1))
2304208019Sthompsa			return;
2305203134Sthompsa	}
2306203134Sthompsa
2307203134Sthompsa	if (!(k->wk_flags & IEEE80211_KEY_GROUP) ||
2308203134Sthompsa	    (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) {
2309203134Sthompsa		/* set initial packet number in IV+EIV */
2310287553Skevlo		if (cipher == IEEE80211_CIPHER_WEP) {
2311203134Sthompsa			memset(iv, 0, sizeof iv);
2312208019Sthompsa			iv[3] = vap->iv_def_txkey << 6;
2313203134Sthompsa		} else {
2314287553Skevlo			if (cipher == IEEE80211_CIPHER_TKIP) {
2315203134Sthompsa				iv[0] = k->wk_keytsc >> 8;
2316203134Sthompsa				iv[1] = (iv[0] | 0x20) & 0x7f;
2317203134Sthompsa				iv[2] = k->wk_keytsc;
2318203134Sthompsa			} else /* CCMP */ {
2319203134Sthompsa				iv[0] = k->wk_keytsc;
2320203134Sthompsa				iv[1] = k->wk_keytsc >> 8;
2321203134Sthompsa				iv[2] = 0;
2322203134Sthompsa			}
2323203134Sthompsa			iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV;
2324203134Sthompsa			iv[4] = k->wk_keytsc >> 16;
2325203134Sthompsa			iv[5] = k->wk_keytsc >> 24;
2326203134Sthompsa			iv[6] = k->wk_keytsc >> 32;
2327203134Sthompsa			iv[7] = k->wk_keytsc >> 40;
2328203134Sthompsa		}
2329209917Sthompsa		if (run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8))
2330208019Sthompsa			return;
2331203134Sthompsa	}
2332203134Sthompsa
2333203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2334203134Sthompsa		/* install group key */
2335209917Sthompsa		if (run_read(sc, RT2860_SKEY_MODE_0_7, &attr))
2336208019Sthompsa			return;
2337203134Sthompsa		attr &= ~(0xf << (k->wk_keyix * 4));
2338203134Sthompsa		attr |= mode << (k->wk_keyix * 4);
2339209917Sthompsa		if (run_write(sc, RT2860_SKEY_MODE_0_7, attr))
2340208019Sthompsa			return;
2341203134Sthompsa	} else {
2342203134Sthompsa		/* install pairwise key */
2343209917Sthompsa		if (run_read(sc, RT2860_WCID_ATTR(wcid), &attr))
2344208019Sthompsa			return;
2345203134Sthompsa		attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN;
2346209917Sthompsa		if (run_write(sc, RT2860_WCID_ATTR(wcid), attr))
2347208019Sthompsa			return;
2348203134Sthompsa	}
2349203134Sthompsa
2350203134Sthompsa	/* TODO create a pass-thru key entry? */
2351203134Sthompsa
2352208019Sthompsa	/* need wcid to delete the right key later */
2353208019Sthompsa	k->wk_pad = wcid;
2354203134Sthompsa}
2355203134Sthompsa
2356203134Sthompsa/*
2357208019Sthompsa * Don't have to be deferred, but in order to keep order of
2358208019Sthompsa * execution, i.e. with run_key_delete(), defer this and let
2359208019Sthompsa * run_cmdq_cb() maintain the order.
2360208019Sthompsa *
2361203134Sthompsa * return 0 on error
2362203134Sthompsa */
2363203134Sthompsastatic int
2364288635Sadrianrun_key_set(struct ieee80211vap *vap, struct ieee80211_key *k)
2365203134Sthompsa{
2366203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2367286950Sadrian	struct run_softc *sc = ic->ic_softc;
2368208019Sthompsa	uint32_t i;
2369208019Sthompsa
2370208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
2371208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
2372208019Sthompsa	sc->cmdq[i].func = run_key_set_cb;
2373208019Sthompsa	sc->cmdq[i].arg0 = NULL;
2374208019Sthompsa	sc->cmdq[i].arg1 = vap;
2375208019Sthompsa	sc->cmdq[i].k = k;
2376288635Sadrian	IEEE80211_ADDR_COPY(sc->cmdq[i].mac, k->wk_macaddr);
2377208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
2378208019Sthompsa
2379209144Sthompsa	/*
2380209144Sthompsa	 * To make sure key will be set when hostapd
2381209144Sthompsa	 * calls iv_key_set() before if_init().
2382209144Sthompsa	 */
2383209917Sthompsa	if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
2384209144Sthompsa		RUN_LOCK(sc);
2385209144Sthompsa		sc->cmdq_key_set = RUN_CMDQ_GO;
2386209144Sthompsa		RUN_UNLOCK(sc);
2387209144Sthompsa	}
2388209144Sthompsa
2389209917Sthompsa	return (1);
2390208019Sthompsa}
2391208019Sthompsa
2392208019Sthompsa/*
2393208019Sthompsa * If wlan is destroyed without being brought down i.e. without
2394208019Sthompsa * wlan down or wpa_cli terminate, this function is called after
2395208019Sthompsa * vap is gone. Don't refer it.
2396208019Sthompsa */
2397208019Sthompsastatic void
2398208019Sthompsarun_key_delete_cb(void *arg)
2399208019Sthompsa{
2400208019Sthompsa	struct run_cmdq *cmdq = arg;
2401208019Sthompsa	struct run_softc *sc = cmdq->arg1;
2402208019Sthompsa	struct ieee80211_key *k = &cmdq->key;
2403203134Sthompsa	uint32_t attr;
2404203134Sthompsa	uint8_t wcid;
2405203134Sthompsa
2406208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2407203134Sthompsa
2408203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2409203134Sthompsa		/* remove group key */
2410208019Sthompsa		DPRINTF("removing group key\n");
2411208019Sthompsa		run_read(sc, RT2860_SKEY_MODE_0_7, &attr);
2412203134Sthompsa		attr &= ~(0xf << (k->wk_keyix * 4));
2413208019Sthompsa		run_write(sc, RT2860_SKEY_MODE_0_7, attr);
2414203134Sthompsa	} else {
2415203134Sthompsa		/* remove pairwise key */
2416208019Sthompsa		DPRINTF("removing key for wcid %x\n", k->wk_pad);
2417208019Sthompsa		/* matching wcid was written to wk_pad in run_key_set() */
2418208019Sthompsa		wcid = k->wk_pad;
2419208019Sthompsa		run_read(sc, RT2860_WCID_ATTR(wcid), &attr);
2420203134Sthompsa		attr &= ~0xf;
2421208019Sthompsa		run_write(sc, RT2860_WCID_ATTR(wcid), attr);
2422208019Sthompsa		run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8);
2423203134Sthompsa	}
2424203134Sthompsa
2425208019Sthompsa	k->wk_pad = 0;
2426203134Sthompsa}
2427203134Sthompsa
2428208019Sthompsa/*
2429208019Sthompsa * return 0 on error
2430208019Sthompsa */
2431208019Sthompsastatic int
2432208019Sthompsarun_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k)
2433203134Sthompsa{
2434208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2435286950Sadrian	struct run_softc *sc = ic->ic_softc;
2436208019Sthompsa	struct ieee80211_key *k0;
2437208019Sthompsa	uint32_t i;
2438203134Sthompsa
2439208019Sthompsa	/*
2440208019Sthompsa	 * When called back, key might be gone. So, make a copy
2441208019Sthompsa	 * of some values need to delete keys before deferring.
2442208019Sthompsa	 * But, because of LOR with node lock, cannot use lock here.
2443208019Sthompsa	 * So, use atomic instead.
2444208019Sthompsa	 */
2445208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
2446208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
2447208019Sthompsa	sc->cmdq[i].func = run_key_delete_cb;
2448208019Sthompsa	sc->cmdq[i].arg0 = NULL;
2449208019Sthompsa	sc->cmdq[i].arg1 = sc;
2450208019Sthompsa	k0 = &sc->cmdq[i].key;
2451208019Sthompsa	k0->wk_flags = k->wk_flags;
2452208019Sthompsa	k0->wk_keyix = k->wk_keyix;
2453208019Sthompsa	/* matching wcid was written to wk_pad in run_key_set() */
2454208019Sthompsa	k0->wk_pad = k->wk_pad;
2455208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
2456208019Sthompsa	return (1);	/* return fake success */
2457203134Sthompsa
2458203134Sthompsa}
2459203134Sthompsa
2460203134Sthompsastatic void
2461206358Srpaulorun_ratectl_to(void *arg)
2462203134Sthompsa{
2463208019Sthompsa	struct run_softc *sc = arg;
2464203134Sthompsa
2465203134Sthompsa	/* do it in a process context, so it can go sleep */
2466287197Sglebius	ieee80211_runtask(&sc->sc_ic, &sc->ratectl_task);
2467203134Sthompsa	/* next timeout will be rescheduled in the callback task */
2468203134Sthompsa}
2469203134Sthompsa
2470203134Sthompsa/* ARGSUSED */
2471203134Sthompsastatic void
2472206358Srpaulorun_ratectl_cb(void *arg, int pending)
2473203134Sthompsa{
2474208019Sthompsa	struct run_softc *sc = arg;
2475287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
2476208019Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
2477203134Sthompsa
2478209917Sthompsa	if (vap == NULL)
2479208019Sthompsa		return;
2480208019Sthompsa
2481262795Shselasky	if (sc->rvp_cnt > 1 || vap->iv_opmode != IEEE80211_M_STA) {
2482203134Sthompsa		/*
2483203134Sthompsa		 * run_reset_livelock() doesn't do anything with AMRR,
2484203134Sthompsa		 * but Ralink wants us to call it every 1 sec. So, we
2485203134Sthompsa		 * piggyback here rather than creating another callout.
2486203134Sthompsa		 * Livelock may occur only in HOSTAP or IBSS mode
2487203134Sthompsa		 * (when h/w is sending beacons).
2488203134Sthompsa		 */
2489203134Sthompsa		RUN_LOCK(sc);
2490203134Sthompsa		run_reset_livelock(sc);
2491208019Sthompsa		/* just in case, there are some stats to drain */
2492208019Sthompsa		run_drain_fifo(sc);
2493203134Sthompsa		RUN_UNLOCK(sc);
2494203134Sthompsa	}
2495203134Sthompsa
2496262795Shselasky	ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc);
2497262795Shselasky
2498257712Shselasky	RUN_LOCK(sc);
2499208019Sthompsa	if(sc->ratectl_run != RUN_RATECTL_OFF)
2500208019Sthompsa		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2501257712Shselasky	RUN_UNLOCK(sc);
2502203134Sthompsa}
2503203134Sthompsa
2504203134Sthompsastatic void
2505208019Sthompsarun_drain_fifo(void *arg)
2506203134Sthompsa{
2507208019Sthompsa	struct run_softc *sc = arg;
2508208019Sthompsa	uint32_t stat;
2509218676Shselasky	uint16_t (*wstat)[3];
2510203134Sthompsa	uint8_t wcid, mcs, pid;
2511218676Shselasky	int8_t retry;
2512203134Sthompsa
2513208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2514203134Sthompsa
2515208019Sthompsa	for (;;) {
2516203134Sthompsa		/* drain Tx status FIFO (maxsize = 16) */
2517203134Sthompsa		run_read(sc, RT2860_TX_STAT_FIFO, &stat);
2518208019Sthompsa		DPRINTFN(4, "tx stat 0x%08x\n", stat);
2519209917Sthompsa		if (!(stat & RT2860_TXQ_VLD))
2520208019Sthompsa			break;
2521203134Sthompsa
2522208019Sthompsa		wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff;
2523203134Sthompsa
2524208019Sthompsa		/* if no ACK was requested, no feedback is available */
2525208019Sthompsa		if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX ||
2526208019Sthompsa		    wcid == 0)
2527208019Sthompsa			continue;
2528203134Sthompsa
2529218676Shselasky		/*
2530218676Shselasky		 * Even though each stat is Tx-complete-status like format,
2531218676Shselasky		 * the device can poll stats. Because there is no guarantee
2532218676Shselasky		 * that the referring node is still around when read the stats.
2533218676Shselasky		 * So that, if we use ieee80211_ratectl_tx_update(), we will
2534218676Shselasky		 * have hard time not to refer already freed node.
2535218676Shselasky		 *
2536218676Shselasky		 * To eliminate such page faults, we poll stats in softc.
2537218676Shselasky		 * Then, update the rates later with ieee80211_ratectl_tx_update().
2538218676Shselasky		 */
2539218676Shselasky		wstat = &(sc->wcid_stats[wcid]);
2540218676Shselasky		(*wstat)[RUN_TXCNT]++;
2541218676Shselasky		if (stat & RT2860_TXQ_OK)
2542218676Shselasky			(*wstat)[RUN_SUCCESS]++;
2543218676Shselasky		else
2544287197Sglebius			counter_u64_add(sc->sc_ic.ic_oerrors, 1);
2545218676Shselasky		/*
2546218676Shselasky		 * Check if there were retries, ie if the Tx success rate is
2547218676Shselasky		 * different from the requested rate. Note that it works only
2548218676Shselasky		 * because we do not allow rate fallback from OFDM to CCK.
2549218676Shselasky		 */
2550218676Shselasky		mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f;
2551218676Shselasky		pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf;
2552218676Shselasky		if ((retry = pid -1 - mcs) > 0) {
2553218676Shselasky			(*wstat)[RUN_TXCNT] += retry;
2554218676Shselasky			(*wstat)[RUN_RETRY] += retry;
2555203134Sthompsa		}
2556208019Sthompsa	}
2557208019Sthompsa	DPRINTFN(3, "count=%d\n", sc->fifo_cnt);
2558208019Sthompsa
2559208019Sthompsa	sc->fifo_cnt = 0;
2560208019Sthompsa}
2561208019Sthompsa
2562208019Sthompsastatic void
2563208019Sthompsarun_iter_func(void *arg, struct ieee80211_node *ni)
2564208019Sthompsa{
2565208019Sthompsa	struct run_softc *sc = arg;
2566208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
2567287552Skevlo	struct run_node *rn = RUN_NODE(ni);
2568218676Shselasky	union run_stats sta[2];
2569218676Shselasky	uint16_t (*wstat)[3];
2570218676Shselasky	int txcnt, success, retrycnt, error;
2571208019Sthompsa
2572218676Shselasky	RUN_LOCK(sc);
2573218676Shselasky
2574262795Shselasky	/* Check for special case */
2575262795Shselasky	if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA &&
2576262795Shselasky	    ni != vap->iv_bss)
2577262795Shselasky		goto fail;
2578262795Shselasky
2579209917Sthompsa	if (sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS ||
2580209917Sthompsa	    vap->iv_opmode == IEEE80211_M_STA)) {
2581203134Sthompsa		/* read statistic counters (clear on read) and update AMRR state */
2582203134Sthompsa		error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta,
2583203134Sthompsa		    sizeof sta);
2584203134Sthompsa		if (error != 0)
2585218676Shselasky			goto fail;
2586203134Sthompsa
2587203134Sthompsa		/* count failed TX as errors */
2588287197Sglebius		if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS,
2589287197Sglebius		    le16toh(sta[0].error.fail));
2590203134Sthompsa
2591218676Shselasky		retrycnt = le16toh(sta[1].tx.retry);
2592218676Shselasky		success = le16toh(sta[1].tx.success);
2593218676Shselasky		txcnt = retrycnt + success + le16toh(sta[0].error.fail);
2594203134Sthompsa
2595218676Shselasky		DPRINTFN(3, "retrycnt=%d success=%d failcnt=%d\n",
2596218676Shselasky			retrycnt, success, le16toh(sta[0].error.fail));
2597218676Shselasky	} else {
2598218676Shselasky		wstat = &(sc->wcid_stats[RUN_AID2WCID(ni->ni_associd)]);
2599203134Sthompsa
2600218676Shselasky		if (wstat == &(sc->wcid_stats[0]) ||
2601218676Shselasky		    wstat > &(sc->wcid_stats[RT2870_WCID_MAX]))
2602218676Shselasky			goto fail;
2603208019Sthompsa
2604218676Shselasky		txcnt = (*wstat)[RUN_TXCNT];
2605218676Shselasky		success = (*wstat)[RUN_SUCCESS];
2606218676Shselasky		retrycnt = (*wstat)[RUN_RETRY];
2607218676Shselasky		DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n",
2608218676Shselasky		    retrycnt, txcnt, success);
2609208019Sthompsa
2610218676Shselasky		memset(wstat, 0, sizeof(*wstat));
2611203134Sthompsa	}
2612203134Sthompsa
2613218676Shselasky	ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt);
2614208019Sthompsa	rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0);
2615218676Shselasky
2616218676Shselaskyfail:
2617218676Shselasky	RUN_UNLOCK(sc);
2618218676Shselasky
2619208019Sthompsa	DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx);
2620208019Sthompsa}
2621203134Sthompsa
2622208019Sthompsastatic void
2623208019Sthompsarun_newassoc_cb(void *arg)
2624208019Sthompsa{
2625208019Sthompsa	struct run_cmdq *cmdq = arg;
2626208019Sthompsa	struct ieee80211_node *ni = cmdq->arg1;
2627286950Sadrian	struct run_softc *sc = ni->ni_vap->iv_ic->ic_softc;
2628208019Sthompsa	uint8_t wcid = cmdq->wcid;
2629203134Sthompsa
2630208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2631208019Sthompsa
2632208019Sthompsa	run_write_region_1(sc, RT2860_WCID_ENTRY(wcid),
2633208019Sthompsa	    ni->ni_macaddr, IEEE80211_ADDR_LEN);
2634218676Shselasky
2635218676Shselasky	memset(&(sc->wcid_stats[wcid]), 0, sizeof(sc->wcid_stats[wcid]));
2636203134Sthompsa}
2637203134Sthompsa
2638203134Sthompsastatic void
2639203134Sthompsarun_newassoc(struct ieee80211_node *ni, int isnew)
2640203134Sthompsa{
2641287552Skevlo	struct run_node *rn = RUN_NODE(ni);
2642203134Sthompsa	struct ieee80211_rateset *rs = &ni->ni_rates;
2643208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
2644208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2645286950Sadrian	struct run_softc *sc = ic->ic_softc;
2646203134Sthompsa	uint8_t rate;
2647208019Sthompsa	uint8_t ridx;
2648245047Shselasky	uint8_t wcid;
2649208019Sthompsa	int i, j;
2650203134Sthompsa
2651245047Shselasky	wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2652245047Shselasky	    1 : RUN_AID2WCID(ni->ni_associd);
2653245047Shselasky
2654209917Sthompsa	if (wcid > RT2870_WCID_MAX) {
2655208019Sthompsa		device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid);
2656208019Sthompsa		return;
2657208019Sthompsa	}
2658203134Sthompsa
2659208019Sthompsa	/* only interested in true associations */
2660209917Sthompsa	if (isnew && ni->ni_associd != 0) {
2661208019Sthompsa
2662208019Sthompsa		/*
2663208019Sthompsa		 * This function could is called though timeout function.
2664208019Sthompsa		 * Need to defer.
2665208019Sthompsa		 */
2666208019Sthompsa		uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store);
2667208019Sthompsa		DPRINTF("cmdq_store=%d\n", cnt);
2668208019Sthompsa		sc->cmdq[cnt].func = run_newassoc_cb;
2669208019Sthompsa		sc->cmdq[cnt].arg0 = NULL;
2670208019Sthompsa		sc->cmdq[cnt].arg1 = ni;
2671208019Sthompsa		sc->cmdq[cnt].wcid = wcid;
2672208019Sthompsa		ieee80211_runtask(ic, &sc->cmdq_task);
2673208019Sthompsa	}
2674208019Sthompsa
2675208019Sthompsa	DPRINTF("new assoc isnew=%d associd=%x addr=%s\n",
2676208019Sthompsa	    isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr));
2677208019Sthompsa
2678203134Sthompsa	for (i = 0; i < rs->rs_nrates; i++) {
2679203134Sthompsa		rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
2680203134Sthompsa		/* convert 802.11 rate to hardware rate index */
2681203134Sthompsa		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2682203134Sthompsa			if (rt2860_rates[ridx].rate == rate)
2683203134Sthompsa				break;
2684203134Sthompsa		rn->ridx[i] = ridx;
2685203134Sthompsa		/* determine rate of control response frames */
2686203134Sthompsa		for (j = i; j >= 0; j--) {
2687203134Sthompsa			if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) &&
2688203134Sthompsa			    rt2860_rates[rn->ridx[i]].phy ==
2689203134Sthompsa			    rt2860_rates[rn->ridx[j]].phy)
2690203134Sthompsa				break;
2691203134Sthompsa		}
2692203134Sthompsa		if (j >= 0) {
2693203134Sthompsa			rn->ctl_ridx[i] = rn->ridx[j];
2694203134Sthompsa		} else {
2695203134Sthompsa			/* no basic rate found, use mandatory one */
2696203134Sthompsa			rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx;
2697203134Sthompsa		}
2698203134Sthompsa		DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n",
2699203134Sthompsa		    rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]);
2700203134Sthompsa	}
2701208019Sthompsa	rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate;
2702208019Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2703208019Sthompsa		if (rt2860_rates[ridx].rate == rate)
2704208019Sthompsa			break;
2705208019Sthompsa	rn->mgt_ridx = ridx;
2706208019Sthompsa	DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx);
2707208019Sthompsa
2708262795Shselasky	RUN_LOCK(sc);
2709262795Shselasky	if(sc->ratectl_run != RUN_RATECTL_OFF)
2710262795Shselasky		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2711262795Shselasky	RUN_UNLOCK(sc);
2712203134Sthompsa}
2713203134Sthompsa
2714203134Sthompsa/*
2715203134Sthompsa * Return the Rx chain with the highest RSSI for a given frame.
2716203134Sthompsa */
2717203134Sthompsastatic __inline uint8_t
2718203134Sthompsarun_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi)
2719203134Sthompsa{
2720203134Sthompsa	uint8_t rxchain = 0;
2721203134Sthompsa
2722203134Sthompsa	if (sc->nrxchains > 1) {
2723203134Sthompsa		if (rxwi->rssi[1] > rxwi->rssi[rxchain])
2724203134Sthompsa			rxchain = 1;
2725203134Sthompsa		if (sc->nrxchains > 2)
2726203134Sthompsa			if (rxwi->rssi[2] > rxwi->rssi[rxchain])
2727203134Sthompsa				rxchain = 2;
2728203134Sthompsa	}
2729209917Sthompsa	return (rxchain);
2730203134Sthompsa}
2731203134Sthompsa
2732203134Sthompsastatic void
2733288603Sadrianrun_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype,
2734288603Sadrian    const struct ieee80211_rx_stats *rxs, int rssi, int nf)
2735288603Sadrian{
2736288603Sadrian	struct ieee80211vap *vap = ni->ni_vap;
2737288603Sadrian	struct run_softc *sc = vap->iv_ic->ic_softc;
2738288603Sadrian	struct run_vap *rvp = RUN_VAP(vap);
2739288603Sadrian	uint64_t ni_tstamp, rx_tstamp;
2740288603Sadrian
2741288603Sadrian	rvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf);
2742288603Sadrian
2743288603Sadrian	if (vap->iv_state == IEEE80211_S_RUN &&
2744288603Sadrian	    (subtype == IEEE80211_FC0_SUBTYPE_BEACON ||
2745288603Sadrian	    subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) {
2746288603Sadrian		ni_tstamp = le64toh(ni->ni_tstamp.tsf);
2747288603Sadrian		RUN_LOCK(sc);
2748288603Sadrian		run_get_tsf(sc, &rx_tstamp);
2749288603Sadrian		RUN_UNLOCK(sc);
2750288603Sadrian		rx_tstamp = le64toh(rx_tstamp);
2751288603Sadrian
2752288603Sadrian		if (ni_tstamp >= rx_tstamp) {
2753288603Sadrian			DPRINTF("ibss merge, tsf %ju tstamp %ju\n",
2754288603Sadrian			    (uintmax_t)rx_tstamp, (uintmax_t)ni_tstamp);
2755288603Sadrian			(void) ieee80211_ibss_merge(ni);
2756288603Sadrian		}
2757288603Sadrian	}
2758288603Sadrian}
2759288603Sadrian
2760288603Sadrianstatic void
2761203134Sthompsarun_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen)
2762203134Sthompsa{
2763287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
2764203134Sthompsa	struct ieee80211_frame *wh;
2765203134Sthompsa	struct ieee80211_node *ni;
2766203134Sthompsa	struct rt2870_rxd *rxd;
2767203134Sthompsa	struct rt2860_rxwi *rxwi;
2768203134Sthompsa	uint32_t flags;
2769259032Skevlo	uint16_t len, rxwisize;
2770203134Sthompsa	uint8_t ant, rssi;
2771203134Sthompsa	int8_t nf;
2772203134Sthompsa
2773203134Sthompsa	rxwi = mtod(m, struct rt2860_rxwi *);
2774203134Sthompsa	len = le16toh(rxwi->len) & 0xfff;
2775260219Skevlo	rxwisize = sizeof(struct rt2860_rxwi);
2776260219Skevlo	if (sc->mac_ver == 0x5592)
2777260219Skevlo		rxwisize += sizeof(uint64_t);
2778260219Skevlo	else if (sc->mac_ver == 0x3593)
2779260219Skevlo		rxwisize += sizeof(uint32_t);
2780203134Sthompsa	if (__predict_false(len > dmalen)) {
2781203134Sthompsa		m_freem(m);
2782287197Sglebius		counter_u64_add(ic->ic_ierrors, 1);
2783203134Sthompsa		DPRINTF("bad RXWI length %u > %u\n", len, dmalen);
2784203134Sthompsa		return;
2785203134Sthompsa	}
2786203134Sthompsa	/* Rx descriptor is located at the end */
2787203134Sthompsa	rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen);
2788203134Sthompsa	flags = le32toh(rxd->flags);
2789203134Sthompsa
2790203134Sthompsa	if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) {
2791203134Sthompsa		m_freem(m);
2792287197Sglebius		counter_u64_add(ic->ic_ierrors, 1);
2793203134Sthompsa		DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV");
2794203134Sthompsa		return;
2795203134Sthompsa	}
2796203134Sthompsa
2797259032Skevlo	m->m_data += rxwisize;
2798259032Skevlo	m->m_pkthdr.len = m->m_len -= rxwisize;
2799203134Sthompsa
2800203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
2801203134Sthompsa
2802260444Skevlo	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
2803260444Skevlo		wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
2804203134Sthompsa		m->m_flags |= M_WEP;
2805203134Sthompsa	}
2806203134Sthompsa
2807209917Sthompsa	if (flags & RT2860_RX_L2PAD) {
2808203134Sthompsa		DPRINTFN(8, "received RT2860_RX_L2PAD frame\n");
2809203134Sthompsa		len += 2;
2810203134Sthompsa	}
2811203134Sthompsa
2812208019Sthompsa	ni = ieee80211_find_rxnode(ic,
2813208019Sthompsa	    mtod(m, struct ieee80211_frame_min *));
2814208019Sthompsa
2815203134Sthompsa	if (__predict_false(flags & RT2860_RX_MICERR)) {
2816203134Sthompsa		/* report MIC failures to net80211 for TKIP */
2817209917Sthompsa		if (ni != NULL)
2818259032Skevlo			ieee80211_notify_michael_failure(ni->ni_vap, wh,
2819259032Skevlo			    rxwi->keyidx);
2820203134Sthompsa		m_freem(m);
2821287197Sglebius		counter_u64_add(ic->ic_ierrors, 1);
2822203134Sthompsa		DPRINTF("MIC error. Someone is lying.\n");
2823203134Sthompsa		return;
2824203134Sthompsa	}
2825203134Sthompsa
2826203134Sthompsa	ant = run_maxrssi_chain(sc, rxwi);
2827203134Sthompsa	rssi = rxwi->rssi[ant];
2828203134Sthompsa	nf = run_rssi2dbm(sc, rssi, ant);
2829203134Sthompsa
2830203134Sthompsa	m->m_pkthdr.len = m->m_len = len;
2831203134Sthompsa
2832203134Sthompsa	if (ni != NULL) {
2833203134Sthompsa		(void)ieee80211_input(ni, m, rssi, nf);
2834203134Sthompsa		ieee80211_free_node(ni);
2835203134Sthompsa	} else {
2836203134Sthompsa		(void)ieee80211_input_all(ic, m, rssi, nf);
2837203134Sthompsa	}
2838203134Sthompsa
2839209917Sthompsa	if (__predict_false(ieee80211_radiotap_active(ic))) {
2840203134Sthompsa		struct run_rx_radiotap_header *tap = &sc->sc_rxtap;
2841258643Shselasky		uint16_t phy;
2842203134Sthompsa
2843203134Sthompsa		tap->wr_flags = 0;
2844236439Shselasky		tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
2845236439Shselasky		tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
2846203134Sthompsa		tap->wr_antsignal = rssi;
2847203134Sthompsa		tap->wr_antenna = ant;
2848203134Sthompsa		tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant);
2849203134Sthompsa		tap->wr_rate = 2;	/* in case it can't be found below */
2850287554Skevlo		run_get_tsf(sc, &tap->wr_tsf);
2851203134Sthompsa		phy = le16toh(rxwi->phy);
2852203134Sthompsa		switch (phy & RT2860_PHY_MODE) {
2853203134Sthompsa		case RT2860_PHY_CCK:
2854203134Sthompsa			switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) {
2855203134Sthompsa			case 0:	tap->wr_rate =   2; break;
2856203134Sthompsa			case 1:	tap->wr_rate =   4; break;
2857203134Sthompsa			case 2:	tap->wr_rate =  11; break;
2858203134Sthompsa			case 3:	tap->wr_rate =  22; break;
2859203134Sthompsa			}
2860203134Sthompsa			if (phy & RT2860_PHY_SHPRE)
2861203134Sthompsa				tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
2862203134Sthompsa			break;
2863203134Sthompsa		case RT2860_PHY_OFDM:
2864203134Sthompsa			switch (phy & RT2860_PHY_MCS) {
2865203134Sthompsa			case 0:	tap->wr_rate =  12; break;
2866203134Sthompsa			case 1:	tap->wr_rate =  18; break;
2867203134Sthompsa			case 2:	tap->wr_rate =  24; break;
2868203134Sthompsa			case 3:	tap->wr_rate =  36; break;
2869203134Sthompsa			case 4:	tap->wr_rate =  48; break;
2870203134Sthompsa			case 5:	tap->wr_rate =  72; break;
2871203134Sthompsa			case 6:	tap->wr_rate =  96; break;
2872203134Sthompsa			case 7:	tap->wr_rate = 108; break;
2873203134Sthompsa			}
2874203134Sthompsa			break;
2875203134Sthompsa		}
2876203134Sthompsa	}
2877203134Sthompsa}
2878203134Sthompsa
2879203134Sthompsastatic void
2880203134Sthompsarun_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
2881203134Sthompsa{
2882203134Sthompsa	struct run_softc *sc = usbd_xfer_softc(xfer);
2883287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
2884203134Sthompsa	struct mbuf *m = NULL;
2885203134Sthompsa	struct mbuf *m0;
2886203134Sthompsa	uint32_t dmalen;
2887259032Skevlo	uint16_t rxwisize;
2888203134Sthompsa	int xferlen;
2889203134Sthompsa
2890260219Skevlo	rxwisize = sizeof(struct rt2860_rxwi);
2891260219Skevlo	if (sc->mac_ver == 0x5592)
2892260219Skevlo		rxwisize += sizeof(uint64_t);
2893260219Skevlo	else if (sc->mac_ver == 0x3593)
2894260219Skevlo		rxwisize += sizeof(uint32_t);
2895259032Skevlo
2896203134Sthompsa	usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL);
2897203134Sthompsa
2898203134Sthompsa	switch (USB_GET_STATE(xfer)) {
2899203134Sthompsa	case USB_ST_TRANSFERRED:
2900203134Sthompsa
2901203134Sthompsa		DPRINTFN(15, "rx done, actlen=%d\n", xferlen);
2902203134Sthompsa
2903259032Skevlo		if (xferlen < (int)(sizeof(uint32_t) + rxwisize +
2904259032Skevlo		    sizeof(struct rt2870_rxd))) {
2905203134Sthompsa			DPRINTF("xfer too short %d\n", xferlen);
2906203134Sthompsa			goto tr_setup;
2907203134Sthompsa		}
2908203134Sthompsa
2909203134Sthompsa		m = sc->rx_m;
2910203134Sthompsa		sc->rx_m = NULL;
2911203134Sthompsa
2912203134Sthompsa		/* FALLTHROUGH */
2913203134Sthompsa	case USB_ST_SETUP:
2914203134Sthompsatr_setup:
2915203134Sthompsa		if (sc->rx_m == NULL) {
2916243857Sglebius			sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
2917203134Sthompsa			    MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */);
2918203134Sthompsa		}
2919203134Sthompsa		if (sc->rx_m == NULL) {
2920203134Sthompsa			DPRINTF("could not allocate mbuf - idle with stall\n");
2921287197Sglebius			counter_u64_add(ic->ic_ierrors, 1);
2922203134Sthompsa			usbd_xfer_set_stall(xfer);
2923203134Sthompsa			usbd_xfer_set_frames(xfer, 0);
2924203134Sthompsa		} else {
2925203134Sthompsa			/*
2926203134Sthompsa			 * Directly loading a mbuf cluster into DMA to
2927203134Sthompsa			 * save some data copying. This works because
2928203134Sthompsa			 * there is only one cluster.
2929203134Sthompsa			 */
2930203134Sthompsa			usbd_xfer_set_frame_data(xfer, 0,
2931203134Sthompsa			    mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ);
2932203134Sthompsa			usbd_xfer_set_frames(xfer, 1);
2933203134Sthompsa		}
2934203134Sthompsa		usbd_transfer_submit(xfer);
2935203134Sthompsa		break;
2936203134Sthompsa
2937203134Sthompsa	default:	/* Error */
2938203134Sthompsa		if (error != USB_ERR_CANCELLED) {
2939203134Sthompsa			/* try to clear stall first */
2940203134Sthompsa			usbd_xfer_set_stall(xfer);
2941203134Sthompsa			if (error == USB_ERR_TIMEOUT)
2942203134Sthompsa				device_printf(sc->sc_dev, "device timeout\n");
2943287197Sglebius			counter_u64_add(ic->ic_ierrors, 1);
2944203134Sthompsa			goto tr_setup;
2945203134Sthompsa		}
2946209917Sthompsa		if (sc->rx_m != NULL) {
2947203134Sthompsa			m_freem(sc->rx_m);
2948203134Sthompsa			sc->rx_m = NULL;
2949203134Sthompsa		}
2950203134Sthompsa		break;
2951203134Sthompsa	}
2952203134Sthompsa
2953203134Sthompsa	if (m == NULL)
2954203134Sthompsa		return;
2955203134Sthompsa
2956203134Sthompsa	/* inputting all the frames must be last */
2957203134Sthompsa
2958203134Sthompsa	RUN_UNLOCK(sc);
2959203134Sthompsa
2960203134Sthompsa	m->m_pkthdr.len = m->m_len = xferlen;
2961203134Sthompsa
2962203134Sthompsa	/* HW can aggregate multiple 802.11 frames in a single USB xfer */
2963203134Sthompsa	for(;;) {
2964203134Sthompsa		dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff;
2965203134Sthompsa
2966233774Shselasky		if ((dmalen >= (uint32_t)-8) || (dmalen == 0) ||
2967233774Shselasky		    ((dmalen & 3) != 0)) {
2968203134Sthompsa			DPRINTF("bad DMA length %u\n", dmalen);
2969203134Sthompsa			break;
2970203134Sthompsa		}
2971233774Shselasky		if ((dmalen + 8) > (uint32_t)xferlen) {
2972203134Sthompsa			DPRINTF("bad DMA length %u > %d\n",
2973203134Sthompsa			dmalen + 8, xferlen);
2974203134Sthompsa			break;
2975203134Sthompsa		}
2976203134Sthompsa
2977203134Sthompsa		/* If it is the last one or a single frame, we won't copy. */
2978209917Sthompsa		if ((xferlen -= dmalen + 8) <= 8) {
2979203134Sthompsa			/* trim 32-bit DMA-len header */
2980203134Sthompsa			m->m_data += 4;
2981203134Sthompsa			m->m_pkthdr.len = m->m_len -= 4;
2982203134Sthompsa			run_rx_frame(sc, m, dmalen);
2983257435Shselasky			m = NULL;	/* don't free source buffer */
2984203134Sthompsa			break;
2985203134Sthompsa		}
2986203134Sthompsa
2987203134Sthompsa		/* copy aggregated frames to another mbuf */
2988243857Sglebius		m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
2989203134Sthompsa		if (__predict_false(m0 == NULL)) {
2990203134Sthompsa			DPRINTF("could not allocate mbuf\n");
2991287197Sglebius			counter_u64_add(ic->ic_ierrors, 1);
2992203134Sthompsa			break;
2993203134Sthompsa		}
2994203134Sthompsa		m_copydata(m, 4 /* skip 32-bit DMA-len header */,
2995203134Sthompsa		    dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t));
2996203134Sthompsa		m0->m_pkthdr.len = m0->m_len =
2997203134Sthompsa		    dmalen + sizeof(struct rt2870_rxd);
2998203134Sthompsa		run_rx_frame(sc, m0, dmalen);
2999203134Sthompsa
3000203134Sthompsa		/* update data ptr */
3001203134Sthompsa		m->m_data += dmalen + 8;
3002203134Sthompsa		m->m_pkthdr.len = m->m_len -= dmalen + 8;
3003203134Sthompsa	}
3004203134Sthompsa
3005257435Shselasky	/* make sure we free the source buffer, if any */
3006257435Shselasky	m_freem(m);
3007257435Shselasky
3008203134Sthompsa	RUN_LOCK(sc);
3009203134Sthompsa}
3010203134Sthompsa
3011203134Sthompsastatic void
3012203134Sthompsarun_tx_free(struct run_endpoint_queue *pq,
3013203134Sthompsa    struct run_tx_data *data, int txerr)
3014203134Sthompsa{
3015203134Sthompsa	if (data->m != NULL) {
3016203134Sthompsa		if (data->m->m_flags & M_TXCB)
3017203134Sthompsa			ieee80211_process_callback(data->ni, data->m,
3018203134Sthompsa			    txerr ? ETIMEDOUT : 0);
3019203134Sthompsa		m_freem(data->m);
3020203134Sthompsa		data->m = NULL;
3021203134Sthompsa
3022209917Sthompsa		if (data->ni == NULL) {
3023203134Sthompsa			DPRINTF("no node\n");
3024203134Sthompsa		} else {
3025203134Sthompsa			ieee80211_free_node(data->ni);
3026203134Sthompsa			data->ni = NULL;
3027203134Sthompsa		}
3028203134Sthompsa	}
3029203134Sthompsa
3030203134Sthompsa	STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
3031203134Sthompsa	pq->tx_nfree++;
3032203134Sthompsa}
3033203134Sthompsa
3034203134Sthompsastatic void
3035257429Shselaskyrun_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index)
3036203134Sthompsa{
3037203134Sthompsa	struct run_softc *sc = usbd_xfer_softc(xfer);
3038287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3039203134Sthompsa	struct run_tx_data *data;
3040203134Sthompsa	struct ieee80211vap *vap = NULL;
3041203134Sthompsa	struct usb_page_cache *pc;
3042203134Sthompsa	struct run_endpoint_queue *pq = &sc->sc_epq[index];
3043203134Sthompsa	struct mbuf *m;
3044203134Sthompsa	usb_frlength_t size;
3045203134Sthompsa	int actlen;
3046203134Sthompsa	int sumlen;
3047203134Sthompsa
3048203134Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
3049203134Sthompsa
3050209917Sthompsa	switch (USB_GET_STATE(xfer)) {
3051203134Sthompsa	case USB_ST_TRANSFERRED:
3052203134Sthompsa		DPRINTFN(11, "transfer complete: %d "
3053203134Sthompsa		    "bytes @ index %d\n", actlen, index);
3054203134Sthompsa
3055203134Sthompsa		data = usbd_xfer_get_priv(xfer);
3056203134Sthompsa		run_tx_free(pq, data, 0);
3057203134Sthompsa		usbd_xfer_set_priv(xfer, NULL);
3058203134Sthompsa
3059203134Sthompsa		/* FALLTHROUGH */
3060203134Sthompsa	case USB_ST_SETUP:
3061203134Sthompsatr_setup:
3062203134Sthompsa		data = STAILQ_FIRST(&pq->tx_qh);
3063209917Sthompsa		if (data == NULL)
3064203134Sthompsa			break;
3065203134Sthompsa
3066203134Sthompsa		STAILQ_REMOVE_HEAD(&pq->tx_qh, next);
3067203134Sthompsa
3068203134Sthompsa		m = data->m;
3069261330Shselasky		size = (sc->mac_ver == 0x5592) ?
3070261330Shselasky		    sizeof(data->desc) + sizeof(uint32_t) : sizeof(data->desc);
3071261076Shselasky		if ((m->m_pkthdr.len +
3072261330Shselasky		    size + 3 + 8) > RUN_MAX_TXSZ) {
3073203134Sthompsa			DPRINTF("data overflow, %u bytes\n",
3074203134Sthompsa			    m->m_pkthdr.len);
3075203134Sthompsa			run_tx_free(pq, data, 1);
3076203134Sthompsa			goto tr_setup;
3077203134Sthompsa		}
3078203134Sthompsa
3079203134Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
3080203134Sthompsa		usbd_copy_in(pc, 0, &data->desc, size);
3081203134Sthompsa		usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len);
3082228508Shselasky		size += m->m_pkthdr.len;
3083228508Shselasky		/*
3084228508Shselasky		 * Align end on a 4-byte boundary, pad 8 bytes (CRC +
3085228508Shselasky		 * 4-byte padding), and be sure to zero those trailing
3086228508Shselasky		 * bytes:
3087228508Shselasky		 */
3088228508Shselasky		usbd_frame_zero(pc, size, ((-size) & 3) + 8);
3089228508Shselasky		size += ((-size) & 3) + 8;
3090203134Sthompsa
3091203134Sthompsa		vap = data->ni->ni_vap;
3092203134Sthompsa		if (ieee80211_radiotap_active_vap(vap)) {
3093203134Sthompsa			struct run_tx_radiotap_header *tap = &sc->sc_txtap;
3094259032Skevlo			struct rt2860_txwi *txwi =
3095208019Sthompsa			    (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd));
3096203134Sthompsa			tap->wt_flags = 0;
3097203134Sthompsa			tap->wt_rate = rt2860_rates[data->ridx].rate;
3098287554Skevlo			run_get_tsf(sc, &tap->wt_tsf);
3099236439Shselasky			tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
3100236439Shselasky			tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
3101203134Sthompsa			tap->wt_hwqueue = index;
3102208019Sthompsa			if (le16toh(txwi->phy) & RT2860_PHY_SHPRE)
3103203134Sthompsa				tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
3104203134Sthompsa
3105203134Sthompsa			ieee80211_radiotap_tx(vap, m);
3106203134Sthompsa		}
3107203134Sthompsa
3108228508Shselasky		DPRINTFN(11, "sending frame len=%u/%u  @ index %d\n",
3109228508Shselasky		    m->m_pkthdr.len, size, index);
3110203134Sthompsa
3111228508Shselasky		usbd_xfer_set_frame_len(xfer, 0, size);
3112203134Sthompsa		usbd_xfer_set_priv(xfer, data);
3113203134Sthompsa		usbd_transfer_submit(xfer);
3114287197Sglebius		run_start(sc);
3115203134Sthompsa
3116203134Sthompsa		break;
3117203134Sthompsa
3118203134Sthompsa	default:
3119203134Sthompsa		DPRINTF("USB transfer error, %s\n",
3120203134Sthompsa		    usbd_errstr(error));
3121203134Sthompsa
3122203134Sthompsa		data = usbd_xfer_get_priv(xfer);
3123203134Sthompsa
3124203134Sthompsa		if (data != NULL) {
3125208019Sthompsa			if(data->ni != NULL)
3126208019Sthompsa				vap = data->ni->ni_vap;
3127203134Sthompsa			run_tx_free(pq, data, error);
3128203134Sthompsa			usbd_xfer_set_priv(xfer, NULL);
3129203134Sthompsa		}
3130287197Sglebius
3131209917Sthompsa		if (vap == NULL)
3132208019Sthompsa			vap = TAILQ_FIRST(&ic->ic_vaps);
3133203134Sthompsa
3134203134Sthompsa		if (error != USB_ERR_CANCELLED) {
3135203134Sthompsa			if (error == USB_ERR_TIMEOUT) {
3136203134Sthompsa				device_printf(sc->sc_dev, "device timeout\n");
3137208019Sthompsa				uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3138208019Sthompsa				DPRINTF("cmdq_store=%d\n", i);
3139208019Sthompsa				sc->cmdq[i].func = run_usb_timeout_cb;
3140208019Sthompsa				sc->cmdq[i].arg0 = vap;
3141208019Sthompsa				ieee80211_runtask(ic, &sc->cmdq_task);
3142203134Sthompsa			}
3143203134Sthompsa
3144203134Sthompsa			/*
3145203134Sthompsa			 * Try to clear stall first, also if other
3146203134Sthompsa			 * errors occur, hence clearing stall
3147203134Sthompsa			 * introduces a 50 ms delay:
3148203134Sthompsa			 */
3149203134Sthompsa			usbd_xfer_set_stall(xfer);
3150203134Sthompsa			goto tr_setup;
3151203134Sthompsa		}
3152203134Sthompsa		break;
3153203134Sthompsa	}
3154203134Sthompsa}
3155203134Sthompsa
3156203134Sthompsastatic void
3157203134Sthompsarun_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error)
3158203134Sthompsa{
3159203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 0);
3160203134Sthompsa}
3161203134Sthompsa
3162203134Sthompsastatic void
3163203134Sthompsarun_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error)
3164203134Sthompsa{
3165203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 1);
3166203134Sthompsa}
3167203134Sthompsa
3168203134Sthompsastatic void
3169203134Sthompsarun_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error)
3170203134Sthompsa{
3171203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 2);
3172203134Sthompsa}
3173203134Sthompsa
3174203134Sthompsastatic void
3175203134Sthompsarun_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error)
3176203134Sthompsa{
3177203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 3);
3178203134Sthompsa}
3179203134Sthompsa
3180203134Sthompsastatic void
3181203134Sthompsarun_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error)
3182203134Sthompsa{
3183203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 4);
3184203134Sthompsa}
3185203134Sthompsa
3186203134Sthompsastatic void
3187203134Sthompsarun_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error)
3188203134Sthompsa{
3189203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 5);
3190203134Sthompsa}
3191203134Sthompsa
3192203134Sthompsastatic void
3193208019Sthompsarun_set_tx_desc(struct run_softc *sc, struct run_tx_data *data)
3194203134Sthompsa{
3195203134Sthompsa	struct mbuf *m = data->m;
3196287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3197208019Sthompsa	struct ieee80211vap *vap = data->ni->ni_vap;
3198203134Sthompsa	struct ieee80211_frame *wh;
3199203134Sthompsa	struct rt2870_txd *txd;
3200203134Sthompsa	struct rt2860_txwi *txwi;
3201259032Skevlo	uint16_t xferlen, txwisize;
3202208019Sthompsa	uint16_t mcs;
3203203134Sthompsa	uint8_t ridx = data->ridx;
3204208019Sthompsa	uint8_t pad;
3205203134Sthompsa
3206203134Sthompsa	/* get MCS code from rate index */
3207208019Sthompsa	mcs = rt2860_rates[ridx].mcs;
3208203134Sthompsa
3209259032Skevlo	txwisize = (sc->mac_ver == 0x5592) ?
3210259032Skevlo	    sizeof(*txwi) + sizeof(uint32_t) : sizeof(*txwi);
3211259032Skevlo	xferlen = txwisize + m->m_pkthdr.len;
3212203134Sthompsa
3213203134Sthompsa	/* roundup to 32-bit alignment */
3214203134Sthompsa	xferlen = (xferlen + 3) & ~3;
3215203134Sthompsa
3216203134Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3217203134Sthompsa	txd->len = htole16(xferlen);
3218203134Sthompsa
3219208019Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3220208019Sthompsa
3221208019Sthompsa	/*
3222208019Sthompsa	 * Ether both are true or both are false, the header
3223208019Sthompsa	 * are nicely aligned to 32-bit. So, no L2 padding.
3224208019Sthompsa	 */
3225208019Sthompsa	if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh))
3226208019Sthompsa		pad = 0;
3227208019Sthompsa	else
3228208019Sthompsa		pad = 2;
3229208019Sthompsa
3230203134Sthompsa	/* setup TX Wireless Information */
3231203134Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3232203134Sthompsa	txwi->len = htole16(m->m_pkthdr.len - pad);
3233203134Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_DS) {
3234270192Skevlo		mcs |= RT2860_PHY_CCK;
3235203134Sthompsa		if (ridx != RT2860_RIDX_CCK1 &&
3236203134Sthompsa		    (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
3237203134Sthompsa			mcs |= RT2860_PHY_SHPRE;
3238203134Sthompsa	} else
3239270192Skevlo		mcs |= RT2860_PHY_OFDM;
3240270192Skevlo	txwi->phy = htole16(mcs);
3241203134Sthompsa
3242203134Sthompsa	/* check if RTS/CTS or CTS-to-self protection is required */
3243203134Sthompsa	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3244203134Sthompsa	    (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold ||
3245203134Sthompsa	     ((ic->ic_flags & IEEE80211_F_USEPROT) &&
3246203134Sthompsa	      rt2860_rates[ridx].phy == IEEE80211_T_OFDM)))
3247208019Sthompsa		txwi->txop |= RT2860_TX_TXOP_HT;
3248203134Sthompsa	else
3249208019Sthompsa		txwi->txop |= RT2860_TX_TXOP_BACKOFF;
3250209144Sthompsa
3251209917Sthompsa	if (vap->iv_opmode != IEEE80211_M_STA && !IEEE80211_QOS_HAS_SEQ(wh))
3252209144Sthompsa		txwi->xflags |= RT2860_TX_NSEQ;
3253203134Sthompsa}
3254203134Sthompsa
3255203134Sthompsa/* This function must be called locked */
3256203134Sthompsastatic int
3257203134Sthompsarun_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3258203134Sthompsa{
3259287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3260208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
3261203134Sthompsa	struct ieee80211_frame *wh;
3262208019Sthompsa	struct ieee80211_channel *chan;
3263203134Sthompsa	const struct ieee80211_txparam *tp;
3264287552Skevlo	struct run_node *rn = RUN_NODE(ni);
3265203134Sthompsa	struct run_tx_data *data;
3266208019Sthompsa	struct rt2870_txd *txd;
3267208019Sthompsa	struct rt2860_txwi *txwi;
3268203134Sthompsa	uint16_t qos;
3269203134Sthompsa	uint16_t dur;
3270208019Sthompsa	uint16_t qid;
3271203134Sthompsa	uint8_t type;
3272203134Sthompsa	uint8_t tid;
3273208019Sthompsa	uint8_t ridx;
3274208019Sthompsa	uint8_t ctl_ridx;
3275203134Sthompsa	uint8_t qflags;
3276203134Sthompsa	uint8_t xflags = 0;
3277203134Sthompsa	int hasqos;
3278203134Sthompsa
3279203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3280203134Sthompsa
3281203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3282203134Sthompsa
3283203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3284203134Sthompsa
3285203134Sthompsa	/*
3286203134Sthompsa	 * There are 7 bulk endpoints: 1 for RX
3287203134Sthompsa	 * and 6 for TX (4 EDCAs + HCCA + Prio).
3288203134Sthompsa	 * Update 03-14-2009:  some devices like the Planex GW-US300MiniS
3289203134Sthompsa	 * seem to have only 4 TX bulk endpoints (Fukaumi Naoki).
3290203134Sthompsa	 */
3291203134Sthompsa	if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) {
3292203134Sthompsa		uint8_t *frm;
3293203134Sthompsa
3294203134Sthompsa		if(IEEE80211_HAS_ADDR4(wh))
3295203134Sthompsa			frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos;
3296203134Sthompsa		else
3297203134Sthompsa			frm =((struct ieee80211_qosframe *)wh)->i_qos;
3298203134Sthompsa
3299203134Sthompsa		qos = le16toh(*(const uint16_t *)frm);
3300203134Sthompsa		tid = qos & IEEE80211_QOS_TID;
3301203134Sthompsa		qid = TID_TO_WME_AC(tid);
3302203134Sthompsa	} else {
3303203134Sthompsa		qos = 0;
3304203134Sthompsa		tid = 0;
3305203134Sthompsa		qid = WME_AC_BE;
3306203134Sthompsa	}
3307203134Sthompsa	qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA;
3308203134Sthompsa
3309203134Sthompsa	DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n",
3310203134Sthompsa	    qos, qid, tid, qflags);
3311203134Sthompsa
3312208019Sthompsa	chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan;
3313208019Sthompsa	tp = &vap->iv_txparms[ieee80211_chan2mode(chan)];
3314203134Sthompsa
3315203134Sthompsa	/* pickup a rate index */
3316203134Sthompsa	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
3317270192Skevlo	    type != IEEE80211_FC0_TYPE_DATA || m->m_flags & M_EAPOL) {
3318203134Sthompsa		ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
3319203134Sthompsa		    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
3320203134Sthompsa		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3321203134Sthompsa	} else {
3322208019Sthompsa		if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
3323208019Sthompsa			ridx = rn->fix_ridx;
3324208019Sthompsa		else
3325208019Sthompsa			ridx = rn->amrr_ridx;
3326203134Sthompsa		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3327203134Sthompsa	}
3328203134Sthompsa
3329203134Sthompsa	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3330203134Sthompsa	    (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) !=
3331203134Sthompsa	     IEEE80211_QOS_ACKPOLICY_NOACK)) {
3332209144Sthompsa		xflags |= RT2860_TX_ACK;
3333203134Sthompsa		if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
3334208019Sthompsa			dur = rt2860_rates[ctl_ridx].sp_ack_dur;
3335203134Sthompsa		else
3336208019Sthompsa			dur = rt2860_rates[ctl_ridx].lp_ack_dur;
3337258919Shselasky		USETW(wh->i_dur, dur);
3338203134Sthompsa	}
3339203134Sthompsa
3340203134Sthompsa	/* reserve slots for mgmt packets, just in case */
3341203134Sthompsa	if (sc->sc_epq[qid].tx_nfree < 3) {
3342203134Sthompsa		DPRINTFN(10, "tx ring %d is full\n", qid);
3343203134Sthompsa		return (-1);
3344203134Sthompsa	}
3345203134Sthompsa
3346203134Sthompsa	data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh);
3347203134Sthompsa	STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next);
3348203134Sthompsa	sc->sc_epq[qid].tx_nfree--;
3349203134Sthompsa
3350208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3351208019Sthompsa	txd->flags = qflags;
3352208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3353208019Sthompsa	txwi->xflags = xflags;
3354259032Skevlo	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
3355245047Shselasky		txwi->wcid = 0;
3356259032Skevlo	else
3357245047Shselasky		txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
3358245047Shselasky		    1 : RUN_AID2WCID(ni->ni_associd);
3359259032Skevlo
3360208019Sthompsa	/* clear leftover garbage bits */
3361208019Sthompsa	txwi->flags = 0;
3362208019Sthompsa	txwi->txop = 0;
3363208019Sthompsa
3364203134Sthompsa	data->m = m;
3365203134Sthompsa	data->ni = ni;
3366203134Sthompsa	data->ridx = ridx;
3367203134Sthompsa
3368208019Sthompsa	run_set_tx_desc(sc, data);
3369203134Sthompsa
3370208019Sthompsa	/*
3371208019Sthompsa	 * The chip keeps track of 2 kind of Tx stats,
3372208019Sthompsa	 *  * TX_STAT_FIFO, for per WCID stats, and
3373208019Sthompsa	 *  * TX_STA_CNT0 for all-TX-in-one stats.
3374208019Sthompsa	 *
3375208019Sthompsa	 * To use FIFO stats, we need to store MCS into the driver-private
3376208019Sthompsa 	 * PacketID field. So that, we can tell whose stats when we read them.
3377208019Sthompsa 	 * We add 1 to the MCS because setting the PacketID field to 0 means
3378208019Sthompsa 	 * that we don't want feedback in TX_STAT_FIFO.
3379208019Sthompsa 	 * And, that's what we want for STA mode, since TX_STA_CNT0 does the job.
3380208019Sthompsa 	 *
3381208019Sthompsa 	 * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx().
3382208019Sthompsa 	 */
3383209917Sthompsa	if (sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP ||
3384209917Sthompsa	    vap->iv_opmode == IEEE80211_M_MBSS) {
3385208019Sthompsa		uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf;
3386208019Sthompsa		txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT);
3387208019Sthompsa
3388208019Sthompsa		/*
3389208019Sthompsa		 * Unlike PCI based devices, we don't get any interrupt from
3390208019Sthompsa		 * USB devices, so we simulate FIFO-is-full interrupt here.
3391208019Sthompsa		 * Ralink recomends to drain FIFO stats every 100 ms, but 16 slots
3392208019Sthompsa		 * quickly get fulled. To prevent overflow, increment a counter on
3393208019Sthompsa		 * every FIFO stat request, so we know how many slots are left.
3394208019Sthompsa		 * We do this only in HOSTAP or multiple vap mode since FIFO stats
3395208019Sthompsa		 * are used only in those modes.
3396208019Sthompsa		 * We just drain stats. AMRR gets updated every 1 sec by
3397208019Sthompsa		 * run_ratectl_cb() via callout.
3398208019Sthompsa		 * Call it early. Otherwise overflow.
3399208019Sthompsa		 */
3400209917Sthompsa		if (sc->fifo_cnt++ == 10) {
3401208019Sthompsa			/*
3402208019Sthompsa			 * With multiple vaps or if_bridge, if_start() is called
3403208019Sthompsa			 * with a non-sleepable lock, tcpinp. So, need to defer.
3404208019Sthompsa			 */
3405208019Sthompsa			uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3406208019Sthompsa			DPRINTFN(6, "cmdq_store=%d\n", i);
3407208019Sthompsa			sc->cmdq[i].func = run_drain_fifo;
3408208019Sthompsa			sc->cmdq[i].arg0 = sc;
3409208019Sthompsa			ieee80211_runtask(ic, &sc->cmdq_task);
3410208019Sthompsa		}
3411208019Sthompsa	}
3412208019Sthompsa
3413203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next);
3414203134Sthompsa
3415203134Sthompsa	usbd_transfer_start(sc->sc_xfer[qid]);
3416203134Sthompsa
3417258840Skevlo	DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n",
3418259032Skevlo	    m->m_pkthdr.len + (int)(sizeof(struct rt2870_txd) +
3419259046Shselasky	    sizeof(struct rt2860_txwi)), rt2860_rates[ridx].rate, qid);
3420203134Sthompsa
3421203134Sthompsa	return (0);
3422203134Sthompsa}
3423203134Sthompsa
3424203134Sthompsastatic int
3425203134Sthompsarun_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3426203134Sthompsa{
3427287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3428287552Skevlo	struct run_node *rn = RUN_NODE(ni);
3429203134Sthompsa	struct run_tx_data *data;
3430203134Sthompsa	struct ieee80211_frame *wh;
3431208019Sthompsa	struct rt2870_txd *txd;
3432208019Sthompsa	struct rt2860_txwi *txwi;
3433203134Sthompsa	uint16_t dur;
3434208019Sthompsa	uint8_t ridx = rn->mgt_ridx;
3435203134Sthompsa	uint8_t type;
3436203134Sthompsa	uint8_t xflags = 0;
3437208019Sthompsa	uint8_t wflags = 0;
3438203134Sthompsa
3439203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3440203134Sthompsa
3441203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3442203134Sthompsa
3443203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3444203134Sthompsa
3445208019Sthompsa	/* tell hardware to add timestamp for probe responses */
3446208019Sthompsa	if ((wh->i_fc[0] &
3447208019Sthompsa	    (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
3448208019Sthompsa	    (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
3449208019Sthompsa		wflags |= RT2860_TX_TS;
3450208019Sthompsa	else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3451203134Sthompsa		xflags |= RT2860_TX_ACK;
3452203134Sthompsa
3453208019Sthompsa		dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate,
3454203134Sthompsa		    ic->ic_flags & IEEE80211_F_SHPREAMBLE);
3455258919Shselasky		USETW(wh->i_dur, dur);
3456203134Sthompsa	}
3457203134Sthompsa
3458287197Sglebius	if (sc->sc_epq[0].tx_nfree == 0)
3459203134Sthompsa		/* let caller free mbuf */
3460203134Sthompsa		return (EIO);
3461203134Sthompsa	data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3462203134Sthompsa	STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3463203134Sthompsa	sc->sc_epq[0].tx_nfree--;
3464203134Sthompsa
3465208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3466208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3467208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3468208019Sthompsa	txwi->wcid = 0xff;
3469208019Sthompsa	txwi->flags = wflags;
3470208019Sthompsa	txwi->xflags = xflags;
3471208019Sthompsa	txwi->txop = 0;	/* clear leftover garbage bits */
3472208019Sthompsa
3473203134Sthompsa	data->m = m;
3474203134Sthompsa	data->ni = ni;
3475203134Sthompsa	data->ridx = ridx;
3476203134Sthompsa
3477208019Sthompsa	run_set_tx_desc(sc, data);
3478203134Sthompsa
3479203134Sthompsa	DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len +
3480258840Skevlo	    (int)(sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi)),
3481208019Sthompsa	    rt2860_rates[ridx].rate);
3482203134Sthompsa
3483203134Sthompsa	STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3484203134Sthompsa
3485203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3486203134Sthompsa
3487203134Sthompsa	return (0);
3488203134Sthompsa}
3489203134Sthompsa
3490203134Sthompsastatic int
3491203134Sthompsarun_sendprot(struct run_softc *sc,
3492203134Sthompsa    const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate)
3493203134Sthompsa{
3494203134Sthompsa	struct ieee80211com *ic = ni->ni_ic;
3495203134Sthompsa	struct ieee80211_frame *wh;
3496203134Sthompsa	struct run_tx_data *data;
3497208019Sthompsa	struct rt2870_txd *txd;
3498208019Sthompsa	struct rt2860_txwi *txwi;
3499203134Sthompsa	struct mbuf *mprot;
3500203134Sthompsa	int ridx;
3501203134Sthompsa	int protrate;
3502203134Sthompsa	int ackrate;
3503203134Sthompsa	int pktlen;
3504203134Sthompsa	int isshort;
3505203134Sthompsa	uint16_t dur;
3506203134Sthompsa	uint8_t type;
3507208019Sthompsa	uint8_t wflags = 0;
3508208019Sthompsa	uint8_t xflags = 0;
3509203134Sthompsa
3510203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3511203134Sthompsa
3512203134Sthompsa	KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY,
3513203134Sthompsa	    ("protection %d", prot));
3514203134Sthompsa
3515203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3516203134Sthompsa	pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
3517203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3518203134Sthompsa
3519203134Sthompsa	protrate = ieee80211_ctl_rate(ic->ic_rt, rate);
3520203134Sthompsa	ackrate = ieee80211_ack_rate(ic->ic_rt, rate);
3521203134Sthompsa
3522203134Sthompsa	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
3523209189Sjkim	dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort)
3524203134Sthompsa	    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3525203134Sthompsa	wflags = RT2860_TX_FRAG;
3526203134Sthompsa
3527203134Sthompsa	/* check that there are free slots before allocating the mbuf */
3528287197Sglebius	if (sc->sc_epq[0].tx_nfree == 0)
3529203134Sthompsa		/* let caller free mbuf */
3530203134Sthompsa		return (ENOBUFS);
3531203134Sthompsa
3532203134Sthompsa	if (prot == IEEE80211_PROT_RTSCTS) {
3533203134Sthompsa		/* NB: CTS is the same size as an ACK */
3534203134Sthompsa		dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3535208019Sthompsa		xflags |= RT2860_TX_ACK;
3536203134Sthompsa		mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur);
3537203134Sthompsa	} else {
3538203134Sthompsa		mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur);
3539203134Sthompsa	}
3540203134Sthompsa	if (mprot == NULL) {
3541287197Sglebius		if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1);
3542203134Sthompsa		DPRINTF("could not allocate mbuf\n");
3543203134Sthompsa		return (ENOBUFS);
3544203134Sthompsa	}
3545203134Sthompsa
3546203134Sthompsa        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3547203134Sthompsa        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3548203134Sthompsa        sc->sc_epq[0].tx_nfree--;
3549203134Sthompsa
3550208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3551208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3552208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3553208019Sthompsa	txwi->wcid = 0xff;
3554208019Sthompsa	txwi->flags = wflags;
3555208019Sthompsa	txwi->xflags = xflags;
3556208019Sthompsa	txwi->txop = 0;	/* clear leftover garbage bits */
3557208019Sthompsa
3558203134Sthompsa	data->m = mprot;
3559203134Sthompsa	data->ni = ieee80211_ref_node(ni);
3560203134Sthompsa
3561203134Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3562203134Sthompsa		if (rt2860_rates[ridx].rate == protrate)
3563203134Sthompsa			break;
3564203134Sthompsa	data->ridx = ridx;
3565203134Sthompsa
3566208019Sthompsa	run_set_tx_desc(sc, data);
3567203134Sthompsa
3568203134Sthompsa        DPRINTFN(1, "sending prot len=%u rate=%u\n",
3569203134Sthompsa            m->m_pkthdr.len, rate);
3570203134Sthompsa
3571203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3572203134Sthompsa
3573203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3574203134Sthompsa
3575203134Sthompsa	return (0);
3576203134Sthompsa}
3577203134Sthompsa
3578203134Sthompsastatic int
3579203134Sthompsarun_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
3580203134Sthompsa    const struct ieee80211_bpf_params *params)
3581203134Sthompsa{
3582203134Sthompsa	struct ieee80211com *ic = ni->ni_ic;
3583203134Sthompsa	struct ieee80211_frame *wh;
3584203134Sthompsa	struct run_tx_data *data;
3585208019Sthompsa	struct rt2870_txd *txd;
3586208019Sthompsa	struct rt2860_txwi *txwi;
3587203134Sthompsa	uint8_t type;
3588208019Sthompsa	uint8_t ridx;
3589208019Sthompsa	uint8_t rate;
3590208019Sthompsa	uint8_t opflags = 0;
3591208019Sthompsa	uint8_t xflags = 0;
3592203134Sthompsa	int error;
3593203134Sthompsa
3594203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3595203134Sthompsa
3596203134Sthompsa	KASSERT(params != NULL, ("no raw xmit params"));
3597203134Sthompsa
3598203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3599203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3600203134Sthompsa
3601203134Sthompsa	rate = params->ibp_rate0;
3602203134Sthompsa	if (!ieee80211_isratevalid(ic->ic_rt, rate)) {
3603203134Sthompsa		/* let caller free mbuf */
3604203134Sthompsa		return (EINVAL);
3605203134Sthompsa	}
3606203134Sthompsa
3607203134Sthompsa	if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0)
3608208019Sthompsa		xflags |= RT2860_TX_ACK;
3609203134Sthompsa	if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) {
3610203134Sthompsa		error = run_sendprot(sc, m, ni,
3611203134Sthompsa		    params->ibp_flags & IEEE80211_BPF_RTS ?
3612203134Sthompsa			IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY,
3613203134Sthompsa		    rate);
3614203134Sthompsa		if (error) {
3615203134Sthompsa			/* let caller free mbuf */
3616209917Sthompsa			return error;
3617203134Sthompsa		}
3618203134Sthompsa		opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS;
3619203134Sthompsa	}
3620203134Sthompsa
3621203134Sthompsa	if (sc->sc_epq[0].tx_nfree == 0) {
3622203134Sthompsa		/* let caller free mbuf */
3623203134Sthompsa		DPRINTF("sending raw frame, but tx ring is full\n");
3624203134Sthompsa		return (EIO);
3625203134Sthompsa	}
3626203134Sthompsa        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3627203134Sthompsa        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3628203134Sthompsa        sc->sc_epq[0].tx_nfree--;
3629203134Sthompsa
3630208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3631208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3632208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3633208019Sthompsa	txwi->wcid = 0xff;
3634208019Sthompsa	txwi->xflags = xflags;
3635208019Sthompsa	txwi->txop = opflags;
3636208019Sthompsa	txwi->flags = 0;	/* clear leftover garbage bits */
3637208019Sthompsa
3638203134Sthompsa        data->m = m;
3639203134Sthompsa        data->ni = ni;
3640203134Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3641203134Sthompsa		if (rt2860_rates[ridx].rate == rate)
3642203134Sthompsa			break;
3643203134Sthompsa	data->ridx = ridx;
3644203134Sthompsa
3645208019Sthompsa        run_set_tx_desc(sc, data);
3646203134Sthompsa
3647203134Sthompsa        DPRINTFN(10, "sending raw frame len=%u rate=%u\n",
3648203134Sthompsa            m->m_pkthdr.len, rate);
3649203134Sthompsa
3650203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3651203134Sthompsa
3652203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3653203134Sthompsa
3654209917Sthompsa        return (0);
3655203134Sthompsa}
3656203134Sthompsa
3657203134Sthompsastatic int
3658203134Sthompsarun_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
3659203134Sthompsa    const struct ieee80211_bpf_params *params)
3660203134Sthompsa{
3661286950Sadrian	struct run_softc *sc = ni->ni_ic->ic_softc;
3662208019Sthompsa	int error = 0;
3663208019Sthompsa
3664203134Sthompsa	RUN_LOCK(sc);
3665203134Sthompsa
3666203134Sthompsa	/* prevent management frames from being sent if we're not ready */
3667287197Sglebius	if (!(sc->sc_flags & RUN_RUNNING)) {
3668287197Sglebius		error = ENETDOWN;
3669208019Sthompsa		goto done;
3670203134Sthompsa	}
3671203134Sthompsa
3672203134Sthompsa	if (params == NULL) {
3673203134Sthompsa		/* tx mgt packet */
3674209917Sthompsa		if ((error = run_tx_mgt(sc, m, ni)) != 0) {
3675203134Sthompsa			DPRINTF("mgt tx failed\n");
3676208019Sthompsa			goto done;
3677203134Sthompsa		}
3678203134Sthompsa	} else {
3679203134Sthompsa		/* tx raw packet with param */
3680209917Sthompsa		if ((error = run_tx_param(sc, m, ni, params)) != 0) {
3681203134Sthompsa			DPRINTF("tx with param failed\n");
3682208019Sthompsa			goto done;
3683203134Sthompsa		}
3684203134Sthompsa	}
3685203134Sthompsa
3686208019Sthompsadone:
3687203134Sthompsa	RUN_UNLOCK(sc);
3688203134Sthompsa
3689209917Sthompsa	if (error != 0) {
3690208019Sthompsa		if(m != NULL)
3691208019Sthompsa			m_freem(m);
3692208019Sthompsa		ieee80211_free_node(ni);
3693208019Sthompsa	}
3694203134Sthompsa
3695203134Sthompsa	return (error);
3696203134Sthompsa}
3697203134Sthompsa
3698287197Sglebiusstatic int
3699287197Sglebiusrun_transmit(struct ieee80211com *ic, struct mbuf *m)
3700287197Sglebius{
3701287197Sglebius	struct run_softc *sc = ic->ic_softc;
3702287197Sglebius	int error;
3703287197Sglebius
3704287197Sglebius	RUN_LOCK(sc);
3705287197Sglebius	if ((sc->sc_flags & RUN_RUNNING) == 0) {
3706287197Sglebius		RUN_UNLOCK(sc);
3707287197Sglebius		return (ENXIO);
3708287197Sglebius	}
3709287197Sglebius	error = mbufq_enqueue(&sc->sc_snd, m);
3710287197Sglebius	if (error) {
3711287197Sglebius		RUN_UNLOCK(sc);
3712287197Sglebius		return (error);
3713287197Sglebius	}
3714287197Sglebius	run_start(sc);
3715287197Sglebius	RUN_UNLOCK(sc);
3716287197Sglebius
3717287197Sglebius	return (0);
3718287197Sglebius}
3719287197Sglebius
3720203134Sthompsastatic void
3721287197Sglebiusrun_start(struct run_softc *sc)
3722203134Sthompsa{
3723203134Sthompsa	struct ieee80211_node *ni;
3724203134Sthompsa	struct mbuf *m;
3725203134Sthompsa
3726287197Sglebius	RUN_LOCK_ASSERT(sc, MA_OWNED);
3727203134Sthompsa
3728287197Sglebius	if ((sc->sc_flags & RUN_RUNNING) == 0)
3729203134Sthompsa		return;
3730203134Sthompsa
3731287197Sglebius	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
3732203134Sthompsa		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
3733203134Sthompsa		if (run_tx(sc, m, ni) != 0) {
3734287197Sglebius			mbufq_prepend(&sc->sc_snd, m);
3735203134Sthompsa			break;
3736203134Sthompsa		}
3737203134Sthompsa	}
3738203134Sthompsa}
3739203134Sthompsa
3740287197Sglebiusstatic void
3741287197Sglebiusrun_parent(struct ieee80211com *ic)
3742203134Sthompsa{
3743286950Sadrian	struct run_softc *sc = ic->ic_softc;
3744208019Sthompsa	int startall = 0;
3745203134Sthompsa
3746246614Shselasky	RUN_LOCK(sc);
3747287197Sglebius	if (sc->sc_detached) {
3748203134Sthompsa		RUN_UNLOCK(sc);
3749287197Sglebius		return;
3750203134Sthompsa	}
3751203134Sthompsa
3752287197Sglebius	if (ic->ic_nrunning > 0) {
3753287197Sglebius		if (!(sc->sc_flags & RUN_RUNNING)) {
3754287197Sglebius			startall = 1;
3755287197Sglebius			run_init_locked(sc);
3756287197Sglebius		} else
3757287197Sglebius			run_update_promisc_locked(sc);
3758287197Sglebius	} else if ((sc->sc_flags & RUN_RUNNING) && sc->rvp_cnt <= 1)
3759287197Sglebius		run_stop(sc);
3760287197Sglebius	RUN_UNLOCK(sc);
3761287197Sglebius	if (startall)
3762287197Sglebius		ieee80211_start_all(ic);
3763203134Sthompsa}
3764203134Sthompsa
3765203134Sthompsastatic void
3766259544Skevlorun_iq_calib(struct run_softc *sc, u_int chan)
3767259544Skevlo{
3768259544Skevlo	uint16_t val;
3769259544Skevlo
3770259544Skevlo	/* Tx0 IQ gain. */
3771259544Skevlo	run_bbp_write(sc, 158, 0x2c);
3772259544Skevlo	if (chan <= 14)
3773259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX0_2GHZ, &val, 1);
3774259544Skevlo	else if (chan <= 64) {
3775259544Skevlo		run_efuse_read(sc,
3776259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5GHZ,
3777259544Skevlo		    &val, 1);
3778259544Skevlo	} else if (chan <= 138) {
3779259544Skevlo		run_efuse_read(sc,
3780259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5GHZ,
3781259544Skevlo		    &val, 1);
3782259544Skevlo	} else if (chan <= 165) {
3783259544Skevlo		run_efuse_read(sc,
3784259544Skevlo	    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5GHZ,
3785259544Skevlo		    &val, 1);
3786259544Skevlo	} else
3787259544Skevlo		val = 0;
3788259547Skevlo	run_bbp_write(sc, 159, val);
3789259544Skevlo
3790259544Skevlo	/* Tx0 IQ phase. */
3791259544Skevlo	run_bbp_write(sc, 158, 0x2d);
3792259544Skevlo	if (chan <= 14) {
3793259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX0_2GHZ,
3794259544Skevlo		    &val, 1);
3795259544Skevlo	} else if (chan <= 64) {
3796259544Skevlo		run_efuse_read(sc,
3797259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5GHZ,
3798259544Skevlo		    &val, 1);
3799259544Skevlo	} else if (chan <= 138) {
3800259544Skevlo		run_efuse_read(sc,
3801259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5GHZ,
3802259544Skevlo		    &val, 1);
3803259544Skevlo	} else if (chan <= 165) {
3804259544Skevlo		run_efuse_read(sc,
3805259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5GHZ,
3806259544Skevlo		    &val, 1);
3807259544Skevlo	} else
3808259544Skevlo		val = 0;
3809259547Skevlo	run_bbp_write(sc, 159, val);
3810259544Skevlo
3811259544Skevlo	/* Tx1 IQ gain. */
3812259544Skevlo	run_bbp_write(sc, 158, 0x4a);
3813259544Skevlo	if (chan <= 14) {
3814259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX1_2GHZ,
3815259544Skevlo		    &val, 1);
3816259544Skevlo	} else if (chan <= 64) {
3817259544Skevlo		run_efuse_read(sc,
3818259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5GHZ,
3819259544Skevlo		    &val, 1);
3820259544Skevlo	} else if (chan <= 138) {
3821259544Skevlo		run_efuse_read(sc,
3822259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5GHZ,
3823259544Skevlo		    &val, 1);
3824259544Skevlo	} else if (chan <= 165) {
3825259544Skevlo		run_efuse_read(sc,
3826259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5GHZ,
3827259544Skevlo		    &val, 1);
3828259544Skevlo	} else
3829259544Skevlo		val = 0;
3830259547Skevlo	run_bbp_write(sc, 159, val);
3831259544Skevlo
3832259544Skevlo	/* Tx1 IQ phase. */
3833259544Skevlo	run_bbp_write(sc, 158, 0x4b);
3834259544Skevlo	if (chan <= 14) {
3835259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX1_2GHZ,
3836259544Skevlo		    &val, 1);
3837259544Skevlo	} else if (chan <= 64) {
3838259544Skevlo		run_efuse_read(sc,
3839259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5GHZ,
3840259544Skevlo		    &val, 1);
3841259544Skevlo	} else if (chan <= 138) {
3842259544Skevlo		run_efuse_read(sc,
3843259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5GHZ,
3844259544Skevlo		    &val, 1);
3845259544Skevlo	} else if (chan <= 165) {
3846259544Skevlo		run_efuse_read(sc,
3847259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5GHZ,
3848259544Skevlo		    &val, 1);
3849259544Skevlo	} else
3850259544Skevlo		val = 0;
3851259547Skevlo	run_bbp_write(sc, 159, val);
3852259544Skevlo
3853259544Skevlo	/* RF IQ compensation control. */
3854259544Skevlo	run_bbp_write(sc, 158, 0x04);
3855259544Skevlo	run_efuse_read(sc, RT5390_EEPROM_RF_IQ_COMPENSATION_CTL,
3856259544Skevlo	    &val, 1);
3857259547Skevlo	run_bbp_write(sc, 159, val);
3858259544Skevlo
3859259544Skevlo	/* RF IQ imbalance compensation control. */
3860259544Skevlo	run_bbp_write(sc, 158, 0x03);
3861259544Skevlo	run_efuse_read(sc,
3862259544Skevlo	    RT5390_EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CTL, &val, 1);
3863259547Skevlo	run_bbp_write(sc, 159, val);
3864259544Skevlo}
3865259544Skevlo
3866259544Skevlostatic void
3867205042Sthompsarun_set_agc(struct run_softc *sc, uint8_t agc)
3868205042Sthompsa{
3869205042Sthompsa	uint8_t bbp;
3870205042Sthompsa
3871205042Sthompsa	if (sc->mac_ver == 0x3572) {
3872205042Sthompsa		run_bbp_read(sc, 27, &bbp);
3873205042Sthompsa		bbp &= ~(0x3 << 5);
3874205042Sthompsa		run_bbp_write(sc, 27, bbp | 0 << 5);	/* select Rx0 */
3875205042Sthompsa		run_bbp_write(sc, 66, agc);
3876205042Sthompsa		run_bbp_write(sc, 27, bbp | 1 << 5);	/* select Rx1 */
3877205042Sthompsa		run_bbp_write(sc, 66, agc);
3878205042Sthompsa	} else
3879205042Sthompsa		run_bbp_write(sc, 66, agc);
3880205042Sthompsa}
3881205042Sthompsa
3882205042Sthompsastatic void
3883203134Sthompsarun_select_chan_group(struct run_softc *sc, int group)
3884203134Sthompsa{
3885203134Sthompsa	uint32_t tmp;
3886205042Sthompsa	uint8_t agc;
3887203134Sthompsa
3888203134Sthompsa	run_bbp_write(sc, 62, 0x37 - sc->lna[group]);
3889203134Sthompsa	run_bbp_write(sc, 63, 0x37 - sc->lna[group]);
3890203134Sthompsa	run_bbp_write(sc, 64, 0x37 - sc->lna[group]);
3891258082Skevlo	if (sc->mac_ver < 0x3572)
3892257955Skevlo		run_bbp_write(sc, 86, 0x00);
3893203134Sthompsa
3894260219Skevlo	if (sc->mac_ver == 0x3593) {
3895260219Skevlo		run_bbp_write(sc, 77, 0x98);
3896260219Skevlo		run_bbp_write(sc, 83, (group == 0) ? 0x8a : 0x9a);
3897260219Skevlo	}
3898260219Skevlo
3899203134Sthompsa	if (group == 0) {
3900203134Sthompsa		if (sc->ext_2ghz_lna) {
3901257955Skevlo			if (sc->mac_ver >= 0x5390)
3902257955Skevlo				run_bbp_write(sc, 75, 0x52);
3903257955Skevlo			else {
3904257955Skevlo				run_bbp_write(sc, 82, 0x62);
3905257955Skevlo				run_bbp_write(sc, 75, 0x46);
3906257955Skevlo			}
3907203134Sthompsa		} else {
3908259032Skevlo			if (sc->mac_ver == 0x5592) {
3909259032Skevlo				run_bbp_write(sc, 79, 0x1c);
3910259032Skevlo				run_bbp_write(sc, 80, 0x0e);
3911259032Skevlo				run_bbp_write(sc, 81, 0x3a);
3912259032Skevlo				run_bbp_write(sc, 82, 0x62);
3913259032Skevlo
3914259032Skevlo				run_bbp_write(sc, 195, 0x80);
3915259032Skevlo				run_bbp_write(sc, 196, 0xe0);
3916259032Skevlo				run_bbp_write(sc, 195, 0x81);
3917259032Skevlo				run_bbp_write(sc, 196, 0x1f);
3918259032Skevlo				run_bbp_write(sc, 195, 0x82);
3919259032Skevlo				run_bbp_write(sc, 196, 0x38);
3920259032Skevlo				run_bbp_write(sc, 195, 0x83);
3921259032Skevlo				run_bbp_write(sc, 196, 0x32);
3922259032Skevlo				run_bbp_write(sc, 195, 0x85);
3923259032Skevlo				run_bbp_write(sc, 196, 0x28);
3924259032Skevlo				run_bbp_write(sc, 195, 0x86);
3925259032Skevlo				run_bbp_write(sc, 196, 0x19);
3926259032Skevlo			} else if (sc->mac_ver >= 0x5390)
3927257955Skevlo				run_bbp_write(sc, 75, 0x50);
3928257955Skevlo			else {
3929260219Skevlo				run_bbp_write(sc, 82,
3930260219Skevlo				    (sc->mac_ver == 0x3593) ? 0x62 : 0x84);
3931257955Skevlo				run_bbp_write(sc, 75, 0x50);
3932257955Skevlo			}
3933203134Sthompsa		}
3934203134Sthompsa	} else {
3935259032Skevlo		if (sc->mac_ver == 0x5592) {
3936259032Skevlo			run_bbp_write(sc, 79, 0x18);
3937259032Skevlo			run_bbp_write(sc, 80, 0x08);
3938259032Skevlo			run_bbp_write(sc, 81, 0x38);
3939259032Skevlo			run_bbp_write(sc, 82, 0x92);
3940259032Skevlo
3941259032Skevlo			run_bbp_write(sc, 195, 0x80);
3942259032Skevlo			run_bbp_write(sc, 196, 0xf0);
3943259032Skevlo			run_bbp_write(sc, 195, 0x81);
3944259032Skevlo			run_bbp_write(sc, 196, 0x1e);
3945259032Skevlo			run_bbp_write(sc, 195, 0x82);
3946259032Skevlo			run_bbp_write(sc, 196, 0x28);
3947259032Skevlo			run_bbp_write(sc, 195, 0x83);
3948259032Skevlo			run_bbp_write(sc, 196, 0x20);
3949259032Skevlo			run_bbp_write(sc, 195, 0x85);
3950259032Skevlo			run_bbp_write(sc, 196, 0x7f);
3951259032Skevlo			run_bbp_write(sc, 195, 0x86);
3952259032Skevlo			run_bbp_write(sc, 196, 0x7f);
3953259032Skevlo		} else if (sc->mac_ver == 0x3572)
3954205042Sthompsa			run_bbp_write(sc, 82, 0x94);
3955205042Sthompsa		else
3956260219Skevlo			run_bbp_write(sc, 82,
3957260219Skevlo			    (sc->mac_ver == 0x3593) ? 0x82 : 0xf2);
3958205042Sthompsa		if (sc->ext_5ghz_lna)
3959203134Sthompsa			run_bbp_write(sc, 75, 0x46);
3960205042Sthompsa		else
3961203134Sthompsa			run_bbp_write(sc, 75, 0x50);
3962203134Sthompsa	}
3963203134Sthompsa
3964203134Sthompsa	run_read(sc, RT2860_TX_BAND_CFG, &tmp);
3965203134Sthompsa	tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P);
3966203134Sthompsa	tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P;
3967203134Sthompsa	run_write(sc, RT2860_TX_BAND_CFG, tmp);
3968203134Sthompsa
3969203134Sthompsa	/* enable appropriate Power Amplifiers and Low Noise Amplifiers */
3970208019Sthompsa	tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN;
3971260219Skevlo	if (sc->mac_ver == 0x3593)
3972260219Skevlo		tmp |= 1 << 29 | 1 << 28;
3973208019Sthompsa	if (sc->nrxchains > 1)
3974208019Sthompsa		tmp |= RT2860_LNA_PE1_EN;
3975203134Sthompsa	if (group == 0) {	/* 2GHz */
3976208019Sthompsa		tmp |= RT2860_PA_PE_G0_EN;
3977203134Sthompsa		if (sc->ntxchains > 1)
3978203134Sthompsa			tmp |= RT2860_PA_PE_G1_EN;
3979260219Skevlo		if (sc->mac_ver == 0x3593) {
3980260219Skevlo			if (sc->ntxchains > 2)
3981260219Skevlo				tmp |= 1 << 25;
3982260219Skevlo		}
3983203134Sthompsa	} else {		/* 5GHz */
3984208019Sthompsa		tmp |= RT2860_PA_PE_A0_EN;
3985203134Sthompsa		if (sc->ntxchains > 1)
3986203134Sthompsa			tmp |= RT2860_PA_PE_A1_EN;
3987203134Sthompsa	}
3988205042Sthompsa	if (sc->mac_ver == 0x3572) {
3989205042Sthompsa		run_rt3070_rf_write(sc, 8, 0x00);
3990205042Sthompsa		run_write(sc, RT2860_TX_PIN_CFG, tmp);
3991205042Sthompsa		run_rt3070_rf_write(sc, 8, 0x80);
3992205042Sthompsa	} else
3993205042Sthompsa		run_write(sc, RT2860_TX_PIN_CFG, tmp);
3994203134Sthompsa
3995259032Skevlo	if (sc->mac_ver == 0x5592) {
3996259032Skevlo		run_bbp_write(sc, 195, 0x8d);
3997259032Skevlo		run_bbp_write(sc, 196, 0x1a);
3998259032Skevlo	}
3999259032Skevlo
4000260219Skevlo	if (sc->mac_ver == 0x3593) {
4001260219Skevlo		run_read(sc, RT2860_GPIO_CTRL, &tmp);
4002260219Skevlo		tmp &= ~0x01010000;
4003260219Skevlo		if (group == 0)
4004260219Skevlo			tmp |= 0x00010000;
4005260219Skevlo		tmp = (tmp & ~0x00009090) | 0x00000090;
4006260219Skevlo		run_write(sc, RT2860_GPIO_CTRL, tmp);
4007260219Skevlo	}
4008260219Skevlo
4009203134Sthompsa	/* set initial AGC value */
4010205042Sthompsa	if (group == 0) {	/* 2GHz band */
4011205042Sthompsa		if (sc->mac_ver >= 0x3070)
4012205042Sthompsa			agc = 0x1c + sc->lna[0] * 2;
4013205042Sthompsa		else
4014205042Sthompsa			agc = 0x2e + sc->lna[0];
4015205042Sthompsa	} else {		/* 5GHz band */
4016259032Skevlo		if (sc->mac_ver == 0x5592)
4017259032Skevlo			agc = 0x24 + sc->lna[group] * 2;
4018260219Skevlo		else if (sc->mac_ver == 0x3572 || sc->mac_ver == 0x3593)
4019205042Sthompsa			agc = 0x22 + (sc->lna[group] * 5) / 3;
4020205042Sthompsa		else
4021205042Sthompsa			agc = 0x32 + (sc->lna[group] * 5) / 3;
4022205042Sthompsa	}
4023205042Sthompsa	run_set_agc(sc, agc);
4024203134Sthompsa}
4025203134Sthompsa
4026203134Sthompsastatic void
4027257429Shselaskyrun_rt2870_set_chan(struct run_softc *sc, u_int chan)
4028203134Sthompsa{
4029203134Sthompsa	const struct rfprog *rfprog = rt2860_rf2850;
4030203134Sthompsa	uint32_t r2, r3, r4;
4031203134Sthompsa	int8_t txpow1, txpow2;
4032203134Sthompsa	int i;
4033203134Sthompsa
4034203134Sthompsa	/* find the settings for this channel (we know it exists) */
4035203134Sthompsa	for (i = 0; rfprog[i].chan != chan; i++);
4036203134Sthompsa
4037203134Sthompsa	r2 = rfprog[i].r2;
4038203134Sthompsa	if (sc->ntxchains == 1)
4039258732Skevlo		r2 |= 1 << 14;		/* 1T: disable Tx chain 2 */
4040203134Sthompsa	if (sc->nrxchains == 1)
4041258732Skevlo		r2 |= 1 << 17 | 1 << 6;	/* 1R: disable Rx chains 2 & 3 */
4042203134Sthompsa	else if (sc->nrxchains == 2)
4043258732Skevlo		r2 |= 1 << 6;		/* 2R: disable Rx chain 3 */
4044203134Sthompsa
4045203134Sthompsa	/* use Tx power values from EEPROM */
4046203134Sthompsa	txpow1 = sc->txpow1[i];
4047203134Sthompsa	txpow2 = sc->txpow2[i];
4048258732Skevlo
4049258732Skevlo	/* Initialize RF R3 and R4. */
4050258732Skevlo	r3 = rfprog[i].r3 & 0xffffc1ff;
4051258732Skevlo	r4 = (rfprog[i].r4 & ~(0x001f87c0)) | (sc->freq << 15);
4052203134Sthompsa	if (chan > 14) {
4053258732Skevlo		if (txpow1 >= 0) {
4054258732Skevlo			txpow1 = (txpow1 > 0xf) ? (0xf) : (txpow1);
4055258732Skevlo			r3 |= (txpow1 << 10) | (1 << 9);
4056258732Skevlo		} else {
4057258732Skevlo			txpow1 += 7;
4058258732Skevlo
4059258732Skevlo			/* txpow1 is not possible larger than 15. */
4060258732Skevlo			r3 |= (txpow1 << 10);
4061258732Skevlo		}
4062258732Skevlo		if (txpow2 >= 0) {
4063258732Skevlo			txpow2 = (txpow2 > 0xf) ? (0xf) : (txpow2);
4064258921Shselasky			r4 |= (txpow2 << 7) | (1 << 6);
4065258732Skevlo		} else {
4066258732Skevlo			txpow2 += 7;
4067258732Skevlo			r4 |= (txpow2 << 7);
4068258732Skevlo		}
4069258732Skevlo	} else {
4070258732Skevlo		/* Set Tx0 power. */
4071258732Skevlo		r3 |= (txpow1 << 9);
4072258732Skevlo
4073258732Skevlo		/* Set frequency offset and Tx1 power. */
4074258732Skevlo		r4 |= (txpow2 << 6);
4075203134Sthompsa	}
4076203134Sthompsa
4077258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4078258733Skevlo	run_rt2870_rf_write(sc, r2);
4079258733Skevlo	run_rt2870_rf_write(sc, r3 & ~(1 << 2));
4080258733Skevlo	run_rt2870_rf_write(sc, r4);
4081203134Sthompsa
4082203134Sthompsa	run_delay(sc, 10);
4083203134Sthompsa
4084258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4085258733Skevlo	run_rt2870_rf_write(sc, r2);
4086258733Skevlo	run_rt2870_rf_write(sc, r3 | (1 << 2));
4087258733Skevlo	run_rt2870_rf_write(sc, r4);
4088203134Sthompsa
4089203134Sthompsa	run_delay(sc, 10);
4090203134Sthompsa
4091258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4092258733Skevlo	run_rt2870_rf_write(sc, r2);
4093258733Skevlo	run_rt2870_rf_write(sc, r3 & ~(1 << 2));
4094258733Skevlo	run_rt2870_rf_write(sc, r4);
4095203134Sthompsa}
4096203134Sthompsa
4097203134Sthompsastatic void
4098257429Shselaskyrun_rt3070_set_chan(struct run_softc *sc, u_int chan)
4099203134Sthompsa{
4100203134Sthompsa	int8_t txpow1, txpow2;
4101203134Sthompsa	uint8_t rf;
4102205042Sthompsa	int i;
4103203134Sthompsa
4104205042Sthompsa	/* find the settings for this channel (we know it exists) */
4105205042Sthompsa	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4106205042Sthompsa
4107203134Sthompsa	/* use Tx power values from EEPROM */
4108205042Sthompsa	txpow1 = sc->txpow1[i];
4109205042Sthompsa	txpow2 = sc->txpow2[i];
4110203134Sthompsa
4111205042Sthompsa	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
4112256720Skevlo
4113256720Skevlo	/* RT3370/RT3390: RF R3 [7:4] is not reserved bits. */
4114256720Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4115256720Skevlo	rf = (rf & ~0x0f) | rt3070_freqs[i].k;
4116256720Skevlo	run_rt3070_rf_write(sc, 3, rf);
4117256720Skevlo
4118203134Sthompsa	run_rt3070_rf_read(sc, 6, &rf);
4119205042Sthompsa	rf = (rf & ~0x03) | rt3070_freqs[i].r;
4120203134Sthompsa	run_rt3070_rf_write(sc, 6, rf);
4121203134Sthompsa
4122203134Sthompsa	/* set Tx0 power */
4123203134Sthompsa	run_rt3070_rf_read(sc, 12, &rf);
4124203134Sthompsa	rf = (rf & ~0x1f) | txpow1;
4125203134Sthompsa	run_rt3070_rf_write(sc, 12, rf);
4126203134Sthompsa
4127203134Sthompsa	/* set Tx1 power */
4128203134Sthompsa	run_rt3070_rf_read(sc, 13, &rf);
4129203134Sthompsa	rf = (rf & ~0x1f) | txpow2;
4130203134Sthompsa	run_rt3070_rf_write(sc, 13, rf);
4131203134Sthompsa
4132203134Sthompsa	run_rt3070_rf_read(sc, 1, &rf);
4133203134Sthompsa	rf &= ~0xfc;
4134203134Sthompsa	if (sc->ntxchains == 1)
4135203134Sthompsa		rf |= 1 << 7 | 1 << 5;	/* 1T: disable Tx chains 2 & 3 */
4136203134Sthompsa	else if (sc->ntxchains == 2)
4137203134Sthompsa		rf |= 1 << 7;		/* 2T: disable Tx chain 3 */
4138203134Sthompsa	if (sc->nrxchains == 1)
4139203134Sthompsa		rf |= 1 << 6 | 1 << 4;	/* 1R: disable Rx chains 2 & 3 */
4140203134Sthompsa	else if (sc->nrxchains == 2)
4141203134Sthompsa		rf |= 1 << 6;		/* 2R: disable Rx chain 3 */
4142203134Sthompsa	run_rt3070_rf_write(sc, 1, rf);
4143203134Sthompsa
4144203134Sthompsa	/* set RF offset */
4145203134Sthompsa	run_rt3070_rf_read(sc, 23, &rf);
4146203134Sthompsa	rf = (rf & ~0x7f) | sc->freq;
4147203134Sthompsa	run_rt3070_rf_write(sc, 23, rf);
4148203134Sthompsa
4149203134Sthompsa	/* program RF filter */
4150205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf);	/* Tx */
4151205042Sthompsa	rf = (rf & ~0x3f) | sc->rf24_20mhz;
4152205042Sthompsa	run_rt3070_rf_write(sc, 24, rf);
4153205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);	/* Rx */
4154205042Sthompsa	rf = (rf & ~0x3f) | sc->rf24_20mhz;
4155205042Sthompsa	run_rt3070_rf_write(sc, 31, rf);
4156203134Sthompsa
4157203134Sthompsa	/* enable RF tuning */
4158203134Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4159203134Sthompsa	run_rt3070_rf_write(sc, 7, rf | 0x01);
4160203134Sthompsa}
4161203134Sthompsa
4162203134Sthompsastatic void
4163205042Sthompsarun_rt3572_set_chan(struct run_softc *sc, u_int chan)
4164205042Sthompsa{
4165205042Sthompsa	int8_t txpow1, txpow2;
4166205042Sthompsa	uint32_t tmp;
4167205042Sthompsa	uint8_t rf;
4168205042Sthompsa	int i;
4169205042Sthompsa
4170205042Sthompsa	/* find the settings for this channel (we know it exists) */
4171205042Sthompsa	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4172205042Sthompsa
4173205042Sthompsa	/* use Tx power values from EEPROM */
4174205042Sthompsa	txpow1 = sc->txpow1[i];
4175205042Sthompsa	txpow2 = sc->txpow2[i];
4176205042Sthompsa
4177205042Sthompsa	if (chan <= 14) {
4178205042Sthompsa		run_bbp_write(sc, 25, sc->bbp25);
4179205042Sthompsa		run_bbp_write(sc, 26, sc->bbp26);
4180205042Sthompsa	} else {
4181205042Sthompsa		/* enable IQ phase correction */
4182205042Sthompsa		run_bbp_write(sc, 25, 0x09);
4183205042Sthompsa		run_bbp_write(sc, 26, 0xff);
4184205042Sthompsa	}
4185205042Sthompsa
4186205042Sthompsa	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
4187205042Sthompsa	run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k);
4188205042Sthompsa	run_rt3070_rf_read(sc, 6, &rf);
4189205042Sthompsa	rf  = (rf & ~0x0f) | rt3070_freqs[i].r;
4190205042Sthompsa	rf |= (chan <= 14) ? 0x08 : 0x04;
4191205042Sthompsa	run_rt3070_rf_write(sc, 6, rf);
4192205042Sthompsa
4193205042Sthompsa	/* set PLL mode */
4194205042Sthompsa	run_rt3070_rf_read(sc, 5, &rf);
4195205042Sthompsa	rf &= ~(0x08 | 0x04);
4196205042Sthompsa	rf |= (chan <= 14) ? 0x04 : 0x08;
4197205042Sthompsa	run_rt3070_rf_write(sc, 5, rf);
4198205042Sthompsa
4199205042Sthompsa	/* set Tx power for chain 0 */
4200205042Sthompsa	if (chan <= 14)
4201205042Sthompsa		rf = 0x60 | txpow1;
4202205042Sthompsa	else
4203205042Sthompsa		rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3);
4204205042Sthompsa	run_rt3070_rf_write(sc, 12, rf);
4205205042Sthompsa
4206205042Sthompsa	/* set Tx power for chain 1 */
4207205042Sthompsa	if (chan <= 14)
4208205042Sthompsa		rf = 0x60 | txpow2;
4209205042Sthompsa	else
4210205042Sthompsa		rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3);
4211205042Sthompsa	run_rt3070_rf_write(sc, 13, rf);
4212205042Sthompsa
4213205042Sthompsa	/* set Tx/Rx streams */
4214205042Sthompsa	run_rt3070_rf_read(sc, 1, &rf);
4215205042Sthompsa	rf &= ~0xfc;
4216205042Sthompsa	if (sc->ntxchains == 1)
4217205042Sthompsa		rf |= 1 << 7 | 1 << 5;  /* 1T: disable Tx chains 2 & 3 */
4218205042Sthompsa	else if (sc->ntxchains == 2)
4219205042Sthompsa		rf |= 1 << 7;           /* 2T: disable Tx chain 3 */
4220205042Sthompsa	if (sc->nrxchains == 1)
4221205042Sthompsa		rf |= 1 << 6 | 1 << 4;  /* 1R: disable Rx chains 2 & 3 */
4222205042Sthompsa	else if (sc->nrxchains == 2)
4223205042Sthompsa		rf |= 1 << 6;           /* 2R: disable Rx chain 3 */
4224205042Sthompsa	run_rt3070_rf_write(sc, 1, rf);
4225205042Sthompsa
4226205042Sthompsa	/* set RF offset */
4227205042Sthompsa	run_rt3070_rf_read(sc, 23, &rf);
4228205042Sthompsa	rf = (rf & ~0x7f) | sc->freq;
4229205042Sthompsa	run_rt3070_rf_write(sc, 23, rf);
4230205042Sthompsa
4231205042Sthompsa	/* program RF filter */
4232205042Sthompsa	rf = sc->rf24_20mhz;
4233205042Sthompsa	run_rt3070_rf_write(sc, 24, rf);	/* Tx */
4234205042Sthompsa	run_rt3070_rf_write(sc, 31, rf);	/* Rx */
4235205042Sthompsa
4236205042Sthompsa	/* enable RF tuning */
4237205042Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4238205042Sthompsa	rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14);
4239205042Sthompsa	run_rt3070_rf_write(sc, 7, rf);
4240205042Sthompsa
4241205042Sthompsa	/* TSSI */
4242205042Sthompsa	rf = (chan <= 14) ? 0xc3 : 0xc0;
4243205042Sthompsa	run_rt3070_rf_write(sc, 9, rf);
4244205042Sthompsa
4245205042Sthompsa	/* set loop filter 1 */
4246205042Sthompsa	run_rt3070_rf_write(sc, 10, 0xf1);
4247205042Sthompsa	/* set loop filter 2 */
4248205042Sthompsa	run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00);
4249205042Sthompsa
4250205042Sthompsa	/* set tx_mx2_ic */
4251205042Sthompsa	run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43);
4252205042Sthompsa	/* set tx_mx1_ic */
4253205042Sthompsa	if (chan <= 14)
4254205042Sthompsa		rf = 0x48 | sc->txmixgain_2ghz;
4255205042Sthompsa	else
4256205042Sthompsa		rf = 0x78 | sc->txmixgain_5ghz;
4257205042Sthompsa	run_rt3070_rf_write(sc, 16, rf);
4258205042Sthompsa
4259205042Sthompsa	/* set tx_lo1 */
4260205042Sthompsa	run_rt3070_rf_write(sc, 17, 0x23);
4261205042Sthompsa	/* set tx_lo2 */
4262205042Sthompsa	if (chan <= 14)
4263205042Sthompsa		rf = 0x93;
4264205042Sthompsa	else if (chan <= 64)
4265205042Sthompsa		rf = 0xb7;
4266205042Sthompsa	else if (chan <= 128)
4267205042Sthompsa		rf = 0x74;
4268205042Sthompsa	else
4269205042Sthompsa		rf = 0x72;
4270205042Sthompsa	run_rt3070_rf_write(sc, 19, rf);
4271205042Sthompsa
4272205042Sthompsa	/* set rx_lo1 */
4273205042Sthompsa	if (chan <= 14)
4274205042Sthompsa		rf = 0xb3;
4275205042Sthompsa	else if (chan <= 64)
4276205042Sthompsa		rf = 0xf6;
4277205042Sthompsa	else if (chan <= 128)
4278205042Sthompsa		rf = 0xf4;
4279205042Sthompsa	else
4280205042Sthompsa		rf = 0xf3;
4281205042Sthompsa	run_rt3070_rf_write(sc, 20, rf);
4282205042Sthompsa
4283205042Sthompsa	/* set pfd_delay */
4284205042Sthompsa	if (chan <= 14)
4285205042Sthompsa		rf = 0x15;
4286205042Sthompsa	else if (chan <= 64)
4287205042Sthompsa		rf = 0x3d;
4288205042Sthompsa	else
4289205042Sthompsa		rf = 0x01;
4290205042Sthompsa	run_rt3070_rf_write(sc, 25, rf);
4291205042Sthompsa
4292205042Sthompsa	/* set rx_lo2 */
4293205042Sthompsa	run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87);
4294205042Sthompsa	/* set ldo_rf_vc */
4295205042Sthompsa	run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01);
4296205042Sthompsa	/* set drv_cc */
4297205042Sthompsa	run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f);
4298205042Sthompsa
4299205042Sthompsa	run_read(sc, RT2860_GPIO_CTRL, &tmp);
4300205042Sthompsa	tmp &= ~0x8080;
4301205042Sthompsa	if (chan <= 14)
4302205042Sthompsa		tmp |= 0x80;
4303205042Sthompsa	run_write(sc, RT2860_GPIO_CTRL, tmp);
4304205042Sthompsa
4305205042Sthompsa	/* enable RF tuning */
4306205042Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4307205042Sthompsa	run_rt3070_rf_write(sc, 7, rf | 0x01);
4308205042Sthompsa
4309205042Sthompsa	run_delay(sc, 2);
4310205042Sthompsa}
4311205042Sthompsa
4312205042Sthompsastatic void
4313260219Skevlorun_rt3593_set_chan(struct run_softc *sc, u_int chan)
4314260219Skevlo{
4315260219Skevlo	int8_t txpow1, txpow2, txpow3;
4316260219Skevlo	uint8_t h20mhz, rf;
4317260219Skevlo	int i;
4318260219Skevlo
4319260219Skevlo	/* find the settings for this channel (we know it exists) */
4320260219Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4321260219Skevlo
4322260219Skevlo	/* use Tx power values from EEPROM */
4323260219Skevlo	txpow1 = sc->txpow1[i];
4324260219Skevlo	txpow2 = sc->txpow2[i];
4325260219Skevlo	txpow3 = (sc->ntxchains == 3) ? sc->txpow3[i] : 0;
4326260219Skevlo
4327260219Skevlo	if (chan <= 14) {
4328260219Skevlo		run_bbp_write(sc, 25, sc->bbp25);
4329260219Skevlo		run_bbp_write(sc, 26, sc->bbp26);
4330260219Skevlo	} else {
4331260219Skevlo		/* Enable IQ phase correction. */
4332260219Skevlo		run_bbp_write(sc, 25, 0x09);
4333260219Skevlo		run_bbp_write(sc, 26, 0xff);
4334260219Skevlo	}
4335260219Skevlo
4336260219Skevlo	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
4337260219Skevlo	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
4338260219Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4339260219Skevlo	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
4340260219Skevlo	run_rt3070_rf_write(sc, 11, rf);
4341260219Skevlo
4342260219Skevlo	/* Set pll_idoh. */
4343260219Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4344260219Skevlo	rf &= ~0x4c;
4345260219Skevlo	rf |= (chan <= 14) ? 0x44 : 0x48;
4346260219Skevlo	run_rt3070_rf_write(sc, 11, rf);
4347260219Skevlo
4348260219Skevlo	if (chan <= 14)
4349260219Skevlo		rf = txpow1 & 0x1f;
4350260219Skevlo	else
4351260219Skevlo		rf = 0x40 | ((txpow1 & 0x18) << 1) | (txpow1 & 0x07);
4352260219Skevlo	run_rt3070_rf_write(sc, 53, rf);
4353260219Skevlo
4354260219Skevlo	if (chan <= 14)
4355260219Skevlo		rf = txpow2 & 0x1f;
4356260219Skevlo	else
4357260219Skevlo		rf = 0x40 | ((txpow2 & 0x18) << 1) | (txpow2 & 0x07);
4358260219Skevlo	run_rt3070_rf_write(sc, 55, rf);
4359260219Skevlo
4360260219Skevlo	if (chan <= 14)
4361260219Skevlo		rf = txpow3 & 0x1f;
4362260219Skevlo	else
4363260219Skevlo		rf = 0x40 | ((txpow3 & 0x18) << 1) | (txpow3 & 0x07);
4364260219Skevlo	run_rt3070_rf_write(sc, 54, rf);
4365260219Skevlo
4366260219Skevlo	rf = RT3070_RF_BLOCK | RT3070_PLL_PD;
4367260219Skevlo	if (sc->ntxchains == 3)
4368260219Skevlo		rf |= RT3070_TX0_PD | RT3070_TX1_PD | RT3070_TX2_PD;
4369260219Skevlo	else
4370260219Skevlo		rf |= RT3070_TX0_PD | RT3070_TX1_PD;
4371260219Skevlo	rf |= RT3070_RX0_PD | RT3070_RX1_PD | RT3070_RX2_PD;
4372260219Skevlo	run_rt3070_rf_write(sc, 1, rf);
4373260219Skevlo
4374260219Skevlo	run_adjust_freq_offset(sc);
4375260219Skevlo
4376260219Skevlo	run_rt3070_rf_write(sc, 31, (chan <= 14) ? 0xa0 : 0x80);
4377260219Skevlo
4378260219Skevlo	h20mhz = (sc->rf24_20mhz & 0x20) >> 5;
4379260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
4380260219Skevlo	rf = (rf & ~0x06) | (h20mhz << 1) | (h20mhz << 2);
4381260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
4382260219Skevlo
4383260219Skevlo	run_rt3070_rf_read(sc, 36, &rf);
4384260219Skevlo	if (chan <= 14)
4385260219Skevlo		rf |= 0x80;
4386260219Skevlo	else
4387260219Skevlo		rf &= ~0x80;
4388260219Skevlo	run_rt3070_rf_write(sc, 36, rf);
4389260219Skevlo
4390260219Skevlo	/* Set vcolo_bs. */
4391260219Skevlo	run_rt3070_rf_write(sc, 34, (chan <= 14) ? 0x3c : 0x20);
4392260219Skevlo	/* Set pfd_delay. */
4393260219Skevlo	run_rt3070_rf_write(sc, 12, (chan <= 14) ? 0x1a : 0x12);
4394260219Skevlo
4395260219Skevlo	/* Set vco bias current control. */
4396260219Skevlo	run_rt3070_rf_read(sc, 6, &rf);
4397260219Skevlo	rf &= ~0xc0;
4398260219Skevlo	if (chan <= 14)
4399260219Skevlo		rf |= 0x40;
4400260219Skevlo	else if (chan <= 128)
4401260219Skevlo		rf |= 0x80;
4402260219Skevlo	else
4403260219Skevlo		rf |= 0x40;
4404260219Skevlo	run_rt3070_rf_write(sc, 6, rf);
4405260219Skevlo
4406260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
4407260219Skevlo	rf = (rf & ~0x18) | 0x10;
4408260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
4409260219Skevlo
4410260219Skevlo	run_rt3070_rf_write(sc, 10, (chan <= 14) ? 0xd3 : 0xd8);
4411260219Skevlo	run_rt3070_rf_write(sc, 13, (chan <= 14) ? 0x12 : 0x23);
4412260219Skevlo
4413260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4414260219Skevlo	rf = (rf & ~0x03) | 0x01;
4415260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4416260219Skevlo	/* Set tx_mx1_cc. */
4417260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4418260219Skevlo	rf &= ~0x1c;
4419260219Skevlo	rf |= (chan <= 14) ? 0x14 : 0x10;
4420260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4421260219Skevlo	/* Set tx_mx1_ic. */
4422260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4423260219Skevlo	rf &= ~0xe0;
4424260219Skevlo	rf |= (chan <= 14) ? 0x60 : 0x40;
4425260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4426260219Skevlo	/* Set tx_lo1_ic. */
4427260219Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4428260219Skevlo	rf &= ~0x1c;
4429260219Skevlo	rf |= (chan <= 14) ? 0x0c : 0x08;
4430260219Skevlo	run_rt3070_rf_write(sc, 49, rf);
4431260219Skevlo	/* Set tx_lo1_en. */
4432260219Skevlo	run_rt3070_rf_read(sc, 50, &rf);
4433260219Skevlo	run_rt3070_rf_write(sc, 50, rf & ~0x20);
4434260219Skevlo	/* Set drv_cc. */
4435260219Skevlo	run_rt3070_rf_read(sc, 57, &rf);
4436260219Skevlo	rf &= ~0xfc;
4437260219Skevlo	rf |= (chan <= 14) ?  0x6c : 0x3c;
4438260219Skevlo	run_rt3070_rf_write(sc, 57, rf);
4439260219Skevlo	/* Set rx_mix1_ic, rxa_lnactr, lna_vc, lna_inbias_en and lna_en. */
4440260219Skevlo	run_rt3070_rf_write(sc, 44, (chan <= 14) ? 0x93 : 0x9b);
4441260219Skevlo	/* Set drv_gnd_a, tx_vga_cc_a and tx_mx2_gain. */
4442260219Skevlo	run_rt3070_rf_write(sc, 52, (chan <= 14) ? 0x45 : 0x05);
4443260219Skevlo	/* Enable VCO calibration. */
4444260219Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4445260219Skevlo	rf &= ~RT5390_VCOCAL;
4446260219Skevlo	rf |= (chan <= 14) ? RT5390_VCOCAL : 0xbe;
4447260219Skevlo	run_rt3070_rf_write(sc, 3, rf);
4448260219Skevlo
4449260219Skevlo	if (chan <= 14)
4450260219Skevlo		rf = 0x23;
4451260219Skevlo	else if (chan <= 64)
4452260219Skevlo		rf = 0x36;
4453260219Skevlo	else if (chan <= 128)
4454260219Skevlo		rf = 0x32;
4455260219Skevlo	else
4456260219Skevlo		rf = 0x30;
4457260219Skevlo	run_rt3070_rf_write(sc, 39, rf);
4458260219Skevlo	if (chan <= 14)
4459260219Skevlo		rf = 0xbb;
4460260219Skevlo	else if (chan <= 64)
4461260219Skevlo		rf = 0xeb;
4462260219Skevlo	else if (chan <= 128)
4463260219Skevlo		rf = 0xb3;
4464260219Skevlo	else
4465260219Skevlo		rf = 0x9b;
4466260219Skevlo	run_rt3070_rf_write(sc, 45, rf);
4467260219Skevlo
4468260219Skevlo	/* Set FEQ/AEQ control. */
4469260219Skevlo	run_bbp_write(sc, 105, 0x34);
4470260219Skevlo}
4471260219Skevlo
4472260219Skevlostatic void
4473257955Skevlorun_rt5390_set_chan(struct run_softc *sc, u_int chan)
4474257955Skevlo{
4475257955Skevlo	int8_t txpow1, txpow2;
4476257955Skevlo	uint8_t rf;
4477257955Skevlo	int i;
4478257955Skevlo
4479257955Skevlo	/* find the settings for this channel (we know it exists) */
4480257955Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4481257955Skevlo
4482257955Skevlo	/* use Tx power values from EEPROM */
4483257955Skevlo	txpow1 = sc->txpow1[i];
4484257955Skevlo	txpow2 = sc->txpow2[i];
4485257955Skevlo
4486257955Skevlo	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
4487257955Skevlo	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
4488257955Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4489257955Skevlo	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
4490257955Skevlo	run_rt3070_rf_write(sc, 11, rf);
4491257955Skevlo
4492257955Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4493257955Skevlo	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
4494257955Skevlo	/* The valid range of the RF R49 is 0x00 to 0x27. */
4495257955Skevlo	if ((rf & 0x3f) > 0x27)
4496257955Skevlo		rf = (rf & ~0x3f) | 0x27;
4497257955Skevlo	run_rt3070_rf_write(sc, 49, rf);
4498257955Skevlo
4499257955Skevlo	if (sc->mac_ver == 0x5392) {
4500257955Skevlo		run_rt3070_rf_read(sc, 50, &rf);
4501257955Skevlo		rf = (rf & ~0x3f) | (txpow2 & 0x3f);
4502257955Skevlo		/* The valid range of the RF R50 is 0x00 to 0x27. */
4503257955Skevlo		if ((rf & 0x3f) > 0x27)
4504257955Skevlo			rf = (rf & ~0x3f) | 0x27;
4505257955Skevlo		run_rt3070_rf_write(sc, 50, rf);
4506257955Skevlo	}
4507257955Skevlo
4508257955Skevlo	run_rt3070_rf_read(sc, 1, &rf);
4509257955Skevlo	rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD;
4510257955Skevlo	if (sc->mac_ver == 0x5392)
4511257955Skevlo		rf |= RT3070_RX1_PD | RT3070_TX1_PD;
4512257955Skevlo	run_rt3070_rf_write(sc, 1, rf);
4513257955Skevlo
4514257955Skevlo	if (sc->mac_ver != 0x5392) {
4515257955Skevlo		run_rt3070_rf_read(sc, 2, &rf);
4516257955Skevlo		rf |= 0x80;
4517257955Skevlo		run_rt3070_rf_write(sc, 2, rf);
4518257955Skevlo		run_delay(sc, 10);
4519257955Skevlo		rf &= 0x7f;
4520257955Skevlo		run_rt3070_rf_write(sc, 2, rf);
4521257955Skevlo	}
4522257955Skevlo
4523257955Skevlo	run_adjust_freq_offset(sc);
4524257955Skevlo
4525257955Skevlo	if (sc->mac_ver == 0x5392) {
4526257955Skevlo		/* Fix for RT5392C. */
4527257955Skevlo		if (sc->mac_rev >= 0x0223) {
4528259030Skevlo			if (chan <= 4)
4529257955Skevlo				rf = 0x0f;
4530259030Skevlo			else if (chan >= 5 && chan <= 7)
4531257955Skevlo				rf = 0x0e;
4532259030Skevlo			else
4533257955Skevlo				rf = 0x0d;
4534257955Skevlo			run_rt3070_rf_write(sc, 23, rf);
4535257955Skevlo
4536259030Skevlo			if (chan <= 4)
4537257955Skevlo				rf = 0x0c;
4538257955Skevlo			else if (chan == 5)
4539257955Skevlo				rf = 0x0b;
4540259030Skevlo			else if (chan >= 6 && chan <= 7)
4541257955Skevlo				rf = 0x0a;
4542259030Skevlo			else if (chan >= 8 && chan <= 10)
4543257955Skevlo				rf = 0x09;
4544259030Skevlo			else
4545257955Skevlo				rf = 0x08;
4546257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4547257955Skevlo		} else {
4548259030Skevlo			if (chan <= 11)
4549257955Skevlo				rf = 0x0f;
4550259030Skevlo			else
4551257955Skevlo				rf = 0x0b;
4552257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4553257955Skevlo		}
4554257955Skevlo	} else {
4555257955Skevlo		/* Fix for RT5390F. */
4556257955Skevlo		if (sc->mac_rev >= 0x0502) {
4557259030Skevlo			if (chan <= 11)
4558257955Skevlo				rf = 0x43;
4559259030Skevlo			else
4560257955Skevlo				rf = 0x23;
4561257955Skevlo			run_rt3070_rf_write(sc, 55, rf);
4562257955Skevlo
4563259030Skevlo			if (chan <= 11)
4564257955Skevlo				rf = 0x0f;
4565257955Skevlo			else if (chan == 12)
4566257955Skevlo				rf = 0x0d;
4567259030Skevlo			else
4568257955Skevlo				rf = 0x0b;
4569257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4570257955Skevlo		} else {
4571257955Skevlo			run_rt3070_rf_write(sc, 55, 0x44);
4572257955Skevlo			run_rt3070_rf_write(sc, 59, 0x8f);
4573257955Skevlo		}
4574257955Skevlo	}
4575257955Skevlo
4576257955Skevlo	/* Enable VCO calibration. */
4577257955Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4578257955Skevlo	rf |= RT5390_VCOCAL;
4579257955Skevlo	run_rt3070_rf_write(sc, 3, rf);
4580257955Skevlo}
4581257955Skevlo
4582257955Skevlostatic void
4583259032Skevlorun_rt5592_set_chan(struct run_softc *sc, u_int chan)
4584259032Skevlo{
4585259032Skevlo	const struct rt5592_freqs *freqs;
4586259032Skevlo	uint32_t tmp;
4587259032Skevlo	uint8_t reg, rf, txpow_bound;
4588259032Skevlo	int8_t txpow1, txpow2;
4589259032Skevlo	int i;
4590259032Skevlo
4591259032Skevlo	run_read(sc, RT5592_DEBUG_INDEX, &tmp);
4592259032Skevlo	freqs = (tmp & RT5592_SEL_XTAL) ?
4593259032Skevlo	    rt5592_freqs_40mhz : rt5592_freqs_20mhz;
4594259032Skevlo
4595259032Skevlo	/* find the settings for this channel (we know it exists) */
4596259032Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++, freqs++);
4597259032Skevlo
4598259032Skevlo	/* use Tx power values from EEPROM */
4599259032Skevlo	txpow1 = sc->txpow1[i];
4600259032Skevlo	txpow2 = sc->txpow2[i];
4601259032Skevlo
4602259032Skevlo	run_read(sc, RT3070_LDO_CFG0, &tmp);
4603259032Skevlo	tmp &= ~0x1c000000;
4604259032Skevlo	if (chan > 14)
4605259032Skevlo		tmp |= 0x14000000;
4606259032Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
4607259032Skevlo
4608259032Skevlo	/* N setting. */
4609259032Skevlo	run_rt3070_rf_write(sc, 8, freqs->n & 0xff);
4610259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4611259032Skevlo	rf &= ~(1 << 4);
4612259032Skevlo	rf |= ((freqs->n & 0x0100) >> 8) << 4;
4613259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4614259032Skevlo
4615259032Skevlo	/* K setting. */
4616259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4617259032Skevlo	rf &= ~0x0f;
4618259032Skevlo	rf |= (freqs->k & 0x0f);
4619259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4620259032Skevlo
4621259032Skevlo	/* Mode setting. */
4622259032Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4623259032Skevlo	rf &= ~0x0c;
4624259032Skevlo	rf |= ((freqs->m - 0x8) & 0x3) << 2;
4625259032Skevlo	run_rt3070_rf_write(sc, 11, rf);
4626259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4627259032Skevlo	rf &= ~(1 << 7);
4628259032Skevlo	rf |= (((freqs->m - 0x8) & 0x4) >> 2) << 7;
4629259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4630259032Skevlo
4631259032Skevlo	/* R setting. */
4632259032Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4633259032Skevlo	rf &= ~0x03;
4634259032Skevlo	rf |= (freqs->r - 0x1);
4635259032Skevlo	run_rt3070_rf_write(sc, 11, rf);
4636259032Skevlo
4637259032Skevlo	if (chan <= 14) {
4638259032Skevlo		/* Initialize RF registers for 2GHZ. */
4639259032Skevlo		for (i = 0; i < nitems(rt5592_2ghz_def_rf); i++) {
4640259032Skevlo			run_rt3070_rf_write(sc, rt5592_2ghz_def_rf[i].reg,
4641259032Skevlo			    rt5592_2ghz_def_rf[i].val);
4642259032Skevlo		}
4643259032Skevlo
4644259032Skevlo		rf = (chan <= 10) ? 0x07 : 0x06;
4645259032Skevlo		run_rt3070_rf_write(sc, 23, rf);
4646259032Skevlo		run_rt3070_rf_write(sc, 59, rf);
4647259032Skevlo
4648259032Skevlo		run_rt3070_rf_write(sc, 55, 0x43);
4649259032Skevlo
4650259032Skevlo		/*
4651259032Skevlo		 * RF R49/R50 Tx power ALC code.
4652259032Skevlo		 * G-band bit<7:6>=1:0, bit<5:0> range from 0x0 ~ 0x27.
4653259032Skevlo		 */
4654259032Skevlo		reg = 2;
4655259032Skevlo		txpow_bound = 0x27;
4656259032Skevlo	} else {
4657259032Skevlo		/* Initialize RF registers for 5GHZ. */
4658259032Skevlo		for (i = 0; i < nitems(rt5592_5ghz_def_rf); i++) {
4659259032Skevlo			run_rt3070_rf_write(sc, rt5592_5ghz_def_rf[i].reg,
4660259032Skevlo			    rt5592_5ghz_def_rf[i].val);
4661259032Skevlo		}
4662259032Skevlo		for (i = 0; i < nitems(rt5592_chan_5ghz); i++) {
4663259032Skevlo			if (chan >= rt5592_chan_5ghz[i].firstchan &&
4664259032Skevlo			    chan <= rt5592_chan_5ghz[i].lastchan) {
4665259032Skevlo				run_rt3070_rf_write(sc, rt5592_chan_5ghz[i].reg,
4666259032Skevlo				    rt5592_chan_5ghz[i].val);
4667259032Skevlo			}
4668259032Skevlo		}
4669259032Skevlo
4670259032Skevlo		/*
4671259032Skevlo		 * RF R49/R50 Tx power ALC code.
4672259032Skevlo		 * A-band bit<7:6>=1:1, bit<5:0> range from 0x0 ~ 0x2b.
4673259032Skevlo		 */
4674259032Skevlo		reg = 3;
4675259032Skevlo		txpow_bound = 0x2b;
4676259032Skevlo	}
4677259032Skevlo
4678259032Skevlo	/* RF R49 ch0 Tx power ALC code. */
4679259032Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4680259032Skevlo	rf &= ~0xc0;
4681259032Skevlo	rf |= (reg << 6);
4682259032Skevlo	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
4683259032Skevlo	if ((rf & 0x3f) > txpow_bound)
4684259032Skevlo		rf = (rf & ~0x3f) | txpow_bound;
4685259032Skevlo	run_rt3070_rf_write(sc, 49, rf);
4686259032Skevlo
4687259032Skevlo	/* RF R50 ch1 Tx power ALC code. */
4688259032Skevlo	run_rt3070_rf_read(sc, 50, &rf);
4689259032Skevlo	rf &= ~(1 << 7 | 1 << 6);
4690259032Skevlo	rf |= (reg << 6);
4691259032Skevlo	rf = (rf & ~0x3f) | (txpow2 & 0x3f);
4692259032Skevlo	if ((rf & 0x3f) > txpow_bound)
4693259032Skevlo		rf = (rf & ~0x3f) | txpow_bound;
4694259032Skevlo	run_rt3070_rf_write(sc, 50, rf);
4695259032Skevlo
4696259032Skevlo	/* Enable RF_BLOCK, PLL_PD, RX0_PD, and TX0_PD. */
4697259032Skevlo	run_rt3070_rf_read(sc, 1, &rf);
4698259032Skevlo	rf |= (RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD);
4699259032Skevlo	if (sc->ntxchains > 1)
4700259032Skevlo		rf |= RT3070_TX1_PD;
4701259032Skevlo	if (sc->nrxchains > 1)
4702259032Skevlo		rf |= RT3070_RX1_PD;
4703259032Skevlo	run_rt3070_rf_write(sc, 1, rf);
4704259032Skevlo
4705259032Skevlo	run_rt3070_rf_write(sc, 6, 0xe4);
4706259032Skevlo
4707259032Skevlo	run_rt3070_rf_write(sc, 30, 0x10);
4708259032Skevlo	run_rt3070_rf_write(sc, 31, 0x80);
4709259032Skevlo	run_rt3070_rf_write(sc, 32, 0x80);
4710259032Skevlo
4711259032Skevlo	run_adjust_freq_offset(sc);
4712259032Skevlo
4713259032Skevlo	/* Enable VCO calibration. */
4714259032Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4715259032Skevlo	rf |= RT5390_VCOCAL;
4716259032Skevlo	run_rt3070_rf_write(sc, 3, rf);
4717259032Skevlo}
4718259032Skevlo
4719259032Skevlostatic void
4720203134Sthompsarun_set_rx_antenna(struct run_softc *sc, int aux)
4721203134Sthompsa{
4722203134Sthompsa	uint32_t tmp;
4723257955Skevlo	uint8_t bbp152;
4724203134Sthompsa
4725203134Sthompsa	if (aux) {
4726257955Skevlo		if (sc->rf_rev == RT5390_RF_5370) {
4727257955Skevlo			run_bbp_read(sc, 152, &bbp152);
4728257955Skevlo			run_bbp_write(sc, 152, bbp152 & ~0x80);
4729259030Skevlo		} else {
4730257955Skevlo			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0);
4731257955Skevlo			run_read(sc, RT2860_GPIO_CTRL, &tmp);
4732257955Skevlo			run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08);
4733257955Skevlo		}
4734203134Sthompsa	} else {
4735257955Skevlo		if (sc->rf_rev == RT5390_RF_5370) {
4736257955Skevlo			run_bbp_read(sc, 152, &bbp152);
4737257955Skevlo			run_bbp_write(sc, 152, bbp152 | 0x80);
4738259030Skevlo		} else {
4739257955Skevlo			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1);
4740257955Skevlo			run_read(sc, RT2860_GPIO_CTRL, &tmp);
4741257955Skevlo			run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808);
4742257955Skevlo		}
4743203134Sthompsa	}
4744203134Sthompsa}
4745203134Sthompsa
4746203134Sthompsastatic int
4747203134Sthompsarun_set_chan(struct run_softc *sc, struct ieee80211_channel *c)
4748203134Sthompsa{
4749287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4750257429Shselasky	u_int chan, group;
4751203134Sthompsa
4752203134Sthompsa	chan = ieee80211_chan2ieee(ic, c);
4753203134Sthompsa	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
4754209917Sthompsa		return (EINVAL);
4755203134Sthompsa
4756259032Skevlo	if (sc->mac_ver == 0x5592)
4757259032Skevlo		run_rt5592_set_chan(sc, chan);
4758259032Skevlo	else if (sc->mac_ver >= 0x5390)
4759257955Skevlo		run_rt5390_set_chan(sc, chan);
4760260219Skevlo	else if (sc->mac_ver == 0x3593)
4761260219Skevlo		run_rt3593_set_chan(sc, chan);
4762257955Skevlo	else if (sc->mac_ver == 0x3572)
4763205042Sthompsa		run_rt3572_set_chan(sc, chan);
4764205042Sthompsa	else if (sc->mac_ver >= 0x3070)
4765203134Sthompsa		run_rt3070_set_chan(sc, chan);
4766203134Sthompsa	else
4767203134Sthompsa		run_rt2870_set_chan(sc, chan);
4768203134Sthompsa
4769203134Sthompsa	/* determine channel group */
4770203134Sthompsa	if (chan <= 14)
4771203134Sthompsa		group = 0;
4772203134Sthompsa	else if (chan <= 64)
4773203134Sthompsa		group = 1;
4774203134Sthompsa	else if (chan <= 128)
4775203134Sthompsa		group = 2;
4776203134Sthompsa	else
4777203134Sthompsa		group = 3;
4778203134Sthompsa
4779203134Sthompsa	/* XXX necessary only when group has changed! */
4780203134Sthompsa	run_select_chan_group(sc, group);
4781203134Sthompsa
4782203134Sthompsa	run_delay(sc, 10);
4783203134Sthompsa
4784259545Skevlo	/* Perform IQ calibration. */
4785259544Skevlo	if (sc->mac_ver >= 0x5392)
4786259544Skevlo		run_iq_calib(sc, chan);
4787259544Skevlo
4788209917Sthompsa	return (0);
4789203134Sthompsa}
4790203134Sthompsa
4791203134Sthompsastatic void
4792203134Sthompsarun_set_channel(struct ieee80211com *ic)
4793203134Sthompsa{
4794286950Sadrian	struct run_softc *sc = ic->ic_softc;
4795203134Sthompsa
4796203134Sthompsa	RUN_LOCK(sc);
4797203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
4798203134Sthompsa	RUN_UNLOCK(sc);
4799203134Sthompsa
4800203134Sthompsa	return;
4801203134Sthompsa}
4802203134Sthompsa
4803203134Sthompsastatic void
4804203134Sthompsarun_scan_start(struct ieee80211com *ic)
4805203134Sthompsa{
4806286950Sadrian	struct run_softc *sc = ic->ic_softc;
4807203134Sthompsa	uint32_t tmp;
4808203134Sthompsa
4809203134Sthompsa	RUN_LOCK(sc);
4810203134Sthompsa
4811203134Sthompsa	/* abort TSF synchronization */
4812203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
4813203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG,
4814203134Sthompsa	    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
4815203134Sthompsa	    RT2860_TBTT_TIMER_EN));
4816287197Sglebius	run_set_bssid(sc, ieee80211broadcastaddr);
4817203134Sthompsa
4818203134Sthompsa	RUN_UNLOCK(sc);
4819203134Sthompsa
4820203134Sthompsa	return;
4821203134Sthompsa}
4822203134Sthompsa
4823203134Sthompsastatic void
4824203134Sthompsarun_scan_end(struct ieee80211com *ic)
4825203134Sthompsa{
4826286950Sadrian	struct run_softc *sc = ic->ic_softc;
4827203134Sthompsa
4828203134Sthompsa	RUN_LOCK(sc);
4829203134Sthompsa
4830203134Sthompsa	run_enable_tsf_sync(sc);
4831203134Sthompsa	/* XXX keep local copy */
4832287197Sglebius	run_set_bssid(sc, ic->ic_macaddr);
4833203134Sthompsa
4834203134Sthompsa	RUN_UNLOCK(sc);
4835203134Sthompsa
4836203134Sthompsa	return;
4837203134Sthompsa}
4838203134Sthompsa
4839208019Sthompsa/*
4840208019Sthompsa * Could be called from ieee80211_node_timeout()
4841208019Sthompsa * (non-sleepable thread)
4842208019Sthompsa */
4843208019Sthompsastatic void
4844208019Sthompsarun_update_beacon(struct ieee80211vap *vap, int item)
4845203134Sthompsa{
4846208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4847288095Sadrian	struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off;
4848288095Sadrian	struct ieee80211_node *ni = vap->iv_bss;
4849286950Sadrian	struct run_softc *sc = ic->ic_softc;
4850218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4851218492Sbschmidt	int mcast = 0;
4852208019Sthompsa	uint32_t i;
4853208019Sthompsa
4854218492Sbschmidt	switch (item) {
4855218492Sbschmidt	case IEEE80211_BEACON_ERP:
4856283540Sglebius		run_updateslot(ic);
4857218492Sbschmidt		break;
4858218492Sbschmidt	case IEEE80211_BEACON_HTINFO:
4859218492Sbschmidt		run_updateprot(ic);
4860218492Sbschmidt		break;
4861218492Sbschmidt	case IEEE80211_BEACON_TIM:
4862218492Sbschmidt		mcast = 1;	/*TODO*/
4863218492Sbschmidt		break;
4864218492Sbschmidt	default:
4865218492Sbschmidt		break;
4866218492Sbschmidt	}
4867218492Sbschmidt
4868288095Sadrian	setbit(bo->bo_flags, item);
4869273448Skevlo	if (rvp->beacon_mbuf == NULL) {
4870288636Sadrian		rvp->beacon_mbuf = ieee80211_beacon_alloc(ni);
4871273448Skevlo		if (rvp->beacon_mbuf == NULL)
4872273448Skevlo			return;
4873273448Skevlo	}
4874288636Sadrian	ieee80211_beacon_update(ni, rvp->beacon_mbuf, mcast);
4875218492Sbschmidt
4876208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
4877208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
4878208019Sthompsa	sc->cmdq[i].func = run_update_beacon_cb;
4879208019Sthompsa	sc->cmdq[i].arg0 = vap;
4880208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
4881208019Sthompsa
4882208019Sthompsa	return;
4883203134Sthompsa}
4884203134Sthompsa
4885203134Sthompsastatic void
4886208019Sthompsarun_update_beacon_cb(void *arg)
4887203134Sthompsa{
4888208019Sthompsa	struct ieee80211vap *vap = arg;
4889288095Sadrian	struct ieee80211_node *ni = vap->iv_bss;
4890218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4891203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4892286950Sadrian	struct run_softc *sc = ic->ic_softc;
4893203134Sthompsa	struct rt2860_txwi txwi;
4894203134Sthompsa	struct mbuf *m;
4895259032Skevlo	uint16_t txwisize;
4896208019Sthompsa	uint8_t ridx;
4897203134Sthompsa
4898288095Sadrian	if (ni->ni_chan == IEEE80211_CHAN_ANYC)
4899208019Sthompsa		return;
4900236439Shselasky	if (ic->ic_bsschan == IEEE80211_CHAN_ANYC)
4901236439Shselasky		return;
4902208019Sthompsa
4903218492Sbschmidt	/*
4904218492Sbschmidt	 * No need to call ieee80211_beacon_update(), run_update_beacon()
4905218492Sbschmidt	 * is taking care of apropriate calls.
4906218492Sbschmidt	 */
4907218492Sbschmidt	if (rvp->beacon_mbuf == NULL) {
4908288636Sadrian		rvp->beacon_mbuf = ieee80211_beacon_alloc(ni);
4909218492Sbschmidt		if (rvp->beacon_mbuf == NULL)
4910218492Sbschmidt			return;
4911218492Sbschmidt	}
4912218492Sbschmidt	m = rvp->beacon_mbuf;
4913203134Sthompsa
4914259032Skevlo	memset(&txwi, 0, sizeof(txwi));
4915203134Sthompsa	txwi.wcid = 0xff;
4916203134Sthompsa	txwi.len = htole16(m->m_pkthdr.len);
4917259032Skevlo
4918203134Sthompsa	/* send beacons at the lowest available rate */
4919208019Sthompsa	ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
4920208019Sthompsa	    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
4921208019Sthompsa	txwi.phy = htole16(rt2860_rates[ridx].mcs);
4922208019Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM)
4923259032Skevlo		txwi.phy |= htole16(RT2860_PHY_OFDM);
4924203134Sthompsa	txwi.txop = RT2860_TX_TXOP_HT;
4925203134Sthompsa	txwi.flags = RT2860_TX_TS;
4926209144Sthompsa	txwi.xflags = RT2860_TX_NSEQ;
4927203134Sthompsa
4928259032Skevlo	txwisize = (sc->mac_ver == 0x5592) ?
4929259032Skevlo	    sizeof(txwi) + sizeof(uint32_t) : sizeof(txwi);
4930259032Skevlo	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id), (uint8_t *)&txwi,
4931259032Skevlo	    txwisize);
4932259032Skevlo	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id) + txwisize,
4933259032Skevlo	    mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1);
4934203134Sthompsa}
4935203134Sthompsa
4936203134Sthompsastatic void
4937203134Sthompsarun_updateprot(struct ieee80211com *ic)
4938203134Sthompsa{
4939286950Sadrian	struct run_softc *sc = ic->ic_softc;
4940218492Sbschmidt	uint32_t i;
4941218492Sbschmidt
4942218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
4943218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
4944218492Sbschmidt	sc->cmdq[i].func = run_updateprot_cb;
4945218492Sbschmidt	sc->cmdq[i].arg0 = ic;
4946218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
4947218492Sbschmidt}
4948218492Sbschmidt
4949218492Sbschmidtstatic void
4950218492Sbschmidtrun_updateprot_cb(void *arg)
4951218492Sbschmidt{
4952218492Sbschmidt	struct ieee80211com *ic = arg;
4953286950Sadrian	struct run_softc *sc = ic->ic_softc;
4954203134Sthompsa	uint32_t tmp;
4955203134Sthompsa
4956203134Sthompsa	tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL;
4957203134Sthompsa	/* setup protection frame rate (MCS code) */
4958203134Sthompsa	tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ?
4959270192Skevlo	    rt2860_rates[RT2860_RIDX_OFDM6].mcs | RT2860_PHY_OFDM :
4960203134Sthompsa	    rt2860_rates[RT2860_RIDX_CCK11].mcs;
4961203134Sthompsa
4962203134Sthompsa	/* CCK frames don't require protection */
4963203134Sthompsa	run_write(sc, RT2860_CCK_PROT_CFG, tmp);
4964203134Sthompsa	if (ic->ic_flags & IEEE80211_F_USEPROT) {
4965203134Sthompsa		if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
4966203134Sthompsa			tmp |= RT2860_PROT_CTRL_RTS_CTS;
4967203134Sthompsa		else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
4968203134Sthompsa			tmp |= RT2860_PROT_CTRL_CTS;
4969203134Sthompsa	}
4970203134Sthompsa	run_write(sc, RT2860_OFDM_PROT_CFG, tmp);
4971203134Sthompsa}
4972203134Sthompsa
4973203134Sthompsastatic void
4974208019Sthompsarun_usb_timeout_cb(void *arg)
4975203134Sthompsa{
4976208019Sthompsa	struct ieee80211vap *vap = arg;
4977286950Sadrian	struct run_softc *sc = vap->iv_ic->ic_softc;
4978203134Sthompsa
4979208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
4980203134Sthompsa
4981203134Sthompsa	if(vap->iv_state == IEEE80211_S_RUN &&
4982203134Sthompsa	    vap->iv_opmode != IEEE80211_M_STA)
4983203134Sthompsa		run_reset_livelock(sc);
4984209917Sthompsa	else if (vap->iv_state == IEEE80211_S_SCAN) {
4985203134Sthompsa		DPRINTF("timeout caused by scan\n");
4986203134Sthompsa		/* cancel bgscan */
4987203134Sthompsa		ieee80211_cancel_scan(vap);
4988203134Sthompsa	} else
4989203134Sthompsa		DPRINTF("timeout by unknown cause\n");
4990203134Sthompsa}
4991203134Sthompsa
4992203134Sthompsastatic void
4993203134Sthompsarun_reset_livelock(struct run_softc *sc)
4994203134Sthompsa{
4995203134Sthompsa	uint32_t tmp;
4996203134Sthompsa
4997208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
4998208019Sthompsa
4999203134Sthompsa	/*
5000203134Sthompsa	 * In IBSS or HostAP modes (when the hardware sends beacons), the MAC
5001203134Sthompsa	 * can run into a livelock and start sending CTS-to-self frames like
5002203134Sthompsa	 * crazy if protection is enabled.  Reset MAC/BBP for a while
5003203134Sthompsa	 */
5004203134Sthompsa	run_read(sc, RT2860_DEBUG, &tmp);
5005208019Sthompsa	DPRINTFN(3, "debug reg %08x\n", tmp);
5006209917Sthompsa	if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) {
5007203134Sthompsa		DPRINTF("CTS-to-self livelock detected\n");
5008203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST);
5009203134Sthompsa		run_delay(sc, 1);
5010203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL,
5011203134Sthompsa		    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
5012203134Sthompsa	}
5013203134Sthompsa}
5014203134Sthompsa
5015203134Sthompsastatic void
5016283540Sglebiusrun_update_promisc_locked(struct run_softc *sc)
5017203134Sthompsa{
5018203134Sthompsa        uint32_t tmp;
5019203134Sthompsa
5020203134Sthompsa	run_read(sc, RT2860_RX_FILTR_CFG, &tmp);
5021203134Sthompsa
5022203134Sthompsa	tmp |= RT2860_DROP_UC_NOME;
5023287197Sglebius        if (sc->sc_ic.ic_promisc > 0)
5024203134Sthompsa		tmp &= ~RT2860_DROP_UC_NOME;
5025203134Sthompsa
5026203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5027203134Sthompsa
5028287197Sglebius        DPRINTF("%s promiscuous mode\n", (sc->sc_ic.ic_promisc > 0) ?
5029203134Sthompsa            "entering" : "leaving");
5030203134Sthompsa}
5031203134Sthompsa
5032203134Sthompsastatic void
5033283540Sglebiusrun_update_promisc(struct ieee80211com *ic)
5034203134Sthompsa{
5035283540Sglebius	struct run_softc *sc = ic->ic_softc;
5036203134Sthompsa
5037287197Sglebius	if ((sc->sc_flags & RUN_RUNNING) == 0)
5038203134Sthompsa		return;
5039203134Sthompsa
5040203134Sthompsa	RUN_LOCK(sc);
5041283540Sglebius	run_update_promisc_locked(sc);
5042203134Sthompsa	RUN_UNLOCK(sc);
5043203134Sthompsa}
5044203134Sthompsa
5045203134Sthompsastatic void
5046203134Sthompsarun_enable_tsf_sync(struct run_softc *sc)
5047203134Sthompsa{
5048287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5049203134Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
5050203134Sthompsa	uint32_t tmp;
5051203134Sthompsa
5052257955Skevlo	DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id,
5053257955Skevlo	    ic->ic_opmode);
5054208019Sthompsa
5055203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
5056203134Sthompsa	tmp &= ~0x1fffff;
5057203134Sthompsa	tmp |= vap->iv_bss->ni_intval * 16;
5058203134Sthompsa	tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN;
5059203134Sthompsa
5060208019Sthompsa	if (ic->ic_opmode == IEEE80211_M_STA) {
5061203134Sthompsa		/*
5062203134Sthompsa		 * Local TSF is always updated with remote TSF on beacon
5063203134Sthompsa		 * reception.
5064203134Sthompsa		 */
5065203134Sthompsa		tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT;
5066208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_IBSS) {
5067203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5068203134Sthompsa	        /*
5069203134Sthompsa	         * Local TSF is updated with remote TSF on beacon reception
5070203134Sthompsa	         * only if the remote TSF is greater than local TSF.
5071203134Sthompsa	         */
5072203134Sthompsa	        tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT;
5073208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
5074208019Sthompsa		    ic->ic_opmode == IEEE80211_M_MBSS) {
5075203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5076203134Sthompsa	        /* SYNC with nobody */
5077203134Sthompsa	        tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT;
5078208019Sthompsa	} else {
5079203134Sthompsa		DPRINTF("Enabling TSF failed. undefined opmode\n");
5080208019Sthompsa		return;
5081208019Sthompsa	}
5082203134Sthompsa
5083203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
5084203134Sthompsa}
5085203134Sthompsa
5086203134Sthompsastatic void
5087287555Skevlorun_enable_tsf(struct run_softc *sc)
5088287555Skevlo{
5089287555Skevlo	uint32_t tmp;
5090287555Skevlo
5091287555Skevlo	if (run_read(sc, RT2860_BCN_TIME_CFG, &tmp) == 0) {
5092287555Skevlo		tmp &= ~(RT2860_BCN_TX_EN | RT2860_TBTT_TIMER_EN);
5093287555Skevlo		tmp |= RT2860_TSF_TIMER_EN;
5094287555Skevlo		run_write(sc, RT2860_BCN_TIME_CFG, tmp);
5095287555Skevlo	}
5096287555Skevlo}
5097287555Skevlo
5098287555Skevlostatic void
5099287554Skevlorun_get_tsf(struct run_softc *sc, uint64_t *buf)
5100287554Skevlo{
5101287554Skevlo	run_read_region_1(sc, RT2860_TSF_TIMER_DW0, (uint8_t *)buf,
5102287554Skevlo	    sizeof(*buf));
5103287554Skevlo}
5104287554Skevlo
5105287554Skevlostatic void
5106203134Sthompsarun_enable_mrr(struct run_softc *sc)
5107203134Sthompsa{
5108259546Skevlo#define	CCK(mcs)	(mcs)
5109259546Skevlo#define	OFDM(mcs)	(1 << 3 | (mcs))
5110203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG0,
5111203134Sthompsa	    OFDM(6) << 28 |	/* 54->48 */
5112203134Sthompsa	    OFDM(5) << 24 |	/* 48->36 */
5113203134Sthompsa	    OFDM(4) << 20 |	/* 36->24 */
5114203134Sthompsa	    OFDM(3) << 16 |	/* 24->18 */
5115203134Sthompsa	    OFDM(2) << 12 |	/* 18->12 */
5116203134Sthompsa	    OFDM(1) <<  8 |	/* 12-> 9 */
5117203134Sthompsa	    OFDM(0) <<  4 |	/*  9-> 6 */
5118203134Sthompsa	    OFDM(0));		/*  6-> 6 */
5119203134Sthompsa
5120203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG1,
5121203134Sthompsa	    CCK(2) << 12 |	/* 11->5.5 */
5122203134Sthompsa	    CCK(1) <<  8 |	/* 5.5-> 2 */
5123203134Sthompsa	    CCK(0) <<  4 |	/*   2-> 1 */
5124203134Sthompsa	    CCK(0));		/*   1-> 1 */
5125203134Sthompsa#undef OFDM
5126203134Sthompsa#undef CCK
5127203134Sthompsa}
5128203134Sthompsa
5129203134Sthompsastatic void
5130203134Sthompsarun_set_txpreamble(struct run_softc *sc)
5131203134Sthompsa{
5132287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5133203134Sthompsa	uint32_t tmp;
5134203134Sthompsa
5135203134Sthompsa	run_read(sc, RT2860_AUTO_RSP_CFG, &tmp);
5136203134Sthompsa	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
5137203134Sthompsa		tmp |= RT2860_CCK_SHORT_EN;
5138203134Sthompsa	else
5139203134Sthompsa		tmp &= ~RT2860_CCK_SHORT_EN;
5140203134Sthompsa	run_write(sc, RT2860_AUTO_RSP_CFG, tmp);
5141203134Sthompsa}
5142203134Sthompsa
5143203134Sthompsastatic void
5144203134Sthompsarun_set_basicrates(struct run_softc *sc)
5145203134Sthompsa{
5146287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5147203134Sthompsa
5148203134Sthompsa	/* set basic rates mask */
5149203134Sthompsa	if (ic->ic_curmode == IEEE80211_MODE_11B)
5150203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003);
5151203134Sthompsa	else if (ic->ic_curmode == IEEE80211_MODE_11A)
5152203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150);
5153203134Sthompsa	else	/* 11g */
5154203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f);
5155203134Sthompsa}
5156203134Sthompsa
5157203134Sthompsastatic void
5158203134Sthompsarun_set_leds(struct run_softc *sc, uint16_t which)
5159203134Sthompsa{
5160203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS,
5161203134Sthompsa	    which | (sc->leds & 0x7f));
5162203134Sthompsa}
5163203134Sthompsa
5164203134Sthompsastatic void
5165203134Sthompsarun_set_bssid(struct run_softc *sc, const uint8_t *bssid)
5166203134Sthompsa{
5167203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW0,
5168203134Sthompsa	    bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24);
5169203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW1,
5170203134Sthompsa	    bssid[4] | bssid[5] << 8);
5171203134Sthompsa}
5172203134Sthompsa
5173203134Sthompsastatic void
5174203134Sthompsarun_set_macaddr(struct run_softc *sc, const uint8_t *addr)
5175203134Sthompsa{
5176203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW0,
5177203134Sthompsa	    addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24);
5178203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW1,
5179203134Sthompsa	    addr[4] | addr[5] << 8 | 0xff << 16);
5180203134Sthompsa}
5181203134Sthompsa
5182203134Sthompsastatic void
5183283540Sglebiusrun_updateslot(struct ieee80211com *ic)
5184203134Sthompsa{
5185283540Sglebius	struct run_softc *sc = ic->ic_softc;
5186218492Sbschmidt	uint32_t i;
5187218492Sbschmidt
5188218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
5189218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
5190218492Sbschmidt	sc->cmdq[i].func = run_updateslot_cb;
5191287197Sglebius	sc->cmdq[i].arg0 = ic;
5192218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
5193218492Sbschmidt
5194218492Sbschmidt	return;
5195218492Sbschmidt}
5196218492Sbschmidt
5197218492Sbschmidt/* ARGSUSED */
5198218492Sbschmidtstatic void
5199218492Sbschmidtrun_updateslot_cb(void *arg)
5200218492Sbschmidt{
5201287197Sglebius	struct ieee80211com *ic = arg;
5202286950Sadrian	struct run_softc *sc = ic->ic_softc;
5203203134Sthompsa	uint32_t tmp;
5204203134Sthompsa
5205203134Sthompsa	run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp);
5206203134Sthompsa	tmp &= ~0xff;
5207203134Sthompsa	tmp |= (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
5208203134Sthompsa	run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp);
5209203134Sthompsa}
5210203134Sthompsa
5211208019Sthompsastatic void
5212283540Sglebiusrun_update_mcast(struct ieee80211com *ic)
5213208019Sthompsa{
5214208019Sthompsa}
5215208019Sthompsa
5216203134Sthompsastatic int8_t
5217203134Sthompsarun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain)
5218203134Sthompsa{
5219287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5220203134Sthompsa	struct ieee80211_channel *c = ic->ic_curchan;
5221203134Sthompsa	int delta;
5222203134Sthompsa
5223203134Sthompsa	if (IEEE80211_IS_CHAN_5GHZ(c)) {
5224257429Shselasky		u_int chan = ieee80211_chan2ieee(ic, c);
5225203134Sthompsa		delta = sc->rssi_5ghz[rxchain];
5226203134Sthompsa
5227203134Sthompsa		/* determine channel group */
5228203134Sthompsa		if (chan <= 64)
5229203134Sthompsa			delta -= sc->lna[1];
5230203134Sthompsa		else if (chan <= 128)
5231203134Sthompsa			delta -= sc->lna[2];
5232203134Sthompsa		else
5233203134Sthompsa			delta -= sc->lna[3];
5234203134Sthompsa	} else
5235203134Sthompsa		delta = sc->rssi_2ghz[rxchain] - sc->lna[0];
5236203134Sthompsa
5237209917Sthompsa	return (-12 - delta - rssi);
5238203134Sthompsa}
5239203134Sthompsa
5240257955Skevlostatic void
5241257955Skevlorun_rt5390_bbp_init(struct run_softc *sc)
5242257955Skevlo{
5243257955Skevlo	int i;
5244259032Skevlo	uint8_t bbp;
5245257955Skevlo
5246259032Skevlo	/* Apply maximum likelihood detection for 2 stream case. */
5247259032Skevlo	run_bbp_read(sc, 105, &bbp);
5248259032Skevlo	if (sc->nrxchains > 1)
5249259032Skevlo		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5250259032Skevlo
5251257955Skevlo	/* Avoid data lost and CRC error. */
5252259032Skevlo	run_bbp_read(sc, 4, &bbp);
5253259031Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5254257955Skevlo
5255259032Skevlo	if (sc->mac_ver == 0x5592) {
5256259032Skevlo		for (i = 0; i < nitems(rt5592_def_bbp); i++) {
5257259032Skevlo			run_bbp_write(sc, rt5592_def_bbp[i].reg,
5258259032Skevlo			    rt5592_def_bbp[i].val);
5259259032Skevlo		}
5260259032Skevlo		for (i = 0; i < nitems(rt5592_bbp_r196); i++) {
5261259032Skevlo			run_bbp_write(sc, 195, i + 0x80);
5262259032Skevlo			run_bbp_write(sc, 196, rt5592_bbp_r196[i]);
5263259032Skevlo		}
5264259032Skevlo	} else {
5265259032Skevlo		for (i = 0; i < nitems(rt5390_def_bbp); i++) {
5266259032Skevlo			run_bbp_write(sc, rt5390_def_bbp[i].reg,
5267259032Skevlo			    rt5390_def_bbp[i].val);
5268259032Skevlo		}
5269257955Skevlo	}
5270257955Skevlo	if (sc->mac_ver == 0x5392) {
5271257955Skevlo		run_bbp_write(sc, 88, 0x90);
5272257955Skevlo		run_bbp_write(sc, 95, 0x9a);
5273257955Skevlo		run_bbp_write(sc, 98, 0x12);
5274257955Skevlo		run_bbp_write(sc, 106, 0x12);
5275257955Skevlo		run_bbp_write(sc, 134, 0xd0);
5276257955Skevlo		run_bbp_write(sc, 135, 0xf6);
5277257955Skevlo		run_bbp_write(sc, 148, 0x84);
5278257955Skevlo	}
5279257955Skevlo
5280259032Skevlo	run_bbp_read(sc, 152, &bbp);
5281259032Skevlo	run_bbp_write(sc, 152, bbp | 0x80);
5282259032Skevlo
5283259032Skevlo	/* Fix BBP254 for RT5592C. */
5284259032Skevlo	if (sc->mac_ver == 0x5592 && sc->mac_rev >= 0x0221) {
5285259032Skevlo		run_bbp_read(sc, 254, &bbp);
5286259032Skevlo		run_bbp_write(sc, 254, bbp | 0x80);
5287259032Skevlo	}
5288259032Skevlo
5289257955Skevlo	/* Disable hardware antenna diversity. */
5290257955Skevlo	if (sc->mac_ver == 0x5390)
5291257955Skevlo		run_bbp_write(sc, 154, 0);
5292259032Skevlo
5293259032Skevlo	/* Initialize Rx CCK/OFDM frequency offset report. */
5294259032Skevlo	run_bbp_write(sc, 142, 1);
5295259032Skevlo	run_bbp_write(sc, 143, 57);
5296257955Skevlo}
5297257955Skevlo
5298203134Sthompsastatic int
5299203134Sthompsarun_bbp_init(struct run_softc *sc)
5300203134Sthompsa{
5301203134Sthompsa	int i, error, ntries;
5302203134Sthompsa	uint8_t bbp0;
5303203134Sthompsa
5304203134Sthompsa	/* wait for BBP to wake up */
5305203134Sthompsa	for (ntries = 0; ntries < 20; ntries++) {
5306203134Sthompsa		if ((error = run_bbp_read(sc, 0, &bbp0)) != 0)
5307203134Sthompsa			return error;
5308203134Sthompsa		if (bbp0 != 0 && bbp0 != 0xff)
5309203134Sthompsa			break;
5310203134Sthompsa	}
5311203134Sthompsa	if (ntries == 20)
5312209917Sthompsa		return (ETIMEDOUT);
5313203134Sthompsa
5314203134Sthompsa	/* initialize BBP registers to default values */
5315257955Skevlo	if (sc->mac_ver >= 0x5390)
5316257955Skevlo		run_rt5390_bbp_init(sc);
5317257955Skevlo	else {
5318257955Skevlo		for (i = 0; i < nitems(rt2860_def_bbp); i++) {
5319257955Skevlo			run_bbp_write(sc, rt2860_def_bbp[i].reg,
5320257955Skevlo			    rt2860_def_bbp[i].val);
5321257955Skevlo		}
5322203134Sthompsa	}
5323203134Sthompsa
5324260219Skevlo	if (sc->mac_ver == 0x3593) {
5325260219Skevlo		run_bbp_write(sc, 79, 0x13);
5326260219Skevlo		run_bbp_write(sc, 80, 0x05);
5327260219Skevlo		run_bbp_write(sc, 81, 0x33);
5328260219Skevlo		run_bbp_write(sc, 86, 0x46);
5329260219Skevlo		run_bbp_write(sc, 137, 0x0f);
5330260219Skevlo	}
5331260219Skevlo
5332203134Sthompsa	/* fix BBP84 for RT2860E */
5333205042Sthompsa	if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101)
5334205042Sthompsa		run_bbp_write(sc, 84, 0x19);
5335203134Sthompsa
5336260219Skevlo	if (sc->mac_ver >= 0x3070 && (sc->mac_ver != 0x3593 &&
5337260219Skevlo	    sc->mac_ver != 0x5592)) {
5338203134Sthompsa		run_bbp_write(sc, 79, 0x13);
5339203134Sthompsa		run_bbp_write(sc, 80, 0x05);
5340203134Sthompsa		run_bbp_write(sc, 81, 0x33);
5341205042Sthompsa	} else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) {
5342203134Sthompsa		run_bbp_write(sc, 69, 0x16);
5343203134Sthompsa		run_bbp_write(sc, 73, 0x12);
5344203134Sthompsa	}
5345209917Sthompsa	return (0);
5346203134Sthompsa}
5347203134Sthompsa
5348203134Sthompsastatic int
5349203134Sthompsarun_rt3070_rf_init(struct run_softc *sc)
5350203134Sthompsa{
5351203134Sthompsa	uint32_t tmp;
5352256722Skevlo	uint8_t bbp4, mingain, rf, target;
5353203134Sthompsa	int i;
5354203134Sthompsa
5355203134Sthompsa	run_rt3070_rf_read(sc, 30, &rf);
5356203134Sthompsa	/* toggle RF R30 bit 7 */
5357203134Sthompsa	run_rt3070_rf_write(sc, 30, rf | 0x80);
5358203134Sthompsa	run_delay(sc, 10);
5359203134Sthompsa	run_rt3070_rf_write(sc, 30, rf & ~0x80);
5360203134Sthompsa
5361203134Sthompsa	/* initialize RF registers to default value */
5362205042Sthompsa	if (sc->mac_ver == 0x3572) {
5363257955Skevlo		for (i = 0; i < nitems(rt3572_def_rf); i++) {
5364205042Sthompsa			run_rt3070_rf_write(sc, rt3572_def_rf[i].reg,
5365205042Sthompsa			    rt3572_def_rf[i].val);
5366205042Sthompsa		}
5367205042Sthompsa	} else {
5368257955Skevlo		for (i = 0; i < nitems(rt3070_def_rf); i++) {
5369205042Sthompsa			run_rt3070_rf_write(sc, rt3070_def_rf[i].reg,
5370205042Sthompsa			    rt3070_def_rf[i].val);
5371205042Sthompsa		}
5372203134Sthompsa	}
5373205042Sthompsa
5374256721Skevlo	if (sc->mac_ver == 0x3070 && sc->mac_rev < 0x0201) {
5375256721Skevlo		/*
5376256721Skevlo		 * Change voltage from 1.2V to 1.35V for RT3070.
5377256721Skevlo		 * The DAC issue (RT3070_LDO_CFG0) has been fixed
5378256721Skevlo		 * in RT3070(F).
5379256721Skevlo		 */
5380203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5381203134Sthompsa		tmp = (tmp & ~0x0f000000) | 0x0d000000;
5382203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5383203134Sthompsa
5384205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5385203134Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5386203134Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5387203134Sthompsa		run_rt3070_rf_write(sc, 31, 0x14);
5388203134Sthompsa
5389203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5390203134Sthompsa		tmp &= ~0x1f000000;
5391205042Sthompsa		if (sc->mac_rev < 0x0211)
5392205042Sthompsa			tmp |= 0x0d000000;	/* 1.3V */
5393203134Sthompsa		else
5394205042Sthompsa			tmp |= 0x01000000;	/* 1.2V */
5395203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5396203134Sthompsa
5397203134Sthompsa		/* patch LNA_PE_G1 */
5398203134Sthompsa		run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5399203134Sthompsa		run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20);
5400208019Sthompsa
5401209917Sthompsa	} else if (sc->mac_ver == 0x3572) {
5402205042Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5403205042Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5404205042Sthompsa
5405208019Sthompsa		/* increase voltage from 1.2V to 1.35V */
5406208019Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5407208019Sthompsa		tmp = (tmp & ~0x1f000000) | 0x0d000000;
5408208019Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5409203134Sthompsa
5410209917Sthompsa		if (sc->mac_rev < 0x0211 || !sc->patch_dac) {
5411203134Sthompsa			run_delay(sc, 1);	/* wait for 1msec */
5412205042Sthompsa			/* decrease voltage back to 1.2V */
5413203134Sthompsa			tmp = (tmp & ~0x1f000000) | 0x01000000;
5414203134Sthompsa			run_write(sc, RT3070_LDO_CFG0, tmp);
5415203134Sthompsa		}
5416203134Sthompsa	}
5417203134Sthompsa
5418203134Sthompsa	/* select 20MHz bandwidth */
5419203134Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5420203134Sthompsa	run_rt3070_rf_write(sc, 31, rf & ~0x20);
5421203134Sthompsa
5422203134Sthompsa	/* calibrate filter for 20MHz bandwidth */
5423203134Sthompsa	sc->rf24_20mhz = 0x1f;	/* default value */
5424205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13;
5425205042Sthompsa	run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz);
5426203134Sthompsa
5427203134Sthompsa	/* select 40MHz bandwidth */
5428203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5429256721Skevlo	run_bbp_write(sc, 4, (bbp4 & ~0x18) | 0x10);
5430205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5431205042Sthompsa	run_rt3070_rf_write(sc, 31, rf | 0x20);
5432203134Sthompsa
5433203134Sthompsa	/* calibrate filter for 40MHz bandwidth */
5434203134Sthompsa	sc->rf24_40mhz = 0x2f;	/* default value */
5435205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15;
5436205042Sthompsa	run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz);
5437203134Sthompsa
5438203134Sthompsa	/* go back to 20MHz bandwidth */
5439203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5440203134Sthompsa	run_bbp_write(sc, 4, bbp4 & ~0x18);
5441203134Sthompsa
5442205042Sthompsa	if (sc->mac_ver == 0x3572) {
5443205042Sthompsa		/* save default BBP registers 25 and 26 values */
5444205042Sthompsa		run_bbp_read(sc, 25, &sc->bbp25);
5445205042Sthompsa		run_bbp_read(sc, 26, &sc->bbp26);
5446256721Skevlo	} else if (sc->mac_rev < 0x0201 || sc->mac_rev < 0x0211)
5447203134Sthompsa		run_rt3070_rf_write(sc, 27, 0x03);
5448203134Sthompsa
5449203134Sthompsa	run_read(sc, RT3070_OPT_14, &tmp);
5450203134Sthompsa	run_write(sc, RT3070_OPT_14, tmp | 1);
5451203134Sthompsa
5452205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5453205042Sthompsa		run_rt3070_rf_read(sc, 17, &rf);
5454205042Sthompsa		rf &= ~RT3070_TX_LO1;
5455205042Sthompsa		if ((sc->mac_ver == 0x3070 ||
5456205042Sthompsa		     (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) &&
5457205042Sthompsa		    !sc->ext_2ghz_lna)
5458205042Sthompsa			rf |= 0x20;	/* fix for long range Rx issue */
5459256722Skevlo		mingain = (sc->mac_ver == 0x3070) ? 1 : 2;
5460256722Skevlo		if (sc->txmixgain_2ghz >= mingain)
5461205042Sthompsa			rf = (rf & ~0x7) | sc->txmixgain_2ghz;
5462205042Sthompsa		run_rt3070_rf_write(sc, 17, rf);
5463205042Sthompsa	}
5464205042Sthompsa
5465270643Skevlo	if (sc->mac_ver == 0x3071) {
5466203134Sthompsa		run_rt3070_rf_read(sc, 1, &rf);
5467203134Sthompsa		rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD);
5468203134Sthompsa		rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD;
5469203134Sthompsa		run_rt3070_rf_write(sc, 1, rf);
5470203134Sthompsa
5471203134Sthompsa		run_rt3070_rf_read(sc, 15, &rf);
5472203134Sthompsa		run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2);
5473203134Sthompsa
5474203134Sthompsa		run_rt3070_rf_read(sc, 20, &rf);
5475203134Sthompsa		run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1);
5476203134Sthompsa
5477203134Sthompsa		run_rt3070_rf_read(sc, 21, &rf);
5478203134Sthompsa		run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2);
5479205042Sthompsa	}
5480203134Sthompsa
5481205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5482205042Sthompsa		/* fix Tx to Rx IQ glitch by raising RF voltage */
5483203134Sthompsa		run_rt3070_rf_read(sc, 27, &rf);
5484203134Sthompsa		rf &= ~0x77;
5485205042Sthompsa		if (sc->mac_rev < 0x0211)
5486203134Sthompsa			rf |= 0x03;
5487203134Sthompsa		run_rt3070_rf_write(sc, 27, rf);
5488203134Sthompsa	}
5489209917Sthompsa	return (0);
5490203134Sthompsa}
5491203134Sthompsa
5492257955Skevlostatic void
5493260219Skevlorun_rt3593_rf_init(struct run_softc *sc)
5494260219Skevlo{
5495260219Skevlo	uint32_t tmp;
5496260219Skevlo	uint8_t rf;
5497260219Skevlo	int i;
5498260219Skevlo
5499260219Skevlo	/* Disable the GPIO bits 4 and 7 for LNA PE control. */
5500260219Skevlo	run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5501260219Skevlo	tmp &= ~(1 << 4 | 1 << 7);
5502260219Skevlo	run_write(sc, RT3070_GPIO_SWITCH, tmp);
5503260219Skevlo
5504260219Skevlo	/* Initialize RF registers to default value. */
5505260219Skevlo	for (i = 0; i < nitems(rt3593_def_rf); i++) {
5506260219Skevlo		run_rt3070_rf_write(sc, rt3593_def_rf[i].reg,
5507260219Skevlo		    rt3593_def_rf[i].val);
5508260219Skevlo	}
5509260219Skevlo
5510260219Skevlo	/* Toggle RF R2 to initiate calibration. */
5511260219Skevlo	run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5512260219Skevlo
5513260219Skevlo	/* Initialize RF frequency offset. */
5514260219Skevlo	run_adjust_freq_offset(sc);
5515260219Skevlo
5516260219Skevlo	run_rt3070_rf_read(sc, 18, &rf);
5517260219Skevlo	run_rt3070_rf_write(sc, 18, rf | RT3593_AUTOTUNE_BYPASS);
5518260219Skevlo
5519260219Skevlo	/*
5520260219Skevlo	 * Increase voltage from 1.2V to 1.35V, wait for 1 msec to
5521260219Skevlo	 * decrease voltage back to 1.2V.
5522260219Skevlo	 */
5523260219Skevlo	run_read(sc, RT3070_LDO_CFG0, &tmp);
5524260219Skevlo	tmp = (tmp & ~0x1f000000) | 0x0d000000;
5525260219Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5526260219Skevlo	run_delay(sc, 1);
5527260219Skevlo	tmp = (tmp & ~0x1f000000) | 0x01000000;
5528260219Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5529260219Skevlo
5530260219Skevlo	sc->rf24_20mhz = 0x1f;
5531260219Skevlo	sc->rf24_40mhz = 0x2f;
5532260219Skevlo
5533260219Skevlo	/* Save default BBP registers 25 and 26 values. */
5534260219Skevlo	run_bbp_read(sc, 25, &sc->bbp25);
5535260219Skevlo	run_bbp_read(sc, 26, &sc->bbp26);
5536260219Skevlo
5537260219Skevlo	run_read(sc, RT3070_OPT_14, &tmp);
5538260219Skevlo	run_write(sc, RT3070_OPT_14, tmp | 1);
5539260219Skevlo}
5540260219Skevlo
5541260219Skevlostatic void
5542257955Skevlorun_rt5390_rf_init(struct run_softc *sc)
5543257955Skevlo{
5544257955Skevlo	uint32_t tmp;
5545257955Skevlo	uint8_t rf;
5546257955Skevlo	int i;
5547257955Skevlo
5548259030Skevlo	/* Toggle RF R2 to initiate calibration. */
5549259030Skevlo	if (sc->mac_ver == 0x5390) {
5550257955Skevlo		run_rt3070_rf_read(sc, 2, &rf);
5551259031Skevlo		run_rt3070_rf_write(sc, 2, rf | RT5390_RESCAL);
5552257955Skevlo		run_delay(sc, 10);
5553259031Skevlo		run_rt3070_rf_write(sc, 2, rf & ~RT5390_RESCAL);
5554259030Skevlo	} else {
5555259031Skevlo		run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5556259030Skevlo		run_delay(sc, 10);
5557257955Skevlo	}
5558257955Skevlo
5559257955Skevlo	/* Initialize RF registers to default value. */
5560259032Skevlo	if (sc->mac_ver == 0x5592) {
5561259032Skevlo		for (i = 0; i < nitems(rt5592_def_rf); i++) {
5562259032Skevlo			run_rt3070_rf_write(sc, rt5592_def_rf[i].reg,
5563259032Skevlo			    rt5592_def_rf[i].val);
5564259032Skevlo		}
5565259032Skevlo		/* Initialize RF frequency offset. */
5566259032Skevlo		run_adjust_freq_offset(sc);
5567259032Skevlo	} else if (sc->mac_ver == 0x5392) {
5568257955Skevlo		for (i = 0; i < nitems(rt5392_def_rf); i++) {
5569257955Skevlo			run_rt3070_rf_write(sc, rt5392_def_rf[i].reg,
5570257955Skevlo			    rt5392_def_rf[i].val);
5571257955Skevlo		}
5572257955Skevlo		if (sc->mac_rev >= 0x0223) {
5573257955Skevlo			run_rt3070_rf_write(sc, 23, 0x0f);
5574257955Skevlo			run_rt3070_rf_write(sc, 24, 0x3e);
5575257955Skevlo			run_rt3070_rf_write(sc, 51, 0x32);
5576257955Skevlo			run_rt3070_rf_write(sc, 53, 0x22);
5577257955Skevlo			run_rt3070_rf_write(sc, 56, 0xc1);
5578257955Skevlo			run_rt3070_rf_write(sc, 59, 0x0f);
5579257955Skevlo		}
5580257955Skevlo	} else {
5581257955Skevlo		for (i = 0; i < nitems(rt5390_def_rf); i++) {
5582257955Skevlo			run_rt3070_rf_write(sc, rt5390_def_rf[i].reg,
5583257955Skevlo			    rt5390_def_rf[i].val);
5584257955Skevlo		}
5585257955Skevlo		if (sc->mac_rev >= 0x0502) {
5586257955Skevlo			run_rt3070_rf_write(sc, 6, 0xe0);
5587257955Skevlo			run_rt3070_rf_write(sc, 25, 0x80);
5588257955Skevlo			run_rt3070_rf_write(sc, 46, 0x73);
5589257955Skevlo			run_rt3070_rf_write(sc, 53, 0x00);
5590257955Skevlo			run_rt3070_rf_write(sc, 56, 0x42);
5591257955Skevlo			run_rt3070_rf_write(sc, 61, 0xd1);
5592257955Skevlo		}
5593257955Skevlo	}
5594257955Skevlo
5595257955Skevlo	sc->rf24_20mhz = 0x1f;	/* default value */
5596259032Skevlo	sc->rf24_40mhz = (sc->mac_ver == 0x5592) ? 0 : 0x2f;
5597257955Skevlo
5598257955Skevlo	if (sc->mac_rev < 0x0211)
5599257955Skevlo		run_rt3070_rf_write(sc, 27, 0x3);
5600257955Skevlo
5601257955Skevlo	run_read(sc, RT3070_OPT_14, &tmp);
5602257955Skevlo	run_write(sc, RT3070_OPT_14, tmp | 1);
5603257955Skevlo}
5604257955Skevlo
5605203134Sthompsastatic int
5606203134Sthompsarun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target,
5607203134Sthompsa    uint8_t *val)
5608203134Sthompsa{
5609203134Sthompsa	uint8_t rf22, rf24;
5610203134Sthompsa	uint8_t bbp55_pb, bbp55_sb, delta;
5611203134Sthompsa	int ntries;
5612203134Sthompsa
5613203134Sthompsa	/* program filter */
5614205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf24);
5615205042Sthompsa	rf24 = (rf24 & 0xc0) | init;	/* initial filter value */
5616203134Sthompsa	run_rt3070_rf_write(sc, 24, rf24);
5617203134Sthompsa
5618203134Sthompsa	/* enable baseband loopback mode */
5619203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5620203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 | 0x01);
5621203134Sthompsa
5622203134Sthompsa	/* set power and frequency of passband test tone */
5623203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5624203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5625203134Sthompsa		/* transmit test tone */
5626203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5627203134Sthompsa		run_delay(sc, 10);
5628203134Sthompsa		/* read received power */
5629203134Sthompsa		run_bbp_read(sc, 55, &bbp55_pb);
5630203134Sthompsa		if (bbp55_pb != 0)
5631203134Sthompsa			break;
5632203134Sthompsa	}
5633203134Sthompsa	if (ntries == 100)
5634257955Skevlo		return (ETIMEDOUT);
5635203134Sthompsa
5636203134Sthompsa	/* set power and frequency of stopband test tone */
5637203134Sthompsa	run_bbp_write(sc, 24, 0x06);
5638203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5639203134Sthompsa		/* transmit test tone */
5640203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5641203134Sthompsa		run_delay(sc, 10);
5642203134Sthompsa		/* read received power */
5643203134Sthompsa		run_bbp_read(sc, 55, &bbp55_sb);
5644203134Sthompsa
5645203134Sthompsa		delta = bbp55_pb - bbp55_sb;
5646203134Sthompsa		if (delta > target)
5647203134Sthompsa			break;
5648203134Sthompsa
5649203134Sthompsa		/* reprogram filter */
5650203134Sthompsa		rf24++;
5651203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5652203134Sthompsa	}
5653203134Sthompsa	if (ntries < 100) {
5654203134Sthompsa		if (rf24 != init)
5655203134Sthompsa			rf24--;	/* backtrack */
5656203134Sthompsa		*val = rf24;
5657203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5658203134Sthompsa	}
5659203134Sthompsa
5660203134Sthompsa	/* restore initial state */
5661203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5662203134Sthompsa
5663203134Sthompsa	/* disable baseband loopback mode */
5664203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5665203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 & ~0x01);
5666203134Sthompsa
5667209917Sthompsa	return (0);
5668203134Sthompsa}
5669203134Sthompsa
5670205042Sthompsastatic void
5671205042Sthompsarun_rt3070_rf_setup(struct run_softc *sc)
5672205042Sthompsa{
5673205042Sthompsa	uint8_t bbp, rf;
5674205042Sthompsa	int i;
5675205042Sthompsa
5676260219Skevlo	if (sc->mac_ver == 0x3572) {
5677205042Sthompsa		/* enable DC filter */
5678205042Sthompsa		if (sc->mac_rev >= 0x0201)
5679205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5680205042Sthompsa
5681205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5682205042Sthompsa		if (sc->ntxchains == 1)
5683205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5684205042Sthompsa		if (sc->nrxchains == 1)
5685205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5686205042Sthompsa		run_bbp_write(sc, 138, bbp);
5687205042Sthompsa
5688205042Sthompsa		if (sc->mac_rev >= 0x0211) {
5689205042Sthompsa			/* improve power consumption */
5690205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5691205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5692205042Sthompsa		}
5693205042Sthompsa
5694205042Sthompsa		run_rt3070_rf_read(sc, 16, &rf);
5695205042Sthompsa		rf = (rf & ~0x07) | sc->txmixgain_2ghz;
5696205042Sthompsa		run_rt3070_rf_write(sc, 16, rf);
5697205042Sthompsa
5698205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5699257409Skevlo		if (sc->mac_rev >= 0x0211) {
5700257409Skevlo			/* enable DC filter */
5701205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5702205042Sthompsa
5703257409Skevlo			/* improve power consumption */
5704257409Skevlo			run_bbp_read(sc, 31, &bbp);
5705257409Skevlo			run_bbp_write(sc, 31, bbp & ~0x03);
5706257409Skevlo		}
5707257409Skevlo
5708205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5709205042Sthompsa		if (sc->ntxchains == 1)
5710205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5711205042Sthompsa		if (sc->nrxchains == 1)
5712205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5713205042Sthompsa		run_bbp_write(sc, 138, bbp);
5714205042Sthompsa
5715205042Sthompsa		run_write(sc, RT2860_TX_SW_CFG1, 0);
5716205042Sthompsa		if (sc->mac_rev < 0x0211) {
5717205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2,
5718205042Sthompsa			    sc->patch_dac ? 0x2c : 0x0f);
5719205042Sthompsa		} else
5720205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5721205042Sthompsa
5722205042Sthompsa	} else if (sc->mac_ver == 0x3070) {
5723205042Sthompsa		if (sc->mac_rev >= 0x0201) {
5724205042Sthompsa			/* enable DC filter */
5725205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5726205042Sthompsa
5727205042Sthompsa			/* improve power consumption */
5728205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5729205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5730205042Sthompsa		}
5731205042Sthompsa
5732256955Skevlo		if (sc->mac_rev < 0x0201) {
5733205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG1, 0);
5734205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0x2c);
5735205042Sthompsa		} else
5736205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5737205042Sthompsa	}
5738205042Sthompsa
5739205042Sthompsa	/* initialize RF registers from ROM for >=RT3071*/
5740260219Skevlo	if (sc->mac_ver >= 0x3071) {
5741205042Sthompsa		for (i = 0; i < 10; i++) {
5742205042Sthompsa			if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff)
5743205042Sthompsa				continue;
5744205042Sthompsa			run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val);
5745205042Sthompsa		}
5746205042Sthompsa	}
5747205042Sthompsa}
5748205042Sthompsa
5749260219Skevlostatic void
5750260219Skevlorun_rt3593_rf_setup(struct run_softc *sc)
5751260219Skevlo{
5752260219Skevlo	uint8_t bbp, rf;
5753260219Skevlo
5754260219Skevlo	if (sc->mac_rev >= 0x0211) {
5755260219Skevlo		/* Enable DC filter. */
5756260219Skevlo		run_bbp_write(sc, 103, 0xc0);
5757260219Skevlo	}
5758260219Skevlo	run_write(sc, RT2860_TX_SW_CFG1, 0);
5759260219Skevlo	if (sc->mac_rev < 0x0211) {
5760260219Skevlo		run_write(sc, RT2860_TX_SW_CFG2,
5761260219Skevlo		    sc->patch_dac ? 0x2c : 0x0f);
5762260219Skevlo	} else
5763260219Skevlo		run_write(sc, RT2860_TX_SW_CFG2, 0);
5764260219Skevlo
5765260219Skevlo	run_rt3070_rf_read(sc, 50, &rf);
5766260219Skevlo	run_rt3070_rf_write(sc, 50, rf & ~RT3593_TX_LO2);
5767260219Skevlo
5768260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
5769260219Skevlo	rf = (rf & ~(RT3593_TX_LO1 | 0x0c)) |
5770260219Skevlo	    ((sc->txmixgain_2ghz & 0x07) << 2);
5771260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
5772260219Skevlo
5773260219Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5774260219Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5775260219Skevlo
5776260219Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5777260219Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5778260219Skevlo
5779260219Skevlo	run_rt3070_rf_read(sc, 1, &rf);
5780260219Skevlo	run_rt3070_rf_write(sc, 1, rf & ~(RT3070_RF_BLOCK | RT3070_PLL_PD));
5781260219Skevlo
5782260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5783260219Skevlo	rf = (rf & ~0x18) | 0x10;
5784260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
5785260219Skevlo
5786260219Skevlo	/* Apply maximum likelihood detection for 2 stream case. */
5787260219Skevlo	run_bbp_read(sc, 105, &bbp);
5788260219Skevlo	if (sc->nrxchains > 1)
5789260219Skevlo		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5790260219Skevlo
5791260219Skevlo	/* Avoid data lost and CRC error. */
5792260219Skevlo	run_bbp_read(sc, 4, &bbp);
5793260219Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5794260219Skevlo
5795260219Skevlo	run_bbp_write(sc, 92, 0x02);
5796260219Skevlo	run_bbp_write(sc, 82, 0x82);
5797260219Skevlo	run_bbp_write(sc, 106, 0x05);
5798260219Skevlo	run_bbp_write(sc, 104, 0x92);
5799260219Skevlo	run_bbp_write(sc, 88, 0x90);
5800260219Skevlo	run_bbp_write(sc, 148, 0xc8);
5801260219Skevlo	run_bbp_write(sc, 47, 0x48);
5802260219Skevlo	run_bbp_write(sc, 120, 0x50);
5803260219Skevlo
5804260219Skevlo	run_bbp_write(sc, 163, 0x9d);
5805260219Skevlo
5806260219Skevlo	/* SNR mapping. */
5807260219Skevlo	run_bbp_write(sc, 142, 0x06);
5808260219Skevlo	run_bbp_write(sc, 143, 0xa0);
5809260219Skevlo	run_bbp_write(sc, 142, 0x07);
5810260219Skevlo	run_bbp_write(sc, 143, 0xa1);
5811260219Skevlo	run_bbp_write(sc, 142, 0x08);
5812260219Skevlo	run_bbp_write(sc, 143, 0xa2);
5813260219Skevlo
5814260219Skevlo	run_bbp_write(sc, 31, 0x08);
5815260219Skevlo	run_bbp_write(sc, 68, 0x0b);
5816260219Skevlo	run_bbp_write(sc, 105, 0x04);
5817260219Skevlo}
5818260219Skevlo
5819260219Skevlostatic void
5820260219Skevlorun_rt5390_rf_setup(struct run_softc *sc)
5821260219Skevlo{
5822260219Skevlo	uint8_t bbp, rf;
5823260219Skevlo
5824260219Skevlo	if (sc->mac_rev >= 0x0211) {
5825260219Skevlo		/* Enable DC filter. */
5826260219Skevlo		run_bbp_write(sc, 103, 0xc0);
5827260219Skevlo
5828260219Skevlo		if (sc->mac_ver != 0x5592) {
5829260219Skevlo			/* Improve power consumption. */
5830260219Skevlo			run_bbp_read(sc, 31, &bbp);
5831260219Skevlo			run_bbp_write(sc, 31, bbp & ~0x03);
5832260219Skevlo		}
5833260219Skevlo	}
5834260219Skevlo
5835260219Skevlo	run_bbp_read(sc, 138, &bbp);
5836260219Skevlo	if (sc->ntxchains == 1)
5837260219Skevlo		bbp |= 0x20;	/* turn off DAC1 */
5838260219Skevlo	if (sc->nrxchains == 1)
5839260219Skevlo		bbp &= ~0x02;	/* turn off ADC1 */
5840260219Skevlo	run_bbp_write(sc, 138, bbp);
5841260219Skevlo
5842260219Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5843260219Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5844260219Skevlo
5845260219Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5846260219Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5847260219Skevlo
5848260219Skevlo	/* Avoid data lost and CRC error. */
5849260219Skevlo	run_bbp_read(sc, 4, &bbp);
5850260219Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5851260219Skevlo
5852260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5853260219Skevlo	rf = (rf & ~0x18) | 0x10;
5854260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
5855260219Skevlo
5856260219Skevlo	if (sc->mac_ver != 0x5592) {
5857260219Skevlo		run_write(sc, RT2860_TX_SW_CFG1, 0);
5858260219Skevlo		if (sc->mac_rev < 0x0211) {
5859260219Skevlo			run_write(sc, RT2860_TX_SW_CFG2,
5860260219Skevlo			    sc->patch_dac ? 0x2c : 0x0f);
5861260219Skevlo		} else
5862260219Skevlo			run_write(sc, RT2860_TX_SW_CFG2, 0);
5863260219Skevlo	}
5864260219Skevlo}
5865260219Skevlo
5866203134Sthompsastatic int
5867203134Sthompsarun_txrx_enable(struct run_softc *sc)
5868203134Sthompsa{
5869287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5870203134Sthompsa	uint32_t tmp;
5871203134Sthompsa	int error, ntries;
5872203134Sthompsa
5873203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN);
5874203134Sthompsa	for (ntries = 0; ntries < 200; ntries++) {
5875203134Sthompsa		if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0)
5876257955Skevlo			return (error);
5877203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5878203134Sthompsa			break;
5879203134Sthompsa		run_delay(sc, 50);
5880203134Sthompsa	}
5881203134Sthompsa	if (ntries == 200)
5882257955Skevlo		return (ETIMEDOUT);
5883203134Sthompsa
5884203134Sthompsa	run_delay(sc, 50);
5885203134Sthompsa
5886203134Sthompsa	tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE;
5887203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
5888203134Sthompsa
5889203134Sthompsa	/* enable Rx bulk aggregation (set timeout and limit) */
5890203134Sthompsa	tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN |
5891203134Sthompsa	    RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2);
5892203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, tmp);
5893203134Sthompsa
5894203134Sthompsa	/* set Rx filter */
5895203134Sthompsa	tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR;
5896203134Sthompsa	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
5897203134Sthompsa		tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL |
5898203134Sthompsa		    RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK |
5899203134Sthompsa		    RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV |
5900203134Sthompsa		    RT2860_DROP_CFACK | RT2860_DROP_CFEND;
5901203134Sthompsa		if (ic->ic_opmode == IEEE80211_M_STA)
5902203134Sthompsa			tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL;
5903203134Sthompsa	}
5904203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5905203134Sthompsa
5906203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
5907203134Sthompsa	    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
5908203134Sthompsa
5909209917Sthompsa	return (0);
5910203134Sthompsa}
5911203134Sthompsa
5912203134Sthompsastatic void
5913259030Skevlorun_adjust_freq_offset(struct run_softc *sc)
5914257955Skevlo{
5915257955Skevlo	uint8_t rf, tmp;
5916257955Skevlo
5917257955Skevlo	run_rt3070_rf_read(sc, 17, &rf);
5918257955Skevlo	tmp = rf;
5919257955Skevlo	rf = (rf & ~0x7f) | (sc->freq & 0x7f);
5920257955Skevlo	rf = MIN(rf, 0x5f);
5921257955Skevlo
5922257955Skevlo	if (tmp != rf)
5923257955Skevlo		run_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf);
5924257955Skevlo}
5925257955Skevlo
5926257955Skevlostatic void
5927203134Sthompsarun_init_locked(struct run_softc *sc)
5928203134Sthompsa{
5929287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5930287197Sglebius	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
5931203134Sthompsa	uint32_t tmp;
5932203134Sthompsa	uint8_t bbp1, bbp3;
5933203134Sthompsa	int i;
5934203134Sthompsa	int ridx;
5935203134Sthompsa	int ntries;
5936203134Sthompsa
5937209917Sthompsa	if (ic->ic_nrunning > 1)
5938208019Sthompsa		return;
5939208019Sthompsa
5940203134Sthompsa	run_stop(sc);
5941203134Sthompsa
5942233283Sbschmidt	if (run_load_microcode(sc) != 0) {
5943233283Sbschmidt		device_printf(sc->sc_dev, "could not load 8051 microcode\n");
5944233283Sbschmidt		goto fail;
5945233283Sbschmidt	}
5946233283Sbschmidt
5947203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5948203134Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0)
5949203134Sthompsa			goto fail;
5950203134Sthompsa		if (tmp != 0 && tmp != 0xffffffff)
5951203134Sthompsa			break;
5952203134Sthompsa		run_delay(sc, 10);
5953203134Sthompsa	}
5954203134Sthompsa	if (ntries == 100)
5955203134Sthompsa		goto fail;
5956203134Sthompsa
5957203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
5958203134Sthompsa		run_setup_tx_list(sc, &sc->sc_epq[i]);
5959203134Sthompsa
5960287197Sglebius	run_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr);
5961203134Sthompsa
5962203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5963203134Sthompsa		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
5964203134Sthompsa			goto fail;
5965203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5966203134Sthompsa			break;
5967203134Sthompsa		run_delay(sc, 10);
5968203134Sthompsa	}
5969203134Sthompsa	if (ntries == 100) {
5970203138Sthompsa		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
5971203134Sthompsa		goto fail;
5972203134Sthompsa	}
5973203134Sthompsa	tmp &= 0xff0;
5974203134Sthompsa	tmp |= RT2860_TX_WB_DDONE;
5975203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
5976203134Sthompsa
5977203134Sthompsa	/* turn off PME_OEN to solve high-current issue */
5978203134Sthompsa	run_read(sc, RT2860_SYS_CTRL, &tmp);
5979203134Sthompsa	run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN);
5980203134Sthompsa
5981203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
5982203134Sthompsa	    RT2860_BBP_HRST | RT2860_MAC_SRST);
5983203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
5984203134Sthompsa
5985203134Sthompsa	if (run_reset(sc) != 0) {
5986203138Sthompsa		device_printf(sc->sc_dev, "could not reset chipset\n");
5987203134Sthompsa		goto fail;
5988203134Sthompsa	}
5989203134Sthompsa
5990203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
5991203134Sthompsa
5992203134Sthompsa	/* init Tx power for all Tx rates (from EEPROM) */
5993203134Sthompsa	for (ridx = 0; ridx < 5; ridx++) {
5994203134Sthompsa		if (sc->txpow20mhz[ridx] == 0xffffffff)
5995203134Sthompsa			continue;
5996203134Sthompsa		run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]);
5997203134Sthompsa	}
5998203134Sthompsa
5999257955Skevlo	for (i = 0; i < nitems(rt2870_def_mac); i++)
6000203134Sthompsa		run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val);
6001203134Sthompsa	run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273);
6002203134Sthompsa	run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344);
6003203134Sthompsa	run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa);
6004203134Sthompsa
6005259030Skevlo	if (sc->mac_ver >= 0x5390) {
6006259030Skevlo		run_write(sc, RT2860_TX_SW_CFG0,
6007259030Skevlo		    4 << RT2860_DLY_PAPE_EN_SHIFT | 4);
6008259030Skevlo		if (sc->mac_ver >= 0x5392) {
6009259030Skevlo			run_write(sc, RT2860_MAX_LEN_CFG, 0x00002fff);
6010259032Skevlo			if (sc->mac_ver == 0x5592) {
6011259032Skevlo				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcba980);
6012259032Skevlo				run_write(sc, RT2860_TXOP_HLDR_ET, 0x00000082);
6013259032Skevlo			} else {
6014259032Skevlo				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcb4980);
6015259032Skevlo				run_write(sc, RT2860_LG_FBK_CFG0, 0xedcba322);
6016259032Skevlo			}
6017259030Skevlo		}
6018260219Skevlo	} else if (sc->mac_ver == 0x3593) {
6019260219Skevlo		run_write(sc, RT2860_TX_SW_CFG0,
6020260219Skevlo		    4 << RT2860_DLY_PAPE_EN_SHIFT | 2);
6021257955Skevlo	} else if (sc->mac_ver >= 0x3070) {
6022203134Sthompsa		/* set delay of PA_PE assertion to 1us (unit of 0.25us) */
6023203134Sthompsa		run_write(sc, RT2860_TX_SW_CFG0,
6024203134Sthompsa		    4 << RT2860_DLY_PAPE_EN_SHIFT);
6025203134Sthompsa	}
6026203134Sthompsa
6027203134Sthompsa	/* wait while MAC is busy */
6028203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
6029203134Sthompsa		if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0)
6030203134Sthompsa			goto fail;
6031203134Sthompsa		if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY)))
6032203134Sthompsa			break;
6033203134Sthompsa		run_delay(sc, 10);
6034203134Sthompsa	}
6035203134Sthompsa	if (ntries == 100)
6036203134Sthompsa		goto fail;
6037203134Sthompsa
6038203134Sthompsa	/* clear Host to MCU mailbox */
6039203134Sthompsa	run_write(sc, RT2860_H2M_BBPAGENT, 0);
6040203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
6041203134Sthompsa	run_delay(sc, 10);
6042203134Sthompsa
6043203134Sthompsa	if (run_bbp_init(sc) != 0) {
6044203138Sthompsa		device_printf(sc->sc_dev, "could not initialize BBP\n");
6045203134Sthompsa		goto fail;
6046203134Sthompsa	}
6047203134Sthompsa
6048203134Sthompsa	/* abort TSF synchronization */
6049203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
6050203134Sthompsa	tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
6051203134Sthompsa	    RT2860_TBTT_TIMER_EN);
6052203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
6053203134Sthompsa
6054203134Sthompsa	/* clear RX WCID search table */
6055203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512);
6056203134Sthompsa	/* clear WCID attribute table */
6057203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32);
6058203134Sthompsa
6059209144Sthompsa	/* hostapd sets a key before init. So, don't clear it. */
6060209917Sthompsa	if (sc->cmdq_key_set != RUN_CMDQ_GO) {
6061209144Sthompsa		/* clear shared key table */
6062209144Sthompsa		run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32);
6063209144Sthompsa		/* clear shared key mode */
6064209144Sthompsa		run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4);
6065209144Sthompsa	}
6066209144Sthompsa
6067203134Sthompsa	run_read(sc, RT2860_US_CYC_CNT, &tmp);
6068203134Sthompsa	tmp = (tmp & ~0xff) | 0x1e;
6069203134Sthompsa	run_write(sc, RT2860_US_CYC_CNT, tmp);
6070203134Sthompsa
6071205042Sthompsa	if (sc->mac_rev != 0x0101)
6072203134Sthompsa		run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f);
6073203134Sthompsa
6074203134Sthompsa	run_write(sc, RT2860_WMM_TXOP0_CFG, 0);
6075203134Sthompsa	run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96);
6076203134Sthompsa
6077203134Sthompsa	/* write vendor-specific BBP values (from EEPROM) */
6078260219Skevlo	if (sc->mac_ver < 0x3593) {
6079257955Skevlo		for (i = 0; i < 10; i++) {
6080257955Skevlo			if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff)
6081257955Skevlo				continue;
6082257955Skevlo			run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val);
6083257955Skevlo		}
6084203134Sthompsa	}
6085203134Sthompsa
6086203134Sthompsa	/* select Main antenna for 1T1R devices */
6087257955Skevlo	if (sc->rf_rev == RT3070_RF_3020 || sc->rf_rev == RT5390_RF_5370)
6088203134Sthompsa		run_set_rx_antenna(sc, 0);
6089203134Sthompsa
6090203134Sthompsa	/* send LEDs operating mode to microcontroller */
6091203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]);
6092203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]);
6093203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]);
6094203134Sthompsa
6095257955Skevlo	if (sc->mac_ver >= 0x5390)
6096257955Skevlo		run_rt5390_rf_init(sc);
6097260219Skevlo	else if (sc->mac_ver == 0x3593)
6098260219Skevlo		run_rt3593_rf_init(sc);
6099257955Skevlo	else if (sc->mac_ver >= 0x3070)
6100205042Sthompsa		run_rt3070_rf_init(sc);
6101205042Sthompsa
6102203134Sthompsa	/* disable non-existing Rx chains */
6103203134Sthompsa	run_bbp_read(sc, 3, &bbp3);
6104203134Sthompsa	bbp3 &= ~(1 << 3 | 1 << 4);
6105203134Sthompsa	if (sc->nrxchains == 2)
6106203134Sthompsa		bbp3 |= 1 << 3;
6107203134Sthompsa	else if (sc->nrxchains == 3)
6108203134Sthompsa		bbp3 |= 1 << 4;
6109203134Sthompsa	run_bbp_write(sc, 3, bbp3);
6110203134Sthompsa
6111203134Sthompsa	/* disable non-existing Tx chains */
6112203134Sthompsa	run_bbp_read(sc, 1, &bbp1);
6113203134Sthompsa	if (sc->ntxchains == 1)
6114203134Sthompsa		bbp1 &= ~(1 << 3 | 1 << 4);
6115203134Sthompsa	run_bbp_write(sc, 1, bbp1);
6116203134Sthompsa
6117260219Skevlo	if (sc->mac_ver >= 0x5390)
6118260219Skevlo		run_rt5390_rf_setup(sc);
6119260219Skevlo	else if (sc->mac_ver == 0x3593)
6120260219Skevlo		run_rt3593_rf_setup(sc);
6121260219Skevlo	else if (sc->mac_ver >= 0x3070)
6122205042Sthompsa		run_rt3070_rf_setup(sc);
6123203134Sthompsa
6124203134Sthompsa	/* select default channel */
6125203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
6126203134Sthompsa
6127203134Sthompsa	/* setup initial protection mode */
6128218492Sbschmidt	run_updateprot_cb(ic);
6129203134Sthompsa
6130203134Sthompsa	/* turn radio LED on */
6131203134Sthompsa	run_set_leds(sc, RT2860_LED_RADIO);
6132203134Sthompsa
6133287197Sglebius	sc->sc_flags |= RUN_RUNNING;
6134208019Sthompsa	sc->cmdq_run = RUN_CMDQ_GO;
6135203134Sthompsa
6136209917Sthompsa	for (i = 0; i != RUN_N_XFER; i++)
6137203134Sthompsa		usbd_xfer_set_stall(sc->sc_xfer[i]);
6138203134Sthompsa
6139203134Sthompsa	usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]);
6140203134Sthompsa
6141203134Sthompsa	if (run_txrx_enable(sc) != 0)
6142203134Sthompsa		goto fail;
6143203134Sthompsa
6144203134Sthompsa	return;
6145203134Sthompsa
6146203134Sthompsafail:
6147203134Sthompsa	run_stop(sc);
6148203134Sthompsa}
6149203134Sthompsa
6150203134Sthompsastatic void
6151203134Sthompsarun_stop(void *arg)
6152203134Sthompsa{
6153203134Sthompsa	struct run_softc *sc = (struct run_softc *)arg;
6154203134Sthompsa	uint32_t tmp;
6155203134Sthompsa	int i;
6156203134Sthompsa	int ntries;
6157203134Sthompsa
6158203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
6159203134Sthompsa
6160287197Sglebius	if (sc->sc_flags & RUN_RUNNING)
6161203134Sthompsa		run_set_leds(sc, 0);	/* turn all LEDs off */
6162203134Sthompsa
6163287197Sglebius	sc->sc_flags &= ~RUN_RUNNING;
6164203134Sthompsa
6165208019Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
6166209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set;
6167208019Sthompsa
6168203134Sthompsa	RUN_UNLOCK(sc);
6169203134Sthompsa
6170203134Sthompsa	for(i = 0; i < RUN_N_XFER; i++)
6171203134Sthompsa		usbd_transfer_drain(sc->sc_xfer[i]);
6172203134Sthompsa
6173203134Sthompsa	RUN_LOCK(sc);
6174203134Sthompsa
6175209917Sthompsa	if (sc->rx_m != NULL) {
6176203134Sthompsa		m_free(sc->rx_m);
6177203134Sthompsa		sc->rx_m = NULL;
6178203134Sthompsa	}
6179203134Sthompsa
6180257955Skevlo	/* Disable Tx/Rx DMA. */
6181257955Skevlo	if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6182257955Skevlo		return;
6183257955Skevlo	tmp &= ~(RT2860_RX_DMA_EN | RT2860_TX_DMA_EN);
6184257955Skevlo	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
6185257955Skevlo
6186258643Shselasky	for (ntries = 0; ntries < 100; ntries++) {
6187257955Skevlo		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6188257955Skevlo			return;
6189257955Skevlo		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
6190257955Skevlo				break;
6191257955Skevlo		run_delay(sc, 10);
6192257955Skevlo	}
6193257955Skevlo	if (ntries == 100) {
6194257955Skevlo		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
6195257955Skevlo		return;
6196257955Skevlo	}
6197257955Skevlo
6198203134Sthompsa	/* disable Tx/Rx */
6199203134Sthompsa	run_read(sc, RT2860_MAC_SYS_CTRL, &tmp);
6200203134Sthompsa	tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
6201203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, tmp);
6202203134Sthompsa
6203203134Sthompsa	/* wait for pending Tx to complete */
6204203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
6205209917Sthompsa		if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0) {
6206203134Sthompsa			DPRINTF("Cannot read Tx queue count\n");
6207203134Sthompsa			break;
6208203134Sthompsa		}
6209209917Sthompsa		if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0) {
6210203134Sthompsa			DPRINTF("All Tx cleared\n");
6211203134Sthompsa			break;
6212203134Sthompsa		}
6213203134Sthompsa		run_delay(sc, 10);
6214203134Sthompsa	}
6215209917Sthompsa	if (ntries >= 100)
6216203134Sthompsa		DPRINTF("There are still pending Tx\n");
6217203134Sthompsa	run_delay(sc, 10);
6218203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
6219203134Sthompsa
6220203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST);
6221203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
6222203134Sthompsa
6223203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
6224203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
6225203134Sthompsa}
6226203134Sthompsa
6227203134Sthompsastatic void
6228257429Shselaskyrun_delay(struct run_softc *sc, u_int ms)
6229203134Sthompsa{
6230203134Sthompsa	usb_pause_mtx(mtx_owned(&sc->sc_mtx) ?
6231203134Sthompsa	    &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms));
6232203134Sthompsa}
6233203134Sthompsa
6234203134Sthompsastatic device_method_t run_methods[] = {
6235203134Sthompsa	/* Device interface */
6236203134Sthompsa	DEVMETHOD(device_probe,		run_match),
6237203134Sthompsa	DEVMETHOD(device_attach,	run_attach),
6238203134Sthompsa	DEVMETHOD(device_detach,	run_detach),
6239246614Shselasky	DEVMETHOD_END
6240203134Sthompsa};
6241203134Sthompsa
6242203134Sthompsastatic driver_t run_driver = {
6243233774Shselasky	.name = "run",
6244233774Shselasky	.methods = run_methods,
6245233774Shselasky	.size = sizeof(struct run_softc)
6246203134Sthompsa};
6247203134Sthompsa
6248203134Sthompsastatic devclass_t run_devclass;
6249203134Sthompsa
6250259812SkevloDRIVER_MODULE(run, uhub, run_driver, run_devclass, run_driver_loaded, NULL);
6251212122SthompsaMODULE_DEPEND(run, wlan, 1, 1, 1);
6252212122SthompsaMODULE_DEPEND(run, usb, 1, 1, 1);
6253212122SthompsaMODULE_DEPEND(run, firmware, 1, 1, 1);
6254212122SthompsaMODULE_VERSION(run, 1);
6255