if_run.c revision 287553
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 287553 2015-09-08 07:53:10Z kevlo $");
22203134Sthompsa
23203134Sthompsa/*-
24257955Skevlo * Ralink Technology RT2700U/RT2800U/RT3000U/RT3900E chipset driver.
25203134Sthompsa * http://www.ralinktech.com/
26203134Sthompsa */
27203134Sthompsa
28203134Sthompsa#include <sys/param.h>
29203134Sthompsa#include <sys/sockio.h>
30203134Sthompsa#include <sys/sysctl.h>
31203134Sthompsa#include <sys/lock.h>
32203134Sthompsa#include <sys/mutex.h>
33203134Sthompsa#include <sys/mbuf.h>
34203134Sthompsa#include <sys/kernel.h>
35203134Sthompsa#include <sys/socket.h>
36203134Sthompsa#include <sys/systm.h>
37203134Sthompsa#include <sys/malloc.h>
38203134Sthompsa#include <sys/module.h>
39203134Sthompsa#include <sys/bus.h>
40203134Sthompsa#include <sys/endian.h>
41203134Sthompsa#include <sys/linker.h>
42203134Sthompsa#include <sys/firmware.h>
43203134Sthompsa#include <sys/kdb.h>
44203134Sthompsa
45203134Sthompsa#include <machine/bus.h>
46203134Sthompsa#include <machine/resource.h>
47203134Sthompsa#include <sys/rman.h>
48203134Sthompsa
49203134Sthompsa#include <net/bpf.h>
50203134Sthompsa#include <net/if.h>
51257176Sglebius#include <net/if_var.h>
52203134Sthompsa#include <net/if_arp.h>
53203134Sthompsa#include <net/ethernet.h>
54203134Sthompsa#include <net/if_dl.h>
55203134Sthompsa#include <net/if_media.h>
56203134Sthompsa#include <net/if_types.h>
57203134Sthompsa
58203134Sthompsa#include <netinet/in.h>
59203134Sthompsa#include <netinet/in_systm.h>
60203134Sthompsa#include <netinet/in_var.h>
61203134Sthompsa#include <netinet/if_ether.h>
62203134Sthompsa#include <netinet/ip.h>
63203134Sthompsa
64203134Sthompsa#include <net80211/ieee80211_var.h>
65203134Sthompsa#include <net80211/ieee80211_regdomain.h>
66203134Sthompsa#include <net80211/ieee80211_radiotap.h>
67206358Srpaulo#include <net80211/ieee80211_ratectl.h>
68203134Sthompsa
69203134Sthompsa#include <dev/usb/usb.h>
70203134Sthompsa#include <dev/usb/usbdi.h>
71203134Sthompsa#include "usbdevs.h"
72203134Sthompsa
73259546Skevlo#define	USB_DEBUG_VAR	run_debug
74203134Sthompsa#include <dev/usb/usb_debug.h>
75259812Skevlo#include <dev/usb/usb_msctest.h>
76203134Sthompsa
77220235Skevlo#include <dev/usb/wlan/if_runreg.h>
78220235Skevlo#include <dev/usb/wlan/if_runvar.h>
79203134Sthompsa
80207077Sthompsa#ifdef	USB_DEBUG
81259546Skevlo#define	RUN_DEBUG
82203134Sthompsa#endif
83203134Sthompsa
84203134Sthompsa#ifdef	RUN_DEBUG
85203134Sthompsaint run_debug = 0;
86227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, run, CTLFLAG_RW, 0, "USB run");
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 *);
385208019Sthompsastatic int	run_key_set(struct ieee80211vap *, struct ieee80211_key *,
386257955Skevlo		    const uint8_t mac[IEEE80211_ADDR_LEN]);
387208019Sthompsastatic void	run_key_delete_cb(void *);
388208019Sthompsastatic int	run_key_delete(struct ieee80211vap *, struct ieee80211_key *);
389206358Srpaulostatic void	run_ratectl_to(void *);
390206358Srpaulostatic void	run_ratectl_cb(void *, int);
391208019Sthompsastatic void	run_drain_fifo(void *);
392203134Sthompsastatic void	run_iter_func(void *, struct ieee80211_node *);
393208019Sthompsastatic void	run_newassoc_cb(void *);
394203134Sthompsastatic void	run_newassoc(struct ieee80211_node *, int);
395203134Sthompsastatic void	run_rx_frame(struct run_softc *, struct mbuf *, uint32_t);
396203134Sthompsastatic void	run_tx_free(struct run_endpoint_queue *pq,
397203134Sthompsa		    struct run_tx_data *, int);
398208019Sthompsastatic void	run_set_tx_desc(struct run_softc *, struct run_tx_data *);
399203134Sthompsastatic int	run_tx(struct run_softc *, struct mbuf *,
400203134Sthompsa		    struct ieee80211_node *);
401203134Sthompsastatic int	run_tx_mgt(struct run_softc *, struct mbuf *,
402203134Sthompsa		    struct ieee80211_node *);
403203134Sthompsastatic int	run_sendprot(struct run_softc *, const struct mbuf *,
404203134Sthompsa		    struct ieee80211_node *, int, int);
405203134Sthompsastatic int	run_tx_param(struct run_softc *, struct mbuf *,
406203134Sthompsa		    struct ieee80211_node *,
407203134Sthompsa		    const struct ieee80211_bpf_params *);
408203134Sthompsastatic int	run_raw_xmit(struct ieee80211_node *, struct mbuf *,
409203134Sthompsa		    const struct ieee80211_bpf_params *);
410287197Sglebiusstatic int	run_transmit(struct ieee80211com *, struct mbuf *);
411287197Sglebiusstatic void	run_start(struct run_softc *);
412287197Sglebiusstatic void	run_parent(struct ieee80211com *);
413259544Skevlostatic void	run_iq_calib(struct run_softc *, u_int);
414205042Sthompsastatic void	run_set_agc(struct run_softc *, uint8_t);
415203134Sthompsastatic void	run_select_chan_group(struct run_softc *, int);
416203134Sthompsastatic void	run_set_rx_antenna(struct run_softc *, int);
417203134Sthompsastatic void	run_rt2870_set_chan(struct run_softc *, u_int);
418203134Sthompsastatic void	run_rt3070_set_chan(struct run_softc *, u_int);
419205042Sthompsastatic void	run_rt3572_set_chan(struct run_softc *, u_int);
420260219Skevlostatic void	run_rt3593_set_chan(struct run_softc *, u_int);
421257955Skevlostatic void	run_rt5390_set_chan(struct run_softc *, u_int);
422259032Skevlostatic void	run_rt5592_set_chan(struct run_softc *, u_int);
423203134Sthompsastatic int	run_set_chan(struct run_softc *, struct ieee80211_channel *);
424203134Sthompsastatic void	run_set_channel(struct ieee80211com *);
425203134Sthompsastatic void	run_scan_start(struct ieee80211com *);
426203134Sthompsastatic void	run_scan_end(struct ieee80211com *);
427203134Sthompsastatic void	run_update_beacon(struct ieee80211vap *, int);
428208019Sthompsastatic void	run_update_beacon_cb(void *);
429203134Sthompsastatic void	run_updateprot(struct ieee80211com *);
430218492Sbschmidtstatic void	run_updateprot_cb(void *);
431208019Sthompsastatic void	run_usb_timeout_cb(void *);
432203134Sthompsastatic void	run_reset_livelock(struct run_softc *);
433203134Sthompsastatic void	run_enable_tsf_sync(struct run_softc *);
434203134Sthompsastatic void	run_enable_mrr(struct run_softc *);
435203134Sthompsastatic void	run_set_txpreamble(struct run_softc *);
436203134Sthompsastatic void	run_set_basicrates(struct run_softc *);
437203134Sthompsastatic void	run_set_leds(struct run_softc *, uint16_t);
438203134Sthompsastatic void	run_set_bssid(struct run_softc *, const uint8_t *);
439203134Sthompsastatic void	run_set_macaddr(struct run_softc *, const uint8_t *);
440283540Sglebiusstatic void	run_updateslot(struct ieee80211com *);
441218492Sbschmidtstatic void	run_updateslot_cb(void *);
442283540Sglebiusstatic void	run_update_mcast(struct ieee80211com *);
443203134Sthompsastatic int8_t	run_rssi2dbm(struct run_softc *, uint8_t, uint8_t);
444283540Sglebiusstatic void	run_update_promisc_locked(struct run_softc *);
445283540Sglebiusstatic void	run_update_promisc(struct ieee80211com *);
446257955Skevlostatic void	run_rt5390_bbp_init(struct run_softc *);
447203134Sthompsastatic int	run_bbp_init(struct run_softc *);
448203134Sthompsastatic int	run_rt3070_rf_init(struct run_softc *);
449260219Skevlostatic void	run_rt3593_rf_init(struct run_softc *);
450257955Skevlostatic void	run_rt5390_rf_init(struct run_softc *);
451203134Sthompsastatic int	run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t,
452203134Sthompsa		    uint8_t *);
453205042Sthompsastatic void	run_rt3070_rf_setup(struct run_softc *);
454260219Skevlostatic void	run_rt3593_rf_setup(struct run_softc *);
455260219Skevlostatic void	run_rt5390_rf_setup(struct run_softc *);
456203134Sthompsastatic int	run_txrx_enable(struct run_softc *);
457257955Skevlostatic void	run_adjust_freq_offset(struct run_softc *);
458203134Sthompsastatic void	run_init_locked(struct run_softc *);
459203134Sthompsastatic void	run_stop(void *);
460257429Shselaskystatic void	run_delay(struct run_softc *, u_int);
461203134Sthompsa
462259812Skevlostatic eventhandler_tag run_etag;
463259812Skevlo
464259544Skevlostatic const struct rt2860_rate {
465259544Skevlo	uint8_t		rate;
466259544Skevlo	uint8_t		mcs;
467259544Skevlo	enum		ieee80211_phytype phy;
468259544Skevlo	uint8_t		ctl_ridx;
469259544Skevlo	uint16_t	sp_ack_dur;
470259544Skevlo	uint16_t	lp_ack_dur;
471259544Skevlo} rt2860_rates[] = {
472259544Skevlo	{   2, 0, IEEE80211_T_DS,   0, 314, 314 },
473259544Skevlo	{   4, 1, IEEE80211_T_DS,   1, 258, 162 },
474259544Skevlo	{  11, 2, IEEE80211_T_DS,   2, 223, 127 },
475259544Skevlo	{  22, 3, IEEE80211_T_DS,   3, 213, 117 },
476259544Skevlo	{  12, 0, IEEE80211_T_OFDM, 4,  60,  60 },
477259544Skevlo	{  18, 1, IEEE80211_T_OFDM, 4,  52,  52 },
478259544Skevlo	{  24, 2, IEEE80211_T_OFDM, 6,  48,  48 },
479259544Skevlo	{  36, 3, IEEE80211_T_OFDM, 6,  44,  44 },
480259544Skevlo	{  48, 4, IEEE80211_T_OFDM, 8,  44,  44 },
481259544Skevlo	{  72, 5, IEEE80211_T_OFDM, 8,  40,  40 },
482259544Skevlo	{  96, 6, IEEE80211_T_OFDM, 8,  40,  40 },
483259544Skevlo	{ 108, 7, IEEE80211_T_OFDM, 8,  40,  40 }
484259544Skevlo};
485259544Skevlo
486203134Sthompsastatic const struct {
487208019Sthompsa	uint16_t	reg;
488203134Sthompsa	uint32_t	val;
489203134Sthompsa} rt2870_def_mac[] = {
490203134Sthompsa	RT2870_DEF_MAC
491203134Sthompsa};
492203134Sthompsa
493203134Sthompsastatic const struct {
494203134Sthompsa	uint8_t	reg;
495203134Sthompsa	uint8_t	val;
496203134Sthompsa} rt2860_def_bbp[] = {
497203134Sthompsa	RT2860_DEF_BBP
498257955Skevlo},rt5390_def_bbp[] = {
499257955Skevlo	RT5390_DEF_BBP
500259032Skevlo},rt5592_def_bbp[] = {
501259032Skevlo	RT5592_DEF_BBP
502203134Sthompsa};
503203134Sthompsa
504259032Skevlo/*
505259032Skevlo * Default values for BBP register R196 for RT5592.
506259032Skevlo */
507259032Skevlostatic const uint8_t rt5592_bbp_r196[] = {
508259032Skevlo	0xe0, 0x1f, 0x38, 0x32, 0x08, 0x28, 0x19, 0x0a, 0xff, 0x00,
509259032Skevlo	0x16, 0x10, 0x10, 0x0b, 0x36, 0x2c, 0x26, 0x24, 0x42, 0x36,
510259032Skevlo	0x30, 0x2d, 0x4c, 0x46, 0x3d, 0x40, 0x3e, 0x42, 0x3d, 0x40,
511259032Skevlo	0x3c, 0x34, 0x2c, 0x2f, 0x3c, 0x35, 0x2e, 0x2a, 0x49, 0x41,
512259032Skevlo	0x36, 0x31, 0x30, 0x30, 0x0e, 0x0d, 0x28, 0x21, 0x1c, 0x16,
513259032Skevlo	0x50, 0x4a, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00,
514259032Skevlo	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
515259032Skevlo	0x00, 0x00, 0x7d, 0x14, 0x32, 0x2c, 0x36, 0x4c, 0x43, 0x2c,
516259032Skevlo	0x2e, 0x36, 0x30, 0x6e
517259032Skevlo};
518259032Skevlo
519203134Sthompsastatic const struct rfprog {
520203134Sthompsa	uint8_t		chan;
521203134Sthompsa	uint32_t	r1, r2, r3, r4;
522203134Sthompsa} rt2860_rf2850[] = {
523203134Sthompsa	RT2860_RF2850
524203134Sthompsa};
525203134Sthompsa
526203134Sthompsastruct {
527203134Sthompsa	uint8_t	n, r, k;
528205042Sthompsa} rt3070_freqs[] = {
529205042Sthompsa	RT3070_RF3052
530203134Sthompsa};
531203134Sthompsa
532259032Skevlostatic const struct rt5592_freqs {
533259032Skevlo	uint16_t	n;
534259032Skevlo	uint8_t		k, m, r;
535259032Skevlo} rt5592_freqs_20mhz[] = {
536259032Skevlo	RT5592_RF5592_20MHZ
537259032Skevlo},rt5592_freqs_40mhz[] = {
538259032Skevlo	RT5592_RF5592_40MHZ
539259032Skevlo};
540259032Skevlo
541203134Sthompsastatic const struct {
542203134Sthompsa	uint8_t	reg;
543203134Sthompsa	uint8_t	val;
544203134Sthompsa} rt3070_def_rf[] = {
545203134Sthompsa	RT3070_DEF_RF
546205042Sthompsa},rt3572_def_rf[] = {
547205042Sthompsa	RT3572_DEF_RF
548260219Skevlo},rt3593_def_rf[] = {
549260219Skevlo	RT3593_DEF_RF
550257955Skevlo},rt5390_def_rf[] = {
551257955Skevlo	RT5390_DEF_RF
552257955Skevlo},rt5392_def_rf[] = {
553257955Skevlo	RT5392_DEF_RF
554259032Skevlo},rt5592_def_rf[] = {
555259032Skevlo	RT5592_DEF_RF
556259032Skevlo},rt5592_2ghz_def_rf[] = {
557259032Skevlo	RT5592_2GHZ_DEF_RF
558259032Skevlo},rt5592_5ghz_def_rf[] = {
559259032Skevlo	RT5592_5GHZ_DEF_RF
560203134Sthompsa};
561203134Sthompsa
562259032Skevlostatic const struct {
563259032Skevlo	u_int	firstchan;
564259032Skevlo	u_int	lastchan;
565259032Skevlo	uint8_t	reg;
566259032Skevlo	uint8_t	val;
567259032Skevlo} rt5592_chan_5ghz[] = {
568259032Skevlo	RT5592_CHAN_5GHZ
569259032Skevlo};
570259032Skevlo
571203134Sthompsastatic const struct usb_config run_config[RUN_N_XFER] = {
572203134Sthompsa    [RUN_BULK_TX_BE] = {
573203134Sthompsa	.type = UE_BULK,
574203134Sthompsa	.endpoint = UE_ADDR_ANY,
575203134Sthompsa	.ep_index = 0,
576203134Sthompsa	.direction = UE_DIR_OUT,
577203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
578203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
579203134Sthompsa	.callback = run_bulk_tx_callback0,
580203134Sthompsa	.timeout = 5000,	/* ms */
581203134Sthompsa    },
582203134Sthompsa    [RUN_BULK_TX_BK] = {
583203134Sthompsa	.type = UE_BULK,
584203134Sthompsa	.endpoint = UE_ADDR_ANY,
585203134Sthompsa	.direction = UE_DIR_OUT,
586203134Sthompsa	.ep_index = 1,
587203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
588203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
589203134Sthompsa	.callback = run_bulk_tx_callback1,
590203134Sthompsa	.timeout = 5000,	/* ms */
591203134Sthompsa    },
592203134Sthompsa    [RUN_BULK_TX_VI] = {
593203134Sthompsa	.type = UE_BULK,
594203134Sthompsa	.endpoint = UE_ADDR_ANY,
595203134Sthompsa	.direction = UE_DIR_OUT,
596203134Sthompsa	.ep_index = 2,
597203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
598203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
599203134Sthompsa	.callback = run_bulk_tx_callback2,
600203134Sthompsa	.timeout = 5000,	/* ms */
601203134Sthompsa    },
602203134Sthompsa    [RUN_BULK_TX_VO] = {
603203134Sthompsa	.type = UE_BULK,
604203134Sthompsa	.endpoint = UE_ADDR_ANY,
605203134Sthompsa	.direction = UE_DIR_OUT,
606203134Sthompsa	.ep_index = 3,
607203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
608203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
609203134Sthompsa	.callback = run_bulk_tx_callback3,
610203134Sthompsa	.timeout = 5000,	/* ms */
611203134Sthompsa    },
612203134Sthompsa    [RUN_BULK_TX_HCCA] = {
613203134Sthompsa	.type = UE_BULK,
614203134Sthompsa	.endpoint = UE_ADDR_ANY,
615203134Sthompsa	.direction = UE_DIR_OUT,
616203134Sthompsa	.ep_index = 4,
617203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
618203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
619203134Sthompsa	.callback = run_bulk_tx_callback4,
620203134Sthompsa	.timeout = 5000,	/* ms */
621203134Sthompsa    },
622203134Sthompsa    [RUN_BULK_TX_PRIO] = {
623203134Sthompsa	.type = UE_BULK,
624203134Sthompsa	.endpoint = UE_ADDR_ANY,
625203134Sthompsa	.direction = UE_DIR_OUT,
626203134Sthompsa	.ep_index = 5,
627203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
628203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
629203134Sthompsa	.callback = run_bulk_tx_callback5,
630203134Sthompsa	.timeout = 5000,	/* ms */
631203134Sthompsa    },
632203134Sthompsa    [RUN_BULK_RX] = {
633203134Sthompsa	.type = UE_BULK,
634203134Sthompsa	.endpoint = UE_ADDR_ANY,
635203134Sthompsa	.direction = UE_DIR_IN,
636203134Sthompsa	.bufsize = RUN_MAX_RXSZ,
637203134Sthompsa	.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
638203134Sthompsa	.callback = run_bulk_rx_callback,
639203134Sthompsa    }
640203134Sthompsa};
641203134Sthompsa
642259812Skevlostatic void
643259812Skevlorun_autoinst(void *arg, struct usb_device *udev,
644259812Skevlo    struct usb_attach_arg *uaa)
645259812Skevlo{
646259812Skevlo	struct usb_interface *iface;
647259812Skevlo	struct usb_interface_descriptor *id;
648259812Skevlo
649259812Skevlo	if (uaa->dev_state != UAA_DEV_READY)
650259812Skevlo		return;
651259812Skevlo
652259812Skevlo	iface = usbd_get_iface(udev, 0);
653259812Skevlo	if (iface == NULL)
654259812Skevlo		return;
655259812Skevlo	id = iface->idesc;
656259812Skevlo	if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
657259812Skevlo		return;
658259812Skevlo	if (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa))
659259812Skevlo		return;
660259812Skevlo
661259812Skevlo	if (usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT) == 0)
662259812Skevlo		uaa->dev_state = UAA_DEV_EJECTING;
663259812Skevlo}
664259812Skevlo
665220235Skevlostatic int
666259812Skevlorun_driver_loaded(struct module *mod, int what, void *arg)
667259812Skevlo{
668259812Skevlo	switch (what) {
669259812Skevlo	case MOD_LOAD:
670259812Skevlo		run_etag = EVENTHANDLER_REGISTER(usb_dev_configured,
671259812Skevlo		    run_autoinst, NULL, EVENTHANDLER_PRI_ANY);
672259812Skevlo		break;
673259812Skevlo	case MOD_UNLOAD:
674259812Skevlo		EVENTHANDLER_DEREGISTER(usb_dev_configured, run_etag);
675259812Skevlo		break;
676259812Skevlo	default:
677259812Skevlo		return (EOPNOTSUPP);
678259812Skevlo	}
679259812Skevlo	return (0);
680259812Skevlo}
681259812Skevlo
682259812Skevlostatic int
683203134Sthompsarun_match(device_t self)
684203134Sthompsa{
685203134Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(self);
686203134Sthompsa
687203134Sthompsa	if (uaa->usb_mode != USB_MODE_HOST)
688203134Sthompsa		return (ENXIO);
689203134Sthompsa	if (uaa->info.bConfigIndex != 0)
690203134Sthompsa		return (ENXIO);
691203134Sthompsa	if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX)
692203134Sthompsa		return (ENXIO);
693203134Sthompsa
694203134Sthompsa	return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa));
695203134Sthompsa}
696203134Sthompsa
697203134Sthompsastatic int
698203134Sthompsarun_attach(device_t self)
699203134Sthompsa{
700203134Sthompsa	struct run_softc *sc = device_get_softc(self);
701203134Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(self);
702287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
703205042Sthompsa	uint32_t ver;
704258082Skevlo	int ntries, error;
705203134Sthompsa	uint8_t iface_index, bands;
706203134Sthompsa
707203134Sthompsa	device_set_usb_desc(self);
708203134Sthompsa	sc->sc_udev = uaa->device;
709203134Sthompsa	sc->sc_dev = self;
710262465Skevlo	if (USB_GET_DRIVER_INFO(uaa) != RUN_EJECT)
711262465Skevlo		sc->sc_flags |= RUN_FLAG_FWLOAD_NEEDED;
712203134Sthompsa
713203134Sthompsa	mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev),
714203134Sthompsa	    MTX_NETWORK_LOCK, MTX_DEF);
715287197Sglebius	mbufq_init(&sc->sc_snd, ifqmaxlen);
716203134Sthompsa
717203134Sthompsa	iface_index = RT2860_IFACE_INDEX;
718208019Sthompsa
719203134Sthompsa	error = usbd_transfer_setup(uaa->device, &iface_index,
720203134Sthompsa	    sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx);
721203134Sthompsa	if (error) {
722205042Sthompsa		device_printf(self, "could not allocate USB transfers, "
723203134Sthompsa		    "err=%s\n", usbd_errstr(error));
724203134Sthompsa		goto detach;
725203134Sthompsa	}
726203134Sthompsa
727203134Sthompsa	RUN_LOCK(sc);
728203134Sthompsa
729203134Sthompsa	/* wait for the chip to settle */
730203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
731209917Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0) {
732203134Sthompsa			RUN_UNLOCK(sc);
733203134Sthompsa			goto detach;
734203134Sthompsa		}
735205042Sthompsa		if (ver != 0 && ver != 0xffffffff)
736203134Sthompsa			break;
737203134Sthompsa		run_delay(sc, 10);
738203134Sthompsa	}
739203134Sthompsa	if (ntries == 100) {
740203138Sthompsa		device_printf(sc->sc_dev,
741203138Sthompsa		    "timeout waiting for NIC to initialize\n");
742203134Sthompsa		RUN_UNLOCK(sc);
743203134Sthompsa		goto detach;
744203134Sthompsa	}
745205042Sthompsa	sc->mac_ver = ver >> 16;
746205042Sthompsa	sc->mac_rev = ver & 0xffff;
747203134Sthompsa
748203134Sthompsa	/* retrieve RF rev. no and various other things from EEPROM */
749203134Sthompsa	run_read_eeprom(sc);
750203134Sthompsa
751203138Sthompsa	device_printf(sc->sc_dev,
752203138Sthompsa	    "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n",
753205042Sthompsa	    sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev),
754287197Sglebius	    sc->ntxchains, sc->nrxchains, ether_sprintf(ic->ic_macaddr));
755203134Sthompsa
756203134Sthompsa	RUN_UNLOCK(sc);
757203134Sthompsa
758283537Sglebius	ic->ic_softc = sc;
759283527Sglebius	ic->ic_name = device_get_nameunit(self);
760203134Sthompsa	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
761203134Sthompsa	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
762208019Sthompsa
763203134Sthompsa	/* set device capabilities */
764203134Sthompsa	ic->ic_caps =
765203134Sthompsa	    IEEE80211_C_STA |		/* station mode supported */
766203134Sthompsa	    IEEE80211_C_MONITOR |	/* monitor mode supported */
767203134Sthompsa	    IEEE80211_C_IBSS |
768203134Sthompsa	    IEEE80211_C_HOSTAP |
769208019Sthompsa	    IEEE80211_C_WDS |		/* 4-address traffic works */
770208019Sthompsa	    IEEE80211_C_MBSS |
771203134Sthompsa	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
772203134Sthompsa	    IEEE80211_C_SHSLOT |	/* short slot time supported */
773203134Sthompsa	    IEEE80211_C_WME |		/* WME */
774214894Sbschmidt	    IEEE80211_C_WPA;		/* WPA1|WPA2(RSN) */
775203134Sthompsa
776203134Sthompsa	ic->ic_cryptocaps =
777203134Sthompsa	    IEEE80211_CRYPTO_WEP |
778203134Sthompsa	    IEEE80211_CRYPTO_AES_CCM |
779203134Sthompsa	    IEEE80211_CRYPTO_TKIPMIC |
780203134Sthompsa	    IEEE80211_CRYPTO_TKIP;
781203134Sthompsa
782203134Sthompsa	ic->ic_flags |= IEEE80211_F_DATAPAD;
783203134Sthompsa	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;
784203134Sthompsa
785203134Sthompsa	bands = 0;
786203134Sthompsa	setbit(&bands, IEEE80211_MODE_11B);
787203134Sthompsa	setbit(&bands, IEEE80211_MODE_11G);
788258082Skevlo	if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850 ||
789260219Skevlo	    sc->rf_rev == RT3070_RF_3052 || sc->rf_rev == RT3593_RF_3053 ||
790260219Skevlo	    sc->rf_rev == RT5592_RF_5592)
791258082Skevlo		setbit(&bands, IEEE80211_MODE_11A);
792203134Sthompsa	ieee80211_init_channels(ic, NULL, &bands);
793203134Sthompsa
794287197Sglebius	ieee80211_ifattach(ic);
795203134Sthompsa
796203134Sthompsa	ic->ic_scan_start = run_scan_start;
797203134Sthompsa	ic->ic_scan_end = run_scan_end;
798203134Sthompsa	ic->ic_set_channel = run_set_channel;
799203134Sthompsa	ic->ic_node_alloc = run_node_alloc;
800203134Sthompsa	ic->ic_newassoc = run_newassoc;
801218492Sbschmidt	ic->ic_updateslot = run_updateslot;
802208019Sthompsa	ic->ic_update_mcast = run_update_mcast;
803203134Sthompsa	ic->ic_wme.wme_update = run_wme_update;
804203134Sthompsa	ic->ic_raw_xmit = run_raw_xmit;
805203134Sthompsa	ic->ic_update_promisc = run_update_promisc;
806203134Sthompsa	ic->ic_vap_create = run_vap_create;
807203134Sthompsa	ic->ic_vap_delete = run_vap_delete;
808287197Sglebius	ic->ic_transmit = run_transmit;
809287197Sglebius	ic->ic_parent = run_parent;
810203134Sthompsa
811203134Sthompsa	ieee80211_radiotap_attach(ic,
812203134Sthompsa	    &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
813203134Sthompsa		RUN_TX_RADIOTAP_PRESENT,
814203134Sthompsa	    &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
815203134Sthompsa		RUN_RX_RADIOTAP_PRESENT);
816203134Sthompsa
817208019Sthompsa	TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc);
818208019Sthompsa	TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc);
819257712Shselasky	usb_callout_init_mtx(&sc->ratectl_ch, &sc->sc_mtx, 0);
820208019Sthompsa
821203134Sthompsa	if (bootverbose)
822203134Sthompsa		ieee80211_announce(ic);
823203134Sthompsa
824209917Sthompsa	return (0);
825203134Sthompsa
826203134Sthompsadetach:
827203134Sthompsa	run_detach(self);
828209917Sthompsa	return (ENXIO);
829203134Sthompsa}
830203134Sthompsa
831203134Sthompsastatic int
832203134Sthompsarun_detach(device_t self)
833203134Sthompsa{
834203134Sthompsa	struct run_softc *sc = device_get_softc(self);
835287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
836203134Sthompsa	int i;
837203134Sthompsa
838246614Shselasky	RUN_LOCK(sc);
839246614Shselasky	sc->sc_detached = 1;
840246614Shselasky	RUN_UNLOCK(sc);
841246614Shselasky
842203134Sthompsa	/* stop all USB transfers */
843203134Sthompsa	usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER);
844203134Sthompsa
845203134Sthompsa	RUN_LOCK(sc);
846209144Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
847209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set = RUN_CMDQ_ABORT;
848209144Sthompsa
849203134Sthompsa	/* free TX list, if any */
850203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
851203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
852203134Sthompsa	RUN_UNLOCK(sc);
853203134Sthompsa
854287197Sglebius	if (sc->sc_ic.ic_softc == sc) {
855208019Sthompsa		/* drain tasks */
856208019Sthompsa		usb_callout_drain(&sc->ratectl_ch);
857208019Sthompsa		ieee80211_draintask(ic, &sc->cmdq_task);
858208019Sthompsa		ieee80211_draintask(ic, &sc->ratectl_task);
859203134Sthompsa		ieee80211_ifdetach(ic);
860203134Sthompsa	}
861203134Sthompsa
862287197Sglebius	mbufq_drain(&sc->sc_snd);
863203134Sthompsa	mtx_destroy(&sc->sc_mtx);
864203134Sthompsa
865203134Sthompsa	return (0);
866203134Sthompsa}
867203134Sthompsa
868203134Sthompsastatic struct ieee80211vap *
869228621Sbschmidtrun_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
870228621Sbschmidt    enum ieee80211_opmode opmode, int flags,
871203134Sthompsa    const uint8_t bssid[IEEE80211_ADDR_LEN],
872203134Sthompsa    const uint8_t mac[IEEE80211_ADDR_LEN])
873203134Sthompsa{
874286950Sadrian	struct run_softc *sc = ic->ic_softc;
875203134Sthompsa	struct run_vap *rvp;
876203134Sthompsa	struct ieee80211vap *vap;
877208019Sthompsa	int i;
878203134Sthompsa
879209917Sthompsa	if (sc->rvp_cnt >= RUN_VAP_MAX) {
880287197Sglebius		device_printf(sc->sc_dev, "number of VAPs maxed out\n");
881209917Sthompsa		return (NULL);
882208019Sthompsa	}
883208019Sthompsa
884208019Sthompsa	switch (opmode) {
885208019Sthompsa	case IEEE80211_M_STA:
886208019Sthompsa		/* enable s/w bmiss handling for sta mode */
887208019Sthompsa		flags |= IEEE80211_CLONE_NOBEACONS;
888208019Sthompsa		/* fall though */
889208019Sthompsa	case IEEE80211_M_IBSS:
890208019Sthompsa	case IEEE80211_M_MONITOR:
891208019Sthompsa	case IEEE80211_M_HOSTAP:
892208019Sthompsa	case IEEE80211_M_MBSS:
893208019Sthompsa		/* other than WDS vaps, only one at a time */
894208019Sthompsa		if (!TAILQ_EMPTY(&ic->ic_vaps))
895209917Sthompsa			return (NULL);
896208019Sthompsa		break;
897208019Sthompsa	case IEEE80211_M_WDS:
898208019Sthompsa		TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next){
899208019Sthompsa			if(vap->iv_opmode != IEEE80211_M_HOSTAP)
900208019Sthompsa				continue;
901208019Sthompsa			/* WDS vap's always share the local mac address. */
902208019Sthompsa			flags &= ~IEEE80211_CLONE_BSSID;
903208019Sthompsa			break;
904208019Sthompsa		}
905209917Sthompsa		if (vap == NULL) {
906287197Sglebius			device_printf(sc->sc_dev,
907287197Sglebius			    "wds only supported in ap mode\n");
908209917Sthompsa			return (NULL);
909208019Sthompsa		}
910208019Sthompsa		break;
911208019Sthompsa	default:
912287197Sglebius		device_printf(sc->sc_dev, "unknown opmode %d\n", opmode);
913209917Sthompsa		return (NULL);
914208019Sthompsa	}
915208019Sthompsa
916287197Sglebius	rvp = malloc(sizeof(struct run_vap), M_80211_VAP, M_WAITOK | M_ZERO);
917203134Sthompsa	vap = &rvp->vap;
918203134Sthompsa
919287197Sglebius	if (ieee80211_vap_setup(ic, vap, name, unit, opmode, flags,
920287197Sglebius	    bssid) != 0) {
921257743Shselasky		/* out of memory */
922257743Shselasky		free(rvp, M_80211_VAP);
923257743Shselasky		return (NULL);
924257743Shselasky	}
925257743Shselasky
926203134Sthompsa	vap->iv_update_beacon = run_update_beacon;
927208019Sthompsa	vap->iv_max_aid = RT2870_WCID_MAX;
928208019Sthompsa	/*
929208019Sthompsa	 * To delete the right key from h/w, we need wcid.
930208019Sthompsa	 * Luckily, there is unused space in ieee80211_key{}, wk_pad,
931208019Sthompsa	 * and matching wcid will be written into there. So, cast
932208019Sthompsa	 * some spells to remove 'const' from ieee80211_key{}
933208019Sthompsa	 */
934208019Sthompsa	vap->iv_key_delete = (void *)run_key_delete;
935208019Sthompsa	vap->iv_key_set = (void *)run_key_set;
936203134Sthompsa
937203134Sthompsa	/* override state transition machine */
938203134Sthompsa	rvp->newstate = vap->iv_newstate;
939203134Sthompsa	vap->iv_newstate = run_newstate;
940203134Sthompsa
941206358Srpaulo	ieee80211_ratectl_init(vap);
942206358Srpaulo	ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */);
943203134Sthompsa
944203134Sthompsa	/* complete setup */
945287197Sglebius	ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status,
946287197Sglebius	    mac);
947208019Sthompsa
948208019Sthompsa	/* make sure id is always unique */
949209917Sthompsa	for (i = 0; i < RUN_VAP_MAX; i++) {
950208019Sthompsa		if((sc->rvp_bmap & 1 << i) == 0){
951208019Sthompsa			sc->rvp_bmap |= 1 << i;
952208019Sthompsa			rvp->rvp_id = i;
953208019Sthompsa			break;
954208019Sthompsa		}
955208019Sthompsa	}
956209917Sthompsa	if (sc->rvp_cnt++ == 0)
957208019Sthompsa		ic->ic_opmode = opmode;
958208019Sthompsa
959209917Sthompsa	if (opmode == IEEE80211_M_HOSTAP)
960209144Sthompsa		sc->cmdq_run = RUN_CMDQ_GO;
961209144Sthompsa
962208019Sthompsa	DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n",
963208019Sthompsa	    rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt);
964208019Sthompsa
965209917Sthompsa	return (vap);
966203134Sthompsa}
967203134Sthompsa
968203134Sthompsastatic void
969203134Sthompsarun_vap_delete(struct ieee80211vap *vap)
970203134Sthompsa{
971203134Sthompsa	struct run_vap *rvp = RUN_VAP(vap);
972203134Sthompsa	struct ieee80211com *ic;
973203134Sthompsa	struct run_softc *sc;
974208019Sthompsa	uint8_t rvp_id;
975203134Sthompsa
976209917Sthompsa	if (vap == NULL)
977203134Sthompsa		return;
978203134Sthompsa
979203134Sthompsa	ic = vap->iv_ic;
980286950Sadrian	sc = ic->ic_softc;
981203134Sthompsa
982205042Sthompsa	RUN_LOCK(sc);
983208019Sthompsa
984218492Sbschmidt	m_freem(rvp->beacon_mbuf);
985218492Sbschmidt	rvp->beacon_mbuf = NULL;
986218492Sbschmidt
987208019Sthompsa	rvp_id = rvp->rvp_id;
988208019Sthompsa	sc->ratectl_run &= ~(1 << rvp_id);
989208019Sthompsa	sc->rvp_bmap &= ~(1 << rvp_id);
990208019Sthompsa	run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128);
991208019Sthompsa	run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512);
992208019Sthompsa	--sc->rvp_cnt;
993208019Sthompsa
994208019Sthompsa	DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n",
995208019Sthompsa	    vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt);
996208019Sthompsa
997205042Sthompsa	RUN_UNLOCK(sc);
998203134Sthompsa
999206358Srpaulo	ieee80211_ratectl_deinit(vap);
1000203134Sthompsa	ieee80211_vap_detach(vap);
1001203134Sthompsa	free(rvp, M_80211_VAP);
1002203134Sthompsa}
1003203134Sthompsa
1004208019Sthompsa/*
1005208019Sthompsa * There are numbers of functions need to be called in context thread.
1006208019Sthompsa * Rather than creating taskqueue event for each of those functions,
1007208019Sthompsa * here is all-for-one taskqueue callback function. This function
1008208019Sthompsa * gurantees deferred functions are executed in the same order they
1009208019Sthompsa * were enqueued.
1010208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[].
1011208019Sthompsa */
1012203134Sthompsastatic void
1013208019Sthompsarun_cmdq_cb(void *arg, int pending)
1014208019Sthompsa{
1015208019Sthompsa	struct run_softc *sc = arg;
1016208019Sthompsa	uint8_t i;
1017208019Sthompsa
1018208019Sthompsa	/* call cmdq[].func locked */
1019208019Sthompsa	RUN_LOCK(sc);
1020209917Sthompsa	for (i = sc->cmdq_exec; sc->cmdq[i].func && pending;
1021209917Sthompsa	    i = sc->cmdq_exec, pending--) {
1022208019Sthompsa		DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending);
1023209917Sthompsa		if (sc->cmdq_run == RUN_CMDQ_GO) {
1024208019Sthompsa			/*
1025208019Sthompsa			 * If arg0 is NULL, callback func needs more
1026208019Sthompsa			 * than one arg. So, pass ptr to cmdq struct.
1027208019Sthompsa			 */
1028209917Sthompsa			if (sc->cmdq[i].arg0)
1029208019Sthompsa				sc->cmdq[i].func(sc->cmdq[i].arg0);
1030208019Sthompsa			else
1031208019Sthompsa				sc->cmdq[i].func(&sc->cmdq[i]);
1032208019Sthompsa		}
1033208019Sthompsa		sc->cmdq[i].arg0 = NULL;
1034208019Sthompsa		sc->cmdq[i].func = NULL;
1035208019Sthompsa		sc->cmdq_exec++;
1036208019Sthompsa		sc->cmdq_exec &= RUN_CMDQ_MASQ;
1037208019Sthompsa	}
1038208019Sthompsa	RUN_UNLOCK(sc);
1039208019Sthompsa}
1040208019Sthompsa
1041208019Sthompsastatic void
1042203134Sthompsarun_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
1043203134Sthompsa{
1044203134Sthompsa	struct run_tx_data *data;
1045203134Sthompsa
1046203134Sthompsa	memset(pq, 0, sizeof(*pq));
1047203134Sthompsa
1048203134Sthompsa	STAILQ_INIT(&pq->tx_qh);
1049203134Sthompsa	STAILQ_INIT(&pq->tx_fh);
1050203134Sthompsa
1051203134Sthompsa	for (data = &pq->tx_data[0];
1052203134Sthompsa	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
1053203134Sthompsa		data->sc = sc;
1054203134Sthompsa		STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
1055203134Sthompsa	}
1056203134Sthompsa	pq->tx_nfree = RUN_TX_RING_COUNT;
1057203134Sthompsa}
1058203134Sthompsa
1059203134Sthompsastatic void
1060203134Sthompsarun_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
1061203134Sthompsa{
1062203134Sthompsa	struct run_tx_data *data;
1063203134Sthompsa
1064203134Sthompsa	/* make sure any subsequent use of the queues will fail */
1065203134Sthompsa	pq->tx_nfree = 0;
1066203134Sthompsa	STAILQ_INIT(&pq->tx_fh);
1067203134Sthompsa	STAILQ_INIT(&pq->tx_qh);
1068203134Sthompsa
1069203134Sthompsa	/* free up all node references and mbufs */
1070203134Sthompsa	for (data = &pq->tx_data[0];
1071209917Sthompsa	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
1072203134Sthompsa		if (data->m != NULL) {
1073203134Sthompsa			m_freem(data->m);
1074203134Sthompsa			data->m = NULL;
1075203134Sthompsa		}
1076203134Sthompsa		if (data->ni != NULL) {
1077203134Sthompsa			ieee80211_free_node(data->ni);
1078203134Sthompsa			data->ni = NULL;
1079203134Sthompsa		}
1080203134Sthompsa	}
1081203134Sthompsa}
1082203134Sthompsa
1083220235Skevlostatic int
1084203134Sthompsarun_load_microcode(struct run_softc *sc)
1085203134Sthompsa{
1086203134Sthompsa	usb_device_request_t req;
1087203137Sthompsa	const struct firmware *fw;
1088203134Sthompsa	const u_char *base;
1089203134Sthompsa	uint32_t tmp;
1090203134Sthompsa	int ntries, error;
1091203134Sthompsa	const uint64_t *temp;
1092203134Sthompsa	uint64_t bytes;
1093203134Sthompsa
1094205042Sthompsa	RUN_UNLOCK(sc);
1095203137Sthompsa	fw = firmware_get("runfw");
1096205042Sthompsa	RUN_LOCK(sc);
1097209917Sthompsa	if (fw == NULL) {
1098203138Sthompsa		device_printf(sc->sc_dev,
1099203138Sthompsa		    "failed loadfirmware of file %s\n", "runfw");
1100203134Sthompsa		return ENOENT;
1101203134Sthompsa	}
1102203134Sthompsa
1103203137Sthompsa	if (fw->datasize != 8192) {
1104203138Sthompsa		device_printf(sc->sc_dev,
1105203138Sthompsa		    "invalid firmware size (should be 8KB)\n");
1106203137Sthompsa		error = EINVAL;
1107203137Sthompsa		goto fail;
1108203134Sthompsa	}
1109203134Sthompsa
1110203134Sthompsa	/*
1111203134Sthompsa	 * RT3071/RT3072 use a different firmware
1112203134Sthompsa	 * run-rt2870 (8KB) contains both,
1113203134Sthompsa	 * first half (4KB) is for rt2870,
1114203134Sthompsa	 * last half is for rt3071.
1115203134Sthompsa	 */
1116203137Sthompsa	base = fw->data;
1117205042Sthompsa	if ((sc->mac_ver) != 0x2860 &&
1118205042Sthompsa	    (sc->mac_ver) != 0x2872 &&
1119209917Sthompsa	    (sc->mac_ver) != 0x3070) {
1120203134Sthompsa		base += 4096;
1121205042Sthompsa	}
1122203134Sthompsa
1123203134Sthompsa	/* cheap sanity check */
1124203137Sthompsa	temp = fw->data;
1125203134Sthompsa	bytes = *temp;
1126257712Shselasky	if (bytes != be64toh(0xffffff0210280210ULL)) {
1127203138Sthompsa		device_printf(sc->sc_dev, "firmware checksum failed\n");
1128203137Sthompsa		error = EINVAL;
1129203137Sthompsa		goto fail;
1130203137Sthompsa	}
1131203134Sthompsa
1132203134Sthompsa	/* write microcode image */
1133262465Skevlo	if (sc->sc_flags & RUN_FLAG_FWLOAD_NEEDED) {
1134260219Skevlo		run_write_region_1(sc, RT2870_FW_BASE, base, 4096);
1135260219Skevlo		run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff);
1136260219Skevlo		run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff);
1137260219Skevlo	}
1138203134Sthompsa
1139203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1140203134Sthompsa	req.bRequest = RT2870_RESET;
1141203134Sthompsa	USETW(req.wValue, 8);
1142203134Sthompsa	USETW(req.wIndex, 0);
1143203134Sthompsa	USETW(req.wLength, 0);
1144220235Skevlo	if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL))
1145220235Skevlo	    != 0) {
1146203138Sthompsa		device_printf(sc->sc_dev, "firmware reset failed\n");
1147203137Sthompsa		goto fail;
1148203137Sthompsa	}
1149203134Sthompsa
1150203134Sthompsa	run_delay(sc, 10);
1151203134Sthompsa
1152260219Skevlo	run_write(sc, RT2860_H2M_BBPAGENT, 0);
1153203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
1154260219Skevlo	run_write(sc, RT2860_H2M_INTSRC, 0);
1155205042Sthompsa	if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0)
1156203137Sthompsa		goto fail;
1157203134Sthompsa
1158203134Sthompsa	/* wait until microcontroller is ready */
1159203134Sthompsa	for (ntries = 0; ntries < 1000; ntries++) {
1160260219Skevlo		if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0)
1161203137Sthompsa			goto fail;
1162203134Sthompsa		if (tmp & RT2860_MCU_READY)
1163203134Sthompsa			break;
1164203134Sthompsa		run_delay(sc, 10);
1165203134Sthompsa	}
1166203134Sthompsa	if (ntries == 1000) {
1167203138Sthompsa		device_printf(sc->sc_dev,
1168203138Sthompsa		    "timeout waiting for MCU to initialize\n");
1169203137Sthompsa		error = ETIMEDOUT;
1170203137Sthompsa		goto fail;
1171203134Sthompsa	}
1172233283Sbschmidt	device_printf(sc->sc_dev, "firmware %s ver. %u.%u loaded\n",
1173233283Sbschmidt	    (base == fw->data) ? "RT2870" : "RT3071",
1174233283Sbschmidt	    *(base + 4092), *(base + 4093));
1175203134Sthompsa
1176203137Sthompsafail:
1177203137Sthompsa	firmware_put(fw, FIRMWARE_UNLOAD);
1178203137Sthompsa	return (error);
1179203134Sthompsa}
1180203134Sthompsa
1181258641Shselaskystatic int
1182203134Sthompsarun_reset(struct run_softc *sc)
1183203134Sthompsa{
1184203134Sthompsa	usb_device_request_t req;
1185203134Sthompsa
1186203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1187203134Sthompsa	req.bRequest = RT2870_RESET;
1188203134Sthompsa	USETW(req.wValue, 1);
1189203134Sthompsa	USETW(req.wIndex, 0);
1190203134Sthompsa	USETW(req.wLength, 0);
1191209917Sthompsa	return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL));
1192203134Sthompsa}
1193203134Sthompsa
1194203134Sthompsastatic usb_error_t
1195203134Sthompsarun_do_request(struct run_softc *sc,
1196203134Sthompsa    struct usb_device_request *req, void *data)
1197203134Sthompsa{
1198203134Sthompsa	usb_error_t err;
1199203134Sthompsa	int ntries = 10;
1200203134Sthompsa
1201203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
1202203134Sthompsa
1203203134Sthompsa	while (ntries--) {
1204203134Sthompsa		err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx,
1205203134Sthompsa		    req, data, 0, NULL, 250 /* ms */);
1206203134Sthompsa		if (err == 0)
1207203134Sthompsa			break;
1208203134Sthompsa		DPRINTFN(1, "Control request failed, %s (retrying)\n",
1209203134Sthompsa		    usbd_errstr(err));
1210203134Sthompsa		run_delay(sc, 10);
1211203134Sthompsa	}
1212203134Sthompsa	return (err);
1213203134Sthompsa}
1214203134Sthompsa
1215203134Sthompsastatic int
1216203134Sthompsarun_read(struct run_softc *sc, uint16_t reg, uint32_t *val)
1217203134Sthompsa{
1218203134Sthompsa	uint32_t tmp;
1219203134Sthompsa	int error;
1220203134Sthompsa
1221203134Sthompsa	error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp);
1222203134Sthompsa	if (error == 0)
1223203134Sthompsa		*val = le32toh(tmp);
1224203134Sthompsa	else
1225203134Sthompsa		*val = 0xffffffff;
1226209917Sthompsa	return (error);
1227203134Sthompsa}
1228203134Sthompsa
1229203134Sthompsastatic int
1230203134Sthompsarun_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len)
1231203134Sthompsa{
1232203134Sthompsa	usb_device_request_t req;
1233203134Sthompsa
1234203134Sthompsa	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1235203134Sthompsa	req.bRequest = RT2870_READ_REGION_1;
1236203134Sthompsa	USETW(req.wValue, 0);
1237203134Sthompsa	USETW(req.wIndex, reg);
1238203134Sthompsa	USETW(req.wLength, len);
1239203134Sthompsa
1240209917Sthompsa	return (run_do_request(sc, &req, buf));
1241203134Sthompsa}
1242203134Sthompsa
1243203134Sthompsastatic int
1244203134Sthompsarun_write_2(struct run_softc *sc, uint16_t reg, uint16_t val)
1245203134Sthompsa{
1246203134Sthompsa	usb_device_request_t req;
1247203134Sthompsa
1248203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1249203134Sthompsa	req.bRequest = RT2870_WRITE_2;
1250203134Sthompsa	USETW(req.wValue, val);
1251203134Sthompsa	USETW(req.wIndex, reg);
1252203134Sthompsa	USETW(req.wLength, 0);
1253203134Sthompsa
1254209917Sthompsa	return (run_do_request(sc, &req, NULL));
1255203134Sthompsa}
1256203134Sthompsa
1257203134Sthompsastatic int
1258203134Sthompsarun_write(struct run_softc *sc, uint16_t reg, uint32_t val)
1259203134Sthompsa{
1260203134Sthompsa	int error;
1261203134Sthompsa
1262203134Sthompsa	if ((error = run_write_2(sc, reg, val & 0xffff)) == 0)
1263203134Sthompsa		error = run_write_2(sc, reg + 2, val >> 16);
1264209917Sthompsa	return (error);
1265203134Sthompsa}
1266203134Sthompsa
1267203134Sthompsastatic int
1268203134Sthompsarun_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf,
1269203134Sthompsa    int len)
1270203134Sthompsa{
1271203134Sthompsa#if 1
1272203134Sthompsa	int i, error = 0;
1273203134Sthompsa	/*
1274203134Sthompsa	 * NB: the WRITE_REGION_1 command is not stable on RT2860.
1275203134Sthompsa	 * We thus issue multiple WRITE_2 commands instead.
1276203134Sthompsa	 */
1277203134Sthompsa	KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n"));
1278203134Sthompsa	for (i = 0; i < len && error == 0; i += 2)
1279203134Sthompsa		error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8);
1280209917Sthompsa	return (error);
1281203134Sthompsa#else
1282203134Sthompsa	usb_device_request_t req;
1283257958Skevlo	int error = 0;
1284203134Sthompsa
1285257958Skevlo	/*
1286257958Skevlo	 * NOTE: It appears the WRITE_REGION_1 command cannot be
1287257958Skevlo	 * passed a huge amount of data, which will crash the
1288257958Skevlo	 * firmware. Limit amount of data passed to 64-bytes at a
1289257958Skevlo	 * time.
1290257958Skevlo	 */
1291257958Skevlo	while (len > 0) {
1292257958Skevlo		int delta = 64;
1293257958Skevlo		if (delta > len)
1294257958Skevlo			delta = len;
1295257958Skevlo
1296257958Skevlo		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1297257958Skevlo		req.bRequest = RT2870_WRITE_REGION_1;
1298257958Skevlo		USETW(req.wValue, 0);
1299257958Skevlo		USETW(req.wIndex, reg);
1300257958Skevlo		USETW(req.wLength, delta);
1301257958Skevlo		error = run_do_request(sc, &req, __DECONST(uint8_t *, buf));
1302257958Skevlo		if (error != 0)
1303257958Skevlo			break;
1304257958Skevlo		reg += delta;
1305257958Skevlo		buf += delta;
1306257958Skevlo		len -= delta;
1307257958Skevlo	}
1308257958Skevlo	return (error);
1309203134Sthompsa#endif
1310203134Sthompsa}
1311203134Sthompsa
1312203134Sthompsastatic int
1313203134Sthompsarun_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len)
1314203134Sthompsa{
1315203134Sthompsa	int i, error = 0;
1316203134Sthompsa
1317203134Sthompsa	KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n"));
1318203134Sthompsa	for (i = 0; i < len && error == 0; i += 4)
1319203134Sthompsa		error = run_write(sc, reg + i, val);
1320209917Sthompsa	return (error);
1321203134Sthompsa}
1322203134Sthompsa
1323203134Sthompsastatic int
1324259544Skevlorun_efuse_read(struct run_softc *sc, uint16_t addr, uint16_t *val, int count)
1325203134Sthompsa{
1326203134Sthompsa	uint32_t tmp;
1327203134Sthompsa	uint16_t reg;
1328203134Sthompsa	int error, ntries;
1329203134Sthompsa
1330203134Sthompsa	if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1331209917Sthompsa		return (error);
1332203134Sthompsa
1333261076Shselasky	if (count == 2)
1334261076Shselasky		addr *= 2;
1335203134Sthompsa	/*-
1336203134Sthompsa	 * Read one 16-byte block into registers EFUSE_DATA[0-3]:
1337203134Sthompsa	 * DATA0: F E D C
1338203134Sthompsa	 * DATA1: B A 9 8
1339203134Sthompsa	 * DATA2: 7 6 5 4
1340203134Sthompsa	 * DATA3: 3 2 1 0
1341203134Sthompsa	 */
1342203134Sthompsa	tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK);
1343203134Sthompsa	tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK;
1344203134Sthompsa	run_write(sc, RT3070_EFUSE_CTRL, tmp);
1345203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1346203134Sthompsa		if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1347209917Sthompsa			return (error);
1348203134Sthompsa		if (!(tmp & RT3070_EFSROM_KICK))
1349203134Sthompsa			break;
1350203134Sthompsa		run_delay(sc, 2);
1351203134Sthompsa	}
1352203134Sthompsa	if (ntries == 100)
1353209917Sthompsa		return (ETIMEDOUT);
1354203134Sthompsa
1355261076Shselasky	if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) {
1356261076Shselasky		*val = 0xffff;	/* address not found */
1357209917Sthompsa		return (0);
1358261076Shselasky	}
1359203134Sthompsa	/* determine to which 32-bit register our 16-bit word belongs */
1360203134Sthompsa	reg = RT3070_EFUSE_DATA3 - (addr & 0xc);
1361203134Sthompsa	if ((error = run_read(sc, reg, &tmp)) != 0)
1362209917Sthompsa		return (error);
1363203134Sthompsa
1364261118Skevlo	tmp >>= (8 * (addr & 0x3));
1365261118Skevlo	*val = (addr & 1) ? tmp >> 16 : tmp & 0xffff;
1366261118Skevlo
1367209917Sthompsa	return (0);
1368203134Sthompsa}
1369203134Sthompsa
1370261124Skevlo/* Read 16-bit from eFUSE ROM for RT3xxx. */
1371203134Sthompsastatic int
1372259544Skevlorun_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1373259544Skevlo{
1374259544Skevlo	return (run_efuse_read(sc, addr, val, 2));
1375259544Skevlo}
1376259544Skevlo
1377259544Skevlostatic int
1378203134Sthompsarun_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1379203134Sthompsa{
1380203134Sthompsa	usb_device_request_t req;
1381203134Sthompsa	uint16_t tmp;
1382203134Sthompsa	int error;
1383203134Sthompsa
1384203134Sthompsa	addr *= 2;
1385203134Sthompsa	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1386203134Sthompsa	req.bRequest = RT2870_EEPROM_READ;
1387203134Sthompsa	USETW(req.wValue, 0);
1388203134Sthompsa	USETW(req.wIndex, addr);
1389260219Skevlo	USETW(req.wLength, sizeof(tmp));
1390203134Sthompsa
1391203134Sthompsa	error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp);
1392203134Sthompsa	if (error == 0)
1393203134Sthompsa		*val = le16toh(tmp);
1394203134Sthompsa	else
1395203134Sthompsa		*val = 0xffff;
1396209917Sthompsa	return (error);
1397203134Sthompsa}
1398203134Sthompsa
1399203134Sthompsastatic __inline int
1400203134Sthompsarun_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val)
1401203134Sthompsa{
1402203134Sthompsa	/* either eFUSE ROM or EEPROM */
1403203134Sthompsa	return sc->sc_srom_read(sc, addr, val);
1404203134Sthompsa}
1405203134Sthompsa
1406203134Sthompsastatic int
1407258733Skevlorun_rt2870_rf_write(struct run_softc *sc, uint32_t val)
1408203134Sthompsa{
1409203134Sthompsa	uint32_t tmp;
1410203134Sthompsa	int error, ntries;
1411203134Sthompsa
1412203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1413203134Sthompsa		if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0)
1414209917Sthompsa			return (error);
1415203134Sthompsa		if (!(tmp & RT2860_RF_REG_CTRL))
1416203134Sthompsa			break;
1417203134Sthompsa	}
1418203134Sthompsa	if (ntries == 10)
1419209917Sthompsa		return (ETIMEDOUT);
1420203134Sthompsa
1421258732Skevlo	return (run_write(sc, RT2860_RF_CSR_CFG0, val));
1422203134Sthompsa}
1423203134Sthompsa
1424203134Sthompsastatic int
1425203134Sthompsarun_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1426203134Sthompsa{
1427203134Sthompsa	uint32_t tmp;
1428203134Sthompsa	int error, ntries;
1429203134Sthompsa
1430203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1431203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1432209917Sthompsa			return (error);
1433203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1434203134Sthompsa			break;
1435203134Sthompsa	}
1436203134Sthompsa	if (ntries == 100)
1437209917Sthompsa		return (ETIMEDOUT);
1438203134Sthompsa
1439203134Sthompsa	tmp = RT3070_RF_KICK | reg << 8;
1440203134Sthompsa	if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0)
1441209917Sthompsa		return (error);
1442203134Sthompsa
1443203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1444203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1445209917Sthompsa			return (error);
1446203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1447203134Sthompsa			break;
1448203134Sthompsa	}
1449203134Sthompsa	if (ntries == 100)
1450209917Sthompsa		return (ETIMEDOUT);
1451203134Sthompsa
1452203134Sthompsa	*val = tmp & 0xff;
1453209917Sthompsa	return (0);
1454203134Sthompsa}
1455203134Sthompsa
1456203134Sthompsastatic int
1457203134Sthompsarun_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1458203134Sthompsa{
1459203134Sthompsa	uint32_t tmp;
1460203134Sthompsa	int error, ntries;
1461203134Sthompsa
1462203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1463203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1464209917Sthompsa			return (error);
1465203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1466203134Sthompsa			break;
1467203134Sthompsa	}
1468203134Sthompsa	if (ntries == 10)
1469209917Sthompsa		return (ETIMEDOUT);
1470203134Sthompsa
1471203134Sthompsa	tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val;
1472209917Sthompsa	return (run_write(sc, RT3070_RF_CSR_CFG, tmp));
1473203134Sthompsa}
1474203134Sthompsa
1475203134Sthompsastatic int
1476203134Sthompsarun_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1477203134Sthompsa{
1478203134Sthompsa	uint32_t tmp;
1479203134Sthompsa	int ntries, error;
1480203134Sthompsa
1481203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1482203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1483209917Sthompsa			return (error);
1484203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1485203134Sthompsa			break;
1486203134Sthompsa	}
1487203134Sthompsa	if (ntries == 10)
1488209917Sthompsa		return (ETIMEDOUT);
1489203134Sthompsa
1490203134Sthompsa	tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8;
1491203134Sthompsa	if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0)
1492209917Sthompsa		return (error);
1493203134Sthompsa
1494203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1495203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1496209917Sthompsa			return (error);
1497203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1498203134Sthompsa			break;
1499203134Sthompsa	}
1500203134Sthompsa	if (ntries == 10)
1501209917Sthompsa		return (ETIMEDOUT);
1502203134Sthompsa
1503203134Sthompsa	*val = tmp & 0xff;
1504209917Sthompsa	return (0);
1505203134Sthompsa}
1506203134Sthompsa
1507203134Sthompsastatic int
1508203134Sthompsarun_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1509203134Sthompsa{
1510203134Sthompsa	uint32_t tmp;
1511203134Sthompsa	int ntries, error;
1512203134Sthompsa
1513203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1514203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1515209917Sthompsa			return (error);
1516203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1517203134Sthompsa			break;
1518203134Sthompsa	}
1519203134Sthompsa	if (ntries == 10)
1520209917Sthompsa		return (ETIMEDOUT);
1521203134Sthompsa
1522203134Sthompsa	tmp = RT2860_BBP_CSR_KICK | reg << 8 | val;
1523209917Sthompsa	return (run_write(sc, RT2860_BBP_CSR_CFG, tmp));
1524203134Sthompsa}
1525203134Sthompsa
1526203134Sthompsa/*
1527203134Sthompsa * Send a command to the 8051 microcontroller unit.
1528203134Sthompsa */
1529203134Sthompsastatic int
1530203134Sthompsarun_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg)
1531203134Sthompsa{
1532203134Sthompsa	uint32_t tmp;
1533203134Sthompsa	int error, ntries;
1534203134Sthompsa
1535203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1536203134Sthompsa		if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0)
1537203134Sthompsa			return error;
1538203134Sthompsa		if (!(tmp & RT2860_H2M_BUSY))
1539203134Sthompsa			break;
1540203134Sthompsa	}
1541203134Sthompsa	if (ntries == 100)
1542203134Sthompsa		return ETIMEDOUT;
1543203134Sthompsa
1544203134Sthompsa	tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg;
1545203134Sthompsa	if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0)
1546203134Sthompsa		error = run_write(sc, RT2860_HOST_CMD, cmd);
1547209917Sthompsa	return (error);
1548203134Sthompsa}
1549203134Sthompsa
1550203134Sthompsa/*
1551203134Sthompsa * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word.
1552203134Sthompsa * Used to adjust per-rate Tx power registers.
1553203134Sthompsa */
1554203134Sthompsastatic __inline uint32_t
1555203134Sthompsab4inc(uint32_t b32, int8_t delta)
1556203134Sthompsa{
1557203134Sthompsa	int8_t i, b4;
1558203134Sthompsa
1559203134Sthompsa	for (i = 0; i < 8; i++) {
1560203134Sthompsa		b4 = b32 & 0xf;
1561203134Sthompsa		b4 += delta;
1562203134Sthompsa		if (b4 < 0)
1563203134Sthompsa			b4 = 0;
1564203134Sthompsa		else if (b4 > 0xf)
1565203134Sthompsa			b4 = 0xf;
1566203134Sthompsa		b32 = b32 >> 4 | b4 << 28;
1567203134Sthompsa	}
1568209917Sthompsa	return (b32);
1569203134Sthompsa}
1570203134Sthompsa
1571203134Sthompsastatic const char *
1572257955Skevlorun_get_rf(uint16_t rev)
1573203134Sthompsa{
1574203134Sthompsa	switch (rev) {
1575203134Sthompsa	case RT2860_RF_2820:	return "RT2820";
1576203134Sthompsa	case RT2860_RF_2850:	return "RT2850";
1577203134Sthompsa	case RT2860_RF_2720:	return "RT2720";
1578203134Sthompsa	case RT2860_RF_2750:	return "RT2750";
1579203134Sthompsa	case RT3070_RF_3020:	return "RT3020";
1580203134Sthompsa	case RT3070_RF_2020:	return "RT2020";
1581203134Sthompsa	case RT3070_RF_3021:	return "RT3021";
1582203134Sthompsa	case RT3070_RF_3022:	return "RT3022";
1583203134Sthompsa	case RT3070_RF_3052:	return "RT3052";
1584260219Skevlo	case RT3593_RF_3053:	return "RT3053";
1585259032Skevlo	case RT5592_RF_5592:	return "RT5592";
1586257955Skevlo	case RT5390_RF_5370:	return "RT5370";
1587257955Skevlo	case RT5390_RF_5372:	return "RT5372";
1588203134Sthompsa	}
1589209917Sthompsa	return ("unknown");
1590203134Sthompsa}
1591203134Sthompsa
1592260219Skevlostatic void
1593260219Skevlorun_rt3593_get_txpower(struct run_softc *sc)
1594260219Skevlo{
1595260219Skevlo	uint16_t addr, val;
1596260219Skevlo	int i;
1597260219Skevlo
1598260219Skevlo	/* Read power settings for 2GHz channels. */
1599260219Skevlo	for (i = 0; i < 14; i += 2) {
1600260219Skevlo		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE1 :
1601260219Skevlo		    RT2860_EEPROM_PWR2GHZ_BASE1;
1602260219Skevlo		run_srom_read(sc, addr + i / 2, &val);
1603260219Skevlo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1604260219Skevlo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1605260219Skevlo
1606260219Skevlo		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE2 :
1607260219Skevlo		    RT2860_EEPROM_PWR2GHZ_BASE2;
1608260219Skevlo		run_srom_read(sc, addr + i / 2, &val);
1609260219Skevlo		sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1610260219Skevlo		sc->txpow2[i + 1] = (int8_t)(val >> 8);
1611260219Skevlo
1612260219Skevlo		if (sc->ntxchains == 3) {
1613260219Skevlo			run_srom_read(sc, RT3593_EEPROM_PWR2GHZ_BASE3 + i / 2,
1614260219Skevlo			    &val);
1615260219Skevlo			sc->txpow3[i + 0] = (int8_t)(val & 0xff);
1616260219Skevlo			sc->txpow3[i + 1] = (int8_t)(val >> 8);
1617260219Skevlo		}
1618260219Skevlo	}
1619260219Skevlo	/* Fix broken Tx power entries. */
1620260219Skevlo	for (i = 0; i < 14; i++) {
1621260542Skevlo		if (sc->txpow1[i] > 31)
1622260219Skevlo			sc->txpow1[i] = 5;
1623260542Skevlo		if (sc->txpow2[i] > 31)
1624260219Skevlo			sc->txpow2[i] = 5;
1625260219Skevlo		if (sc->ntxchains == 3) {
1626260542Skevlo			if (sc->txpow3[i] > 31)
1627260219Skevlo				sc->txpow3[i] = 5;
1628260219Skevlo		}
1629260219Skevlo	}
1630260219Skevlo	/* Read power settings for 5GHz channels. */
1631260219Skevlo	for (i = 0; i < 40; i += 2) {
1632260219Skevlo		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1633260219Skevlo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1634260219Skevlo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1635260219Skevlo
1636260219Skevlo		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1637260219Skevlo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1638260219Skevlo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1639260219Skevlo
1640260219Skevlo		if (sc->ntxchains == 3) {
1641260219Skevlo			run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE3 + i / 2,
1642260219Skevlo			    &val);
1643260219Skevlo			sc->txpow3[i + 14] = (int8_t)(val & 0xff);
1644260219Skevlo			sc->txpow3[i + 15] = (int8_t)(val >> 8);
1645260219Skevlo		}
1646260219Skevlo	}
1647260219Skevlo}
1648260219Skevlo
1649260219Skevlostatic void
1650260219Skevlorun_get_txpower(struct run_softc *sc)
1651260219Skevlo{
1652260219Skevlo	uint16_t val;
1653260219Skevlo	int i;
1654260219Skevlo
1655260219Skevlo	/* Read power settings for 2GHz channels. */
1656260219Skevlo	for (i = 0; i < 14; i += 2) {
1657260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val);
1658260219Skevlo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1659260219Skevlo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1660260219Skevlo
1661260219Skevlo		if (sc->mac_ver != 0x5390) {
1662260219Skevlo			run_srom_read(sc,
1663260219Skevlo			    RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val);
1664260219Skevlo			sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1665260219Skevlo			sc->txpow2[i + 1] = (int8_t)(val >> 8);
1666260219Skevlo		}
1667260219Skevlo	}
1668260219Skevlo	/* Fix broken Tx power entries. */
1669260219Skevlo	for (i = 0; i < 14; i++) {
1670260219Skevlo		if (sc->mac_ver >= 0x5390) {
1671260219Skevlo			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 27)
1672260219Skevlo				sc->txpow1[i] = 5;
1673260219Skevlo		} else {
1674260219Skevlo			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31)
1675260219Skevlo				sc->txpow1[i] = 5;
1676260219Skevlo		}
1677260219Skevlo		if (sc->mac_ver > 0x5390) {
1678260219Skevlo			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 27)
1679260219Skevlo				sc->txpow2[i] = 5;
1680260219Skevlo		} else if (sc->mac_ver < 0x5390) {
1681260219Skevlo			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31)
1682260219Skevlo				sc->txpow2[i] = 5;
1683260219Skevlo		}
1684260219Skevlo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1685260219Skevlo		    rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]);
1686260219Skevlo	}
1687260219Skevlo	/* Read power settings for 5GHz channels. */
1688260219Skevlo	for (i = 0; i < 40; i += 2) {
1689260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1690260219Skevlo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1691260219Skevlo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1692260219Skevlo
1693260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1694260219Skevlo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1695260219Skevlo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1696260219Skevlo	}
1697260219Skevlo	/* Fix broken Tx power entries. */
1698260219Skevlo	for (i = 0; i < 40; i++ ) {
1699260219Skevlo		if (sc->mac_ver != 0x5592) {
1700260219Skevlo			if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15)
1701260219Skevlo				sc->txpow1[14 + i] = 5;
1702260219Skevlo			if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15)
1703260219Skevlo				sc->txpow2[14 + i] = 5;
1704260219Skevlo		}
1705260219Skevlo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1706260219Skevlo		    rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i],
1707260219Skevlo		    sc->txpow2[14 + i]);
1708260219Skevlo	}
1709260219Skevlo}
1710260219Skevlo
1711258641Shselaskystatic int
1712203134Sthompsarun_read_eeprom(struct run_softc *sc)
1713203134Sthompsa{
1714287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
1715203134Sthompsa	int8_t delta_2ghz, delta_5ghz;
1716203134Sthompsa	uint32_t tmp;
1717203134Sthompsa	uint16_t val;
1718203134Sthompsa	int ridx, ant, i;
1719203134Sthompsa
1720203134Sthompsa	/* check whether the ROM is eFUSE ROM or EEPROM */
1721203134Sthompsa	sc->sc_srom_read = run_eeprom_read_2;
1722205042Sthompsa	if (sc->mac_ver >= 0x3070) {
1723203134Sthompsa		run_read(sc, RT3070_EFUSE_CTRL, &tmp);
1724203134Sthompsa		DPRINTF("EFUSE_CTRL=0x%08x\n", tmp);
1725261118Skevlo		if ((tmp & RT3070_SEL_EFUSE) || sc->mac_ver == 0x3593)
1726203134Sthompsa			sc->sc_srom_read = run_efuse_read_2;
1727203134Sthompsa	}
1728203134Sthompsa
1729203134Sthompsa	/* read ROM version */
1730203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_VERSION, &val);
1731203134Sthompsa	DPRINTF("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8);
1732203134Sthompsa
1733203134Sthompsa	/* read MAC address */
1734203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC01, &val);
1735287197Sglebius	ic->ic_macaddr[0] = val & 0xff;
1736287197Sglebius	ic->ic_macaddr[1] = val >> 8;
1737203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC23, &val);
1738287197Sglebius	ic->ic_macaddr[2] = val & 0xff;
1739287197Sglebius	ic->ic_macaddr[3] = val >> 8;
1740203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC45, &val);
1741287197Sglebius	ic->ic_macaddr[4] = val & 0xff;
1742287197Sglebius	ic->ic_macaddr[5] = val >> 8;
1743203134Sthompsa
1744260219Skevlo	if (sc->mac_ver < 0x3593) {
1745257955Skevlo		/* read vender BBP settings */
1746205042Sthompsa		for (i = 0; i < 10; i++) {
1747257955Skevlo			run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val);
1748257955Skevlo			sc->bbp[i].val = val & 0xff;
1749257955Skevlo			sc->bbp[i].reg = val >> 8;
1750257955Skevlo			DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg,
1751257955Skevlo			    sc->bbp[i].val);
1752205042Sthompsa		}
1753257955Skevlo		if (sc->mac_ver >= 0x3071) {
1754257955Skevlo			/* read vendor RF settings */
1755257955Skevlo			for (i = 0; i < 10; i++) {
1756257955Skevlo				run_srom_read(sc, RT3071_EEPROM_RF_BASE + i,
1757257955Skevlo				   &val);
1758257955Skevlo				sc->rf[i].val = val & 0xff;
1759257955Skevlo				sc->rf[i].reg = val >> 8;
1760257955Skevlo				DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg,
1761257955Skevlo				    sc->rf[i].val);
1762257955Skevlo			}
1763257955Skevlo		}
1764205042Sthompsa	}
1765203134Sthompsa
1766203134Sthompsa	/* read RF frequency offset from EEPROM */
1767260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1768260219Skevlo	    RT3593_EEPROM_FREQ, &val);
1769203134Sthompsa	sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0;
1770203134Sthompsa	DPRINTF("EEPROM freq offset %d\n", sc->freq & 0xff);
1771203134Sthompsa
1772260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1773260219Skevlo	    RT3593_EEPROM_FREQ_LEDS, &val);
1774205042Sthompsa	if (val >> 8 != 0xff) {
1775203134Sthompsa		/* read LEDs operating mode */
1776205042Sthompsa		sc->leds = val >> 8;
1777260219Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED1 :
1778260219Skevlo		    RT3593_EEPROM_LED1, &sc->led[0]);
1779260219Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED2 :
1780260219Skevlo		    RT3593_EEPROM_LED2, &sc->led[1]);
1781260219Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED3 :
1782260219Skevlo		    RT3593_EEPROM_LED3, &sc->led[2]);
1783203134Sthompsa	} else {
1784203134Sthompsa		/* broken EEPROM, use default settings */
1785203134Sthompsa		sc->leds = 0x01;
1786203134Sthompsa		sc->led[0] = 0x5555;
1787203134Sthompsa		sc->led[1] = 0x2221;
1788203134Sthompsa		sc->led[2] = 0x5627;	/* differs from RT2860 */
1789203134Sthompsa	}
1790203134Sthompsa	DPRINTF("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n",
1791203134Sthompsa	    sc->leds, sc->led[0], sc->led[1], sc->led[2]);
1792203134Sthompsa
1793203134Sthompsa	/* read RF information */
1794259032Skevlo	if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392)
1795257955Skevlo		run_srom_read(sc, 0x00, &val);
1796257955Skevlo	else
1797257955Skevlo		run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1798257955Skevlo
1799203134Sthompsa	if (val == 0xffff) {
1800260219Skevlo		device_printf(sc->sc_dev,
1801260219Skevlo		    "invalid EEPROM antenna info, using default\n");
1802203134Sthompsa		DPRINTF("invalid EEPROM antenna info, using default\n");
1803205042Sthompsa		if (sc->mac_ver == 0x3572) {
1804205042Sthompsa			/* default to RF3052 2T2R */
1805205042Sthompsa			sc->rf_rev = RT3070_RF_3052;
1806205042Sthompsa			sc->ntxchains = 2;
1807205042Sthompsa			sc->nrxchains = 2;
1808205042Sthompsa		} else if (sc->mac_ver >= 0x3070) {
1809203134Sthompsa			/* default to RF3020 1T1R */
1810203134Sthompsa			sc->rf_rev = RT3070_RF_3020;
1811203134Sthompsa			sc->ntxchains = 1;
1812203134Sthompsa			sc->nrxchains = 1;
1813203134Sthompsa		} else {
1814203134Sthompsa			/* default to RF2820 1T2R */
1815203134Sthompsa			sc->rf_rev = RT2860_RF_2820;
1816203134Sthompsa			sc->ntxchains = 1;
1817203134Sthompsa			sc->nrxchains = 2;
1818203134Sthompsa		}
1819203134Sthompsa	} else {
1820259032Skevlo		if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) {
1821257955Skevlo			sc->rf_rev = val;
1822257955Skevlo			run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1823257955Skevlo		} else
1824257955Skevlo			sc->rf_rev = (val >> 8) & 0xf;
1825203134Sthompsa		sc->ntxchains = (val >> 4) & 0xf;
1826203134Sthompsa		sc->nrxchains = val & 0xf;
1827203134Sthompsa	}
1828257955Skevlo	DPRINTF("EEPROM RF rev=0x%04x chains=%dT%dR\n",
1829203134Sthompsa	    sc->rf_rev, sc->ntxchains, sc->nrxchains);
1830203134Sthompsa
1831208019Sthompsa	/* check if RF supports automatic Tx access gain control */
1832203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_CONFIG, &val);
1833203134Sthompsa	DPRINTF("EEPROM CFG 0x%04x\n", val);
1834205042Sthompsa	/* check if driver should patch the DAC issue */
1835205042Sthompsa	if ((val >> 8) != 0xff)
1836205042Sthompsa		sc->patch_dac = (val >> 15) & 1;
1837203134Sthompsa	if ((val & 0xff) != 0xff) {
1838203134Sthompsa		sc->ext_5ghz_lna = (val >> 3) & 1;
1839203134Sthompsa		sc->ext_2ghz_lna = (val >> 2) & 1;
1840205042Sthompsa		/* check if RF supports automatic Tx access gain control */
1841203134Sthompsa		sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1;
1842205042Sthompsa		/* check if we have a hardware radio switch */
1843205042Sthompsa		sc->rfswitch = val & 1;
1844203134Sthompsa	}
1845203134Sthompsa
1846260219Skevlo	/* Read Tx power settings. */
1847260219Skevlo	if (sc->mac_ver == 0x3593)
1848260219Skevlo		run_rt3593_get_txpower(sc);
1849260219Skevlo	else
1850260219Skevlo		run_get_txpower(sc);
1851203134Sthompsa
1852203134Sthompsa	/* read Tx power compensation for each Tx rate */
1853203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val);
1854203134Sthompsa	delta_2ghz = delta_5ghz = 0;
1855203134Sthompsa	if ((val & 0xff) != 0xff && (val & 0x80)) {
1856203134Sthompsa		delta_2ghz = val & 0xf;
1857203134Sthompsa		if (!(val & 0x40))	/* negative number */
1858203134Sthompsa			delta_2ghz = -delta_2ghz;
1859203134Sthompsa	}
1860203134Sthompsa	val >>= 8;
1861203134Sthompsa	if ((val & 0xff) != 0xff && (val & 0x80)) {
1862203134Sthompsa		delta_5ghz = val & 0xf;
1863203134Sthompsa		if (!(val & 0x40))	/* negative number */
1864203134Sthompsa			delta_5ghz = -delta_5ghz;
1865203134Sthompsa	}
1866203134Sthompsa	DPRINTF("power compensation=%d (2GHz), %d (5GHz)\n",
1867203134Sthompsa	    delta_2ghz, delta_5ghz);
1868203134Sthompsa
1869203134Sthompsa	for (ridx = 0; ridx < 5; ridx++) {
1870203134Sthompsa		uint32_t reg;
1871203134Sthompsa
1872208019Sthompsa		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val);
1873208019Sthompsa		reg = val;
1874208019Sthompsa		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val);
1875208019Sthompsa		reg |= (uint32_t)val << 16;
1876203134Sthompsa
1877203134Sthompsa		sc->txpow20mhz[ridx] = reg;
1878203134Sthompsa		sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz);
1879203134Sthompsa		sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz);
1880203134Sthompsa
1881203134Sthompsa		DPRINTF("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, "
1882203134Sthompsa		    "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx],
1883203134Sthompsa		    sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]);
1884203134Sthompsa	}
1885203134Sthompsa
1886260219Skevlo	/* Read RSSI offsets and LNA gains from EEPROM. */
1887260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_2GHZ :
1888260219Skevlo	    RT3593_EEPROM_RSSI1_2GHZ, &val);
1889203134Sthompsa	sc->rssi_2ghz[0] = val & 0xff;	/* Ant A */
1890203134Sthompsa	sc->rssi_2ghz[1] = val >> 8;	/* Ant B */
1891260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_2GHZ :
1892260219Skevlo	    RT3593_EEPROM_RSSI2_2GHZ, &val);
1893205042Sthompsa	if (sc->mac_ver >= 0x3070) {
1894260219Skevlo		if (sc->mac_ver == 0x3593) {
1895260219Skevlo			sc->txmixgain_2ghz = 0;
1896260219Skevlo			sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1897260219Skevlo		} else {
1898260219Skevlo			/*
1899260219Skevlo			 * On RT3070 chips (limited to 2 Rx chains), this ROM
1900260219Skevlo			 * field contains the Tx mixer gain for the 2GHz band.
1901260219Skevlo			 */
1902260219Skevlo			if ((val & 0xff) != 0xff)
1903260219Skevlo				sc->txmixgain_2ghz = val & 0x7;
1904260219Skevlo		}
1905205042Sthompsa		DPRINTF("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz);
1906205042Sthompsa	} else
1907205042Sthompsa		sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1908260219Skevlo	if (sc->mac_ver == 0x3593)
1909260219Skevlo		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
1910203134Sthompsa	sc->lna[2] = val >> 8;		/* channel group 2 */
1911203134Sthompsa
1912260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_5GHZ :
1913260219Skevlo	    RT3593_EEPROM_RSSI1_5GHZ, &val);
1914203134Sthompsa	sc->rssi_5ghz[0] = val & 0xff;	/* Ant A */
1915203134Sthompsa	sc->rssi_5ghz[1] = val >> 8;	/* Ant B */
1916260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_5GHZ :
1917260219Skevlo	    RT3593_EEPROM_RSSI2_5GHZ, &val);
1918205042Sthompsa	if (sc->mac_ver == 0x3572) {
1919205042Sthompsa		/*
1920205042Sthompsa		 * On RT3572 chips (limited to 2 Rx chains), this ROM
1921205042Sthompsa		 * field contains the Tx mixer gain for the 5GHz band.
1922205042Sthompsa		 */
1923205042Sthompsa		if ((val & 0xff) != 0xff)
1924205042Sthompsa			sc->txmixgain_5ghz = val & 0x7;
1925205042Sthompsa		DPRINTF("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz);
1926205042Sthompsa	} else
1927205042Sthompsa		sc->rssi_5ghz[2] = val & 0xff;	/* Ant C */
1928260219Skevlo	if (sc->mac_ver == 0x3593) {
1929260219Skevlo		sc->txmixgain_5ghz = 0;
1930260219Skevlo		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
1931260219Skevlo	}
1932203134Sthompsa	sc->lna[3] = val >> 8;		/* channel group 3 */
1933203134Sthompsa
1934260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LNA :
1935260219Skevlo	    RT3593_EEPROM_LNA, &val);
1936203134Sthompsa	sc->lna[0] = val & 0xff;	/* channel group 0 */
1937203134Sthompsa	sc->lna[1] = val >> 8;		/* channel group 1 */
1938203134Sthompsa
1939203134Sthompsa	/* fix broken 5GHz LNA entries */
1940203134Sthompsa	if (sc->lna[2] == 0 || sc->lna[2] == 0xff) {
1941203134Sthompsa		DPRINTF("invalid LNA for channel group %d\n", 2);
1942203134Sthompsa		sc->lna[2] = sc->lna[1];
1943203134Sthompsa	}
1944203134Sthompsa	if (sc->lna[3] == 0 || sc->lna[3] == 0xff) {
1945203134Sthompsa		DPRINTF("invalid LNA for channel group %d\n", 3);
1946203134Sthompsa		sc->lna[3] = sc->lna[1];
1947203134Sthompsa	}
1948203134Sthompsa
1949203134Sthompsa	/* fix broken RSSI offset entries */
1950203134Sthompsa	for (ant = 0; ant < 3; ant++) {
1951203134Sthompsa		if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) {
1952203134Sthompsa			DPRINTF("invalid RSSI%d offset: %d (2GHz)\n",
1953203134Sthompsa			    ant + 1, sc->rssi_2ghz[ant]);
1954203134Sthompsa			sc->rssi_2ghz[ant] = 0;
1955203134Sthompsa		}
1956203134Sthompsa		if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) {
1957203134Sthompsa			DPRINTF("invalid RSSI%d offset: %d (5GHz)\n",
1958203134Sthompsa			    ant + 1, sc->rssi_5ghz[ant]);
1959203134Sthompsa			sc->rssi_5ghz[ant] = 0;
1960203134Sthompsa		}
1961203134Sthompsa	}
1962209917Sthompsa	return (0);
1963203134Sthompsa}
1964203134Sthompsa
1965218676Shselaskystatic struct ieee80211_node *
1966203134Sthompsarun_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
1967203134Sthompsa{
1968203134Sthompsa	return malloc(sizeof (struct run_node), M_DEVBUF, M_NOWAIT | M_ZERO);
1969203134Sthompsa}
1970203134Sthompsa
1971203134Sthompsastatic int
1972203134Sthompsarun_media_change(struct ifnet *ifp)
1973203134Sthompsa{
1974208019Sthompsa	struct ieee80211vap *vap = ifp->if_softc;
1975208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
1976203134Sthompsa	const struct ieee80211_txparam *tp;
1977286950Sadrian	struct run_softc *sc = ic->ic_softc;
1978203134Sthompsa	uint8_t rate, ridx;
1979203134Sthompsa	int error;
1980203134Sthompsa
1981203134Sthompsa	RUN_LOCK(sc);
1982203134Sthompsa
1983203134Sthompsa	error = ieee80211_media_change(ifp);
1984209917Sthompsa	if (error != ENETRESET) {
1985203134Sthompsa		RUN_UNLOCK(sc);
1986209917Sthompsa		return (error);
1987208019Sthompsa	}
1988203134Sthompsa
1989203134Sthompsa	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
1990203134Sthompsa	if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
1991212127Sthompsa		struct ieee80211_node *ni;
1992212127Sthompsa		struct run_node	*rn;
1993212127Sthompsa
1994203134Sthompsa		rate = ic->ic_sup_rates[ic->ic_curmode].
1995203134Sthompsa		    rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL;
1996203134Sthompsa		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
1997203134Sthompsa			if (rt2860_rates[ridx].rate == rate)
1998203134Sthompsa				break;
1999212127Sthompsa		ni = ieee80211_ref_node(vap->iv_bss);
2000287552Skevlo		rn = RUN_NODE(ni);
2001208019Sthompsa		rn->fix_ridx = ridx;
2002208019Sthompsa		DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx);
2003212127Sthompsa		ieee80211_free_node(ni);
2004203134Sthompsa	}
2005203134Sthompsa
2006208019Sthompsa#if 0
2007203134Sthompsa	if ((ifp->if_flags & IFF_UP) &&
2008287197Sglebius	    (ifp->if_drv_flags &  RUN_RUNNING)){
2009203134Sthompsa		run_init_locked(sc);
2010203134Sthompsa	}
2011208019Sthompsa#endif
2012203134Sthompsa
2013203134Sthompsa	RUN_UNLOCK(sc);
2014203134Sthompsa
2015209917Sthompsa	return (0);
2016203134Sthompsa}
2017203134Sthompsa
2018203134Sthompsastatic int
2019203134Sthompsarun_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
2020203134Sthompsa{
2021203134Sthompsa	const struct ieee80211_txparam *tp;
2022203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2023286950Sadrian	struct run_softc *sc = ic->ic_softc;
2024203134Sthompsa	struct run_vap *rvp = RUN_VAP(vap);
2025203134Sthompsa	enum ieee80211_state ostate;
2026208019Sthompsa	uint32_t sta[3];
2027203134Sthompsa	uint32_t tmp;
2028208019Sthompsa	uint8_t ratectl;
2029208019Sthompsa	uint8_t restart_ratectl = 0;
2030208019Sthompsa	uint8_t bid = 1 << rvp->rvp_id;
2031203134Sthompsa
2032203134Sthompsa	ostate = vap->iv_state;
2033203134Sthompsa	DPRINTF("%s -> %s\n",
2034203134Sthompsa		ieee80211_state_name[ostate],
2035203134Sthompsa		ieee80211_state_name[nstate]);
2036203134Sthompsa
2037203134Sthompsa	IEEE80211_UNLOCK(ic);
2038203134Sthompsa	RUN_LOCK(sc);
2039203134Sthompsa
2040208019Sthompsa	ratectl = sc->ratectl_run; /* remember current state */
2041208019Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
2042208019Sthompsa	usb_callout_stop(&sc->ratectl_ch);
2043203134Sthompsa
2044203134Sthompsa	if (ostate == IEEE80211_S_RUN) {
2045203134Sthompsa		/* turn link LED off */
2046203134Sthompsa		run_set_leds(sc, RT2860_LED_RADIO);
2047203134Sthompsa	}
2048203134Sthompsa
2049203134Sthompsa	switch (nstate) {
2050203134Sthompsa	case IEEE80211_S_INIT:
2051208019Sthompsa		restart_ratectl = 1;
2052208019Sthompsa
2053208019Sthompsa		if (ostate != IEEE80211_S_RUN)
2054208019Sthompsa			break;
2055208019Sthompsa
2056208019Sthompsa		ratectl &= ~bid;
2057208019Sthompsa		sc->runbmap &= ~bid;
2058208019Sthompsa
2059208019Sthompsa		/* abort TSF synchronization if there is no vap running */
2060209917Sthompsa		if (--sc->running == 0) {
2061203134Sthompsa			run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
2062203134Sthompsa			run_write(sc, RT2860_BCN_TIME_CFG,
2063203134Sthompsa			    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
2064203134Sthompsa			    RT2860_TBTT_TIMER_EN));
2065203134Sthompsa		}
2066203134Sthompsa		break;
2067203134Sthompsa
2068203134Sthompsa	case IEEE80211_S_RUN:
2069209917Sthompsa		if (!(sc->runbmap & bid)) {
2070208019Sthompsa			if(sc->running++)
2071208019Sthompsa				restart_ratectl = 1;
2072208019Sthompsa			sc->runbmap |= bid;
2073208019Sthompsa		}
2074203134Sthompsa
2075218492Sbschmidt		m_freem(rvp->beacon_mbuf);
2076218492Sbschmidt		rvp->beacon_mbuf = NULL;
2077218492Sbschmidt
2078209917Sthompsa		switch (vap->iv_opmode) {
2079208019Sthompsa		case IEEE80211_M_HOSTAP:
2080208019Sthompsa		case IEEE80211_M_MBSS:
2081208019Sthompsa			sc->ap_running |= bid;
2082208019Sthompsa			ic->ic_opmode = vap->iv_opmode;
2083208019Sthompsa			run_update_beacon_cb(vap);
2084208019Sthompsa			break;
2085208019Sthompsa		case IEEE80211_M_IBSS:
2086208019Sthompsa			sc->adhoc_running |= bid;
2087209917Sthompsa			if (!sc->ap_running)
2088208019Sthompsa				ic->ic_opmode = vap->iv_opmode;
2089208019Sthompsa			run_update_beacon_cb(vap);
2090208019Sthompsa			break;
2091208019Sthompsa		case IEEE80211_M_STA:
2092208019Sthompsa			sc->sta_running |= bid;
2093209917Sthompsa			if (!sc->ap_running && !sc->adhoc_running)
2094208019Sthompsa				ic->ic_opmode = vap->iv_opmode;
2095208019Sthompsa
2096208019Sthompsa			/* read statistic counters (clear on read) */
2097208019Sthompsa			run_read_region_1(sc, RT2860_TX_STA_CNT0,
2098208019Sthompsa			    (uint8_t *)sta, sizeof sta);
2099208019Sthompsa
2100208019Sthompsa			break;
2101208019Sthompsa		default:
2102208019Sthompsa			ic->ic_opmode = vap->iv_opmode;
2103208019Sthompsa			break;
2104208019Sthompsa		}
2105208019Sthompsa
2106203134Sthompsa		if (vap->iv_opmode != IEEE80211_M_MONITOR) {
2107212127Sthompsa			struct ieee80211_node *ni;
2108212127Sthompsa
2109236439Shselasky			if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) {
2110236439Shselasky				RUN_UNLOCK(sc);
2111236439Shselasky				IEEE80211_LOCK(ic);
2112236439Shselasky				return (-1);
2113236439Shselasky			}
2114283540Sglebius			run_updateslot(ic);
2115203134Sthompsa			run_enable_mrr(sc);
2116203134Sthompsa			run_set_txpreamble(sc);
2117203134Sthompsa			run_set_basicrates(sc);
2118212127Sthompsa			ni = ieee80211_ref_node(vap->iv_bss);
2119287197Sglebius			IEEE80211_ADDR_COPY(ic->ic_macaddr, ni->ni_bssid);
2120203134Sthompsa			run_set_bssid(sc, ni->ni_bssid);
2121212127Sthompsa			ieee80211_free_node(ni);
2122208019Sthompsa			run_enable_tsf_sync(sc);
2123203134Sthompsa
2124208019Sthompsa			/* enable automatic rate adaptation */
2125208019Sthompsa			tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
2126208019Sthompsa			if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
2127208019Sthompsa				ratectl |= bid;
2128203134Sthompsa		}
2129203134Sthompsa
2130203134Sthompsa		/* turn link LED on */
2131203134Sthompsa		run_set_leds(sc, RT2860_LED_RADIO |
2132208019Sthompsa		    (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ?
2133203134Sthompsa		     RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ));
2134203134Sthompsa
2135203134Sthompsa		break;
2136203134Sthompsa	default:
2137203134Sthompsa		DPRINTFN(6, "undefined case\n");
2138203134Sthompsa		break;
2139203134Sthompsa	}
2140203134Sthompsa
2141208019Sthompsa	/* restart amrr for running VAPs */
2142209917Sthompsa	if ((sc->ratectl_run = ratectl) && restart_ratectl)
2143208019Sthompsa		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2144208019Sthompsa
2145203134Sthompsa	RUN_UNLOCK(sc);
2146203134Sthompsa	IEEE80211_LOCK(ic);
2147203134Sthompsa
2148203134Sthompsa	return(rvp->newstate(vap, nstate, arg));
2149203134Sthompsa}
2150203134Sthompsa
2151203134Sthompsa/* ARGSUSED */
2152203134Sthompsastatic void
2153208019Sthompsarun_wme_update_cb(void *arg)
2154203134Sthompsa{
2155203134Sthompsa	struct ieee80211com *ic = arg;
2156286950Sadrian	struct run_softc *sc = ic->ic_softc;
2157203134Sthompsa	struct ieee80211_wme_state *wmesp = &ic->ic_wme;
2158203134Sthompsa	int aci, error = 0;
2159203134Sthompsa
2160208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2161203134Sthompsa
2162203134Sthompsa	/* update MAC TX configuration registers */
2163203134Sthompsa	for (aci = 0; aci < WME_NUM_AC; aci++) {
2164203134Sthompsa		error = run_write(sc, RT2860_EDCA_AC_CFG(aci),
2165203134Sthompsa		    wmesp->wme_params[aci].wmep_logcwmax << 16 |
2166203134Sthompsa		    wmesp->wme_params[aci].wmep_logcwmin << 12 |
2167203134Sthompsa		    wmesp->wme_params[aci].wmep_aifsn  <<  8 |
2168203134Sthompsa		    wmesp->wme_params[aci].wmep_txopLimit);
2169209917Sthompsa		if (error) goto err;
2170203134Sthompsa	}
2171203134Sthompsa
2172203134Sthompsa	/* update SCH/DMA registers too */
2173203134Sthompsa	error = run_write(sc, RT2860_WMM_AIFSN_CFG,
2174203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_aifsn  << 12 |
2175203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_aifsn  <<  8 |
2176203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_aifsn  <<  4 |
2177203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_aifsn);
2178209917Sthompsa	if (error) goto err;
2179203134Sthompsa	error = run_write(sc, RT2860_WMM_CWMIN_CFG,
2180203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_logcwmin << 12 |
2181203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_logcwmin <<  8 |
2182203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_logcwmin <<  4 |
2183203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_logcwmin);
2184209917Sthompsa	if (error) goto err;
2185203134Sthompsa	error = run_write(sc, RT2860_WMM_CWMAX_CFG,
2186203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_logcwmax << 12 |
2187203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_logcwmax <<  8 |
2188203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_logcwmax <<  4 |
2189203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_logcwmax);
2190209917Sthompsa	if (error) goto err;
2191203134Sthompsa	error = run_write(sc, RT2860_WMM_TXOP0_CFG,
2192203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_txopLimit << 16 |
2193203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_txopLimit);
2194209917Sthompsa	if (error) goto err;
2195203134Sthompsa	error = run_write(sc, RT2860_WMM_TXOP1_CFG,
2196203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_txopLimit << 16 |
2197203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_txopLimit);
2198203134Sthompsa
2199203134Sthompsaerr:
2200209917Sthompsa	if (error)
2201203134Sthompsa		DPRINTF("WME update failed\n");
2202203134Sthompsa
2203203134Sthompsa	return;
2204203134Sthompsa}
2205203134Sthompsa
2206208019Sthompsastatic int
2207208019Sthompsarun_wme_update(struct ieee80211com *ic)
2208208019Sthompsa{
2209286950Sadrian	struct run_softc *sc = ic->ic_softc;
2210208019Sthompsa
2211208019Sthompsa	/* sometime called wothout lock */
2212209917Sthompsa	if (mtx_owned(&ic->ic_comlock.mtx)) {
2213208019Sthompsa		uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
2214208019Sthompsa		DPRINTF("cmdq_store=%d\n", i);
2215208019Sthompsa		sc->cmdq[i].func = run_wme_update_cb;
2216208019Sthompsa		sc->cmdq[i].arg0 = ic;
2217208019Sthompsa		ieee80211_runtask(ic, &sc->cmdq_task);
2218209918Sthompsa		return (0);
2219208019Sthompsa	}
2220208019Sthompsa
2221208019Sthompsa	RUN_LOCK(sc);
2222208019Sthompsa	run_wme_update_cb(ic);
2223208019Sthompsa	RUN_UNLOCK(sc);
2224208019Sthompsa
2225287552Skevlo	/* return whatever, upper layer doesn't care anyway */
2226208019Sthompsa	return (0);
2227208019Sthompsa}
2228208019Sthompsa
2229203134Sthompsastatic void
2230208019Sthompsarun_key_set_cb(void *arg)
2231203134Sthompsa{
2232208019Sthompsa	struct run_cmdq *cmdq = arg;
2233208019Sthompsa	struct ieee80211vap *vap = cmdq->arg1;
2234208019Sthompsa	struct ieee80211_key *k = cmdq->k;
2235203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2236286950Sadrian	struct run_softc *sc = ic->ic_softc;
2237203134Sthompsa	struct ieee80211_node *ni;
2238287553Skevlo	u_int cipher = k->wk_cipher->ic_cipher;
2239203134Sthompsa	uint32_t attr;
2240203134Sthompsa	uint16_t base, associd;
2241209144Sthompsa	uint8_t mode, wcid, iv[8];
2242203134Sthompsa
2243208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2244203134Sthompsa
2245209917Sthompsa	if (vap->iv_opmode == IEEE80211_M_HOSTAP)
2246208019Sthompsa		ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac);
2247209144Sthompsa	else
2248203134Sthompsa		ni = vap->iv_bss;
2249208019Sthompsa	associd = (ni != NULL) ? ni->ni_associd : 0;
2250203134Sthompsa
2251203134Sthompsa	/* map net80211 cipher to RT2860 security mode */
2252287553Skevlo	switch (cipher) {
2253203134Sthompsa	case IEEE80211_CIPHER_WEP:
2254203134Sthompsa		if(k->wk_keylen < 8)
2255203134Sthompsa			mode = RT2860_MODE_WEP40;
2256203134Sthompsa		else
2257203134Sthompsa			mode = RT2860_MODE_WEP104;
2258203134Sthompsa		break;
2259203134Sthompsa	case IEEE80211_CIPHER_TKIP:
2260203134Sthompsa		mode = RT2860_MODE_TKIP;
2261203134Sthompsa		break;
2262203134Sthompsa	case IEEE80211_CIPHER_AES_CCM:
2263203134Sthompsa		mode = RT2860_MODE_AES_CCMP;
2264203134Sthompsa		break;
2265203134Sthompsa	default:
2266203134Sthompsa		DPRINTF("undefined case\n");
2267208019Sthompsa		return;
2268203134Sthompsa	}
2269203134Sthompsa
2270208019Sthompsa	DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n",
2271203134Sthompsa	    associd, k->wk_keyix, mode,
2272208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise",
2273208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off",
2274208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off");
2275203134Sthompsa
2276203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2277203134Sthompsa		wcid = 0;	/* NB: update WCID0 for group keys */
2278208019Sthompsa		base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix);
2279203134Sthompsa	} else {
2280245047Shselasky		wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2281245047Shselasky		    1 : RUN_AID2WCID(associd);
2282203134Sthompsa		base = RT2860_PKEY(wcid);
2283203134Sthompsa	}
2284203134Sthompsa
2285287553Skevlo	if (cipher == IEEE80211_CIPHER_TKIP) {
2286203134Sthompsa		if(run_write_region_1(sc, base, k->wk_key, 16))
2287208019Sthompsa			return;
2288209144Sthompsa		if(run_write_region_1(sc, base + 16, &k->wk_key[16], 8))	/* wk_txmic */
2289208019Sthompsa			return;
2290209144Sthompsa		if(run_write_region_1(sc, base + 24, &k->wk_key[24], 8))	/* wk_rxmic */
2291208019Sthompsa			return;
2292203134Sthompsa	} else {
2293203134Sthompsa		/* roundup len to 16-bit: XXX fix write_region_1() instead */
2294203134Sthompsa		if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1))
2295208019Sthompsa			return;
2296203134Sthompsa	}
2297203134Sthompsa
2298203134Sthompsa	if (!(k->wk_flags & IEEE80211_KEY_GROUP) ||
2299203134Sthompsa	    (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) {
2300203134Sthompsa		/* set initial packet number in IV+EIV */
2301287553Skevlo		if (cipher == IEEE80211_CIPHER_WEP) {
2302203134Sthompsa			memset(iv, 0, sizeof iv);
2303208019Sthompsa			iv[3] = vap->iv_def_txkey << 6;
2304203134Sthompsa		} else {
2305287553Skevlo			if (cipher == IEEE80211_CIPHER_TKIP) {
2306203134Sthompsa				iv[0] = k->wk_keytsc >> 8;
2307203134Sthompsa				iv[1] = (iv[0] | 0x20) & 0x7f;
2308203134Sthompsa				iv[2] = k->wk_keytsc;
2309203134Sthompsa			} else /* CCMP */ {
2310203134Sthompsa				iv[0] = k->wk_keytsc;
2311203134Sthompsa				iv[1] = k->wk_keytsc >> 8;
2312203134Sthompsa				iv[2] = 0;
2313203134Sthompsa			}
2314203134Sthompsa			iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV;
2315203134Sthompsa			iv[4] = k->wk_keytsc >> 16;
2316203134Sthompsa			iv[5] = k->wk_keytsc >> 24;
2317203134Sthompsa			iv[6] = k->wk_keytsc >> 32;
2318203134Sthompsa			iv[7] = k->wk_keytsc >> 40;
2319203134Sthompsa		}
2320209917Sthompsa		if (run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8))
2321208019Sthompsa			return;
2322203134Sthompsa	}
2323203134Sthompsa
2324203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2325203134Sthompsa		/* install group key */
2326209917Sthompsa		if (run_read(sc, RT2860_SKEY_MODE_0_7, &attr))
2327208019Sthompsa			return;
2328203134Sthompsa		attr &= ~(0xf << (k->wk_keyix * 4));
2329203134Sthompsa		attr |= mode << (k->wk_keyix * 4);
2330209917Sthompsa		if (run_write(sc, RT2860_SKEY_MODE_0_7, attr))
2331208019Sthompsa			return;
2332203134Sthompsa	} else {
2333203134Sthompsa		/* install pairwise key */
2334209917Sthompsa		if (run_read(sc, RT2860_WCID_ATTR(wcid), &attr))
2335208019Sthompsa			return;
2336203134Sthompsa		attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN;
2337209917Sthompsa		if (run_write(sc, RT2860_WCID_ATTR(wcid), attr))
2338208019Sthompsa			return;
2339203134Sthompsa	}
2340203134Sthompsa
2341203134Sthompsa	/* TODO create a pass-thru key entry? */
2342203134Sthompsa
2343208019Sthompsa	/* need wcid to delete the right key later */
2344208019Sthompsa	k->wk_pad = wcid;
2345203134Sthompsa}
2346203134Sthompsa
2347203134Sthompsa/*
2348208019Sthompsa * Don't have to be deferred, but in order to keep order of
2349208019Sthompsa * execution, i.e. with run_key_delete(), defer this and let
2350208019Sthompsa * run_cmdq_cb() maintain the order.
2351208019Sthompsa *
2352203134Sthompsa * return 0 on error
2353203134Sthompsa */
2354203134Sthompsastatic int
2355208019Sthompsarun_key_set(struct ieee80211vap *vap, struct ieee80211_key *k,
2356208019Sthompsa		const uint8_t mac[IEEE80211_ADDR_LEN])
2357203134Sthompsa{
2358203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2359286950Sadrian	struct run_softc *sc = ic->ic_softc;
2360208019Sthompsa	uint32_t i;
2361208019Sthompsa
2362208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
2363208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
2364208019Sthompsa	sc->cmdq[i].func = run_key_set_cb;
2365208019Sthompsa	sc->cmdq[i].arg0 = NULL;
2366208019Sthompsa	sc->cmdq[i].arg1 = vap;
2367208019Sthompsa	sc->cmdq[i].k = k;
2368208019Sthompsa	IEEE80211_ADDR_COPY(sc->cmdq[i].mac, mac);
2369208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
2370208019Sthompsa
2371209144Sthompsa	/*
2372209144Sthompsa	 * To make sure key will be set when hostapd
2373209144Sthompsa	 * calls iv_key_set() before if_init().
2374209144Sthompsa	 */
2375209917Sthompsa	if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
2376209144Sthompsa		RUN_LOCK(sc);
2377209144Sthompsa		sc->cmdq_key_set = RUN_CMDQ_GO;
2378209144Sthompsa		RUN_UNLOCK(sc);
2379209144Sthompsa	}
2380209144Sthompsa
2381209917Sthompsa	return (1);
2382208019Sthompsa}
2383208019Sthompsa
2384208019Sthompsa/*
2385208019Sthompsa * If wlan is destroyed without being brought down i.e. without
2386208019Sthompsa * wlan down or wpa_cli terminate, this function is called after
2387208019Sthompsa * vap is gone. Don't refer it.
2388208019Sthompsa */
2389208019Sthompsastatic void
2390208019Sthompsarun_key_delete_cb(void *arg)
2391208019Sthompsa{
2392208019Sthompsa	struct run_cmdq *cmdq = arg;
2393208019Sthompsa	struct run_softc *sc = cmdq->arg1;
2394208019Sthompsa	struct ieee80211_key *k = &cmdq->key;
2395203134Sthompsa	uint32_t attr;
2396203134Sthompsa	uint8_t wcid;
2397203134Sthompsa
2398208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2399203134Sthompsa
2400203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2401203134Sthompsa		/* remove group key */
2402208019Sthompsa		DPRINTF("removing group key\n");
2403208019Sthompsa		run_read(sc, RT2860_SKEY_MODE_0_7, &attr);
2404203134Sthompsa		attr &= ~(0xf << (k->wk_keyix * 4));
2405208019Sthompsa		run_write(sc, RT2860_SKEY_MODE_0_7, attr);
2406203134Sthompsa	} else {
2407203134Sthompsa		/* remove pairwise key */
2408208019Sthompsa		DPRINTF("removing key for wcid %x\n", k->wk_pad);
2409208019Sthompsa		/* matching wcid was written to wk_pad in run_key_set() */
2410208019Sthompsa		wcid = k->wk_pad;
2411208019Sthompsa		run_read(sc, RT2860_WCID_ATTR(wcid), &attr);
2412203134Sthompsa		attr &= ~0xf;
2413208019Sthompsa		run_write(sc, RT2860_WCID_ATTR(wcid), attr);
2414208019Sthompsa		run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8);
2415203134Sthompsa	}
2416203134Sthompsa
2417208019Sthompsa	k->wk_pad = 0;
2418203134Sthompsa}
2419203134Sthompsa
2420208019Sthompsa/*
2421208019Sthompsa * return 0 on error
2422208019Sthompsa */
2423208019Sthompsastatic int
2424208019Sthompsarun_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k)
2425203134Sthompsa{
2426208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2427286950Sadrian	struct run_softc *sc = ic->ic_softc;
2428208019Sthompsa	struct ieee80211_key *k0;
2429208019Sthompsa	uint32_t i;
2430203134Sthompsa
2431208019Sthompsa	/*
2432208019Sthompsa	 * When called back, key might be gone. So, make a copy
2433208019Sthompsa	 * of some values need to delete keys before deferring.
2434208019Sthompsa	 * But, because of LOR with node lock, cannot use lock here.
2435208019Sthompsa	 * So, use atomic instead.
2436208019Sthompsa	 */
2437208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
2438208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
2439208019Sthompsa	sc->cmdq[i].func = run_key_delete_cb;
2440208019Sthompsa	sc->cmdq[i].arg0 = NULL;
2441208019Sthompsa	sc->cmdq[i].arg1 = sc;
2442208019Sthompsa	k0 = &sc->cmdq[i].key;
2443208019Sthompsa	k0->wk_flags = k->wk_flags;
2444208019Sthompsa	k0->wk_keyix = k->wk_keyix;
2445208019Sthompsa	/* matching wcid was written to wk_pad in run_key_set() */
2446208019Sthompsa	k0->wk_pad = k->wk_pad;
2447208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
2448208019Sthompsa	return (1);	/* return fake success */
2449203134Sthompsa
2450203134Sthompsa}
2451203134Sthompsa
2452203134Sthompsastatic void
2453206358Srpaulorun_ratectl_to(void *arg)
2454203134Sthompsa{
2455208019Sthompsa	struct run_softc *sc = arg;
2456203134Sthompsa
2457203134Sthompsa	/* do it in a process context, so it can go sleep */
2458287197Sglebius	ieee80211_runtask(&sc->sc_ic, &sc->ratectl_task);
2459203134Sthompsa	/* next timeout will be rescheduled in the callback task */
2460203134Sthompsa}
2461203134Sthompsa
2462203134Sthompsa/* ARGSUSED */
2463203134Sthompsastatic void
2464206358Srpaulorun_ratectl_cb(void *arg, int pending)
2465203134Sthompsa{
2466208019Sthompsa	struct run_softc *sc = arg;
2467287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
2468208019Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
2469203134Sthompsa
2470209917Sthompsa	if (vap == NULL)
2471208019Sthompsa		return;
2472208019Sthompsa
2473262795Shselasky	if (sc->rvp_cnt > 1 || vap->iv_opmode != IEEE80211_M_STA) {
2474203134Sthompsa		/*
2475203134Sthompsa		 * run_reset_livelock() doesn't do anything with AMRR,
2476203134Sthompsa		 * but Ralink wants us to call it every 1 sec. So, we
2477203134Sthompsa		 * piggyback here rather than creating another callout.
2478203134Sthompsa		 * Livelock may occur only in HOSTAP or IBSS mode
2479203134Sthompsa		 * (when h/w is sending beacons).
2480203134Sthompsa		 */
2481203134Sthompsa		RUN_LOCK(sc);
2482203134Sthompsa		run_reset_livelock(sc);
2483208019Sthompsa		/* just in case, there are some stats to drain */
2484208019Sthompsa		run_drain_fifo(sc);
2485203134Sthompsa		RUN_UNLOCK(sc);
2486203134Sthompsa	}
2487203134Sthompsa
2488262795Shselasky	ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc);
2489262795Shselasky
2490257712Shselasky	RUN_LOCK(sc);
2491208019Sthompsa	if(sc->ratectl_run != RUN_RATECTL_OFF)
2492208019Sthompsa		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2493257712Shselasky	RUN_UNLOCK(sc);
2494203134Sthompsa}
2495203134Sthompsa
2496203134Sthompsastatic void
2497208019Sthompsarun_drain_fifo(void *arg)
2498203134Sthompsa{
2499208019Sthompsa	struct run_softc *sc = arg;
2500208019Sthompsa	uint32_t stat;
2501218676Shselasky	uint16_t (*wstat)[3];
2502203134Sthompsa	uint8_t wcid, mcs, pid;
2503218676Shselasky	int8_t retry;
2504203134Sthompsa
2505208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2506203134Sthompsa
2507208019Sthompsa	for (;;) {
2508203134Sthompsa		/* drain Tx status FIFO (maxsize = 16) */
2509203134Sthompsa		run_read(sc, RT2860_TX_STAT_FIFO, &stat);
2510208019Sthompsa		DPRINTFN(4, "tx stat 0x%08x\n", stat);
2511209917Sthompsa		if (!(stat & RT2860_TXQ_VLD))
2512208019Sthompsa			break;
2513203134Sthompsa
2514208019Sthompsa		wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff;
2515203134Sthompsa
2516208019Sthompsa		/* if no ACK was requested, no feedback is available */
2517208019Sthompsa		if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX ||
2518208019Sthompsa		    wcid == 0)
2519208019Sthompsa			continue;
2520203134Sthompsa
2521218676Shselasky		/*
2522218676Shselasky		 * Even though each stat is Tx-complete-status like format,
2523218676Shselasky		 * the device can poll stats. Because there is no guarantee
2524218676Shselasky		 * that the referring node is still around when read the stats.
2525218676Shselasky		 * So that, if we use ieee80211_ratectl_tx_update(), we will
2526218676Shselasky		 * have hard time not to refer already freed node.
2527218676Shselasky		 *
2528218676Shselasky		 * To eliminate such page faults, we poll stats in softc.
2529218676Shselasky		 * Then, update the rates later with ieee80211_ratectl_tx_update().
2530218676Shselasky		 */
2531218676Shselasky		wstat = &(sc->wcid_stats[wcid]);
2532218676Shselasky		(*wstat)[RUN_TXCNT]++;
2533218676Shselasky		if (stat & RT2860_TXQ_OK)
2534218676Shselasky			(*wstat)[RUN_SUCCESS]++;
2535218676Shselasky		else
2536287197Sglebius			counter_u64_add(sc->sc_ic.ic_oerrors, 1);
2537218676Shselasky		/*
2538218676Shselasky		 * Check if there were retries, ie if the Tx success rate is
2539218676Shselasky		 * different from the requested rate. Note that it works only
2540218676Shselasky		 * because we do not allow rate fallback from OFDM to CCK.
2541218676Shselasky		 */
2542218676Shselasky		mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f;
2543218676Shselasky		pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf;
2544218676Shselasky		if ((retry = pid -1 - mcs) > 0) {
2545218676Shselasky			(*wstat)[RUN_TXCNT] += retry;
2546218676Shselasky			(*wstat)[RUN_RETRY] += retry;
2547203134Sthompsa		}
2548208019Sthompsa	}
2549208019Sthompsa	DPRINTFN(3, "count=%d\n", sc->fifo_cnt);
2550208019Sthompsa
2551208019Sthompsa	sc->fifo_cnt = 0;
2552208019Sthompsa}
2553208019Sthompsa
2554208019Sthompsastatic void
2555208019Sthompsarun_iter_func(void *arg, struct ieee80211_node *ni)
2556208019Sthompsa{
2557208019Sthompsa	struct run_softc *sc = arg;
2558208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
2559287552Skevlo	struct run_node *rn = RUN_NODE(ni);
2560218676Shselasky	union run_stats sta[2];
2561218676Shselasky	uint16_t (*wstat)[3];
2562218676Shselasky	int txcnt, success, retrycnt, error;
2563208019Sthompsa
2564218676Shselasky	RUN_LOCK(sc);
2565218676Shselasky
2566262795Shselasky	/* Check for special case */
2567262795Shselasky	if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA &&
2568262795Shselasky	    ni != vap->iv_bss)
2569262795Shselasky		goto fail;
2570262795Shselasky
2571209917Sthompsa	if (sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS ||
2572209917Sthompsa	    vap->iv_opmode == IEEE80211_M_STA)) {
2573203134Sthompsa		/* read statistic counters (clear on read) and update AMRR state */
2574203134Sthompsa		error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta,
2575203134Sthompsa		    sizeof sta);
2576203134Sthompsa		if (error != 0)
2577218676Shselasky			goto fail;
2578203134Sthompsa
2579203134Sthompsa		/* count failed TX as errors */
2580287197Sglebius		if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS,
2581287197Sglebius		    le16toh(sta[0].error.fail));
2582203134Sthompsa
2583218676Shselasky		retrycnt = le16toh(sta[1].tx.retry);
2584218676Shselasky		success = le16toh(sta[1].tx.success);
2585218676Shselasky		txcnt = retrycnt + success + le16toh(sta[0].error.fail);
2586203134Sthompsa
2587218676Shselasky		DPRINTFN(3, "retrycnt=%d success=%d failcnt=%d\n",
2588218676Shselasky			retrycnt, success, le16toh(sta[0].error.fail));
2589218676Shselasky	} else {
2590218676Shselasky		wstat = &(sc->wcid_stats[RUN_AID2WCID(ni->ni_associd)]);
2591203134Sthompsa
2592218676Shselasky		if (wstat == &(sc->wcid_stats[0]) ||
2593218676Shselasky		    wstat > &(sc->wcid_stats[RT2870_WCID_MAX]))
2594218676Shselasky			goto fail;
2595208019Sthompsa
2596218676Shselasky		txcnt = (*wstat)[RUN_TXCNT];
2597218676Shselasky		success = (*wstat)[RUN_SUCCESS];
2598218676Shselasky		retrycnt = (*wstat)[RUN_RETRY];
2599218676Shselasky		DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n",
2600218676Shselasky		    retrycnt, txcnt, success);
2601208019Sthompsa
2602218676Shselasky		memset(wstat, 0, sizeof(*wstat));
2603203134Sthompsa	}
2604203134Sthompsa
2605218676Shselasky	ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt);
2606208019Sthompsa	rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0);
2607218676Shselasky
2608218676Shselaskyfail:
2609218676Shselasky	RUN_UNLOCK(sc);
2610218676Shselasky
2611208019Sthompsa	DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx);
2612208019Sthompsa}
2613203134Sthompsa
2614208019Sthompsastatic void
2615208019Sthompsarun_newassoc_cb(void *arg)
2616208019Sthompsa{
2617208019Sthompsa	struct run_cmdq *cmdq = arg;
2618208019Sthompsa	struct ieee80211_node *ni = cmdq->arg1;
2619286950Sadrian	struct run_softc *sc = ni->ni_vap->iv_ic->ic_softc;
2620208019Sthompsa	uint8_t wcid = cmdq->wcid;
2621203134Sthompsa
2622208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2623208019Sthompsa
2624208019Sthompsa	run_write_region_1(sc, RT2860_WCID_ENTRY(wcid),
2625208019Sthompsa	    ni->ni_macaddr, IEEE80211_ADDR_LEN);
2626218676Shselasky
2627218676Shselasky	memset(&(sc->wcid_stats[wcid]), 0, sizeof(sc->wcid_stats[wcid]));
2628203134Sthompsa}
2629203134Sthompsa
2630203134Sthompsastatic void
2631203134Sthompsarun_newassoc(struct ieee80211_node *ni, int isnew)
2632203134Sthompsa{
2633287552Skevlo	struct run_node *rn = RUN_NODE(ni);
2634203134Sthompsa	struct ieee80211_rateset *rs = &ni->ni_rates;
2635208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
2636208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2637286950Sadrian	struct run_softc *sc = ic->ic_softc;
2638203134Sthompsa	uint8_t rate;
2639208019Sthompsa	uint8_t ridx;
2640245047Shselasky	uint8_t wcid;
2641208019Sthompsa	int i, j;
2642203134Sthompsa
2643245047Shselasky	wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2644245047Shselasky	    1 : RUN_AID2WCID(ni->ni_associd);
2645245047Shselasky
2646209917Sthompsa	if (wcid > RT2870_WCID_MAX) {
2647208019Sthompsa		device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid);
2648208019Sthompsa		return;
2649208019Sthompsa	}
2650203134Sthompsa
2651208019Sthompsa	/* only interested in true associations */
2652209917Sthompsa	if (isnew && ni->ni_associd != 0) {
2653208019Sthompsa
2654208019Sthompsa		/*
2655208019Sthompsa		 * This function could is called though timeout function.
2656208019Sthompsa		 * Need to defer.
2657208019Sthompsa		 */
2658208019Sthompsa		uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store);
2659208019Sthompsa		DPRINTF("cmdq_store=%d\n", cnt);
2660208019Sthompsa		sc->cmdq[cnt].func = run_newassoc_cb;
2661208019Sthompsa		sc->cmdq[cnt].arg0 = NULL;
2662208019Sthompsa		sc->cmdq[cnt].arg1 = ni;
2663208019Sthompsa		sc->cmdq[cnt].wcid = wcid;
2664208019Sthompsa		ieee80211_runtask(ic, &sc->cmdq_task);
2665208019Sthompsa	}
2666208019Sthompsa
2667208019Sthompsa	DPRINTF("new assoc isnew=%d associd=%x addr=%s\n",
2668208019Sthompsa	    isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr));
2669208019Sthompsa
2670203134Sthompsa	for (i = 0; i < rs->rs_nrates; i++) {
2671203134Sthompsa		rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
2672203134Sthompsa		/* convert 802.11 rate to hardware rate index */
2673203134Sthompsa		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2674203134Sthompsa			if (rt2860_rates[ridx].rate == rate)
2675203134Sthompsa				break;
2676203134Sthompsa		rn->ridx[i] = ridx;
2677203134Sthompsa		/* determine rate of control response frames */
2678203134Sthompsa		for (j = i; j >= 0; j--) {
2679203134Sthompsa			if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) &&
2680203134Sthompsa			    rt2860_rates[rn->ridx[i]].phy ==
2681203134Sthompsa			    rt2860_rates[rn->ridx[j]].phy)
2682203134Sthompsa				break;
2683203134Sthompsa		}
2684203134Sthompsa		if (j >= 0) {
2685203134Sthompsa			rn->ctl_ridx[i] = rn->ridx[j];
2686203134Sthompsa		} else {
2687203134Sthompsa			/* no basic rate found, use mandatory one */
2688203134Sthompsa			rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx;
2689203134Sthompsa		}
2690203134Sthompsa		DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n",
2691203134Sthompsa		    rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]);
2692203134Sthompsa	}
2693208019Sthompsa	rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate;
2694208019Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2695208019Sthompsa		if (rt2860_rates[ridx].rate == rate)
2696208019Sthompsa			break;
2697208019Sthompsa	rn->mgt_ridx = ridx;
2698208019Sthompsa	DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx);
2699208019Sthompsa
2700262795Shselasky	RUN_LOCK(sc);
2701262795Shselasky	if(sc->ratectl_run != RUN_RATECTL_OFF)
2702262795Shselasky		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2703262795Shselasky	RUN_UNLOCK(sc);
2704203134Sthompsa}
2705203134Sthompsa
2706203134Sthompsa/*
2707203134Sthompsa * Return the Rx chain with the highest RSSI for a given frame.
2708203134Sthompsa */
2709203134Sthompsastatic __inline uint8_t
2710203134Sthompsarun_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi)
2711203134Sthompsa{
2712203134Sthompsa	uint8_t rxchain = 0;
2713203134Sthompsa
2714203134Sthompsa	if (sc->nrxchains > 1) {
2715203134Sthompsa		if (rxwi->rssi[1] > rxwi->rssi[rxchain])
2716203134Sthompsa			rxchain = 1;
2717203134Sthompsa		if (sc->nrxchains > 2)
2718203134Sthompsa			if (rxwi->rssi[2] > rxwi->rssi[rxchain])
2719203134Sthompsa				rxchain = 2;
2720203134Sthompsa	}
2721209917Sthompsa	return (rxchain);
2722203134Sthompsa}
2723203134Sthompsa
2724203134Sthompsastatic void
2725203134Sthompsarun_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen)
2726203134Sthompsa{
2727287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
2728203134Sthompsa	struct ieee80211_frame *wh;
2729203134Sthompsa	struct ieee80211_node *ni;
2730203134Sthompsa	struct rt2870_rxd *rxd;
2731203134Sthompsa	struct rt2860_rxwi *rxwi;
2732203134Sthompsa	uint32_t flags;
2733259032Skevlo	uint16_t len, rxwisize;
2734203134Sthompsa	uint8_t ant, rssi;
2735203134Sthompsa	int8_t nf;
2736203134Sthompsa
2737203134Sthompsa	rxwi = mtod(m, struct rt2860_rxwi *);
2738203134Sthompsa	len = le16toh(rxwi->len) & 0xfff;
2739260219Skevlo	rxwisize = sizeof(struct rt2860_rxwi);
2740260219Skevlo	if (sc->mac_ver == 0x5592)
2741260219Skevlo		rxwisize += sizeof(uint64_t);
2742260219Skevlo	else if (sc->mac_ver == 0x3593)
2743260219Skevlo		rxwisize += sizeof(uint32_t);
2744203134Sthompsa	if (__predict_false(len > dmalen)) {
2745203134Sthompsa		m_freem(m);
2746287197Sglebius		counter_u64_add(ic->ic_ierrors, 1);
2747203134Sthompsa		DPRINTF("bad RXWI length %u > %u\n", len, dmalen);
2748203134Sthompsa		return;
2749203134Sthompsa	}
2750203134Sthompsa	/* Rx descriptor is located at the end */
2751203134Sthompsa	rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen);
2752203134Sthompsa	flags = le32toh(rxd->flags);
2753203134Sthompsa
2754203134Sthompsa	if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) {
2755203134Sthompsa		m_freem(m);
2756287197Sglebius		counter_u64_add(ic->ic_ierrors, 1);
2757203134Sthompsa		DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV");
2758203134Sthompsa		return;
2759203134Sthompsa	}
2760203134Sthompsa
2761259032Skevlo	m->m_data += rxwisize;
2762259032Skevlo	m->m_pkthdr.len = m->m_len -= rxwisize;
2763203134Sthompsa
2764203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
2765203134Sthompsa
2766260444Skevlo	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
2767260444Skevlo		wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
2768203134Sthompsa		m->m_flags |= M_WEP;
2769203134Sthompsa	}
2770203134Sthompsa
2771209917Sthompsa	if (flags & RT2860_RX_L2PAD) {
2772203134Sthompsa		DPRINTFN(8, "received RT2860_RX_L2PAD frame\n");
2773203134Sthompsa		len += 2;
2774203134Sthompsa	}
2775203134Sthompsa
2776208019Sthompsa	ni = ieee80211_find_rxnode(ic,
2777208019Sthompsa	    mtod(m, struct ieee80211_frame_min *));
2778208019Sthompsa
2779203134Sthompsa	if (__predict_false(flags & RT2860_RX_MICERR)) {
2780203134Sthompsa		/* report MIC failures to net80211 for TKIP */
2781209917Sthompsa		if (ni != NULL)
2782259032Skevlo			ieee80211_notify_michael_failure(ni->ni_vap, wh,
2783259032Skevlo			    rxwi->keyidx);
2784203134Sthompsa		m_freem(m);
2785287197Sglebius		counter_u64_add(ic->ic_ierrors, 1);
2786203134Sthompsa		DPRINTF("MIC error. Someone is lying.\n");
2787203134Sthompsa		return;
2788203134Sthompsa	}
2789203134Sthompsa
2790203134Sthompsa	ant = run_maxrssi_chain(sc, rxwi);
2791203134Sthompsa	rssi = rxwi->rssi[ant];
2792203134Sthompsa	nf = run_rssi2dbm(sc, rssi, ant);
2793203134Sthompsa
2794203134Sthompsa	m->m_pkthdr.len = m->m_len = len;
2795203134Sthompsa
2796203134Sthompsa	if (ni != NULL) {
2797203134Sthompsa		(void)ieee80211_input(ni, m, rssi, nf);
2798203134Sthompsa		ieee80211_free_node(ni);
2799203134Sthompsa	} else {
2800203134Sthompsa		(void)ieee80211_input_all(ic, m, rssi, nf);
2801203134Sthompsa	}
2802203134Sthompsa
2803209917Sthompsa	if (__predict_false(ieee80211_radiotap_active(ic))) {
2804203134Sthompsa		struct run_rx_radiotap_header *tap = &sc->sc_rxtap;
2805258643Shselasky		uint16_t phy;
2806203134Sthompsa
2807203134Sthompsa		tap->wr_flags = 0;
2808236439Shselasky		tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
2809236439Shselasky		tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
2810203134Sthompsa		tap->wr_antsignal = rssi;
2811203134Sthompsa		tap->wr_antenna = ant;
2812203134Sthompsa		tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant);
2813203134Sthompsa		tap->wr_rate = 2;	/* in case it can't be found below */
2814203134Sthompsa		phy = le16toh(rxwi->phy);
2815203134Sthompsa		switch (phy & RT2860_PHY_MODE) {
2816203134Sthompsa		case RT2860_PHY_CCK:
2817203134Sthompsa			switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) {
2818203134Sthompsa			case 0:	tap->wr_rate =   2; break;
2819203134Sthompsa			case 1:	tap->wr_rate =   4; break;
2820203134Sthompsa			case 2:	tap->wr_rate =  11; break;
2821203134Sthompsa			case 3:	tap->wr_rate =  22; break;
2822203134Sthompsa			}
2823203134Sthompsa			if (phy & RT2860_PHY_SHPRE)
2824203134Sthompsa				tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
2825203134Sthompsa			break;
2826203134Sthompsa		case RT2860_PHY_OFDM:
2827203134Sthompsa			switch (phy & RT2860_PHY_MCS) {
2828203134Sthompsa			case 0:	tap->wr_rate =  12; break;
2829203134Sthompsa			case 1:	tap->wr_rate =  18; break;
2830203134Sthompsa			case 2:	tap->wr_rate =  24; break;
2831203134Sthompsa			case 3:	tap->wr_rate =  36; break;
2832203134Sthompsa			case 4:	tap->wr_rate =  48; break;
2833203134Sthompsa			case 5:	tap->wr_rate =  72; break;
2834203134Sthompsa			case 6:	tap->wr_rate =  96; break;
2835203134Sthompsa			case 7:	tap->wr_rate = 108; break;
2836203134Sthompsa			}
2837203134Sthompsa			break;
2838203134Sthompsa		}
2839203134Sthompsa	}
2840203134Sthompsa}
2841203134Sthompsa
2842203134Sthompsastatic void
2843203134Sthompsarun_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
2844203134Sthompsa{
2845203134Sthompsa	struct run_softc *sc = usbd_xfer_softc(xfer);
2846287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
2847203134Sthompsa	struct mbuf *m = NULL;
2848203134Sthompsa	struct mbuf *m0;
2849203134Sthompsa	uint32_t dmalen;
2850259032Skevlo	uint16_t rxwisize;
2851203134Sthompsa	int xferlen;
2852203134Sthompsa
2853260219Skevlo	rxwisize = sizeof(struct rt2860_rxwi);
2854260219Skevlo	if (sc->mac_ver == 0x5592)
2855260219Skevlo		rxwisize += sizeof(uint64_t);
2856260219Skevlo	else if (sc->mac_ver == 0x3593)
2857260219Skevlo		rxwisize += sizeof(uint32_t);
2858259032Skevlo
2859203134Sthompsa	usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL);
2860203134Sthompsa
2861203134Sthompsa	switch (USB_GET_STATE(xfer)) {
2862203134Sthompsa	case USB_ST_TRANSFERRED:
2863203134Sthompsa
2864203134Sthompsa		DPRINTFN(15, "rx done, actlen=%d\n", xferlen);
2865203134Sthompsa
2866259032Skevlo		if (xferlen < (int)(sizeof(uint32_t) + rxwisize +
2867259032Skevlo		    sizeof(struct rt2870_rxd))) {
2868203134Sthompsa			DPRINTF("xfer too short %d\n", xferlen);
2869203134Sthompsa			goto tr_setup;
2870203134Sthompsa		}
2871203134Sthompsa
2872203134Sthompsa		m = sc->rx_m;
2873203134Sthompsa		sc->rx_m = NULL;
2874203134Sthompsa
2875203134Sthompsa		/* FALLTHROUGH */
2876203134Sthompsa	case USB_ST_SETUP:
2877203134Sthompsatr_setup:
2878203134Sthompsa		if (sc->rx_m == NULL) {
2879243857Sglebius			sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
2880203134Sthompsa			    MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */);
2881203134Sthompsa		}
2882203134Sthompsa		if (sc->rx_m == NULL) {
2883203134Sthompsa			DPRINTF("could not allocate mbuf - idle with stall\n");
2884287197Sglebius			counter_u64_add(ic->ic_ierrors, 1);
2885203134Sthompsa			usbd_xfer_set_stall(xfer);
2886203134Sthompsa			usbd_xfer_set_frames(xfer, 0);
2887203134Sthompsa		} else {
2888203134Sthompsa			/*
2889203134Sthompsa			 * Directly loading a mbuf cluster into DMA to
2890203134Sthompsa			 * save some data copying. This works because
2891203134Sthompsa			 * there is only one cluster.
2892203134Sthompsa			 */
2893203134Sthompsa			usbd_xfer_set_frame_data(xfer, 0,
2894203134Sthompsa			    mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ);
2895203134Sthompsa			usbd_xfer_set_frames(xfer, 1);
2896203134Sthompsa		}
2897203134Sthompsa		usbd_transfer_submit(xfer);
2898203134Sthompsa		break;
2899203134Sthompsa
2900203134Sthompsa	default:	/* Error */
2901203134Sthompsa		if (error != USB_ERR_CANCELLED) {
2902203134Sthompsa			/* try to clear stall first */
2903203134Sthompsa			usbd_xfer_set_stall(xfer);
2904203134Sthompsa			if (error == USB_ERR_TIMEOUT)
2905203134Sthompsa				device_printf(sc->sc_dev, "device timeout\n");
2906287197Sglebius			counter_u64_add(ic->ic_ierrors, 1);
2907203134Sthompsa			goto tr_setup;
2908203134Sthompsa		}
2909209917Sthompsa		if (sc->rx_m != NULL) {
2910203134Sthompsa			m_freem(sc->rx_m);
2911203134Sthompsa			sc->rx_m = NULL;
2912203134Sthompsa		}
2913203134Sthompsa		break;
2914203134Sthompsa	}
2915203134Sthompsa
2916203134Sthompsa	if (m == NULL)
2917203134Sthompsa		return;
2918203134Sthompsa
2919203134Sthompsa	/* inputting all the frames must be last */
2920203134Sthompsa
2921203134Sthompsa	RUN_UNLOCK(sc);
2922203134Sthompsa
2923203134Sthompsa	m->m_pkthdr.len = m->m_len = xferlen;
2924203134Sthompsa
2925203134Sthompsa	/* HW can aggregate multiple 802.11 frames in a single USB xfer */
2926203134Sthompsa	for(;;) {
2927203134Sthompsa		dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff;
2928203134Sthompsa
2929233774Shselasky		if ((dmalen >= (uint32_t)-8) || (dmalen == 0) ||
2930233774Shselasky		    ((dmalen & 3) != 0)) {
2931203134Sthompsa			DPRINTF("bad DMA length %u\n", dmalen);
2932203134Sthompsa			break;
2933203134Sthompsa		}
2934233774Shselasky		if ((dmalen + 8) > (uint32_t)xferlen) {
2935203134Sthompsa			DPRINTF("bad DMA length %u > %d\n",
2936203134Sthompsa			dmalen + 8, xferlen);
2937203134Sthompsa			break;
2938203134Sthompsa		}
2939203134Sthompsa
2940203134Sthompsa		/* If it is the last one or a single frame, we won't copy. */
2941209917Sthompsa		if ((xferlen -= dmalen + 8) <= 8) {
2942203134Sthompsa			/* trim 32-bit DMA-len header */
2943203134Sthompsa			m->m_data += 4;
2944203134Sthompsa			m->m_pkthdr.len = m->m_len -= 4;
2945203134Sthompsa			run_rx_frame(sc, m, dmalen);
2946257435Shselasky			m = NULL;	/* don't free source buffer */
2947203134Sthompsa			break;
2948203134Sthompsa		}
2949203134Sthompsa
2950203134Sthompsa		/* copy aggregated frames to another mbuf */
2951243857Sglebius		m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
2952203134Sthompsa		if (__predict_false(m0 == NULL)) {
2953203134Sthompsa			DPRINTF("could not allocate mbuf\n");
2954287197Sglebius			counter_u64_add(ic->ic_ierrors, 1);
2955203134Sthompsa			break;
2956203134Sthompsa		}
2957203134Sthompsa		m_copydata(m, 4 /* skip 32-bit DMA-len header */,
2958203134Sthompsa		    dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t));
2959203134Sthompsa		m0->m_pkthdr.len = m0->m_len =
2960203134Sthompsa		    dmalen + sizeof(struct rt2870_rxd);
2961203134Sthompsa		run_rx_frame(sc, m0, dmalen);
2962203134Sthompsa
2963203134Sthompsa		/* update data ptr */
2964203134Sthompsa		m->m_data += dmalen + 8;
2965203134Sthompsa		m->m_pkthdr.len = m->m_len -= dmalen + 8;
2966203134Sthompsa	}
2967203134Sthompsa
2968257435Shselasky	/* make sure we free the source buffer, if any */
2969257435Shselasky	m_freem(m);
2970257435Shselasky
2971203134Sthompsa	RUN_LOCK(sc);
2972203134Sthompsa}
2973203134Sthompsa
2974203134Sthompsastatic void
2975203134Sthompsarun_tx_free(struct run_endpoint_queue *pq,
2976203134Sthompsa    struct run_tx_data *data, int txerr)
2977203134Sthompsa{
2978203134Sthompsa	if (data->m != NULL) {
2979203134Sthompsa		if (data->m->m_flags & M_TXCB)
2980203134Sthompsa			ieee80211_process_callback(data->ni, data->m,
2981203134Sthompsa			    txerr ? ETIMEDOUT : 0);
2982203134Sthompsa		m_freem(data->m);
2983203134Sthompsa		data->m = NULL;
2984203134Sthompsa
2985209917Sthompsa		if (data->ni == NULL) {
2986203134Sthompsa			DPRINTF("no node\n");
2987203134Sthompsa		} else {
2988203134Sthompsa			ieee80211_free_node(data->ni);
2989203134Sthompsa			data->ni = NULL;
2990203134Sthompsa		}
2991203134Sthompsa	}
2992203134Sthompsa
2993203134Sthompsa	STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
2994203134Sthompsa	pq->tx_nfree++;
2995203134Sthompsa}
2996203134Sthompsa
2997203134Sthompsastatic void
2998257429Shselaskyrun_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index)
2999203134Sthompsa{
3000203134Sthompsa	struct run_softc *sc = usbd_xfer_softc(xfer);
3001287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3002203134Sthompsa	struct run_tx_data *data;
3003203134Sthompsa	struct ieee80211vap *vap = NULL;
3004203134Sthompsa	struct usb_page_cache *pc;
3005203134Sthompsa	struct run_endpoint_queue *pq = &sc->sc_epq[index];
3006203134Sthompsa	struct mbuf *m;
3007203134Sthompsa	usb_frlength_t size;
3008203134Sthompsa	int actlen;
3009203134Sthompsa	int sumlen;
3010203134Sthompsa
3011203134Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
3012203134Sthompsa
3013209917Sthompsa	switch (USB_GET_STATE(xfer)) {
3014203134Sthompsa	case USB_ST_TRANSFERRED:
3015203134Sthompsa		DPRINTFN(11, "transfer complete: %d "
3016203134Sthompsa		    "bytes @ index %d\n", actlen, index);
3017203134Sthompsa
3018203134Sthompsa		data = usbd_xfer_get_priv(xfer);
3019203134Sthompsa		run_tx_free(pq, data, 0);
3020203134Sthompsa		usbd_xfer_set_priv(xfer, NULL);
3021203134Sthompsa
3022203134Sthompsa		/* FALLTHROUGH */
3023203134Sthompsa	case USB_ST_SETUP:
3024203134Sthompsatr_setup:
3025203134Sthompsa		data = STAILQ_FIRST(&pq->tx_qh);
3026209917Sthompsa		if (data == NULL)
3027203134Sthompsa			break;
3028203134Sthompsa
3029203134Sthompsa		STAILQ_REMOVE_HEAD(&pq->tx_qh, next);
3030203134Sthompsa
3031203134Sthompsa		m = data->m;
3032261330Shselasky		size = (sc->mac_ver == 0x5592) ?
3033261330Shselasky		    sizeof(data->desc) + sizeof(uint32_t) : sizeof(data->desc);
3034261076Shselasky		if ((m->m_pkthdr.len +
3035261330Shselasky		    size + 3 + 8) > RUN_MAX_TXSZ) {
3036203134Sthompsa			DPRINTF("data overflow, %u bytes\n",
3037203134Sthompsa			    m->m_pkthdr.len);
3038203134Sthompsa			run_tx_free(pq, data, 1);
3039203134Sthompsa			goto tr_setup;
3040203134Sthompsa		}
3041203134Sthompsa
3042203134Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
3043203134Sthompsa		usbd_copy_in(pc, 0, &data->desc, size);
3044203134Sthompsa		usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len);
3045228508Shselasky		size += m->m_pkthdr.len;
3046228508Shselasky		/*
3047228508Shselasky		 * Align end on a 4-byte boundary, pad 8 bytes (CRC +
3048228508Shselasky		 * 4-byte padding), and be sure to zero those trailing
3049228508Shselasky		 * bytes:
3050228508Shselasky		 */
3051228508Shselasky		usbd_frame_zero(pc, size, ((-size) & 3) + 8);
3052228508Shselasky		size += ((-size) & 3) + 8;
3053203134Sthompsa
3054203134Sthompsa		vap = data->ni->ni_vap;
3055203134Sthompsa		if (ieee80211_radiotap_active_vap(vap)) {
3056203134Sthompsa			struct run_tx_radiotap_header *tap = &sc->sc_txtap;
3057259032Skevlo			struct rt2860_txwi *txwi =
3058208019Sthompsa			    (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd));
3059203134Sthompsa			tap->wt_flags = 0;
3060203134Sthompsa			tap->wt_rate = rt2860_rates[data->ridx].rate;
3061236439Shselasky			tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
3062236439Shselasky			tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
3063203134Sthompsa			tap->wt_hwqueue = index;
3064208019Sthompsa			if (le16toh(txwi->phy) & RT2860_PHY_SHPRE)
3065203134Sthompsa				tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
3066203134Sthompsa
3067203134Sthompsa			ieee80211_radiotap_tx(vap, m);
3068203134Sthompsa		}
3069203134Sthompsa
3070228508Shselasky		DPRINTFN(11, "sending frame len=%u/%u  @ index %d\n",
3071228508Shselasky		    m->m_pkthdr.len, size, index);
3072203134Sthompsa
3073228508Shselasky		usbd_xfer_set_frame_len(xfer, 0, size);
3074203134Sthompsa		usbd_xfer_set_priv(xfer, data);
3075203134Sthompsa		usbd_transfer_submit(xfer);
3076287197Sglebius		run_start(sc);
3077203134Sthompsa
3078203134Sthompsa		break;
3079203134Sthompsa
3080203134Sthompsa	default:
3081203134Sthompsa		DPRINTF("USB transfer error, %s\n",
3082203134Sthompsa		    usbd_errstr(error));
3083203134Sthompsa
3084203134Sthompsa		data = usbd_xfer_get_priv(xfer);
3085203134Sthompsa
3086203134Sthompsa		if (data != NULL) {
3087208019Sthompsa			if(data->ni != NULL)
3088208019Sthompsa				vap = data->ni->ni_vap;
3089203134Sthompsa			run_tx_free(pq, data, error);
3090203134Sthompsa			usbd_xfer_set_priv(xfer, NULL);
3091203134Sthompsa		}
3092287197Sglebius
3093209917Sthompsa		if (vap == NULL)
3094208019Sthompsa			vap = TAILQ_FIRST(&ic->ic_vaps);
3095203134Sthompsa
3096203134Sthompsa		if (error != USB_ERR_CANCELLED) {
3097203134Sthompsa			if (error == USB_ERR_TIMEOUT) {
3098203134Sthompsa				device_printf(sc->sc_dev, "device timeout\n");
3099208019Sthompsa				uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3100208019Sthompsa				DPRINTF("cmdq_store=%d\n", i);
3101208019Sthompsa				sc->cmdq[i].func = run_usb_timeout_cb;
3102208019Sthompsa				sc->cmdq[i].arg0 = vap;
3103208019Sthompsa				ieee80211_runtask(ic, &sc->cmdq_task);
3104203134Sthompsa			}
3105203134Sthompsa
3106203134Sthompsa			/*
3107203134Sthompsa			 * Try to clear stall first, also if other
3108203134Sthompsa			 * errors occur, hence clearing stall
3109203134Sthompsa			 * introduces a 50 ms delay:
3110203134Sthompsa			 */
3111203134Sthompsa			usbd_xfer_set_stall(xfer);
3112203134Sthompsa			goto tr_setup;
3113203134Sthompsa		}
3114203134Sthompsa		break;
3115203134Sthompsa	}
3116203134Sthompsa}
3117203134Sthompsa
3118203134Sthompsastatic void
3119203134Sthompsarun_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error)
3120203134Sthompsa{
3121203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 0);
3122203134Sthompsa}
3123203134Sthompsa
3124203134Sthompsastatic void
3125203134Sthompsarun_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error)
3126203134Sthompsa{
3127203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 1);
3128203134Sthompsa}
3129203134Sthompsa
3130203134Sthompsastatic void
3131203134Sthompsarun_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error)
3132203134Sthompsa{
3133203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 2);
3134203134Sthompsa}
3135203134Sthompsa
3136203134Sthompsastatic void
3137203134Sthompsarun_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error)
3138203134Sthompsa{
3139203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 3);
3140203134Sthompsa}
3141203134Sthompsa
3142203134Sthompsastatic void
3143203134Sthompsarun_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error)
3144203134Sthompsa{
3145203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 4);
3146203134Sthompsa}
3147203134Sthompsa
3148203134Sthompsastatic void
3149203134Sthompsarun_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error)
3150203134Sthompsa{
3151203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 5);
3152203134Sthompsa}
3153203134Sthompsa
3154203134Sthompsastatic void
3155208019Sthompsarun_set_tx_desc(struct run_softc *sc, struct run_tx_data *data)
3156203134Sthompsa{
3157203134Sthompsa	struct mbuf *m = data->m;
3158287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3159208019Sthompsa	struct ieee80211vap *vap = data->ni->ni_vap;
3160203134Sthompsa	struct ieee80211_frame *wh;
3161203134Sthompsa	struct rt2870_txd *txd;
3162203134Sthompsa	struct rt2860_txwi *txwi;
3163259032Skevlo	uint16_t xferlen, txwisize;
3164208019Sthompsa	uint16_t mcs;
3165203134Sthompsa	uint8_t ridx = data->ridx;
3166208019Sthompsa	uint8_t pad;
3167203134Sthompsa
3168203134Sthompsa	/* get MCS code from rate index */
3169208019Sthompsa	mcs = rt2860_rates[ridx].mcs;
3170203134Sthompsa
3171259032Skevlo	txwisize = (sc->mac_ver == 0x5592) ?
3172259032Skevlo	    sizeof(*txwi) + sizeof(uint32_t) : sizeof(*txwi);
3173259032Skevlo	xferlen = txwisize + m->m_pkthdr.len;
3174203134Sthompsa
3175203134Sthompsa	/* roundup to 32-bit alignment */
3176203134Sthompsa	xferlen = (xferlen + 3) & ~3;
3177203134Sthompsa
3178203134Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3179203134Sthompsa	txd->len = htole16(xferlen);
3180203134Sthompsa
3181208019Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3182208019Sthompsa
3183208019Sthompsa	/*
3184208019Sthompsa	 * Ether both are true or both are false, the header
3185208019Sthompsa	 * are nicely aligned to 32-bit. So, no L2 padding.
3186208019Sthompsa	 */
3187208019Sthompsa	if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh))
3188208019Sthompsa		pad = 0;
3189208019Sthompsa	else
3190208019Sthompsa		pad = 2;
3191208019Sthompsa
3192203134Sthompsa	/* setup TX Wireless Information */
3193203134Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3194203134Sthompsa	txwi->len = htole16(m->m_pkthdr.len - pad);
3195203134Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_DS) {
3196270192Skevlo		mcs |= RT2860_PHY_CCK;
3197203134Sthompsa		if (ridx != RT2860_RIDX_CCK1 &&
3198203134Sthompsa		    (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
3199203134Sthompsa			mcs |= RT2860_PHY_SHPRE;
3200203134Sthompsa	} else
3201270192Skevlo		mcs |= RT2860_PHY_OFDM;
3202270192Skevlo	txwi->phy = htole16(mcs);
3203203134Sthompsa
3204203134Sthompsa	/* check if RTS/CTS or CTS-to-self protection is required */
3205203134Sthompsa	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3206203134Sthompsa	    (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold ||
3207203134Sthompsa	     ((ic->ic_flags & IEEE80211_F_USEPROT) &&
3208203134Sthompsa	      rt2860_rates[ridx].phy == IEEE80211_T_OFDM)))
3209208019Sthompsa		txwi->txop |= RT2860_TX_TXOP_HT;
3210203134Sthompsa	else
3211208019Sthompsa		txwi->txop |= RT2860_TX_TXOP_BACKOFF;
3212209144Sthompsa
3213209917Sthompsa	if (vap->iv_opmode != IEEE80211_M_STA && !IEEE80211_QOS_HAS_SEQ(wh))
3214209144Sthompsa		txwi->xflags |= RT2860_TX_NSEQ;
3215203134Sthompsa}
3216203134Sthompsa
3217203134Sthompsa/* This function must be called locked */
3218203134Sthompsastatic int
3219203134Sthompsarun_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3220203134Sthompsa{
3221287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3222208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
3223203134Sthompsa	struct ieee80211_frame *wh;
3224208019Sthompsa	struct ieee80211_channel *chan;
3225203134Sthompsa	const struct ieee80211_txparam *tp;
3226287552Skevlo	struct run_node *rn = RUN_NODE(ni);
3227203134Sthompsa	struct run_tx_data *data;
3228208019Sthompsa	struct rt2870_txd *txd;
3229208019Sthompsa	struct rt2860_txwi *txwi;
3230203134Sthompsa	uint16_t qos;
3231203134Sthompsa	uint16_t dur;
3232208019Sthompsa	uint16_t qid;
3233203134Sthompsa	uint8_t type;
3234203134Sthompsa	uint8_t tid;
3235208019Sthompsa	uint8_t ridx;
3236208019Sthompsa	uint8_t ctl_ridx;
3237203134Sthompsa	uint8_t qflags;
3238203134Sthompsa	uint8_t xflags = 0;
3239203134Sthompsa	int hasqos;
3240203134Sthompsa
3241203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3242203134Sthompsa
3243203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3244203134Sthompsa
3245203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3246203134Sthompsa
3247203134Sthompsa	/*
3248203134Sthompsa	 * There are 7 bulk endpoints: 1 for RX
3249203134Sthompsa	 * and 6 for TX (4 EDCAs + HCCA + Prio).
3250203134Sthompsa	 * Update 03-14-2009:  some devices like the Planex GW-US300MiniS
3251203134Sthompsa	 * seem to have only 4 TX bulk endpoints (Fukaumi Naoki).
3252203134Sthompsa	 */
3253203134Sthompsa	if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) {
3254203134Sthompsa		uint8_t *frm;
3255203134Sthompsa
3256203134Sthompsa		if(IEEE80211_HAS_ADDR4(wh))
3257203134Sthompsa			frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos;
3258203134Sthompsa		else
3259203134Sthompsa			frm =((struct ieee80211_qosframe *)wh)->i_qos;
3260203134Sthompsa
3261203134Sthompsa		qos = le16toh(*(const uint16_t *)frm);
3262203134Sthompsa		tid = qos & IEEE80211_QOS_TID;
3263203134Sthompsa		qid = TID_TO_WME_AC(tid);
3264203134Sthompsa	} else {
3265203134Sthompsa		qos = 0;
3266203134Sthompsa		tid = 0;
3267203134Sthompsa		qid = WME_AC_BE;
3268203134Sthompsa	}
3269203134Sthompsa	qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA;
3270203134Sthompsa
3271203134Sthompsa	DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n",
3272203134Sthompsa	    qos, qid, tid, qflags);
3273203134Sthompsa
3274208019Sthompsa	chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan;
3275208019Sthompsa	tp = &vap->iv_txparms[ieee80211_chan2mode(chan)];
3276203134Sthompsa
3277203134Sthompsa	/* pickup a rate index */
3278203134Sthompsa	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
3279270192Skevlo	    type != IEEE80211_FC0_TYPE_DATA || m->m_flags & M_EAPOL) {
3280203134Sthompsa		ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
3281203134Sthompsa		    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
3282203134Sthompsa		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3283203134Sthompsa	} else {
3284208019Sthompsa		if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
3285208019Sthompsa			ridx = rn->fix_ridx;
3286208019Sthompsa		else
3287208019Sthompsa			ridx = rn->amrr_ridx;
3288203134Sthompsa		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3289203134Sthompsa	}
3290203134Sthompsa
3291203134Sthompsa	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3292203134Sthompsa	    (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) !=
3293203134Sthompsa	     IEEE80211_QOS_ACKPOLICY_NOACK)) {
3294209144Sthompsa		xflags |= RT2860_TX_ACK;
3295203134Sthompsa		if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
3296208019Sthompsa			dur = rt2860_rates[ctl_ridx].sp_ack_dur;
3297203134Sthompsa		else
3298208019Sthompsa			dur = rt2860_rates[ctl_ridx].lp_ack_dur;
3299258919Shselasky		USETW(wh->i_dur, dur);
3300203134Sthompsa	}
3301203134Sthompsa
3302203134Sthompsa	/* reserve slots for mgmt packets, just in case */
3303203134Sthompsa	if (sc->sc_epq[qid].tx_nfree < 3) {
3304203134Sthompsa		DPRINTFN(10, "tx ring %d is full\n", qid);
3305203134Sthompsa		return (-1);
3306203134Sthompsa	}
3307203134Sthompsa
3308203134Sthompsa	data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh);
3309203134Sthompsa	STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next);
3310203134Sthompsa	sc->sc_epq[qid].tx_nfree--;
3311203134Sthompsa
3312208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3313208019Sthompsa	txd->flags = qflags;
3314208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3315208019Sthompsa	txwi->xflags = xflags;
3316259032Skevlo	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
3317245047Shselasky		txwi->wcid = 0;
3318259032Skevlo	else
3319245047Shselasky		txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
3320245047Shselasky		    1 : RUN_AID2WCID(ni->ni_associd);
3321259032Skevlo
3322208019Sthompsa	/* clear leftover garbage bits */
3323208019Sthompsa	txwi->flags = 0;
3324208019Sthompsa	txwi->txop = 0;
3325208019Sthompsa
3326203134Sthompsa	data->m = m;
3327203134Sthompsa	data->ni = ni;
3328203134Sthompsa	data->ridx = ridx;
3329203134Sthompsa
3330208019Sthompsa	run_set_tx_desc(sc, data);
3331203134Sthompsa
3332208019Sthompsa	/*
3333208019Sthompsa	 * The chip keeps track of 2 kind of Tx stats,
3334208019Sthompsa	 *  * TX_STAT_FIFO, for per WCID stats, and
3335208019Sthompsa	 *  * TX_STA_CNT0 for all-TX-in-one stats.
3336208019Sthompsa	 *
3337208019Sthompsa	 * To use FIFO stats, we need to store MCS into the driver-private
3338208019Sthompsa 	 * PacketID field. So that, we can tell whose stats when we read them.
3339208019Sthompsa 	 * We add 1 to the MCS because setting the PacketID field to 0 means
3340208019Sthompsa 	 * that we don't want feedback in TX_STAT_FIFO.
3341208019Sthompsa 	 * And, that's what we want for STA mode, since TX_STA_CNT0 does the job.
3342208019Sthompsa 	 *
3343208019Sthompsa 	 * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx().
3344208019Sthompsa 	 */
3345209917Sthompsa	if (sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP ||
3346209917Sthompsa	    vap->iv_opmode == IEEE80211_M_MBSS) {
3347208019Sthompsa		uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf;
3348208019Sthompsa		txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT);
3349208019Sthompsa
3350208019Sthompsa		/*
3351208019Sthompsa		 * Unlike PCI based devices, we don't get any interrupt from
3352208019Sthompsa		 * USB devices, so we simulate FIFO-is-full interrupt here.
3353208019Sthompsa		 * Ralink recomends to drain FIFO stats every 100 ms, but 16 slots
3354208019Sthompsa		 * quickly get fulled. To prevent overflow, increment a counter on
3355208019Sthompsa		 * every FIFO stat request, so we know how many slots are left.
3356208019Sthompsa		 * We do this only in HOSTAP or multiple vap mode since FIFO stats
3357208019Sthompsa		 * are used only in those modes.
3358208019Sthompsa		 * We just drain stats. AMRR gets updated every 1 sec by
3359208019Sthompsa		 * run_ratectl_cb() via callout.
3360208019Sthompsa		 * Call it early. Otherwise overflow.
3361208019Sthompsa		 */
3362209917Sthompsa		if (sc->fifo_cnt++ == 10) {
3363208019Sthompsa			/*
3364208019Sthompsa			 * With multiple vaps or if_bridge, if_start() is called
3365208019Sthompsa			 * with a non-sleepable lock, tcpinp. So, need to defer.
3366208019Sthompsa			 */
3367208019Sthompsa			uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3368208019Sthompsa			DPRINTFN(6, "cmdq_store=%d\n", i);
3369208019Sthompsa			sc->cmdq[i].func = run_drain_fifo;
3370208019Sthompsa			sc->cmdq[i].arg0 = sc;
3371208019Sthompsa			ieee80211_runtask(ic, &sc->cmdq_task);
3372208019Sthompsa		}
3373208019Sthompsa	}
3374208019Sthompsa
3375203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next);
3376203134Sthompsa
3377203134Sthompsa	usbd_transfer_start(sc->sc_xfer[qid]);
3378203134Sthompsa
3379258840Skevlo	DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n",
3380259032Skevlo	    m->m_pkthdr.len + (int)(sizeof(struct rt2870_txd) +
3381259046Shselasky	    sizeof(struct rt2860_txwi)), rt2860_rates[ridx].rate, qid);
3382203134Sthompsa
3383203134Sthompsa	return (0);
3384203134Sthompsa}
3385203134Sthompsa
3386203134Sthompsastatic int
3387203134Sthompsarun_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3388203134Sthompsa{
3389287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3390287552Skevlo	struct run_node *rn = RUN_NODE(ni);
3391203134Sthompsa	struct run_tx_data *data;
3392203134Sthompsa	struct ieee80211_frame *wh;
3393208019Sthompsa	struct rt2870_txd *txd;
3394208019Sthompsa	struct rt2860_txwi *txwi;
3395203134Sthompsa	uint16_t dur;
3396208019Sthompsa	uint8_t ridx = rn->mgt_ridx;
3397203134Sthompsa	uint8_t type;
3398203134Sthompsa	uint8_t xflags = 0;
3399208019Sthompsa	uint8_t wflags = 0;
3400203134Sthompsa
3401203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3402203134Sthompsa
3403203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3404203134Sthompsa
3405203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3406203134Sthompsa
3407208019Sthompsa	/* tell hardware to add timestamp for probe responses */
3408208019Sthompsa	if ((wh->i_fc[0] &
3409208019Sthompsa	    (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
3410208019Sthompsa	    (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
3411208019Sthompsa		wflags |= RT2860_TX_TS;
3412208019Sthompsa	else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3413203134Sthompsa		xflags |= RT2860_TX_ACK;
3414203134Sthompsa
3415208019Sthompsa		dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate,
3416203134Sthompsa		    ic->ic_flags & IEEE80211_F_SHPREAMBLE);
3417258919Shselasky		USETW(wh->i_dur, dur);
3418203134Sthompsa	}
3419203134Sthompsa
3420287197Sglebius	if (sc->sc_epq[0].tx_nfree == 0)
3421203134Sthompsa		/* let caller free mbuf */
3422203134Sthompsa		return (EIO);
3423203134Sthompsa	data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3424203134Sthompsa	STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3425203134Sthompsa	sc->sc_epq[0].tx_nfree--;
3426203134Sthompsa
3427208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3428208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3429208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3430208019Sthompsa	txwi->wcid = 0xff;
3431208019Sthompsa	txwi->flags = wflags;
3432208019Sthompsa	txwi->xflags = xflags;
3433208019Sthompsa	txwi->txop = 0;	/* clear leftover garbage bits */
3434208019Sthompsa
3435203134Sthompsa	data->m = m;
3436203134Sthompsa	data->ni = ni;
3437203134Sthompsa	data->ridx = ridx;
3438203134Sthompsa
3439208019Sthompsa	run_set_tx_desc(sc, data);
3440203134Sthompsa
3441203134Sthompsa	DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len +
3442258840Skevlo	    (int)(sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi)),
3443208019Sthompsa	    rt2860_rates[ridx].rate);
3444203134Sthompsa
3445203134Sthompsa	STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3446203134Sthompsa
3447203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3448203134Sthompsa
3449203134Sthompsa	return (0);
3450203134Sthompsa}
3451203134Sthompsa
3452203134Sthompsastatic int
3453203134Sthompsarun_sendprot(struct run_softc *sc,
3454203134Sthompsa    const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate)
3455203134Sthompsa{
3456203134Sthompsa	struct ieee80211com *ic = ni->ni_ic;
3457203134Sthompsa	struct ieee80211_frame *wh;
3458203134Sthompsa	struct run_tx_data *data;
3459208019Sthompsa	struct rt2870_txd *txd;
3460208019Sthompsa	struct rt2860_txwi *txwi;
3461203134Sthompsa	struct mbuf *mprot;
3462203134Sthompsa	int ridx;
3463203134Sthompsa	int protrate;
3464203134Sthompsa	int ackrate;
3465203134Sthompsa	int pktlen;
3466203134Sthompsa	int isshort;
3467203134Sthompsa	uint16_t dur;
3468203134Sthompsa	uint8_t type;
3469208019Sthompsa	uint8_t wflags = 0;
3470208019Sthompsa	uint8_t xflags = 0;
3471203134Sthompsa
3472203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3473203134Sthompsa
3474203134Sthompsa	KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY,
3475203134Sthompsa	    ("protection %d", prot));
3476203134Sthompsa
3477203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3478203134Sthompsa	pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
3479203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3480203134Sthompsa
3481203134Sthompsa	protrate = ieee80211_ctl_rate(ic->ic_rt, rate);
3482203134Sthompsa	ackrate = ieee80211_ack_rate(ic->ic_rt, rate);
3483203134Sthompsa
3484203134Sthompsa	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
3485209189Sjkim	dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort)
3486203134Sthompsa	    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3487203134Sthompsa	wflags = RT2860_TX_FRAG;
3488203134Sthompsa
3489203134Sthompsa	/* check that there are free slots before allocating the mbuf */
3490287197Sglebius	if (sc->sc_epq[0].tx_nfree == 0)
3491203134Sthompsa		/* let caller free mbuf */
3492203134Sthompsa		return (ENOBUFS);
3493203134Sthompsa
3494203134Sthompsa	if (prot == IEEE80211_PROT_RTSCTS) {
3495203134Sthompsa		/* NB: CTS is the same size as an ACK */
3496203134Sthompsa		dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3497208019Sthompsa		xflags |= RT2860_TX_ACK;
3498203134Sthompsa		mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur);
3499203134Sthompsa	} else {
3500203134Sthompsa		mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur);
3501203134Sthompsa	}
3502203134Sthompsa	if (mprot == NULL) {
3503287197Sglebius		if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1);
3504203134Sthompsa		DPRINTF("could not allocate mbuf\n");
3505203134Sthompsa		return (ENOBUFS);
3506203134Sthompsa	}
3507203134Sthompsa
3508203134Sthompsa        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3509203134Sthompsa        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3510203134Sthompsa        sc->sc_epq[0].tx_nfree--;
3511203134Sthompsa
3512208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3513208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3514208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3515208019Sthompsa	txwi->wcid = 0xff;
3516208019Sthompsa	txwi->flags = wflags;
3517208019Sthompsa	txwi->xflags = xflags;
3518208019Sthompsa	txwi->txop = 0;	/* clear leftover garbage bits */
3519208019Sthompsa
3520203134Sthompsa	data->m = mprot;
3521203134Sthompsa	data->ni = ieee80211_ref_node(ni);
3522203134Sthompsa
3523203134Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3524203134Sthompsa		if (rt2860_rates[ridx].rate == protrate)
3525203134Sthompsa			break;
3526203134Sthompsa	data->ridx = ridx;
3527203134Sthompsa
3528208019Sthompsa	run_set_tx_desc(sc, data);
3529203134Sthompsa
3530203134Sthompsa        DPRINTFN(1, "sending prot len=%u rate=%u\n",
3531203134Sthompsa            m->m_pkthdr.len, rate);
3532203134Sthompsa
3533203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3534203134Sthompsa
3535203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3536203134Sthompsa
3537203134Sthompsa	return (0);
3538203134Sthompsa}
3539203134Sthompsa
3540203134Sthompsastatic int
3541203134Sthompsarun_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
3542203134Sthompsa    const struct ieee80211_bpf_params *params)
3543203134Sthompsa{
3544203134Sthompsa	struct ieee80211com *ic = ni->ni_ic;
3545203134Sthompsa	struct ieee80211_frame *wh;
3546203134Sthompsa	struct run_tx_data *data;
3547208019Sthompsa	struct rt2870_txd *txd;
3548208019Sthompsa	struct rt2860_txwi *txwi;
3549203134Sthompsa	uint8_t type;
3550208019Sthompsa	uint8_t ridx;
3551208019Sthompsa	uint8_t rate;
3552208019Sthompsa	uint8_t opflags = 0;
3553208019Sthompsa	uint8_t xflags = 0;
3554203134Sthompsa	int error;
3555203134Sthompsa
3556203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3557203134Sthompsa
3558203134Sthompsa	KASSERT(params != NULL, ("no raw xmit params"));
3559203134Sthompsa
3560203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3561203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3562203134Sthompsa
3563203134Sthompsa	rate = params->ibp_rate0;
3564203134Sthompsa	if (!ieee80211_isratevalid(ic->ic_rt, rate)) {
3565203134Sthompsa		/* let caller free mbuf */
3566203134Sthompsa		return (EINVAL);
3567203134Sthompsa	}
3568203134Sthompsa
3569203134Sthompsa	if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0)
3570208019Sthompsa		xflags |= RT2860_TX_ACK;
3571203134Sthompsa	if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) {
3572203134Sthompsa		error = run_sendprot(sc, m, ni,
3573203134Sthompsa		    params->ibp_flags & IEEE80211_BPF_RTS ?
3574203134Sthompsa			IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY,
3575203134Sthompsa		    rate);
3576203134Sthompsa		if (error) {
3577203134Sthompsa			/* let caller free mbuf */
3578209917Sthompsa			return error;
3579203134Sthompsa		}
3580203134Sthompsa		opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS;
3581203134Sthompsa	}
3582203134Sthompsa
3583203134Sthompsa	if (sc->sc_epq[0].tx_nfree == 0) {
3584203134Sthompsa		/* let caller free mbuf */
3585203134Sthompsa		DPRINTF("sending raw frame, but tx ring is full\n");
3586203134Sthompsa		return (EIO);
3587203134Sthompsa	}
3588203134Sthompsa        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3589203134Sthompsa        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3590203134Sthompsa        sc->sc_epq[0].tx_nfree--;
3591203134Sthompsa
3592208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3593208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3594208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3595208019Sthompsa	txwi->wcid = 0xff;
3596208019Sthompsa	txwi->xflags = xflags;
3597208019Sthompsa	txwi->txop = opflags;
3598208019Sthompsa	txwi->flags = 0;	/* clear leftover garbage bits */
3599208019Sthompsa
3600203134Sthompsa        data->m = m;
3601203134Sthompsa        data->ni = ni;
3602203134Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3603203134Sthompsa		if (rt2860_rates[ridx].rate == rate)
3604203134Sthompsa			break;
3605203134Sthompsa	data->ridx = ridx;
3606203134Sthompsa
3607208019Sthompsa        run_set_tx_desc(sc, data);
3608203134Sthompsa
3609203134Sthompsa        DPRINTFN(10, "sending raw frame len=%u rate=%u\n",
3610203134Sthompsa            m->m_pkthdr.len, rate);
3611203134Sthompsa
3612203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3613203134Sthompsa
3614203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3615203134Sthompsa
3616209917Sthompsa        return (0);
3617203134Sthompsa}
3618203134Sthompsa
3619203134Sthompsastatic int
3620203134Sthompsarun_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
3621203134Sthompsa    const struct ieee80211_bpf_params *params)
3622203134Sthompsa{
3623286950Sadrian	struct run_softc *sc = ni->ni_ic->ic_softc;
3624208019Sthompsa	int error = 0;
3625208019Sthompsa
3626203134Sthompsa	RUN_LOCK(sc);
3627203134Sthompsa
3628203134Sthompsa	/* prevent management frames from being sent if we're not ready */
3629287197Sglebius	if (!(sc->sc_flags & RUN_RUNNING)) {
3630287197Sglebius		error = ENETDOWN;
3631208019Sthompsa		goto done;
3632203134Sthompsa	}
3633203134Sthompsa
3634203134Sthompsa	if (params == NULL) {
3635203134Sthompsa		/* tx mgt packet */
3636209917Sthompsa		if ((error = run_tx_mgt(sc, m, ni)) != 0) {
3637203134Sthompsa			DPRINTF("mgt tx failed\n");
3638208019Sthompsa			goto done;
3639203134Sthompsa		}
3640203134Sthompsa	} else {
3641203134Sthompsa		/* tx raw packet with param */
3642209917Sthompsa		if ((error = run_tx_param(sc, m, ni, params)) != 0) {
3643203134Sthompsa			DPRINTF("tx with param failed\n");
3644208019Sthompsa			goto done;
3645203134Sthompsa		}
3646203134Sthompsa	}
3647203134Sthompsa
3648208019Sthompsadone:
3649203134Sthompsa	RUN_UNLOCK(sc);
3650203134Sthompsa
3651209917Sthompsa	if (error != 0) {
3652208019Sthompsa		if(m != NULL)
3653208019Sthompsa			m_freem(m);
3654208019Sthompsa		ieee80211_free_node(ni);
3655208019Sthompsa	}
3656203134Sthompsa
3657203134Sthompsa	return (error);
3658203134Sthompsa}
3659203134Sthompsa
3660287197Sglebiusstatic int
3661287197Sglebiusrun_transmit(struct ieee80211com *ic, struct mbuf *m)
3662287197Sglebius{
3663287197Sglebius	struct run_softc *sc = ic->ic_softc;
3664287197Sglebius	int error;
3665287197Sglebius
3666287197Sglebius	RUN_LOCK(sc);
3667287197Sglebius	if ((sc->sc_flags & RUN_RUNNING) == 0) {
3668287197Sglebius		RUN_UNLOCK(sc);
3669287197Sglebius		return (ENXIO);
3670287197Sglebius	}
3671287197Sglebius	error = mbufq_enqueue(&sc->sc_snd, m);
3672287197Sglebius	if (error) {
3673287197Sglebius		RUN_UNLOCK(sc);
3674287197Sglebius		return (error);
3675287197Sglebius	}
3676287197Sglebius	run_start(sc);
3677287197Sglebius	RUN_UNLOCK(sc);
3678287197Sglebius
3679287197Sglebius	return (0);
3680287197Sglebius}
3681287197Sglebius
3682203134Sthompsastatic void
3683287197Sglebiusrun_start(struct run_softc *sc)
3684203134Sthompsa{
3685203134Sthompsa	struct ieee80211_node *ni;
3686203134Sthompsa	struct mbuf *m;
3687203134Sthompsa
3688287197Sglebius	RUN_LOCK_ASSERT(sc, MA_OWNED);
3689203134Sthompsa
3690287197Sglebius	if ((sc->sc_flags & RUN_RUNNING) == 0)
3691203134Sthompsa		return;
3692203134Sthompsa
3693287197Sglebius	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
3694203134Sthompsa		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
3695203134Sthompsa		if (run_tx(sc, m, ni) != 0) {
3696287197Sglebius			mbufq_prepend(&sc->sc_snd, m);
3697203134Sthompsa			break;
3698203134Sthompsa		}
3699203134Sthompsa	}
3700203134Sthompsa}
3701203134Sthompsa
3702287197Sglebiusstatic void
3703287197Sglebiusrun_parent(struct ieee80211com *ic)
3704203134Sthompsa{
3705286950Sadrian	struct run_softc *sc = ic->ic_softc;
3706208019Sthompsa	int startall = 0;
3707203134Sthompsa
3708246614Shselasky	RUN_LOCK(sc);
3709287197Sglebius	if (sc->sc_detached) {
3710203134Sthompsa		RUN_UNLOCK(sc);
3711287197Sglebius		return;
3712203134Sthompsa	}
3713203134Sthompsa
3714287197Sglebius	if (ic->ic_nrunning > 0) {
3715287197Sglebius		if (!(sc->sc_flags & RUN_RUNNING)) {
3716287197Sglebius			startall = 1;
3717287197Sglebius			run_init_locked(sc);
3718287197Sglebius		} else
3719287197Sglebius			run_update_promisc_locked(sc);
3720287197Sglebius	} else if ((sc->sc_flags & RUN_RUNNING) && sc->rvp_cnt <= 1)
3721287197Sglebius		run_stop(sc);
3722287197Sglebius	RUN_UNLOCK(sc);
3723287197Sglebius	if (startall)
3724287197Sglebius		ieee80211_start_all(ic);
3725203134Sthompsa}
3726203134Sthompsa
3727203134Sthompsastatic void
3728259544Skevlorun_iq_calib(struct run_softc *sc, u_int chan)
3729259544Skevlo{
3730259544Skevlo	uint16_t val;
3731259544Skevlo
3732259544Skevlo	/* Tx0 IQ gain. */
3733259544Skevlo	run_bbp_write(sc, 158, 0x2c);
3734259544Skevlo	if (chan <= 14)
3735259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX0_2GHZ, &val, 1);
3736259544Skevlo	else if (chan <= 64) {
3737259544Skevlo		run_efuse_read(sc,
3738259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5GHZ,
3739259544Skevlo		    &val, 1);
3740259544Skevlo	} else if (chan <= 138) {
3741259544Skevlo		run_efuse_read(sc,
3742259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5GHZ,
3743259544Skevlo		    &val, 1);
3744259544Skevlo	} else if (chan <= 165) {
3745259544Skevlo		run_efuse_read(sc,
3746259544Skevlo	    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5GHZ,
3747259544Skevlo		    &val, 1);
3748259544Skevlo	} else
3749259544Skevlo		val = 0;
3750259547Skevlo	run_bbp_write(sc, 159, val);
3751259544Skevlo
3752259544Skevlo	/* Tx0 IQ phase. */
3753259544Skevlo	run_bbp_write(sc, 158, 0x2d);
3754259544Skevlo	if (chan <= 14) {
3755259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX0_2GHZ,
3756259544Skevlo		    &val, 1);
3757259544Skevlo	} else if (chan <= 64) {
3758259544Skevlo		run_efuse_read(sc,
3759259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5GHZ,
3760259544Skevlo		    &val, 1);
3761259544Skevlo	} else if (chan <= 138) {
3762259544Skevlo		run_efuse_read(sc,
3763259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5GHZ,
3764259544Skevlo		    &val, 1);
3765259544Skevlo	} else if (chan <= 165) {
3766259544Skevlo		run_efuse_read(sc,
3767259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5GHZ,
3768259544Skevlo		    &val, 1);
3769259544Skevlo	} else
3770259544Skevlo		val = 0;
3771259547Skevlo	run_bbp_write(sc, 159, val);
3772259544Skevlo
3773259544Skevlo	/* Tx1 IQ gain. */
3774259544Skevlo	run_bbp_write(sc, 158, 0x4a);
3775259544Skevlo	if (chan <= 14) {
3776259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX1_2GHZ,
3777259544Skevlo		    &val, 1);
3778259544Skevlo	} else if (chan <= 64) {
3779259544Skevlo		run_efuse_read(sc,
3780259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5GHZ,
3781259544Skevlo		    &val, 1);
3782259544Skevlo	} else if (chan <= 138) {
3783259544Skevlo		run_efuse_read(sc,
3784259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5GHZ,
3785259544Skevlo		    &val, 1);
3786259544Skevlo	} else if (chan <= 165) {
3787259544Skevlo		run_efuse_read(sc,
3788259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5GHZ,
3789259544Skevlo		    &val, 1);
3790259544Skevlo	} else
3791259544Skevlo		val = 0;
3792259547Skevlo	run_bbp_write(sc, 159, val);
3793259544Skevlo
3794259544Skevlo	/* Tx1 IQ phase. */
3795259544Skevlo	run_bbp_write(sc, 158, 0x4b);
3796259544Skevlo	if (chan <= 14) {
3797259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX1_2GHZ,
3798259544Skevlo		    &val, 1);
3799259544Skevlo	} else if (chan <= 64) {
3800259544Skevlo		run_efuse_read(sc,
3801259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5GHZ,
3802259544Skevlo		    &val, 1);
3803259544Skevlo	} else if (chan <= 138) {
3804259544Skevlo		run_efuse_read(sc,
3805259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5GHZ,
3806259544Skevlo		    &val, 1);
3807259544Skevlo	} else if (chan <= 165) {
3808259544Skevlo		run_efuse_read(sc,
3809259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5GHZ,
3810259544Skevlo		    &val, 1);
3811259544Skevlo	} else
3812259544Skevlo		val = 0;
3813259547Skevlo	run_bbp_write(sc, 159, val);
3814259544Skevlo
3815259544Skevlo	/* RF IQ compensation control. */
3816259544Skevlo	run_bbp_write(sc, 158, 0x04);
3817259544Skevlo	run_efuse_read(sc, RT5390_EEPROM_RF_IQ_COMPENSATION_CTL,
3818259544Skevlo	    &val, 1);
3819259547Skevlo	run_bbp_write(sc, 159, val);
3820259544Skevlo
3821259544Skevlo	/* RF IQ imbalance compensation control. */
3822259544Skevlo	run_bbp_write(sc, 158, 0x03);
3823259544Skevlo	run_efuse_read(sc,
3824259544Skevlo	    RT5390_EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CTL, &val, 1);
3825259547Skevlo	run_bbp_write(sc, 159, val);
3826259544Skevlo}
3827259544Skevlo
3828259544Skevlostatic void
3829205042Sthompsarun_set_agc(struct run_softc *sc, uint8_t agc)
3830205042Sthompsa{
3831205042Sthompsa	uint8_t bbp;
3832205042Sthompsa
3833205042Sthompsa	if (sc->mac_ver == 0x3572) {
3834205042Sthompsa		run_bbp_read(sc, 27, &bbp);
3835205042Sthompsa		bbp &= ~(0x3 << 5);
3836205042Sthompsa		run_bbp_write(sc, 27, bbp | 0 << 5);	/* select Rx0 */
3837205042Sthompsa		run_bbp_write(sc, 66, agc);
3838205042Sthompsa		run_bbp_write(sc, 27, bbp | 1 << 5);	/* select Rx1 */
3839205042Sthompsa		run_bbp_write(sc, 66, agc);
3840205042Sthompsa	} else
3841205042Sthompsa		run_bbp_write(sc, 66, agc);
3842205042Sthompsa}
3843205042Sthompsa
3844205042Sthompsastatic void
3845203134Sthompsarun_select_chan_group(struct run_softc *sc, int group)
3846203134Sthompsa{
3847203134Sthompsa	uint32_t tmp;
3848205042Sthompsa	uint8_t agc;
3849203134Sthompsa
3850203134Sthompsa	run_bbp_write(sc, 62, 0x37 - sc->lna[group]);
3851203134Sthompsa	run_bbp_write(sc, 63, 0x37 - sc->lna[group]);
3852203134Sthompsa	run_bbp_write(sc, 64, 0x37 - sc->lna[group]);
3853258082Skevlo	if (sc->mac_ver < 0x3572)
3854257955Skevlo		run_bbp_write(sc, 86, 0x00);
3855203134Sthompsa
3856260219Skevlo	if (sc->mac_ver == 0x3593) {
3857260219Skevlo		run_bbp_write(sc, 77, 0x98);
3858260219Skevlo		run_bbp_write(sc, 83, (group == 0) ? 0x8a : 0x9a);
3859260219Skevlo	}
3860260219Skevlo
3861203134Sthompsa	if (group == 0) {
3862203134Sthompsa		if (sc->ext_2ghz_lna) {
3863257955Skevlo			if (sc->mac_ver >= 0x5390)
3864257955Skevlo				run_bbp_write(sc, 75, 0x52);
3865257955Skevlo			else {
3866257955Skevlo				run_bbp_write(sc, 82, 0x62);
3867257955Skevlo				run_bbp_write(sc, 75, 0x46);
3868257955Skevlo			}
3869203134Sthompsa		} else {
3870259032Skevlo			if (sc->mac_ver == 0x5592) {
3871259032Skevlo				run_bbp_write(sc, 79, 0x1c);
3872259032Skevlo				run_bbp_write(sc, 80, 0x0e);
3873259032Skevlo				run_bbp_write(sc, 81, 0x3a);
3874259032Skevlo				run_bbp_write(sc, 82, 0x62);
3875259032Skevlo
3876259032Skevlo				run_bbp_write(sc, 195, 0x80);
3877259032Skevlo				run_bbp_write(sc, 196, 0xe0);
3878259032Skevlo				run_bbp_write(sc, 195, 0x81);
3879259032Skevlo				run_bbp_write(sc, 196, 0x1f);
3880259032Skevlo				run_bbp_write(sc, 195, 0x82);
3881259032Skevlo				run_bbp_write(sc, 196, 0x38);
3882259032Skevlo				run_bbp_write(sc, 195, 0x83);
3883259032Skevlo				run_bbp_write(sc, 196, 0x32);
3884259032Skevlo				run_bbp_write(sc, 195, 0x85);
3885259032Skevlo				run_bbp_write(sc, 196, 0x28);
3886259032Skevlo				run_bbp_write(sc, 195, 0x86);
3887259032Skevlo				run_bbp_write(sc, 196, 0x19);
3888259032Skevlo			} else if (sc->mac_ver >= 0x5390)
3889257955Skevlo				run_bbp_write(sc, 75, 0x50);
3890257955Skevlo			else {
3891260219Skevlo				run_bbp_write(sc, 82,
3892260219Skevlo				    (sc->mac_ver == 0x3593) ? 0x62 : 0x84);
3893257955Skevlo				run_bbp_write(sc, 75, 0x50);
3894257955Skevlo			}
3895203134Sthompsa		}
3896203134Sthompsa	} else {
3897259032Skevlo		if (sc->mac_ver == 0x5592) {
3898259032Skevlo			run_bbp_write(sc, 79, 0x18);
3899259032Skevlo			run_bbp_write(sc, 80, 0x08);
3900259032Skevlo			run_bbp_write(sc, 81, 0x38);
3901259032Skevlo			run_bbp_write(sc, 82, 0x92);
3902259032Skevlo
3903259032Skevlo			run_bbp_write(sc, 195, 0x80);
3904259032Skevlo			run_bbp_write(sc, 196, 0xf0);
3905259032Skevlo			run_bbp_write(sc, 195, 0x81);
3906259032Skevlo			run_bbp_write(sc, 196, 0x1e);
3907259032Skevlo			run_bbp_write(sc, 195, 0x82);
3908259032Skevlo			run_bbp_write(sc, 196, 0x28);
3909259032Skevlo			run_bbp_write(sc, 195, 0x83);
3910259032Skevlo			run_bbp_write(sc, 196, 0x20);
3911259032Skevlo			run_bbp_write(sc, 195, 0x85);
3912259032Skevlo			run_bbp_write(sc, 196, 0x7f);
3913259032Skevlo			run_bbp_write(sc, 195, 0x86);
3914259032Skevlo			run_bbp_write(sc, 196, 0x7f);
3915259032Skevlo		} else if (sc->mac_ver == 0x3572)
3916205042Sthompsa			run_bbp_write(sc, 82, 0x94);
3917205042Sthompsa		else
3918260219Skevlo			run_bbp_write(sc, 82,
3919260219Skevlo			    (sc->mac_ver == 0x3593) ? 0x82 : 0xf2);
3920205042Sthompsa		if (sc->ext_5ghz_lna)
3921203134Sthompsa			run_bbp_write(sc, 75, 0x46);
3922205042Sthompsa		else
3923203134Sthompsa			run_bbp_write(sc, 75, 0x50);
3924203134Sthompsa	}
3925203134Sthompsa
3926203134Sthompsa	run_read(sc, RT2860_TX_BAND_CFG, &tmp);
3927203134Sthompsa	tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P);
3928203134Sthompsa	tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P;
3929203134Sthompsa	run_write(sc, RT2860_TX_BAND_CFG, tmp);
3930203134Sthompsa
3931203134Sthompsa	/* enable appropriate Power Amplifiers and Low Noise Amplifiers */
3932208019Sthompsa	tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN;
3933260219Skevlo	if (sc->mac_ver == 0x3593)
3934260219Skevlo		tmp |= 1 << 29 | 1 << 28;
3935208019Sthompsa	if (sc->nrxchains > 1)
3936208019Sthompsa		tmp |= RT2860_LNA_PE1_EN;
3937203134Sthompsa	if (group == 0) {	/* 2GHz */
3938208019Sthompsa		tmp |= RT2860_PA_PE_G0_EN;
3939203134Sthompsa		if (sc->ntxchains > 1)
3940203134Sthompsa			tmp |= RT2860_PA_PE_G1_EN;
3941260219Skevlo		if (sc->mac_ver == 0x3593) {
3942260219Skevlo			if (sc->ntxchains > 2)
3943260219Skevlo				tmp |= 1 << 25;
3944260219Skevlo		}
3945203134Sthompsa	} else {		/* 5GHz */
3946208019Sthompsa		tmp |= RT2860_PA_PE_A0_EN;
3947203134Sthompsa		if (sc->ntxchains > 1)
3948203134Sthompsa			tmp |= RT2860_PA_PE_A1_EN;
3949203134Sthompsa	}
3950205042Sthompsa	if (sc->mac_ver == 0x3572) {
3951205042Sthompsa		run_rt3070_rf_write(sc, 8, 0x00);
3952205042Sthompsa		run_write(sc, RT2860_TX_PIN_CFG, tmp);
3953205042Sthompsa		run_rt3070_rf_write(sc, 8, 0x80);
3954205042Sthompsa	} else
3955205042Sthompsa		run_write(sc, RT2860_TX_PIN_CFG, tmp);
3956203134Sthompsa
3957259032Skevlo	if (sc->mac_ver == 0x5592) {
3958259032Skevlo		run_bbp_write(sc, 195, 0x8d);
3959259032Skevlo		run_bbp_write(sc, 196, 0x1a);
3960259032Skevlo	}
3961259032Skevlo
3962260219Skevlo	if (sc->mac_ver == 0x3593) {
3963260219Skevlo		run_read(sc, RT2860_GPIO_CTRL, &tmp);
3964260219Skevlo		tmp &= ~0x01010000;
3965260219Skevlo		if (group == 0)
3966260219Skevlo			tmp |= 0x00010000;
3967260219Skevlo		tmp = (tmp & ~0x00009090) | 0x00000090;
3968260219Skevlo		run_write(sc, RT2860_GPIO_CTRL, tmp);
3969260219Skevlo	}
3970260219Skevlo
3971203134Sthompsa	/* set initial AGC value */
3972205042Sthompsa	if (group == 0) {	/* 2GHz band */
3973205042Sthompsa		if (sc->mac_ver >= 0x3070)
3974205042Sthompsa			agc = 0x1c + sc->lna[0] * 2;
3975205042Sthompsa		else
3976205042Sthompsa			agc = 0x2e + sc->lna[0];
3977205042Sthompsa	} else {		/* 5GHz band */
3978259032Skevlo		if (sc->mac_ver == 0x5592)
3979259032Skevlo			agc = 0x24 + sc->lna[group] * 2;
3980260219Skevlo		else if (sc->mac_ver == 0x3572 || sc->mac_ver == 0x3593)
3981205042Sthompsa			agc = 0x22 + (sc->lna[group] * 5) / 3;
3982205042Sthompsa		else
3983205042Sthompsa			agc = 0x32 + (sc->lna[group] * 5) / 3;
3984205042Sthompsa	}
3985205042Sthompsa	run_set_agc(sc, agc);
3986203134Sthompsa}
3987203134Sthompsa
3988203134Sthompsastatic void
3989257429Shselaskyrun_rt2870_set_chan(struct run_softc *sc, u_int chan)
3990203134Sthompsa{
3991203134Sthompsa	const struct rfprog *rfprog = rt2860_rf2850;
3992203134Sthompsa	uint32_t r2, r3, r4;
3993203134Sthompsa	int8_t txpow1, txpow2;
3994203134Sthompsa	int i;
3995203134Sthompsa
3996203134Sthompsa	/* find the settings for this channel (we know it exists) */
3997203134Sthompsa	for (i = 0; rfprog[i].chan != chan; i++);
3998203134Sthompsa
3999203134Sthompsa	r2 = rfprog[i].r2;
4000203134Sthompsa	if (sc->ntxchains == 1)
4001258732Skevlo		r2 |= 1 << 14;		/* 1T: disable Tx chain 2 */
4002203134Sthompsa	if (sc->nrxchains == 1)
4003258732Skevlo		r2 |= 1 << 17 | 1 << 6;	/* 1R: disable Rx chains 2 & 3 */
4004203134Sthompsa	else if (sc->nrxchains == 2)
4005258732Skevlo		r2 |= 1 << 6;		/* 2R: disable Rx chain 3 */
4006203134Sthompsa
4007203134Sthompsa	/* use Tx power values from EEPROM */
4008203134Sthompsa	txpow1 = sc->txpow1[i];
4009203134Sthompsa	txpow2 = sc->txpow2[i];
4010258732Skevlo
4011258732Skevlo	/* Initialize RF R3 and R4. */
4012258732Skevlo	r3 = rfprog[i].r3 & 0xffffc1ff;
4013258732Skevlo	r4 = (rfprog[i].r4 & ~(0x001f87c0)) | (sc->freq << 15);
4014203134Sthompsa	if (chan > 14) {
4015258732Skevlo		if (txpow1 >= 0) {
4016258732Skevlo			txpow1 = (txpow1 > 0xf) ? (0xf) : (txpow1);
4017258732Skevlo			r3 |= (txpow1 << 10) | (1 << 9);
4018258732Skevlo		} else {
4019258732Skevlo			txpow1 += 7;
4020258732Skevlo
4021258732Skevlo			/* txpow1 is not possible larger than 15. */
4022258732Skevlo			r3 |= (txpow1 << 10);
4023258732Skevlo		}
4024258732Skevlo		if (txpow2 >= 0) {
4025258732Skevlo			txpow2 = (txpow2 > 0xf) ? (0xf) : (txpow2);
4026258921Shselasky			r4 |= (txpow2 << 7) | (1 << 6);
4027258732Skevlo		} else {
4028258732Skevlo			txpow2 += 7;
4029258732Skevlo			r4 |= (txpow2 << 7);
4030258732Skevlo		}
4031258732Skevlo	} else {
4032258732Skevlo		/* Set Tx0 power. */
4033258732Skevlo		r3 |= (txpow1 << 9);
4034258732Skevlo
4035258732Skevlo		/* Set frequency offset and Tx1 power. */
4036258732Skevlo		r4 |= (txpow2 << 6);
4037203134Sthompsa	}
4038203134Sthompsa
4039258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4040258733Skevlo	run_rt2870_rf_write(sc, r2);
4041258733Skevlo	run_rt2870_rf_write(sc, r3 & ~(1 << 2));
4042258733Skevlo	run_rt2870_rf_write(sc, r4);
4043203134Sthompsa
4044203134Sthompsa	run_delay(sc, 10);
4045203134Sthompsa
4046258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4047258733Skevlo	run_rt2870_rf_write(sc, r2);
4048258733Skevlo	run_rt2870_rf_write(sc, r3 | (1 << 2));
4049258733Skevlo	run_rt2870_rf_write(sc, r4);
4050203134Sthompsa
4051203134Sthompsa	run_delay(sc, 10);
4052203134Sthompsa
4053258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4054258733Skevlo	run_rt2870_rf_write(sc, r2);
4055258733Skevlo	run_rt2870_rf_write(sc, r3 & ~(1 << 2));
4056258733Skevlo	run_rt2870_rf_write(sc, r4);
4057203134Sthompsa}
4058203134Sthompsa
4059203134Sthompsastatic void
4060257429Shselaskyrun_rt3070_set_chan(struct run_softc *sc, u_int chan)
4061203134Sthompsa{
4062203134Sthompsa	int8_t txpow1, txpow2;
4063203134Sthompsa	uint8_t rf;
4064205042Sthompsa	int i;
4065203134Sthompsa
4066205042Sthompsa	/* find the settings for this channel (we know it exists) */
4067205042Sthompsa	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4068205042Sthompsa
4069203134Sthompsa	/* use Tx power values from EEPROM */
4070205042Sthompsa	txpow1 = sc->txpow1[i];
4071205042Sthompsa	txpow2 = sc->txpow2[i];
4072203134Sthompsa
4073205042Sthompsa	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
4074256720Skevlo
4075256720Skevlo	/* RT3370/RT3390: RF R3 [7:4] is not reserved bits. */
4076256720Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4077256720Skevlo	rf = (rf & ~0x0f) | rt3070_freqs[i].k;
4078256720Skevlo	run_rt3070_rf_write(sc, 3, rf);
4079256720Skevlo
4080203134Sthompsa	run_rt3070_rf_read(sc, 6, &rf);
4081205042Sthompsa	rf = (rf & ~0x03) | rt3070_freqs[i].r;
4082203134Sthompsa	run_rt3070_rf_write(sc, 6, rf);
4083203134Sthompsa
4084203134Sthompsa	/* set Tx0 power */
4085203134Sthompsa	run_rt3070_rf_read(sc, 12, &rf);
4086203134Sthompsa	rf = (rf & ~0x1f) | txpow1;
4087203134Sthompsa	run_rt3070_rf_write(sc, 12, rf);
4088203134Sthompsa
4089203134Sthompsa	/* set Tx1 power */
4090203134Sthompsa	run_rt3070_rf_read(sc, 13, &rf);
4091203134Sthompsa	rf = (rf & ~0x1f) | txpow2;
4092203134Sthompsa	run_rt3070_rf_write(sc, 13, rf);
4093203134Sthompsa
4094203134Sthompsa	run_rt3070_rf_read(sc, 1, &rf);
4095203134Sthompsa	rf &= ~0xfc;
4096203134Sthompsa	if (sc->ntxchains == 1)
4097203134Sthompsa		rf |= 1 << 7 | 1 << 5;	/* 1T: disable Tx chains 2 & 3 */
4098203134Sthompsa	else if (sc->ntxchains == 2)
4099203134Sthompsa		rf |= 1 << 7;		/* 2T: disable Tx chain 3 */
4100203134Sthompsa	if (sc->nrxchains == 1)
4101203134Sthompsa		rf |= 1 << 6 | 1 << 4;	/* 1R: disable Rx chains 2 & 3 */
4102203134Sthompsa	else if (sc->nrxchains == 2)
4103203134Sthompsa		rf |= 1 << 6;		/* 2R: disable Rx chain 3 */
4104203134Sthompsa	run_rt3070_rf_write(sc, 1, rf);
4105203134Sthompsa
4106203134Sthompsa	/* set RF offset */
4107203134Sthompsa	run_rt3070_rf_read(sc, 23, &rf);
4108203134Sthompsa	rf = (rf & ~0x7f) | sc->freq;
4109203134Sthompsa	run_rt3070_rf_write(sc, 23, rf);
4110203134Sthompsa
4111203134Sthompsa	/* program RF filter */
4112205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf);	/* Tx */
4113205042Sthompsa	rf = (rf & ~0x3f) | sc->rf24_20mhz;
4114205042Sthompsa	run_rt3070_rf_write(sc, 24, rf);
4115205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);	/* Rx */
4116205042Sthompsa	rf = (rf & ~0x3f) | sc->rf24_20mhz;
4117205042Sthompsa	run_rt3070_rf_write(sc, 31, rf);
4118203134Sthompsa
4119203134Sthompsa	/* enable RF tuning */
4120203134Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4121203134Sthompsa	run_rt3070_rf_write(sc, 7, rf | 0x01);
4122203134Sthompsa}
4123203134Sthompsa
4124203134Sthompsastatic void
4125205042Sthompsarun_rt3572_set_chan(struct run_softc *sc, u_int chan)
4126205042Sthompsa{
4127205042Sthompsa	int8_t txpow1, txpow2;
4128205042Sthompsa	uint32_t tmp;
4129205042Sthompsa	uint8_t rf;
4130205042Sthompsa	int i;
4131205042Sthompsa
4132205042Sthompsa	/* find the settings for this channel (we know it exists) */
4133205042Sthompsa	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4134205042Sthompsa
4135205042Sthompsa	/* use Tx power values from EEPROM */
4136205042Sthompsa	txpow1 = sc->txpow1[i];
4137205042Sthompsa	txpow2 = sc->txpow2[i];
4138205042Sthompsa
4139205042Sthompsa	if (chan <= 14) {
4140205042Sthompsa		run_bbp_write(sc, 25, sc->bbp25);
4141205042Sthompsa		run_bbp_write(sc, 26, sc->bbp26);
4142205042Sthompsa	} else {
4143205042Sthompsa		/* enable IQ phase correction */
4144205042Sthompsa		run_bbp_write(sc, 25, 0x09);
4145205042Sthompsa		run_bbp_write(sc, 26, 0xff);
4146205042Sthompsa	}
4147205042Sthompsa
4148205042Sthompsa	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
4149205042Sthompsa	run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k);
4150205042Sthompsa	run_rt3070_rf_read(sc, 6, &rf);
4151205042Sthompsa	rf  = (rf & ~0x0f) | rt3070_freqs[i].r;
4152205042Sthompsa	rf |= (chan <= 14) ? 0x08 : 0x04;
4153205042Sthompsa	run_rt3070_rf_write(sc, 6, rf);
4154205042Sthompsa
4155205042Sthompsa	/* set PLL mode */
4156205042Sthompsa	run_rt3070_rf_read(sc, 5, &rf);
4157205042Sthompsa	rf &= ~(0x08 | 0x04);
4158205042Sthompsa	rf |= (chan <= 14) ? 0x04 : 0x08;
4159205042Sthompsa	run_rt3070_rf_write(sc, 5, rf);
4160205042Sthompsa
4161205042Sthompsa	/* set Tx power for chain 0 */
4162205042Sthompsa	if (chan <= 14)
4163205042Sthompsa		rf = 0x60 | txpow1;
4164205042Sthompsa	else
4165205042Sthompsa		rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3);
4166205042Sthompsa	run_rt3070_rf_write(sc, 12, rf);
4167205042Sthompsa
4168205042Sthompsa	/* set Tx power for chain 1 */
4169205042Sthompsa	if (chan <= 14)
4170205042Sthompsa		rf = 0x60 | txpow2;
4171205042Sthompsa	else
4172205042Sthompsa		rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3);
4173205042Sthompsa	run_rt3070_rf_write(sc, 13, rf);
4174205042Sthompsa
4175205042Sthompsa	/* set Tx/Rx streams */
4176205042Sthompsa	run_rt3070_rf_read(sc, 1, &rf);
4177205042Sthompsa	rf &= ~0xfc;
4178205042Sthompsa	if (sc->ntxchains == 1)
4179205042Sthompsa		rf |= 1 << 7 | 1 << 5;  /* 1T: disable Tx chains 2 & 3 */
4180205042Sthompsa	else if (sc->ntxchains == 2)
4181205042Sthompsa		rf |= 1 << 7;           /* 2T: disable Tx chain 3 */
4182205042Sthompsa	if (sc->nrxchains == 1)
4183205042Sthompsa		rf |= 1 << 6 | 1 << 4;  /* 1R: disable Rx chains 2 & 3 */
4184205042Sthompsa	else if (sc->nrxchains == 2)
4185205042Sthompsa		rf |= 1 << 6;           /* 2R: disable Rx chain 3 */
4186205042Sthompsa	run_rt3070_rf_write(sc, 1, rf);
4187205042Sthompsa
4188205042Sthompsa	/* set RF offset */
4189205042Sthompsa	run_rt3070_rf_read(sc, 23, &rf);
4190205042Sthompsa	rf = (rf & ~0x7f) | sc->freq;
4191205042Sthompsa	run_rt3070_rf_write(sc, 23, rf);
4192205042Sthompsa
4193205042Sthompsa	/* program RF filter */
4194205042Sthompsa	rf = sc->rf24_20mhz;
4195205042Sthompsa	run_rt3070_rf_write(sc, 24, rf);	/* Tx */
4196205042Sthompsa	run_rt3070_rf_write(sc, 31, rf);	/* Rx */
4197205042Sthompsa
4198205042Sthompsa	/* enable RF tuning */
4199205042Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4200205042Sthompsa	rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14);
4201205042Sthompsa	run_rt3070_rf_write(sc, 7, rf);
4202205042Sthompsa
4203205042Sthompsa	/* TSSI */
4204205042Sthompsa	rf = (chan <= 14) ? 0xc3 : 0xc0;
4205205042Sthompsa	run_rt3070_rf_write(sc, 9, rf);
4206205042Sthompsa
4207205042Sthompsa	/* set loop filter 1 */
4208205042Sthompsa	run_rt3070_rf_write(sc, 10, 0xf1);
4209205042Sthompsa	/* set loop filter 2 */
4210205042Sthompsa	run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00);
4211205042Sthompsa
4212205042Sthompsa	/* set tx_mx2_ic */
4213205042Sthompsa	run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43);
4214205042Sthompsa	/* set tx_mx1_ic */
4215205042Sthompsa	if (chan <= 14)
4216205042Sthompsa		rf = 0x48 | sc->txmixgain_2ghz;
4217205042Sthompsa	else
4218205042Sthompsa		rf = 0x78 | sc->txmixgain_5ghz;
4219205042Sthompsa	run_rt3070_rf_write(sc, 16, rf);
4220205042Sthompsa
4221205042Sthompsa	/* set tx_lo1 */
4222205042Sthompsa	run_rt3070_rf_write(sc, 17, 0x23);
4223205042Sthompsa	/* set tx_lo2 */
4224205042Sthompsa	if (chan <= 14)
4225205042Sthompsa		rf = 0x93;
4226205042Sthompsa	else if (chan <= 64)
4227205042Sthompsa		rf = 0xb7;
4228205042Sthompsa	else if (chan <= 128)
4229205042Sthompsa		rf = 0x74;
4230205042Sthompsa	else
4231205042Sthompsa		rf = 0x72;
4232205042Sthompsa	run_rt3070_rf_write(sc, 19, rf);
4233205042Sthompsa
4234205042Sthompsa	/* set rx_lo1 */
4235205042Sthompsa	if (chan <= 14)
4236205042Sthompsa		rf = 0xb3;
4237205042Sthompsa	else if (chan <= 64)
4238205042Sthompsa		rf = 0xf6;
4239205042Sthompsa	else if (chan <= 128)
4240205042Sthompsa		rf = 0xf4;
4241205042Sthompsa	else
4242205042Sthompsa		rf = 0xf3;
4243205042Sthompsa	run_rt3070_rf_write(sc, 20, rf);
4244205042Sthompsa
4245205042Sthompsa	/* set pfd_delay */
4246205042Sthompsa	if (chan <= 14)
4247205042Sthompsa		rf = 0x15;
4248205042Sthompsa	else if (chan <= 64)
4249205042Sthompsa		rf = 0x3d;
4250205042Sthompsa	else
4251205042Sthompsa		rf = 0x01;
4252205042Sthompsa	run_rt3070_rf_write(sc, 25, rf);
4253205042Sthompsa
4254205042Sthompsa	/* set rx_lo2 */
4255205042Sthompsa	run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87);
4256205042Sthompsa	/* set ldo_rf_vc */
4257205042Sthompsa	run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01);
4258205042Sthompsa	/* set drv_cc */
4259205042Sthompsa	run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f);
4260205042Sthompsa
4261205042Sthompsa	run_read(sc, RT2860_GPIO_CTRL, &tmp);
4262205042Sthompsa	tmp &= ~0x8080;
4263205042Sthompsa	if (chan <= 14)
4264205042Sthompsa		tmp |= 0x80;
4265205042Sthompsa	run_write(sc, RT2860_GPIO_CTRL, tmp);
4266205042Sthompsa
4267205042Sthompsa	/* enable RF tuning */
4268205042Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4269205042Sthompsa	run_rt3070_rf_write(sc, 7, rf | 0x01);
4270205042Sthompsa
4271205042Sthompsa	run_delay(sc, 2);
4272205042Sthompsa}
4273205042Sthompsa
4274205042Sthompsastatic void
4275260219Skevlorun_rt3593_set_chan(struct run_softc *sc, u_int chan)
4276260219Skevlo{
4277260219Skevlo	int8_t txpow1, txpow2, txpow3;
4278260219Skevlo	uint8_t h20mhz, rf;
4279260219Skevlo	int i;
4280260219Skevlo
4281260219Skevlo	/* find the settings for this channel (we know it exists) */
4282260219Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4283260219Skevlo
4284260219Skevlo	/* use Tx power values from EEPROM */
4285260219Skevlo	txpow1 = sc->txpow1[i];
4286260219Skevlo	txpow2 = sc->txpow2[i];
4287260219Skevlo	txpow3 = (sc->ntxchains == 3) ? sc->txpow3[i] : 0;
4288260219Skevlo
4289260219Skevlo	if (chan <= 14) {
4290260219Skevlo		run_bbp_write(sc, 25, sc->bbp25);
4291260219Skevlo		run_bbp_write(sc, 26, sc->bbp26);
4292260219Skevlo	} else {
4293260219Skevlo		/* Enable IQ phase correction. */
4294260219Skevlo		run_bbp_write(sc, 25, 0x09);
4295260219Skevlo		run_bbp_write(sc, 26, 0xff);
4296260219Skevlo	}
4297260219Skevlo
4298260219Skevlo	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
4299260219Skevlo	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
4300260219Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4301260219Skevlo	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
4302260219Skevlo	run_rt3070_rf_write(sc, 11, rf);
4303260219Skevlo
4304260219Skevlo	/* Set pll_idoh. */
4305260219Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4306260219Skevlo	rf &= ~0x4c;
4307260219Skevlo	rf |= (chan <= 14) ? 0x44 : 0x48;
4308260219Skevlo	run_rt3070_rf_write(sc, 11, rf);
4309260219Skevlo
4310260219Skevlo	if (chan <= 14)
4311260219Skevlo		rf = txpow1 & 0x1f;
4312260219Skevlo	else
4313260219Skevlo		rf = 0x40 | ((txpow1 & 0x18) << 1) | (txpow1 & 0x07);
4314260219Skevlo	run_rt3070_rf_write(sc, 53, rf);
4315260219Skevlo
4316260219Skevlo	if (chan <= 14)
4317260219Skevlo		rf = txpow2 & 0x1f;
4318260219Skevlo	else
4319260219Skevlo		rf = 0x40 | ((txpow2 & 0x18) << 1) | (txpow2 & 0x07);
4320260219Skevlo	run_rt3070_rf_write(sc, 55, rf);
4321260219Skevlo
4322260219Skevlo	if (chan <= 14)
4323260219Skevlo		rf = txpow3 & 0x1f;
4324260219Skevlo	else
4325260219Skevlo		rf = 0x40 | ((txpow3 & 0x18) << 1) | (txpow3 & 0x07);
4326260219Skevlo	run_rt3070_rf_write(sc, 54, rf);
4327260219Skevlo
4328260219Skevlo	rf = RT3070_RF_BLOCK | RT3070_PLL_PD;
4329260219Skevlo	if (sc->ntxchains == 3)
4330260219Skevlo		rf |= RT3070_TX0_PD | RT3070_TX1_PD | RT3070_TX2_PD;
4331260219Skevlo	else
4332260219Skevlo		rf |= RT3070_TX0_PD | RT3070_TX1_PD;
4333260219Skevlo	rf |= RT3070_RX0_PD | RT3070_RX1_PD | RT3070_RX2_PD;
4334260219Skevlo	run_rt3070_rf_write(sc, 1, rf);
4335260219Skevlo
4336260219Skevlo	run_adjust_freq_offset(sc);
4337260219Skevlo
4338260219Skevlo	run_rt3070_rf_write(sc, 31, (chan <= 14) ? 0xa0 : 0x80);
4339260219Skevlo
4340260219Skevlo	h20mhz = (sc->rf24_20mhz & 0x20) >> 5;
4341260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
4342260219Skevlo	rf = (rf & ~0x06) | (h20mhz << 1) | (h20mhz << 2);
4343260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
4344260219Skevlo
4345260219Skevlo	run_rt3070_rf_read(sc, 36, &rf);
4346260219Skevlo	if (chan <= 14)
4347260219Skevlo		rf |= 0x80;
4348260219Skevlo	else
4349260219Skevlo		rf &= ~0x80;
4350260219Skevlo	run_rt3070_rf_write(sc, 36, rf);
4351260219Skevlo
4352260219Skevlo	/* Set vcolo_bs. */
4353260219Skevlo	run_rt3070_rf_write(sc, 34, (chan <= 14) ? 0x3c : 0x20);
4354260219Skevlo	/* Set pfd_delay. */
4355260219Skevlo	run_rt3070_rf_write(sc, 12, (chan <= 14) ? 0x1a : 0x12);
4356260219Skevlo
4357260219Skevlo	/* Set vco bias current control. */
4358260219Skevlo	run_rt3070_rf_read(sc, 6, &rf);
4359260219Skevlo	rf &= ~0xc0;
4360260219Skevlo	if (chan <= 14)
4361260219Skevlo		rf |= 0x40;
4362260219Skevlo	else if (chan <= 128)
4363260219Skevlo		rf |= 0x80;
4364260219Skevlo	else
4365260219Skevlo		rf |= 0x40;
4366260219Skevlo	run_rt3070_rf_write(sc, 6, rf);
4367260219Skevlo
4368260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
4369260219Skevlo	rf = (rf & ~0x18) | 0x10;
4370260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
4371260219Skevlo
4372260219Skevlo	run_rt3070_rf_write(sc, 10, (chan <= 14) ? 0xd3 : 0xd8);
4373260219Skevlo	run_rt3070_rf_write(sc, 13, (chan <= 14) ? 0x12 : 0x23);
4374260219Skevlo
4375260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4376260219Skevlo	rf = (rf & ~0x03) | 0x01;
4377260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4378260219Skevlo	/* Set tx_mx1_cc. */
4379260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4380260219Skevlo	rf &= ~0x1c;
4381260219Skevlo	rf |= (chan <= 14) ? 0x14 : 0x10;
4382260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4383260219Skevlo	/* Set tx_mx1_ic. */
4384260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4385260219Skevlo	rf &= ~0xe0;
4386260219Skevlo	rf |= (chan <= 14) ? 0x60 : 0x40;
4387260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4388260219Skevlo	/* Set tx_lo1_ic. */
4389260219Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4390260219Skevlo	rf &= ~0x1c;
4391260219Skevlo	rf |= (chan <= 14) ? 0x0c : 0x08;
4392260219Skevlo	run_rt3070_rf_write(sc, 49, rf);
4393260219Skevlo	/* Set tx_lo1_en. */
4394260219Skevlo	run_rt3070_rf_read(sc, 50, &rf);
4395260219Skevlo	run_rt3070_rf_write(sc, 50, rf & ~0x20);
4396260219Skevlo	/* Set drv_cc. */
4397260219Skevlo	run_rt3070_rf_read(sc, 57, &rf);
4398260219Skevlo	rf &= ~0xfc;
4399260219Skevlo	rf |= (chan <= 14) ?  0x6c : 0x3c;
4400260219Skevlo	run_rt3070_rf_write(sc, 57, rf);
4401260219Skevlo	/* Set rx_mix1_ic, rxa_lnactr, lna_vc, lna_inbias_en and lna_en. */
4402260219Skevlo	run_rt3070_rf_write(sc, 44, (chan <= 14) ? 0x93 : 0x9b);
4403260219Skevlo	/* Set drv_gnd_a, tx_vga_cc_a and tx_mx2_gain. */
4404260219Skevlo	run_rt3070_rf_write(sc, 52, (chan <= 14) ? 0x45 : 0x05);
4405260219Skevlo	/* Enable VCO calibration. */
4406260219Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4407260219Skevlo	rf &= ~RT5390_VCOCAL;
4408260219Skevlo	rf |= (chan <= 14) ? RT5390_VCOCAL : 0xbe;
4409260219Skevlo	run_rt3070_rf_write(sc, 3, rf);
4410260219Skevlo
4411260219Skevlo	if (chan <= 14)
4412260219Skevlo		rf = 0x23;
4413260219Skevlo	else if (chan <= 64)
4414260219Skevlo		rf = 0x36;
4415260219Skevlo	else if (chan <= 128)
4416260219Skevlo		rf = 0x32;
4417260219Skevlo	else
4418260219Skevlo		rf = 0x30;
4419260219Skevlo	run_rt3070_rf_write(sc, 39, rf);
4420260219Skevlo	if (chan <= 14)
4421260219Skevlo		rf = 0xbb;
4422260219Skevlo	else if (chan <= 64)
4423260219Skevlo		rf = 0xeb;
4424260219Skevlo	else if (chan <= 128)
4425260219Skevlo		rf = 0xb3;
4426260219Skevlo	else
4427260219Skevlo		rf = 0x9b;
4428260219Skevlo	run_rt3070_rf_write(sc, 45, rf);
4429260219Skevlo
4430260219Skevlo	/* Set FEQ/AEQ control. */
4431260219Skevlo	run_bbp_write(sc, 105, 0x34);
4432260219Skevlo}
4433260219Skevlo
4434260219Skevlostatic void
4435257955Skevlorun_rt5390_set_chan(struct run_softc *sc, u_int chan)
4436257955Skevlo{
4437257955Skevlo	int8_t txpow1, txpow2;
4438257955Skevlo	uint8_t rf;
4439257955Skevlo	int i;
4440257955Skevlo
4441257955Skevlo	/* find the settings for this channel (we know it exists) */
4442257955Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4443257955Skevlo
4444257955Skevlo	/* use Tx power values from EEPROM */
4445257955Skevlo	txpow1 = sc->txpow1[i];
4446257955Skevlo	txpow2 = sc->txpow2[i];
4447257955Skevlo
4448257955Skevlo	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
4449257955Skevlo	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
4450257955Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4451257955Skevlo	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
4452257955Skevlo	run_rt3070_rf_write(sc, 11, rf);
4453257955Skevlo
4454257955Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4455257955Skevlo	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
4456257955Skevlo	/* The valid range of the RF R49 is 0x00 to 0x27. */
4457257955Skevlo	if ((rf & 0x3f) > 0x27)
4458257955Skevlo		rf = (rf & ~0x3f) | 0x27;
4459257955Skevlo	run_rt3070_rf_write(sc, 49, rf);
4460257955Skevlo
4461257955Skevlo	if (sc->mac_ver == 0x5392) {
4462257955Skevlo		run_rt3070_rf_read(sc, 50, &rf);
4463257955Skevlo		rf = (rf & ~0x3f) | (txpow2 & 0x3f);
4464257955Skevlo		/* The valid range of the RF R50 is 0x00 to 0x27. */
4465257955Skevlo		if ((rf & 0x3f) > 0x27)
4466257955Skevlo			rf = (rf & ~0x3f) | 0x27;
4467257955Skevlo		run_rt3070_rf_write(sc, 50, rf);
4468257955Skevlo	}
4469257955Skevlo
4470257955Skevlo	run_rt3070_rf_read(sc, 1, &rf);
4471257955Skevlo	rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD;
4472257955Skevlo	if (sc->mac_ver == 0x5392)
4473257955Skevlo		rf |= RT3070_RX1_PD | RT3070_TX1_PD;
4474257955Skevlo	run_rt3070_rf_write(sc, 1, rf);
4475257955Skevlo
4476257955Skevlo	if (sc->mac_ver != 0x5392) {
4477257955Skevlo		run_rt3070_rf_read(sc, 2, &rf);
4478257955Skevlo		rf |= 0x80;
4479257955Skevlo		run_rt3070_rf_write(sc, 2, rf);
4480257955Skevlo		run_delay(sc, 10);
4481257955Skevlo		rf &= 0x7f;
4482257955Skevlo		run_rt3070_rf_write(sc, 2, rf);
4483257955Skevlo	}
4484257955Skevlo
4485257955Skevlo	run_adjust_freq_offset(sc);
4486257955Skevlo
4487257955Skevlo	if (sc->mac_ver == 0x5392) {
4488257955Skevlo		/* Fix for RT5392C. */
4489257955Skevlo		if (sc->mac_rev >= 0x0223) {
4490259030Skevlo			if (chan <= 4)
4491257955Skevlo				rf = 0x0f;
4492259030Skevlo			else if (chan >= 5 && chan <= 7)
4493257955Skevlo				rf = 0x0e;
4494259030Skevlo			else
4495257955Skevlo				rf = 0x0d;
4496257955Skevlo			run_rt3070_rf_write(sc, 23, rf);
4497257955Skevlo
4498259030Skevlo			if (chan <= 4)
4499257955Skevlo				rf = 0x0c;
4500257955Skevlo			else if (chan == 5)
4501257955Skevlo				rf = 0x0b;
4502259030Skevlo			else if (chan >= 6 && chan <= 7)
4503257955Skevlo				rf = 0x0a;
4504259030Skevlo			else if (chan >= 8 && chan <= 10)
4505257955Skevlo				rf = 0x09;
4506259030Skevlo			else
4507257955Skevlo				rf = 0x08;
4508257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4509257955Skevlo		} else {
4510259030Skevlo			if (chan <= 11)
4511257955Skevlo				rf = 0x0f;
4512259030Skevlo			else
4513257955Skevlo				rf = 0x0b;
4514257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4515257955Skevlo		}
4516257955Skevlo	} else {
4517257955Skevlo		/* Fix for RT5390F. */
4518257955Skevlo		if (sc->mac_rev >= 0x0502) {
4519259030Skevlo			if (chan <= 11)
4520257955Skevlo				rf = 0x43;
4521259030Skevlo			else
4522257955Skevlo				rf = 0x23;
4523257955Skevlo			run_rt3070_rf_write(sc, 55, rf);
4524257955Skevlo
4525259030Skevlo			if (chan <= 11)
4526257955Skevlo				rf = 0x0f;
4527257955Skevlo			else if (chan == 12)
4528257955Skevlo				rf = 0x0d;
4529259030Skevlo			else
4530257955Skevlo				rf = 0x0b;
4531257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4532257955Skevlo		} else {
4533257955Skevlo			run_rt3070_rf_write(sc, 55, 0x44);
4534257955Skevlo			run_rt3070_rf_write(sc, 59, 0x8f);
4535257955Skevlo		}
4536257955Skevlo	}
4537257955Skevlo
4538257955Skevlo	/* Enable VCO calibration. */
4539257955Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4540257955Skevlo	rf |= RT5390_VCOCAL;
4541257955Skevlo	run_rt3070_rf_write(sc, 3, rf);
4542257955Skevlo}
4543257955Skevlo
4544257955Skevlostatic void
4545259032Skevlorun_rt5592_set_chan(struct run_softc *sc, u_int chan)
4546259032Skevlo{
4547259032Skevlo	const struct rt5592_freqs *freqs;
4548259032Skevlo	uint32_t tmp;
4549259032Skevlo	uint8_t reg, rf, txpow_bound;
4550259032Skevlo	int8_t txpow1, txpow2;
4551259032Skevlo	int i;
4552259032Skevlo
4553259032Skevlo	run_read(sc, RT5592_DEBUG_INDEX, &tmp);
4554259032Skevlo	freqs = (tmp & RT5592_SEL_XTAL) ?
4555259032Skevlo	    rt5592_freqs_40mhz : rt5592_freqs_20mhz;
4556259032Skevlo
4557259032Skevlo	/* find the settings for this channel (we know it exists) */
4558259032Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++, freqs++);
4559259032Skevlo
4560259032Skevlo	/* use Tx power values from EEPROM */
4561259032Skevlo	txpow1 = sc->txpow1[i];
4562259032Skevlo	txpow2 = sc->txpow2[i];
4563259032Skevlo
4564259032Skevlo	run_read(sc, RT3070_LDO_CFG0, &tmp);
4565259032Skevlo	tmp &= ~0x1c000000;
4566259032Skevlo	if (chan > 14)
4567259032Skevlo		tmp |= 0x14000000;
4568259032Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
4569259032Skevlo
4570259032Skevlo	/* N setting. */
4571259032Skevlo	run_rt3070_rf_write(sc, 8, freqs->n & 0xff);
4572259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4573259032Skevlo	rf &= ~(1 << 4);
4574259032Skevlo	rf |= ((freqs->n & 0x0100) >> 8) << 4;
4575259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4576259032Skevlo
4577259032Skevlo	/* K setting. */
4578259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4579259032Skevlo	rf &= ~0x0f;
4580259032Skevlo	rf |= (freqs->k & 0x0f);
4581259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4582259032Skevlo
4583259032Skevlo	/* Mode setting. */
4584259032Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4585259032Skevlo	rf &= ~0x0c;
4586259032Skevlo	rf |= ((freqs->m - 0x8) & 0x3) << 2;
4587259032Skevlo	run_rt3070_rf_write(sc, 11, rf);
4588259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4589259032Skevlo	rf &= ~(1 << 7);
4590259032Skevlo	rf |= (((freqs->m - 0x8) & 0x4) >> 2) << 7;
4591259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4592259032Skevlo
4593259032Skevlo	/* R setting. */
4594259032Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4595259032Skevlo	rf &= ~0x03;
4596259032Skevlo	rf |= (freqs->r - 0x1);
4597259032Skevlo	run_rt3070_rf_write(sc, 11, rf);
4598259032Skevlo
4599259032Skevlo	if (chan <= 14) {
4600259032Skevlo		/* Initialize RF registers for 2GHZ. */
4601259032Skevlo		for (i = 0; i < nitems(rt5592_2ghz_def_rf); i++) {
4602259032Skevlo			run_rt3070_rf_write(sc, rt5592_2ghz_def_rf[i].reg,
4603259032Skevlo			    rt5592_2ghz_def_rf[i].val);
4604259032Skevlo		}
4605259032Skevlo
4606259032Skevlo		rf = (chan <= 10) ? 0x07 : 0x06;
4607259032Skevlo		run_rt3070_rf_write(sc, 23, rf);
4608259032Skevlo		run_rt3070_rf_write(sc, 59, rf);
4609259032Skevlo
4610259032Skevlo		run_rt3070_rf_write(sc, 55, 0x43);
4611259032Skevlo
4612259032Skevlo		/*
4613259032Skevlo		 * RF R49/R50 Tx power ALC code.
4614259032Skevlo		 * G-band bit<7:6>=1:0, bit<5:0> range from 0x0 ~ 0x27.
4615259032Skevlo		 */
4616259032Skevlo		reg = 2;
4617259032Skevlo		txpow_bound = 0x27;
4618259032Skevlo	} else {
4619259032Skevlo		/* Initialize RF registers for 5GHZ. */
4620259032Skevlo		for (i = 0; i < nitems(rt5592_5ghz_def_rf); i++) {
4621259032Skevlo			run_rt3070_rf_write(sc, rt5592_5ghz_def_rf[i].reg,
4622259032Skevlo			    rt5592_5ghz_def_rf[i].val);
4623259032Skevlo		}
4624259032Skevlo		for (i = 0; i < nitems(rt5592_chan_5ghz); i++) {
4625259032Skevlo			if (chan >= rt5592_chan_5ghz[i].firstchan &&
4626259032Skevlo			    chan <= rt5592_chan_5ghz[i].lastchan) {
4627259032Skevlo				run_rt3070_rf_write(sc, rt5592_chan_5ghz[i].reg,
4628259032Skevlo				    rt5592_chan_5ghz[i].val);
4629259032Skevlo			}
4630259032Skevlo		}
4631259032Skevlo
4632259032Skevlo		/*
4633259032Skevlo		 * RF R49/R50 Tx power ALC code.
4634259032Skevlo		 * A-band bit<7:6>=1:1, bit<5:0> range from 0x0 ~ 0x2b.
4635259032Skevlo		 */
4636259032Skevlo		reg = 3;
4637259032Skevlo		txpow_bound = 0x2b;
4638259032Skevlo	}
4639259032Skevlo
4640259032Skevlo	/* RF R49 ch0 Tx power ALC code. */
4641259032Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4642259032Skevlo	rf &= ~0xc0;
4643259032Skevlo	rf |= (reg << 6);
4644259032Skevlo	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
4645259032Skevlo	if ((rf & 0x3f) > txpow_bound)
4646259032Skevlo		rf = (rf & ~0x3f) | txpow_bound;
4647259032Skevlo	run_rt3070_rf_write(sc, 49, rf);
4648259032Skevlo
4649259032Skevlo	/* RF R50 ch1 Tx power ALC code. */
4650259032Skevlo	run_rt3070_rf_read(sc, 50, &rf);
4651259032Skevlo	rf &= ~(1 << 7 | 1 << 6);
4652259032Skevlo	rf |= (reg << 6);
4653259032Skevlo	rf = (rf & ~0x3f) | (txpow2 & 0x3f);
4654259032Skevlo	if ((rf & 0x3f) > txpow_bound)
4655259032Skevlo		rf = (rf & ~0x3f) | txpow_bound;
4656259032Skevlo	run_rt3070_rf_write(sc, 50, rf);
4657259032Skevlo
4658259032Skevlo	/* Enable RF_BLOCK, PLL_PD, RX0_PD, and TX0_PD. */
4659259032Skevlo	run_rt3070_rf_read(sc, 1, &rf);
4660259032Skevlo	rf |= (RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD);
4661259032Skevlo	if (sc->ntxchains > 1)
4662259032Skevlo		rf |= RT3070_TX1_PD;
4663259032Skevlo	if (sc->nrxchains > 1)
4664259032Skevlo		rf |= RT3070_RX1_PD;
4665259032Skevlo	run_rt3070_rf_write(sc, 1, rf);
4666259032Skevlo
4667259032Skevlo	run_rt3070_rf_write(sc, 6, 0xe4);
4668259032Skevlo
4669259032Skevlo	run_rt3070_rf_write(sc, 30, 0x10);
4670259032Skevlo	run_rt3070_rf_write(sc, 31, 0x80);
4671259032Skevlo	run_rt3070_rf_write(sc, 32, 0x80);
4672259032Skevlo
4673259032Skevlo	run_adjust_freq_offset(sc);
4674259032Skevlo
4675259032Skevlo	/* Enable VCO calibration. */
4676259032Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4677259032Skevlo	rf |= RT5390_VCOCAL;
4678259032Skevlo	run_rt3070_rf_write(sc, 3, rf);
4679259032Skevlo}
4680259032Skevlo
4681259032Skevlostatic void
4682203134Sthompsarun_set_rx_antenna(struct run_softc *sc, int aux)
4683203134Sthompsa{
4684203134Sthompsa	uint32_t tmp;
4685257955Skevlo	uint8_t bbp152;
4686203134Sthompsa
4687203134Sthompsa	if (aux) {
4688257955Skevlo		if (sc->rf_rev == RT5390_RF_5370) {
4689257955Skevlo			run_bbp_read(sc, 152, &bbp152);
4690257955Skevlo			run_bbp_write(sc, 152, bbp152 & ~0x80);
4691259030Skevlo		} else {
4692257955Skevlo			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0);
4693257955Skevlo			run_read(sc, RT2860_GPIO_CTRL, &tmp);
4694257955Skevlo			run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08);
4695257955Skevlo		}
4696203134Sthompsa	} else {
4697257955Skevlo		if (sc->rf_rev == RT5390_RF_5370) {
4698257955Skevlo			run_bbp_read(sc, 152, &bbp152);
4699257955Skevlo			run_bbp_write(sc, 152, bbp152 | 0x80);
4700259030Skevlo		} else {
4701257955Skevlo			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1);
4702257955Skevlo			run_read(sc, RT2860_GPIO_CTRL, &tmp);
4703257955Skevlo			run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808);
4704257955Skevlo		}
4705203134Sthompsa	}
4706203134Sthompsa}
4707203134Sthompsa
4708203134Sthompsastatic int
4709203134Sthompsarun_set_chan(struct run_softc *sc, struct ieee80211_channel *c)
4710203134Sthompsa{
4711287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4712257429Shselasky	u_int chan, group;
4713203134Sthompsa
4714203134Sthompsa	chan = ieee80211_chan2ieee(ic, c);
4715203134Sthompsa	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
4716209917Sthompsa		return (EINVAL);
4717203134Sthompsa
4718259032Skevlo	if (sc->mac_ver == 0x5592)
4719259032Skevlo		run_rt5592_set_chan(sc, chan);
4720259032Skevlo	else if (sc->mac_ver >= 0x5390)
4721257955Skevlo		run_rt5390_set_chan(sc, chan);
4722260219Skevlo	else if (sc->mac_ver == 0x3593)
4723260219Skevlo		run_rt3593_set_chan(sc, chan);
4724257955Skevlo	else if (sc->mac_ver == 0x3572)
4725205042Sthompsa		run_rt3572_set_chan(sc, chan);
4726205042Sthompsa	else if (sc->mac_ver >= 0x3070)
4727203134Sthompsa		run_rt3070_set_chan(sc, chan);
4728203134Sthompsa	else
4729203134Sthompsa		run_rt2870_set_chan(sc, chan);
4730203134Sthompsa
4731203134Sthompsa	/* determine channel group */
4732203134Sthompsa	if (chan <= 14)
4733203134Sthompsa		group = 0;
4734203134Sthompsa	else if (chan <= 64)
4735203134Sthompsa		group = 1;
4736203134Sthompsa	else if (chan <= 128)
4737203134Sthompsa		group = 2;
4738203134Sthompsa	else
4739203134Sthompsa		group = 3;
4740203134Sthompsa
4741203134Sthompsa	/* XXX necessary only when group has changed! */
4742203134Sthompsa	run_select_chan_group(sc, group);
4743203134Sthompsa
4744203134Sthompsa	run_delay(sc, 10);
4745203134Sthompsa
4746259545Skevlo	/* Perform IQ calibration. */
4747259544Skevlo	if (sc->mac_ver >= 0x5392)
4748259544Skevlo		run_iq_calib(sc, chan);
4749259544Skevlo
4750209917Sthompsa	return (0);
4751203134Sthompsa}
4752203134Sthompsa
4753203134Sthompsastatic void
4754203134Sthompsarun_set_channel(struct ieee80211com *ic)
4755203134Sthompsa{
4756286950Sadrian	struct run_softc *sc = ic->ic_softc;
4757203134Sthompsa
4758203134Sthompsa	RUN_LOCK(sc);
4759203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
4760203134Sthompsa	RUN_UNLOCK(sc);
4761203134Sthompsa
4762203134Sthompsa	return;
4763203134Sthompsa}
4764203134Sthompsa
4765203134Sthompsastatic void
4766203134Sthompsarun_scan_start(struct ieee80211com *ic)
4767203134Sthompsa{
4768286950Sadrian	struct run_softc *sc = ic->ic_softc;
4769203134Sthompsa	uint32_t tmp;
4770203134Sthompsa
4771203134Sthompsa	RUN_LOCK(sc);
4772203134Sthompsa
4773203134Sthompsa	/* abort TSF synchronization */
4774203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
4775203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG,
4776203134Sthompsa	    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
4777203134Sthompsa	    RT2860_TBTT_TIMER_EN));
4778287197Sglebius	run_set_bssid(sc, ieee80211broadcastaddr);
4779203134Sthompsa
4780203134Sthompsa	RUN_UNLOCK(sc);
4781203134Sthompsa
4782203134Sthompsa	return;
4783203134Sthompsa}
4784203134Sthompsa
4785203134Sthompsastatic void
4786203134Sthompsarun_scan_end(struct ieee80211com *ic)
4787203134Sthompsa{
4788286950Sadrian	struct run_softc *sc = ic->ic_softc;
4789203134Sthompsa
4790203134Sthompsa	RUN_LOCK(sc);
4791203134Sthompsa
4792203134Sthompsa	run_enable_tsf_sync(sc);
4793203134Sthompsa	/* XXX keep local copy */
4794287197Sglebius	run_set_bssid(sc, ic->ic_macaddr);
4795203134Sthompsa
4796203134Sthompsa	RUN_UNLOCK(sc);
4797203134Sthompsa
4798203134Sthompsa	return;
4799203134Sthompsa}
4800203134Sthompsa
4801208019Sthompsa/*
4802208019Sthompsa * Could be called from ieee80211_node_timeout()
4803208019Sthompsa * (non-sleepable thread)
4804208019Sthompsa */
4805208019Sthompsastatic void
4806208019Sthompsarun_update_beacon(struct ieee80211vap *vap, int item)
4807203134Sthompsa{
4808208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4809286950Sadrian	struct run_softc *sc = ic->ic_softc;
4810218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4811218492Sbschmidt	int mcast = 0;
4812208019Sthompsa	uint32_t i;
4813208019Sthompsa
4814218492Sbschmidt	KASSERT(vap != NULL, ("no beacon"));
4815218492Sbschmidt
4816218492Sbschmidt	switch (item) {
4817218492Sbschmidt	case IEEE80211_BEACON_ERP:
4818283540Sglebius		run_updateslot(ic);
4819218492Sbschmidt		break;
4820218492Sbschmidt	case IEEE80211_BEACON_HTINFO:
4821218492Sbschmidt		run_updateprot(ic);
4822218492Sbschmidt		break;
4823218492Sbschmidt	case IEEE80211_BEACON_TIM:
4824218492Sbschmidt		mcast = 1;	/*TODO*/
4825218492Sbschmidt		break;
4826218492Sbschmidt	default:
4827218492Sbschmidt		break;
4828218492Sbschmidt	}
4829218492Sbschmidt
4830218492Sbschmidt	setbit(rvp->bo.bo_flags, item);
4831273448Skevlo	if (rvp->beacon_mbuf == NULL) {
4832273448Skevlo		rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss,
4833273448Skevlo		    &rvp->bo);
4834273448Skevlo		if (rvp->beacon_mbuf == NULL)
4835273448Skevlo			return;
4836273448Skevlo	}
4837218492Sbschmidt	ieee80211_beacon_update(vap->iv_bss, &rvp->bo, rvp->beacon_mbuf, mcast);
4838218492Sbschmidt
4839208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
4840208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
4841208019Sthompsa	sc->cmdq[i].func = run_update_beacon_cb;
4842208019Sthompsa	sc->cmdq[i].arg0 = vap;
4843208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
4844208019Sthompsa
4845208019Sthompsa	return;
4846203134Sthompsa}
4847203134Sthompsa
4848203134Sthompsastatic void
4849208019Sthompsarun_update_beacon_cb(void *arg)
4850203134Sthompsa{
4851208019Sthompsa	struct ieee80211vap *vap = arg;
4852218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4853203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4854286950Sadrian	struct run_softc *sc = ic->ic_softc;
4855203134Sthompsa	struct rt2860_txwi txwi;
4856203134Sthompsa	struct mbuf *m;
4857259032Skevlo	uint16_t txwisize;
4858208019Sthompsa	uint8_t ridx;
4859203134Sthompsa
4860209917Sthompsa	if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC)
4861208019Sthompsa		return;
4862236439Shselasky	if (ic->ic_bsschan == IEEE80211_CHAN_ANYC)
4863236439Shselasky		return;
4864208019Sthompsa
4865218492Sbschmidt	/*
4866218492Sbschmidt	 * No need to call ieee80211_beacon_update(), run_update_beacon()
4867218492Sbschmidt	 * is taking care of apropriate calls.
4868218492Sbschmidt	 */
4869218492Sbschmidt	if (rvp->beacon_mbuf == NULL) {
4870218492Sbschmidt		rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss,
4871218492Sbschmidt		    &rvp->bo);
4872218492Sbschmidt		if (rvp->beacon_mbuf == NULL)
4873218492Sbschmidt			return;
4874218492Sbschmidt	}
4875218492Sbschmidt	m = rvp->beacon_mbuf;
4876203134Sthompsa
4877259032Skevlo	memset(&txwi, 0, sizeof(txwi));
4878203134Sthompsa	txwi.wcid = 0xff;
4879203134Sthompsa	txwi.len = htole16(m->m_pkthdr.len);
4880259032Skevlo
4881203134Sthompsa	/* send beacons at the lowest available rate */
4882208019Sthompsa	ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
4883208019Sthompsa	    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
4884208019Sthompsa	txwi.phy = htole16(rt2860_rates[ridx].mcs);
4885208019Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM)
4886259032Skevlo		txwi.phy |= htole16(RT2860_PHY_OFDM);
4887203134Sthompsa	txwi.txop = RT2860_TX_TXOP_HT;
4888203134Sthompsa	txwi.flags = RT2860_TX_TS;
4889209144Sthompsa	txwi.xflags = RT2860_TX_NSEQ;
4890203134Sthompsa
4891259032Skevlo	txwisize = (sc->mac_ver == 0x5592) ?
4892259032Skevlo	    sizeof(txwi) + sizeof(uint32_t) : sizeof(txwi);
4893259032Skevlo	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id), (uint8_t *)&txwi,
4894259032Skevlo	    txwisize);
4895259032Skevlo	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id) + txwisize,
4896259032Skevlo	    mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1);
4897203134Sthompsa}
4898203134Sthompsa
4899203134Sthompsastatic void
4900203134Sthompsarun_updateprot(struct ieee80211com *ic)
4901203134Sthompsa{
4902286950Sadrian	struct run_softc *sc = ic->ic_softc;
4903218492Sbschmidt	uint32_t i;
4904218492Sbschmidt
4905218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
4906218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
4907218492Sbschmidt	sc->cmdq[i].func = run_updateprot_cb;
4908218492Sbschmidt	sc->cmdq[i].arg0 = ic;
4909218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
4910218492Sbschmidt}
4911218492Sbschmidt
4912218492Sbschmidtstatic void
4913218492Sbschmidtrun_updateprot_cb(void *arg)
4914218492Sbschmidt{
4915218492Sbschmidt	struct ieee80211com *ic = arg;
4916286950Sadrian	struct run_softc *sc = ic->ic_softc;
4917203134Sthompsa	uint32_t tmp;
4918203134Sthompsa
4919203134Sthompsa	tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL;
4920203134Sthompsa	/* setup protection frame rate (MCS code) */
4921203134Sthompsa	tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ?
4922270192Skevlo	    rt2860_rates[RT2860_RIDX_OFDM6].mcs | RT2860_PHY_OFDM :
4923203134Sthompsa	    rt2860_rates[RT2860_RIDX_CCK11].mcs;
4924203134Sthompsa
4925203134Sthompsa	/* CCK frames don't require protection */
4926203134Sthompsa	run_write(sc, RT2860_CCK_PROT_CFG, tmp);
4927203134Sthompsa	if (ic->ic_flags & IEEE80211_F_USEPROT) {
4928203134Sthompsa		if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
4929203134Sthompsa			tmp |= RT2860_PROT_CTRL_RTS_CTS;
4930203134Sthompsa		else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
4931203134Sthompsa			tmp |= RT2860_PROT_CTRL_CTS;
4932203134Sthompsa	}
4933203134Sthompsa	run_write(sc, RT2860_OFDM_PROT_CFG, tmp);
4934203134Sthompsa}
4935203134Sthompsa
4936203134Sthompsastatic void
4937208019Sthompsarun_usb_timeout_cb(void *arg)
4938203134Sthompsa{
4939208019Sthompsa	struct ieee80211vap *vap = arg;
4940286950Sadrian	struct run_softc *sc = vap->iv_ic->ic_softc;
4941203134Sthompsa
4942208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
4943203134Sthompsa
4944203134Sthompsa	if(vap->iv_state == IEEE80211_S_RUN &&
4945203134Sthompsa	    vap->iv_opmode != IEEE80211_M_STA)
4946203134Sthompsa		run_reset_livelock(sc);
4947209917Sthompsa	else if (vap->iv_state == IEEE80211_S_SCAN) {
4948203134Sthompsa		DPRINTF("timeout caused by scan\n");
4949203134Sthompsa		/* cancel bgscan */
4950203134Sthompsa		ieee80211_cancel_scan(vap);
4951203134Sthompsa	} else
4952203134Sthompsa		DPRINTF("timeout by unknown cause\n");
4953203134Sthompsa}
4954203134Sthompsa
4955203134Sthompsastatic void
4956203134Sthompsarun_reset_livelock(struct run_softc *sc)
4957203134Sthompsa{
4958203134Sthompsa	uint32_t tmp;
4959203134Sthompsa
4960208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
4961208019Sthompsa
4962203134Sthompsa	/*
4963203134Sthompsa	 * In IBSS or HostAP modes (when the hardware sends beacons), the MAC
4964203134Sthompsa	 * can run into a livelock and start sending CTS-to-self frames like
4965203134Sthompsa	 * crazy if protection is enabled.  Reset MAC/BBP for a while
4966203134Sthompsa	 */
4967203134Sthompsa	run_read(sc, RT2860_DEBUG, &tmp);
4968208019Sthompsa	DPRINTFN(3, "debug reg %08x\n", tmp);
4969209917Sthompsa	if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) {
4970203134Sthompsa		DPRINTF("CTS-to-self livelock detected\n");
4971203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST);
4972203134Sthompsa		run_delay(sc, 1);
4973203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL,
4974203134Sthompsa		    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
4975203134Sthompsa	}
4976203134Sthompsa}
4977203134Sthompsa
4978203134Sthompsastatic void
4979283540Sglebiusrun_update_promisc_locked(struct run_softc *sc)
4980203134Sthompsa{
4981203134Sthompsa        uint32_t tmp;
4982203134Sthompsa
4983203134Sthompsa	run_read(sc, RT2860_RX_FILTR_CFG, &tmp);
4984203134Sthompsa
4985203134Sthompsa	tmp |= RT2860_DROP_UC_NOME;
4986287197Sglebius        if (sc->sc_ic.ic_promisc > 0)
4987203134Sthompsa		tmp &= ~RT2860_DROP_UC_NOME;
4988203134Sthompsa
4989203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
4990203134Sthompsa
4991287197Sglebius        DPRINTF("%s promiscuous mode\n", (sc->sc_ic.ic_promisc > 0) ?
4992203134Sthompsa            "entering" : "leaving");
4993203134Sthompsa}
4994203134Sthompsa
4995203134Sthompsastatic void
4996283540Sglebiusrun_update_promisc(struct ieee80211com *ic)
4997203134Sthompsa{
4998283540Sglebius	struct run_softc *sc = ic->ic_softc;
4999203134Sthompsa
5000287197Sglebius	if ((sc->sc_flags & RUN_RUNNING) == 0)
5001203134Sthompsa		return;
5002203134Sthompsa
5003203134Sthompsa	RUN_LOCK(sc);
5004283540Sglebius	run_update_promisc_locked(sc);
5005203134Sthompsa	RUN_UNLOCK(sc);
5006203134Sthompsa}
5007203134Sthompsa
5008203134Sthompsastatic void
5009203134Sthompsarun_enable_tsf_sync(struct run_softc *sc)
5010203134Sthompsa{
5011287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5012203134Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
5013203134Sthompsa	uint32_t tmp;
5014203134Sthompsa
5015257955Skevlo	DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id,
5016257955Skevlo	    ic->ic_opmode);
5017208019Sthompsa
5018203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
5019203134Sthompsa	tmp &= ~0x1fffff;
5020203134Sthompsa	tmp |= vap->iv_bss->ni_intval * 16;
5021203134Sthompsa	tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN;
5022203134Sthompsa
5023208019Sthompsa	if (ic->ic_opmode == IEEE80211_M_STA) {
5024203134Sthompsa		/*
5025203134Sthompsa		 * Local TSF is always updated with remote TSF on beacon
5026203134Sthompsa		 * reception.
5027203134Sthompsa		 */
5028203134Sthompsa		tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT;
5029208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_IBSS) {
5030203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5031203134Sthompsa	        /*
5032203134Sthompsa	         * Local TSF is updated with remote TSF on beacon reception
5033203134Sthompsa	         * only if the remote TSF is greater than local TSF.
5034203134Sthompsa	         */
5035203134Sthompsa	        tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT;
5036208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
5037208019Sthompsa		    ic->ic_opmode == IEEE80211_M_MBSS) {
5038203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5039203134Sthompsa	        /* SYNC with nobody */
5040203134Sthompsa	        tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT;
5041208019Sthompsa	} else {
5042203134Sthompsa		DPRINTF("Enabling TSF failed. undefined opmode\n");
5043208019Sthompsa		return;
5044208019Sthompsa	}
5045203134Sthompsa
5046203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
5047203134Sthompsa}
5048203134Sthompsa
5049203134Sthompsastatic void
5050203134Sthompsarun_enable_mrr(struct run_softc *sc)
5051203134Sthompsa{
5052259546Skevlo#define	CCK(mcs)	(mcs)
5053259546Skevlo#define	OFDM(mcs)	(1 << 3 | (mcs))
5054203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG0,
5055203134Sthompsa	    OFDM(6) << 28 |	/* 54->48 */
5056203134Sthompsa	    OFDM(5) << 24 |	/* 48->36 */
5057203134Sthompsa	    OFDM(4) << 20 |	/* 36->24 */
5058203134Sthompsa	    OFDM(3) << 16 |	/* 24->18 */
5059203134Sthompsa	    OFDM(2) << 12 |	/* 18->12 */
5060203134Sthompsa	    OFDM(1) <<  8 |	/* 12-> 9 */
5061203134Sthompsa	    OFDM(0) <<  4 |	/*  9-> 6 */
5062203134Sthompsa	    OFDM(0));		/*  6-> 6 */
5063203134Sthompsa
5064203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG1,
5065203134Sthompsa	    CCK(2) << 12 |	/* 11->5.5 */
5066203134Sthompsa	    CCK(1) <<  8 |	/* 5.5-> 2 */
5067203134Sthompsa	    CCK(0) <<  4 |	/*   2-> 1 */
5068203134Sthompsa	    CCK(0));		/*   1-> 1 */
5069203134Sthompsa#undef OFDM
5070203134Sthompsa#undef CCK
5071203134Sthompsa}
5072203134Sthompsa
5073203134Sthompsastatic void
5074203134Sthompsarun_set_txpreamble(struct run_softc *sc)
5075203134Sthompsa{
5076287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5077203134Sthompsa	uint32_t tmp;
5078203134Sthompsa
5079203134Sthompsa	run_read(sc, RT2860_AUTO_RSP_CFG, &tmp);
5080203134Sthompsa	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
5081203134Sthompsa		tmp |= RT2860_CCK_SHORT_EN;
5082203134Sthompsa	else
5083203134Sthompsa		tmp &= ~RT2860_CCK_SHORT_EN;
5084203134Sthompsa	run_write(sc, RT2860_AUTO_RSP_CFG, tmp);
5085203134Sthompsa}
5086203134Sthompsa
5087203134Sthompsastatic void
5088203134Sthompsarun_set_basicrates(struct run_softc *sc)
5089203134Sthompsa{
5090287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5091203134Sthompsa
5092203134Sthompsa	/* set basic rates mask */
5093203134Sthompsa	if (ic->ic_curmode == IEEE80211_MODE_11B)
5094203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003);
5095203134Sthompsa	else if (ic->ic_curmode == IEEE80211_MODE_11A)
5096203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150);
5097203134Sthompsa	else	/* 11g */
5098203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f);
5099203134Sthompsa}
5100203134Sthompsa
5101203134Sthompsastatic void
5102203134Sthompsarun_set_leds(struct run_softc *sc, uint16_t which)
5103203134Sthompsa{
5104203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS,
5105203134Sthompsa	    which | (sc->leds & 0x7f));
5106203134Sthompsa}
5107203134Sthompsa
5108203134Sthompsastatic void
5109203134Sthompsarun_set_bssid(struct run_softc *sc, const uint8_t *bssid)
5110203134Sthompsa{
5111203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW0,
5112203134Sthompsa	    bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24);
5113203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW1,
5114203134Sthompsa	    bssid[4] | bssid[5] << 8);
5115203134Sthompsa}
5116203134Sthompsa
5117203134Sthompsastatic void
5118203134Sthompsarun_set_macaddr(struct run_softc *sc, const uint8_t *addr)
5119203134Sthompsa{
5120203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW0,
5121203134Sthompsa	    addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24);
5122203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW1,
5123203134Sthompsa	    addr[4] | addr[5] << 8 | 0xff << 16);
5124203134Sthompsa}
5125203134Sthompsa
5126203134Sthompsastatic void
5127283540Sglebiusrun_updateslot(struct ieee80211com *ic)
5128203134Sthompsa{
5129283540Sglebius	struct run_softc *sc = ic->ic_softc;
5130218492Sbschmidt	uint32_t i;
5131218492Sbschmidt
5132218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
5133218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
5134218492Sbschmidt	sc->cmdq[i].func = run_updateslot_cb;
5135287197Sglebius	sc->cmdq[i].arg0 = ic;
5136218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
5137218492Sbschmidt
5138218492Sbschmidt	return;
5139218492Sbschmidt}
5140218492Sbschmidt
5141218492Sbschmidt/* ARGSUSED */
5142218492Sbschmidtstatic void
5143218492Sbschmidtrun_updateslot_cb(void *arg)
5144218492Sbschmidt{
5145287197Sglebius	struct ieee80211com *ic = arg;
5146286950Sadrian	struct run_softc *sc = ic->ic_softc;
5147203134Sthompsa	uint32_t tmp;
5148203134Sthompsa
5149203134Sthompsa	run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp);
5150203134Sthompsa	tmp &= ~0xff;
5151203134Sthompsa	tmp |= (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
5152203134Sthompsa	run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp);
5153203134Sthompsa}
5154203134Sthompsa
5155208019Sthompsastatic void
5156283540Sglebiusrun_update_mcast(struct ieee80211com *ic)
5157208019Sthompsa{
5158208019Sthompsa}
5159208019Sthompsa
5160203134Sthompsastatic int8_t
5161203134Sthompsarun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain)
5162203134Sthompsa{
5163287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5164203134Sthompsa	struct ieee80211_channel *c = ic->ic_curchan;
5165203134Sthompsa	int delta;
5166203134Sthompsa
5167203134Sthompsa	if (IEEE80211_IS_CHAN_5GHZ(c)) {
5168257429Shselasky		u_int chan = ieee80211_chan2ieee(ic, c);
5169203134Sthompsa		delta = sc->rssi_5ghz[rxchain];
5170203134Sthompsa
5171203134Sthompsa		/* determine channel group */
5172203134Sthompsa		if (chan <= 64)
5173203134Sthompsa			delta -= sc->lna[1];
5174203134Sthompsa		else if (chan <= 128)
5175203134Sthompsa			delta -= sc->lna[2];
5176203134Sthompsa		else
5177203134Sthompsa			delta -= sc->lna[3];
5178203134Sthompsa	} else
5179203134Sthompsa		delta = sc->rssi_2ghz[rxchain] - sc->lna[0];
5180203134Sthompsa
5181209917Sthompsa	return (-12 - delta - rssi);
5182203134Sthompsa}
5183203134Sthompsa
5184257955Skevlostatic void
5185257955Skevlorun_rt5390_bbp_init(struct run_softc *sc)
5186257955Skevlo{
5187257955Skevlo	int i;
5188259032Skevlo	uint8_t bbp;
5189257955Skevlo
5190259032Skevlo	/* Apply maximum likelihood detection for 2 stream case. */
5191259032Skevlo	run_bbp_read(sc, 105, &bbp);
5192259032Skevlo	if (sc->nrxchains > 1)
5193259032Skevlo		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5194259032Skevlo
5195257955Skevlo	/* Avoid data lost and CRC error. */
5196259032Skevlo	run_bbp_read(sc, 4, &bbp);
5197259031Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5198257955Skevlo
5199259032Skevlo	if (sc->mac_ver == 0x5592) {
5200259032Skevlo		for (i = 0; i < nitems(rt5592_def_bbp); i++) {
5201259032Skevlo			run_bbp_write(sc, rt5592_def_bbp[i].reg,
5202259032Skevlo			    rt5592_def_bbp[i].val);
5203259032Skevlo		}
5204259032Skevlo		for (i = 0; i < nitems(rt5592_bbp_r196); i++) {
5205259032Skevlo			run_bbp_write(sc, 195, i + 0x80);
5206259032Skevlo			run_bbp_write(sc, 196, rt5592_bbp_r196[i]);
5207259032Skevlo		}
5208259032Skevlo	} else {
5209259032Skevlo		for (i = 0; i < nitems(rt5390_def_bbp); i++) {
5210259032Skevlo			run_bbp_write(sc, rt5390_def_bbp[i].reg,
5211259032Skevlo			    rt5390_def_bbp[i].val);
5212259032Skevlo		}
5213257955Skevlo	}
5214257955Skevlo	if (sc->mac_ver == 0x5392) {
5215257955Skevlo		run_bbp_write(sc, 88, 0x90);
5216257955Skevlo		run_bbp_write(sc, 95, 0x9a);
5217257955Skevlo		run_bbp_write(sc, 98, 0x12);
5218257955Skevlo		run_bbp_write(sc, 106, 0x12);
5219257955Skevlo		run_bbp_write(sc, 134, 0xd0);
5220257955Skevlo		run_bbp_write(sc, 135, 0xf6);
5221257955Skevlo		run_bbp_write(sc, 148, 0x84);
5222257955Skevlo	}
5223257955Skevlo
5224259032Skevlo	run_bbp_read(sc, 152, &bbp);
5225259032Skevlo	run_bbp_write(sc, 152, bbp | 0x80);
5226259032Skevlo
5227259032Skevlo	/* Fix BBP254 for RT5592C. */
5228259032Skevlo	if (sc->mac_ver == 0x5592 && sc->mac_rev >= 0x0221) {
5229259032Skevlo		run_bbp_read(sc, 254, &bbp);
5230259032Skevlo		run_bbp_write(sc, 254, bbp | 0x80);
5231259032Skevlo	}
5232259032Skevlo
5233257955Skevlo	/* Disable hardware antenna diversity. */
5234257955Skevlo	if (sc->mac_ver == 0x5390)
5235257955Skevlo		run_bbp_write(sc, 154, 0);
5236259032Skevlo
5237259032Skevlo	/* Initialize Rx CCK/OFDM frequency offset report. */
5238259032Skevlo	run_bbp_write(sc, 142, 1);
5239259032Skevlo	run_bbp_write(sc, 143, 57);
5240257955Skevlo}
5241257955Skevlo
5242203134Sthompsastatic int
5243203134Sthompsarun_bbp_init(struct run_softc *sc)
5244203134Sthompsa{
5245203134Sthompsa	int i, error, ntries;
5246203134Sthompsa	uint8_t bbp0;
5247203134Sthompsa
5248203134Sthompsa	/* wait for BBP to wake up */
5249203134Sthompsa	for (ntries = 0; ntries < 20; ntries++) {
5250203134Sthompsa		if ((error = run_bbp_read(sc, 0, &bbp0)) != 0)
5251203134Sthompsa			return error;
5252203134Sthompsa		if (bbp0 != 0 && bbp0 != 0xff)
5253203134Sthompsa			break;
5254203134Sthompsa	}
5255203134Sthompsa	if (ntries == 20)
5256209917Sthompsa		return (ETIMEDOUT);
5257203134Sthompsa
5258203134Sthompsa	/* initialize BBP registers to default values */
5259257955Skevlo	if (sc->mac_ver >= 0x5390)
5260257955Skevlo		run_rt5390_bbp_init(sc);
5261257955Skevlo	else {
5262257955Skevlo		for (i = 0; i < nitems(rt2860_def_bbp); i++) {
5263257955Skevlo			run_bbp_write(sc, rt2860_def_bbp[i].reg,
5264257955Skevlo			    rt2860_def_bbp[i].val);
5265257955Skevlo		}
5266203134Sthompsa	}
5267203134Sthompsa
5268260219Skevlo	if (sc->mac_ver == 0x3593) {
5269260219Skevlo		run_bbp_write(sc, 79, 0x13);
5270260219Skevlo		run_bbp_write(sc, 80, 0x05);
5271260219Skevlo		run_bbp_write(sc, 81, 0x33);
5272260219Skevlo		run_bbp_write(sc, 86, 0x46);
5273260219Skevlo		run_bbp_write(sc, 137, 0x0f);
5274260219Skevlo	}
5275260219Skevlo
5276203134Sthompsa	/* fix BBP84 for RT2860E */
5277205042Sthompsa	if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101)
5278205042Sthompsa		run_bbp_write(sc, 84, 0x19);
5279203134Sthompsa
5280260219Skevlo	if (sc->mac_ver >= 0x3070 && (sc->mac_ver != 0x3593 &&
5281260219Skevlo	    sc->mac_ver != 0x5592)) {
5282203134Sthompsa		run_bbp_write(sc, 79, 0x13);
5283203134Sthompsa		run_bbp_write(sc, 80, 0x05);
5284203134Sthompsa		run_bbp_write(sc, 81, 0x33);
5285205042Sthompsa	} else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) {
5286203134Sthompsa		run_bbp_write(sc, 69, 0x16);
5287203134Sthompsa		run_bbp_write(sc, 73, 0x12);
5288203134Sthompsa	}
5289209917Sthompsa	return (0);
5290203134Sthompsa}
5291203134Sthompsa
5292203134Sthompsastatic int
5293203134Sthompsarun_rt3070_rf_init(struct run_softc *sc)
5294203134Sthompsa{
5295203134Sthompsa	uint32_t tmp;
5296256722Skevlo	uint8_t bbp4, mingain, rf, target;
5297203134Sthompsa	int i;
5298203134Sthompsa
5299203134Sthompsa	run_rt3070_rf_read(sc, 30, &rf);
5300203134Sthompsa	/* toggle RF R30 bit 7 */
5301203134Sthompsa	run_rt3070_rf_write(sc, 30, rf | 0x80);
5302203134Sthompsa	run_delay(sc, 10);
5303203134Sthompsa	run_rt3070_rf_write(sc, 30, rf & ~0x80);
5304203134Sthompsa
5305203134Sthompsa	/* initialize RF registers to default value */
5306205042Sthompsa	if (sc->mac_ver == 0x3572) {
5307257955Skevlo		for (i = 0; i < nitems(rt3572_def_rf); i++) {
5308205042Sthompsa			run_rt3070_rf_write(sc, rt3572_def_rf[i].reg,
5309205042Sthompsa			    rt3572_def_rf[i].val);
5310205042Sthompsa		}
5311205042Sthompsa	} else {
5312257955Skevlo		for (i = 0; i < nitems(rt3070_def_rf); i++) {
5313205042Sthompsa			run_rt3070_rf_write(sc, rt3070_def_rf[i].reg,
5314205042Sthompsa			    rt3070_def_rf[i].val);
5315205042Sthompsa		}
5316203134Sthompsa	}
5317205042Sthompsa
5318256721Skevlo	if (sc->mac_ver == 0x3070 && sc->mac_rev < 0x0201) {
5319256721Skevlo		/*
5320256721Skevlo		 * Change voltage from 1.2V to 1.35V for RT3070.
5321256721Skevlo		 * The DAC issue (RT3070_LDO_CFG0) has been fixed
5322256721Skevlo		 * in RT3070(F).
5323256721Skevlo		 */
5324203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5325203134Sthompsa		tmp = (tmp & ~0x0f000000) | 0x0d000000;
5326203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5327203134Sthompsa
5328205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5329203134Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5330203134Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5331203134Sthompsa		run_rt3070_rf_write(sc, 31, 0x14);
5332203134Sthompsa
5333203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5334203134Sthompsa		tmp &= ~0x1f000000;
5335205042Sthompsa		if (sc->mac_rev < 0x0211)
5336205042Sthompsa			tmp |= 0x0d000000;	/* 1.3V */
5337203134Sthompsa		else
5338205042Sthompsa			tmp |= 0x01000000;	/* 1.2V */
5339203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5340203134Sthompsa
5341203134Sthompsa		/* patch LNA_PE_G1 */
5342203134Sthompsa		run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5343203134Sthompsa		run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20);
5344208019Sthompsa
5345209917Sthompsa	} else if (sc->mac_ver == 0x3572) {
5346205042Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5347205042Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5348205042Sthompsa
5349208019Sthompsa		/* increase voltage from 1.2V to 1.35V */
5350208019Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5351208019Sthompsa		tmp = (tmp & ~0x1f000000) | 0x0d000000;
5352208019Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5353203134Sthompsa
5354209917Sthompsa		if (sc->mac_rev < 0x0211 || !sc->patch_dac) {
5355203134Sthompsa			run_delay(sc, 1);	/* wait for 1msec */
5356205042Sthompsa			/* decrease voltage back to 1.2V */
5357203134Sthompsa			tmp = (tmp & ~0x1f000000) | 0x01000000;
5358203134Sthompsa			run_write(sc, RT3070_LDO_CFG0, tmp);
5359203134Sthompsa		}
5360203134Sthompsa	}
5361203134Sthompsa
5362203134Sthompsa	/* select 20MHz bandwidth */
5363203134Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5364203134Sthompsa	run_rt3070_rf_write(sc, 31, rf & ~0x20);
5365203134Sthompsa
5366203134Sthompsa	/* calibrate filter for 20MHz bandwidth */
5367203134Sthompsa	sc->rf24_20mhz = 0x1f;	/* default value */
5368205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13;
5369205042Sthompsa	run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz);
5370203134Sthompsa
5371203134Sthompsa	/* select 40MHz bandwidth */
5372203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5373256721Skevlo	run_bbp_write(sc, 4, (bbp4 & ~0x18) | 0x10);
5374205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5375205042Sthompsa	run_rt3070_rf_write(sc, 31, rf | 0x20);
5376203134Sthompsa
5377203134Sthompsa	/* calibrate filter for 40MHz bandwidth */
5378203134Sthompsa	sc->rf24_40mhz = 0x2f;	/* default value */
5379205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15;
5380205042Sthompsa	run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz);
5381203134Sthompsa
5382203134Sthompsa	/* go back to 20MHz bandwidth */
5383203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5384203134Sthompsa	run_bbp_write(sc, 4, bbp4 & ~0x18);
5385203134Sthompsa
5386205042Sthompsa	if (sc->mac_ver == 0x3572) {
5387205042Sthompsa		/* save default BBP registers 25 and 26 values */
5388205042Sthompsa		run_bbp_read(sc, 25, &sc->bbp25);
5389205042Sthompsa		run_bbp_read(sc, 26, &sc->bbp26);
5390256721Skevlo	} else if (sc->mac_rev < 0x0201 || sc->mac_rev < 0x0211)
5391203134Sthompsa		run_rt3070_rf_write(sc, 27, 0x03);
5392203134Sthompsa
5393203134Sthompsa	run_read(sc, RT3070_OPT_14, &tmp);
5394203134Sthompsa	run_write(sc, RT3070_OPT_14, tmp | 1);
5395203134Sthompsa
5396205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5397205042Sthompsa		run_rt3070_rf_read(sc, 17, &rf);
5398205042Sthompsa		rf &= ~RT3070_TX_LO1;
5399205042Sthompsa		if ((sc->mac_ver == 0x3070 ||
5400205042Sthompsa		     (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) &&
5401205042Sthompsa		    !sc->ext_2ghz_lna)
5402205042Sthompsa			rf |= 0x20;	/* fix for long range Rx issue */
5403256722Skevlo		mingain = (sc->mac_ver == 0x3070) ? 1 : 2;
5404256722Skevlo		if (sc->txmixgain_2ghz >= mingain)
5405205042Sthompsa			rf = (rf & ~0x7) | sc->txmixgain_2ghz;
5406205042Sthompsa		run_rt3070_rf_write(sc, 17, rf);
5407205042Sthompsa	}
5408205042Sthompsa
5409270643Skevlo	if (sc->mac_ver == 0x3071) {
5410203134Sthompsa		run_rt3070_rf_read(sc, 1, &rf);
5411203134Sthompsa		rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD);
5412203134Sthompsa		rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD;
5413203134Sthompsa		run_rt3070_rf_write(sc, 1, rf);
5414203134Sthompsa
5415203134Sthompsa		run_rt3070_rf_read(sc, 15, &rf);
5416203134Sthompsa		run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2);
5417203134Sthompsa
5418203134Sthompsa		run_rt3070_rf_read(sc, 20, &rf);
5419203134Sthompsa		run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1);
5420203134Sthompsa
5421203134Sthompsa		run_rt3070_rf_read(sc, 21, &rf);
5422203134Sthompsa		run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2);
5423205042Sthompsa	}
5424203134Sthompsa
5425205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5426205042Sthompsa		/* fix Tx to Rx IQ glitch by raising RF voltage */
5427203134Sthompsa		run_rt3070_rf_read(sc, 27, &rf);
5428203134Sthompsa		rf &= ~0x77;
5429205042Sthompsa		if (sc->mac_rev < 0x0211)
5430203134Sthompsa			rf |= 0x03;
5431203134Sthompsa		run_rt3070_rf_write(sc, 27, rf);
5432203134Sthompsa	}
5433209917Sthompsa	return (0);
5434203134Sthompsa}
5435203134Sthompsa
5436257955Skevlostatic void
5437260219Skevlorun_rt3593_rf_init(struct run_softc *sc)
5438260219Skevlo{
5439260219Skevlo	uint32_t tmp;
5440260219Skevlo	uint8_t rf;
5441260219Skevlo	int i;
5442260219Skevlo
5443260219Skevlo	/* Disable the GPIO bits 4 and 7 for LNA PE control. */
5444260219Skevlo	run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5445260219Skevlo	tmp &= ~(1 << 4 | 1 << 7);
5446260219Skevlo	run_write(sc, RT3070_GPIO_SWITCH, tmp);
5447260219Skevlo
5448260219Skevlo	/* Initialize RF registers to default value. */
5449260219Skevlo	for (i = 0; i < nitems(rt3593_def_rf); i++) {
5450260219Skevlo		run_rt3070_rf_write(sc, rt3593_def_rf[i].reg,
5451260219Skevlo		    rt3593_def_rf[i].val);
5452260219Skevlo	}
5453260219Skevlo
5454260219Skevlo	/* Toggle RF R2 to initiate calibration. */
5455260219Skevlo	run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5456260219Skevlo
5457260219Skevlo	/* Initialize RF frequency offset. */
5458260219Skevlo	run_adjust_freq_offset(sc);
5459260219Skevlo
5460260219Skevlo	run_rt3070_rf_read(sc, 18, &rf);
5461260219Skevlo	run_rt3070_rf_write(sc, 18, rf | RT3593_AUTOTUNE_BYPASS);
5462260219Skevlo
5463260219Skevlo	/*
5464260219Skevlo	 * Increase voltage from 1.2V to 1.35V, wait for 1 msec to
5465260219Skevlo	 * decrease voltage back to 1.2V.
5466260219Skevlo	 */
5467260219Skevlo	run_read(sc, RT3070_LDO_CFG0, &tmp);
5468260219Skevlo	tmp = (tmp & ~0x1f000000) | 0x0d000000;
5469260219Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5470260219Skevlo	run_delay(sc, 1);
5471260219Skevlo	tmp = (tmp & ~0x1f000000) | 0x01000000;
5472260219Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5473260219Skevlo
5474260219Skevlo	sc->rf24_20mhz = 0x1f;
5475260219Skevlo	sc->rf24_40mhz = 0x2f;
5476260219Skevlo
5477260219Skevlo	/* Save default BBP registers 25 and 26 values. */
5478260219Skevlo	run_bbp_read(sc, 25, &sc->bbp25);
5479260219Skevlo	run_bbp_read(sc, 26, &sc->bbp26);
5480260219Skevlo
5481260219Skevlo	run_read(sc, RT3070_OPT_14, &tmp);
5482260219Skevlo	run_write(sc, RT3070_OPT_14, tmp | 1);
5483260219Skevlo}
5484260219Skevlo
5485260219Skevlostatic void
5486257955Skevlorun_rt5390_rf_init(struct run_softc *sc)
5487257955Skevlo{
5488257955Skevlo	uint32_t tmp;
5489257955Skevlo	uint8_t rf;
5490257955Skevlo	int i;
5491257955Skevlo
5492259030Skevlo	/* Toggle RF R2 to initiate calibration. */
5493259030Skevlo	if (sc->mac_ver == 0x5390) {
5494257955Skevlo		run_rt3070_rf_read(sc, 2, &rf);
5495259031Skevlo		run_rt3070_rf_write(sc, 2, rf | RT5390_RESCAL);
5496257955Skevlo		run_delay(sc, 10);
5497259031Skevlo		run_rt3070_rf_write(sc, 2, rf & ~RT5390_RESCAL);
5498259030Skevlo	} else {
5499259031Skevlo		run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5500259030Skevlo		run_delay(sc, 10);
5501257955Skevlo	}
5502257955Skevlo
5503257955Skevlo	/* Initialize RF registers to default value. */
5504259032Skevlo	if (sc->mac_ver == 0x5592) {
5505259032Skevlo		for (i = 0; i < nitems(rt5592_def_rf); i++) {
5506259032Skevlo			run_rt3070_rf_write(sc, rt5592_def_rf[i].reg,
5507259032Skevlo			    rt5592_def_rf[i].val);
5508259032Skevlo		}
5509259032Skevlo		/* Initialize RF frequency offset. */
5510259032Skevlo		run_adjust_freq_offset(sc);
5511259032Skevlo	} else if (sc->mac_ver == 0x5392) {
5512257955Skevlo		for (i = 0; i < nitems(rt5392_def_rf); i++) {
5513257955Skevlo			run_rt3070_rf_write(sc, rt5392_def_rf[i].reg,
5514257955Skevlo			    rt5392_def_rf[i].val);
5515257955Skevlo		}
5516257955Skevlo		if (sc->mac_rev >= 0x0223) {
5517257955Skevlo			run_rt3070_rf_write(sc, 23, 0x0f);
5518257955Skevlo			run_rt3070_rf_write(sc, 24, 0x3e);
5519257955Skevlo			run_rt3070_rf_write(sc, 51, 0x32);
5520257955Skevlo			run_rt3070_rf_write(sc, 53, 0x22);
5521257955Skevlo			run_rt3070_rf_write(sc, 56, 0xc1);
5522257955Skevlo			run_rt3070_rf_write(sc, 59, 0x0f);
5523257955Skevlo		}
5524257955Skevlo	} else {
5525257955Skevlo		for (i = 0; i < nitems(rt5390_def_rf); i++) {
5526257955Skevlo			run_rt3070_rf_write(sc, rt5390_def_rf[i].reg,
5527257955Skevlo			    rt5390_def_rf[i].val);
5528257955Skevlo		}
5529257955Skevlo		if (sc->mac_rev >= 0x0502) {
5530257955Skevlo			run_rt3070_rf_write(sc, 6, 0xe0);
5531257955Skevlo			run_rt3070_rf_write(sc, 25, 0x80);
5532257955Skevlo			run_rt3070_rf_write(sc, 46, 0x73);
5533257955Skevlo			run_rt3070_rf_write(sc, 53, 0x00);
5534257955Skevlo			run_rt3070_rf_write(sc, 56, 0x42);
5535257955Skevlo			run_rt3070_rf_write(sc, 61, 0xd1);
5536257955Skevlo		}
5537257955Skevlo	}
5538257955Skevlo
5539257955Skevlo	sc->rf24_20mhz = 0x1f;	/* default value */
5540259032Skevlo	sc->rf24_40mhz = (sc->mac_ver == 0x5592) ? 0 : 0x2f;
5541257955Skevlo
5542257955Skevlo	if (sc->mac_rev < 0x0211)
5543257955Skevlo		run_rt3070_rf_write(sc, 27, 0x3);
5544257955Skevlo
5545257955Skevlo	run_read(sc, RT3070_OPT_14, &tmp);
5546257955Skevlo	run_write(sc, RT3070_OPT_14, tmp | 1);
5547257955Skevlo}
5548257955Skevlo
5549203134Sthompsastatic int
5550203134Sthompsarun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target,
5551203134Sthompsa    uint8_t *val)
5552203134Sthompsa{
5553203134Sthompsa	uint8_t rf22, rf24;
5554203134Sthompsa	uint8_t bbp55_pb, bbp55_sb, delta;
5555203134Sthompsa	int ntries;
5556203134Sthompsa
5557203134Sthompsa	/* program filter */
5558205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf24);
5559205042Sthompsa	rf24 = (rf24 & 0xc0) | init;	/* initial filter value */
5560203134Sthompsa	run_rt3070_rf_write(sc, 24, rf24);
5561203134Sthompsa
5562203134Sthompsa	/* enable baseband loopback mode */
5563203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5564203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 | 0x01);
5565203134Sthompsa
5566203134Sthompsa	/* set power and frequency of passband test tone */
5567203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5568203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5569203134Sthompsa		/* transmit test tone */
5570203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5571203134Sthompsa		run_delay(sc, 10);
5572203134Sthompsa		/* read received power */
5573203134Sthompsa		run_bbp_read(sc, 55, &bbp55_pb);
5574203134Sthompsa		if (bbp55_pb != 0)
5575203134Sthompsa			break;
5576203134Sthompsa	}
5577203134Sthompsa	if (ntries == 100)
5578257955Skevlo		return (ETIMEDOUT);
5579203134Sthompsa
5580203134Sthompsa	/* set power and frequency of stopband test tone */
5581203134Sthompsa	run_bbp_write(sc, 24, 0x06);
5582203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5583203134Sthompsa		/* transmit test tone */
5584203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5585203134Sthompsa		run_delay(sc, 10);
5586203134Sthompsa		/* read received power */
5587203134Sthompsa		run_bbp_read(sc, 55, &bbp55_sb);
5588203134Sthompsa
5589203134Sthompsa		delta = bbp55_pb - bbp55_sb;
5590203134Sthompsa		if (delta > target)
5591203134Sthompsa			break;
5592203134Sthompsa
5593203134Sthompsa		/* reprogram filter */
5594203134Sthompsa		rf24++;
5595203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5596203134Sthompsa	}
5597203134Sthompsa	if (ntries < 100) {
5598203134Sthompsa		if (rf24 != init)
5599203134Sthompsa			rf24--;	/* backtrack */
5600203134Sthompsa		*val = rf24;
5601203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5602203134Sthompsa	}
5603203134Sthompsa
5604203134Sthompsa	/* restore initial state */
5605203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5606203134Sthompsa
5607203134Sthompsa	/* disable baseband loopback mode */
5608203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5609203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 & ~0x01);
5610203134Sthompsa
5611209917Sthompsa	return (0);
5612203134Sthompsa}
5613203134Sthompsa
5614205042Sthompsastatic void
5615205042Sthompsarun_rt3070_rf_setup(struct run_softc *sc)
5616205042Sthompsa{
5617205042Sthompsa	uint8_t bbp, rf;
5618205042Sthompsa	int i;
5619205042Sthompsa
5620260219Skevlo	if (sc->mac_ver == 0x3572) {
5621205042Sthompsa		/* enable DC filter */
5622205042Sthompsa		if (sc->mac_rev >= 0x0201)
5623205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5624205042Sthompsa
5625205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5626205042Sthompsa		if (sc->ntxchains == 1)
5627205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5628205042Sthompsa		if (sc->nrxchains == 1)
5629205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5630205042Sthompsa		run_bbp_write(sc, 138, bbp);
5631205042Sthompsa
5632205042Sthompsa		if (sc->mac_rev >= 0x0211) {
5633205042Sthompsa			/* improve power consumption */
5634205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5635205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5636205042Sthompsa		}
5637205042Sthompsa
5638205042Sthompsa		run_rt3070_rf_read(sc, 16, &rf);
5639205042Sthompsa		rf = (rf & ~0x07) | sc->txmixgain_2ghz;
5640205042Sthompsa		run_rt3070_rf_write(sc, 16, rf);
5641205042Sthompsa
5642205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5643257409Skevlo		if (sc->mac_rev >= 0x0211) {
5644257409Skevlo			/* enable DC filter */
5645205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5646205042Sthompsa
5647257409Skevlo			/* improve power consumption */
5648257409Skevlo			run_bbp_read(sc, 31, &bbp);
5649257409Skevlo			run_bbp_write(sc, 31, bbp & ~0x03);
5650257409Skevlo		}
5651257409Skevlo
5652205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5653205042Sthompsa		if (sc->ntxchains == 1)
5654205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5655205042Sthompsa		if (sc->nrxchains == 1)
5656205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5657205042Sthompsa		run_bbp_write(sc, 138, bbp);
5658205042Sthompsa
5659205042Sthompsa		run_write(sc, RT2860_TX_SW_CFG1, 0);
5660205042Sthompsa		if (sc->mac_rev < 0x0211) {
5661205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2,
5662205042Sthompsa			    sc->patch_dac ? 0x2c : 0x0f);
5663205042Sthompsa		} else
5664205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5665205042Sthompsa
5666205042Sthompsa	} else if (sc->mac_ver == 0x3070) {
5667205042Sthompsa		if (sc->mac_rev >= 0x0201) {
5668205042Sthompsa			/* enable DC filter */
5669205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5670205042Sthompsa
5671205042Sthompsa			/* improve power consumption */
5672205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5673205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5674205042Sthompsa		}
5675205042Sthompsa
5676256955Skevlo		if (sc->mac_rev < 0x0201) {
5677205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG1, 0);
5678205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0x2c);
5679205042Sthompsa		} else
5680205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5681205042Sthompsa	}
5682205042Sthompsa
5683205042Sthompsa	/* initialize RF registers from ROM for >=RT3071*/
5684260219Skevlo	if (sc->mac_ver >= 0x3071) {
5685205042Sthompsa		for (i = 0; i < 10; i++) {
5686205042Sthompsa			if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff)
5687205042Sthompsa				continue;
5688205042Sthompsa			run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val);
5689205042Sthompsa		}
5690205042Sthompsa	}
5691205042Sthompsa}
5692205042Sthompsa
5693260219Skevlostatic void
5694260219Skevlorun_rt3593_rf_setup(struct run_softc *sc)
5695260219Skevlo{
5696260219Skevlo	uint8_t bbp, rf;
5697260219Skevlo
5698260219Skevlo	if (sc->mac_rev >= 0x0211) {
5699260219Skevlo		/* Enable DC filter. */
5700260219Skevlo		run_bbp_write(sc, 103, 0xc0);
5701260219Skevlo	}
5702260219Skevlo	run_write(sc, RT2860_TX_SW_CFG1, 0);
5703260219Skevlo	if (sc->mac_rev < 0x0211) {
5704260219Skevlo		run_write(sc, RT2860_TX_SW_CFG2,
5705260219Skevlo		    sc->patch_dac ? 0x2c : 0x0f);
5706260219Skevlo	} else
5707260219Skevlo		run_write(sc, RT2860_TX_SW_CFG2, 0);
5708260219Skevlo
5709260219Skevlo	run_rt3070_rf_read(sc, 50, &rf);
5710260219Skevlo	run_rt3070_rf_write(sc, 50, rf & ~RT3593_TX_LO2);
5711260219Skevlo
5712260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
5713260219Skevlo	rf = (rf & ~(RT3593_TX_LO1 | 0x0c)) |
5714260219Skevlo	    ((sc->txmixgain_2ghz & 0x07) << 2);
5715260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
5716260219Skevlo
5717260219Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5718260219Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5719260219Skevlo
5720260219Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5721260219Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5722260219Skevlo
5723260219Skevlo	run_rt3070_rf_read(sc, 1, &rf);
5724260219Skevlo	run_rt3070_rf_write(sc, 1, rf & ~(RT3070_RF_BLOCK | RT3070_PLL_PD));
5725260219Skevlo
5726260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5727260219Skevlo	rf = (rf & ~0x18) | 0x10;
5728260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
5729260219Skevlo
5730260219Skevlo	/* Apply maximum likelihood detection for 2 stream case. */
5731260219Skevlo	run_bbp_read(sc, 105, &bbp);
5732260219Skevlo	if (sc->nrxchains > 1)
5733260219Skevlo		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5734260219Skevlo
5735260219Skevlo	/* Avoid data lost and CRC error. */
5736260219Skevlo	run_bbp_read(sc, 4, &bbp);
5737260219Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5738260219Skevlo
5739260219Skevlo	run_bbp_write(sc, 92, 0x02);
5740260219Skevlo	run_bbp_write(sc, 82, 0x82);
5741260219Skevlo	run_bbp_write(sc, 106, 0x05);
5742260219Skevlo	run_bbp_write(sc, 104, 0x92);
5743260219Skevlo	run_bbp_write(sc, 88, 0x90);
5744260219Skevlo	run_bbp_write(sc, 148, 0xc8);
5745260219Skevlo	run_bbp_write(sc, 47, 0x48);
5746260219Skevlo	run_bbp_write(sc, 120, 0x50);
5747260219Skevlo
5748260219Skevlo	run_bbp_write(sc, 163, 0x9d);
5749260219Skevlo
5750260219Skevlo	/* SNR mapping. */
5751260219Skevlo	run_bbp_write(sc, 142, 0x06);
5752260219Skevlo	run_bbp_write(sc, 143, 0xa0);
5753260219Skevlo	run_bbp_write(sc, 142, 0x07);
5754260219Skevlo	run_bbp_write(sc, 143, 0xa1);
5755260219Skevlo	run_bbp_write(sc, 142, 0x08);
5756260219Skevlo	run_bbp_write(sc, 143, 0xa2);
5757260219Skevlo
5758260219Skevlo	run_bbp_write(sc, 31, 0x08);
5759260219Skevlo	run_bbp_write(sc, 68, 0x0b);
5760260219Skevlo	run_bbp_write(sc, 105, 0x04);
5761260219Skevlo}
5762260219Skevlo
5763260219Skevlostatic void
5764260219Skevlorun_rt5390_rf_setup(struct run_softc *sc)
5765260219Skevlo{
5766260219Skevlo	uint8_t bbp, rf;
5767260219Skevlo
5768260219Skevlo	if (sc->mac_rev >= 0x0211) {
5769260219Skevlo		/* Enable DC filter. */
5770260219Skevlo		run_bbp_write(sc, 103, 0xc0);
5771260219Skevlo
5772260219Skevlo		if (sc->mac_ver != 0x5592) {
5773260219Skevlo			/* Improve power consumption. */
5774260219Skevlo			run_bbp_read(sc, 31, &bbp);
5775260219Skevlo			run_bbp_write(sc, 31, bbp & ~0x03);
5776260219Skevlo		}
5777260219Skevlo	}
5778260219Skevlo
5779260219Skevlo	run_bbp_read(sc, 138, &bbp);
5780260219Skevlo	if (sc->ntxchains == 1)
5781260219Skevlo		bbp |= 0x20;	/* turn off DAC1 */
5782260219Skevlo	if (sc->nrxchains == 1)
5783260219Skevlo		bbp &= ~0x02;	/* turn off ADC1 */
5784260219Skevlo	run_bbp_write(sc, 138, bbp);
5785260219Skevlo
5786260219Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5787260219Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5788260219Skevlo
5789260219Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5790260219Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5791260219Skevlo
5792260219Skevlo	/* Avoid data lost and CRC error. */
5793260219Skevlo	run_bbp_read(sc, 4, &bbp);
5794260219Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5795260219Skevlo
5796260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5797260219Skevlo	rf = (rf & ~0x18) | 0x10;
5798260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
5799260219Skevlo
5800260219Skevlo	if (sc->mac_ver != 0x5592) {
5801260219Skevlo		run_write(sc, RT2860_TX_SW_CFG1, 0);
5802260219Skevlo		if (sc->mac_rev < 0x0211) {
5803260219Skevlo			run_write(sc, RT2860_TX_SW_CFG2,
5804260219Skevlo			    sc->patch_dac ? 0x2c : 0x0f);
5805260219Skevlo		} else
5806260219Skevlo			run_write(sc, RT2860_TX_SW_CFG2, 0);
5807260219Skevlo	}
5808260219Skevlo}
5809260219Skevlo
5810203134Sthompsastatic int
5811203134Sthompsarun_txrx_enable(struct run_softc *sc)
5812203134Sthompsa{
5813287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5814203134Sthompsa	uint32_t tmp;
5815203134Sthompsa	int error, ntries;
5816203134Sthompsa
5817203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN);
5818203134Sthompsa	for (ntries = 0; ntries < 200; ntries++) {
5819203134Sthompsa		if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0)
5820257955Skevlo			return (error);
5821203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5822203134Sthompsa			break;
5823203134Sthompsa		run_delay(sc, 50);
5824203134Sthompsa	}
5825203134Sthompsa	if (ntries == 200)
5826257955Skevlo		return (ETIMEDOUT);
5827203134Sthompsa
5828203134Sthompsa	run_delay(sc, 50);
5829203134Sthompsa
5830203134Sthompsa	tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE;
5831203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
5832203134Sthompsa
5833203134Sthompsa	/* enable Rx bulk aggregation (set timeout and limit) */
5834203134Sthompsa	tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN |
5835203134Sthompsa	    RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2);
5836203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, tmp);
5837203134Sthompsa
5838203134Sthompsa	/* set Rx filter */
5839203134Sthompsa	tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR;
5840203134Sthompsa	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
5841203134Sthompsa		tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL |
5842203134Sthompsa		    RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK |
5843203134Sthompsa		    RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV |
5844203134Sthompsa		    RT2860_DROP_CFACK | RT2860_DROP_CFEND;
5845203134Sthompsa		if (ic->ic_opmode == IEEE80211_M_STA)
5846203134Sthompsa			tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL;
5847203134Sthompsa	}
5848203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5849203134Sthompsa
5850203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
5851203134Sthompsa	    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
5852203134Sthompsa
5853209917Sthompsa	return (0);
5854203134Sthompsa}
5855203134Sthompsa
5856203134Sthompsastatic void
5857259030Skevlorun_adjust_freq_offset(struct run_softc *sc)
5858257955Skevlo{
5859257955Skevlo	uint8_t rf, tmp;
5860257955Skevlo
5861257955Skevlo	run_rt3070_rf_read(sc, 17, &rf);
5862257955Skevlo	tmp = rf;
5863257955Skevlo	rf = (rf & ~0x7f) | (sc->freq & 0x7f);
5864257955Skevlo	rf = MIN(rf, 0x5f);
5865257955Skevlo
5866257955Skevlo	if (tmp != rf)
5867257955Skevlo		run_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf);
5868257955Skevlo}
5869257955Skevlo
5870257955Skevlostatic void
5871203134Sthompsarun_init_locked(struct run_softc *sc)
5872203134Sthompsa{
5873287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5874287197Sglebius	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
5875203134Sthompsa	uint32_t tmp;
5876203134Sthompsa	uint8_t bbp1, bbp3;
5877203134Sthompsa	int i;
5878203134Sthompsa	int ridx;
5879203134Sthompsa	int ntries;
5880203134Sthompsa
5881209917Sthompsa	if (ic->ic_nrunning > 1)
5882208019Sthompsa		return;
5883208019Sthompsa
5884203134Sthompsa	run_stop(sc);
5885203134Sthompsa
5886233283Sbschmidt	if (run_load_microcode(sc) != 0) {
5887233283Sbschmidt		device_printf(sc->sc_dev, "could not load 8051 microcode\n");
5888233283Sbschmidt		goto fail;
5889233283Sbschmidt	}
5890233283Sbschmidt
5891203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5892203134Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0)
5893203134Sthompsa			goto fail;
5894203134Sthompsa		if (tmp != 0 && tmp != 0xffffffff)
5895203134Sthompsa			break;
5896203134Sthompsa		run_delay(sc, 10);
5897203134Sthompsa	}
5898203134Sthompsa	if (ntries == 100)
5899203134Sthompsa		goto fail;
5900203134Sthompsa
5901203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
5902203134Sthompsa		run_setup_tx_list(sc, &sc->sc_epq[i]);
5903203134Sthompsa
5904287197Sglebius	run_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr);
5905203134Sthompsa
5906203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5907203134Sthompsa		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
5908203134Sthompsa			goto fail;
5909203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5910203134Sthompsa			break;
5911203134Sthompsa		run_delay(sc, 10);
5912203134Sthompsa	}
5913203134Sthompsa	if (ntries == 100) {
5914203138Sthompsa		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
5915203134Sthompsa		goto fail;
5916203134Sthompsa	}
5917203134Sthompsa	tmp &= 0xff0;
5918203134Sthompsa	tmp |= RT2860_TX_WB_DDONE;
5919203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
5920203134Sthompsa
5921203134Sthompsa	/* turn off PME_OEN to solve high-current issue */
5922203134Sthompsa	run_read(sc, RT2860_SYS_CTRL, &tmp);
5923203134Sthompsa	run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN);
5924203134Sthompsa
5925203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
5926203134Sthompsa	    RT2860_BBP_HRST | RT2860_MAC_SRST);
5927203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
5928203134Sthompsa
5929203134Sthompsa	if (run_reset(sc) != 0) {
5930203138Sthompsa		device_printf(sc->sc_dev, "could not reset chipset\n");
5931203134Sthompsa		goto fail;
5932203134Sthompsa	}
5933203134Sthompsa
5934203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
5935203134Sthompsa
5936203134Sthompsa	/* init Tx power for all Tx rates (from EEPROM) */
5937203134Sthompsa	for (ridx = 0; ridx < 5; ridx++) {
5938203134Sthompsa		if (sc->txpow20mhz[ridx] == 0xffffffff)
5939203134Sthompsa			continue;
5940203134Sthompsa		run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]);
5941203134Sthompsa	}
5942203134Sthompsa
5943257955Skevlo	for (i = 0; i < nitems(rt2870_def_mac); i++)
5944203134Sthompsa		run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val);
5945203134Sthompsa	run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273);
5946203134Sthompsa	run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344);
5947203134Sthompsa	run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa);
5948203134Sthompsa
5949259030Skevlo	if (sc->mac_ver >= 0x5390) {
5950259030Skevlo		run_write(sc, RT2860_TX_SW_CFG0,
5951259030Skevlo		    4 << RT2860_DLY_PAPE_EN_SHIFT | 4);
5952259030Skevlo		if (sc->mac_ver >= 0x5392) {
5953259030Skevlo			run_write(sc, RT2860_MAX_LEN_CFG, 0x00002fff);
5954259032Skevlo			if (sc->mac_ver == 0x5592) {
5955259032Skevlo				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcba980);
5956259032Skevlo				run_write(sc, RT2860_TXOP_HLDR_ET, 0x00000082);
5957259032Skevlo			} else {
5958259032Skevlo				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcb4980);
5959259032Skevlo				run_write(sc, RT2860_LG_FBK_CFG0, 0xedcba322);
5960259032Skevlo			}
5961259030Skevlo		}
5962260219Skevlo	} else if (sc->mac_ver == 0x3593) {
5963260219Skevlo		run_write(sc, RT2860_TX_SW_CFG0,
5964260219Skevlo		    4 << RT2860_DLY_PAPE_EN_SHIFT | 2);
5965257955Skevlo	} else if (sc->mac_ver >= 0x3070) {
5966203134Sthompsa		/* set delay of PA_PE assertion to 1us (unit of 0.25us) */
5967203134Sthompsa		run_write(sc, RT2860_TX_SW_CFG0,
5968203134Sthompsa		    4 << RT2860_DLY_PAPE_EN_SHIFT);
5969203134Sthompsa	}
5970203134Sthompsa
5971203134Sthompsa	/* wait while MAC is busy */
5972203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5973203134Sthompsa		if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0)
5974203134Sthompsa			goto fail;
5975203134Sthompsa		if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY)))
5976203134Sthompsa			break;
5977203134Sthompsa		run_delay(sc, 10);
5978203134Sthompsa	}
5979203134Sthompsa	if (ntries == 100)
5980203134Sthompsa		goto fail;
5981203134Sthompsa
5982203134Sthompsa	/* clear Host to MCU mailbox */
5983203134Sthompsa	run_write(sc, RT2860_H2M_BBPAGENT, 0);
5984203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
5985203134Sthompsa	run_delay(sc, 10);
5986203134Sthompsa
5987203134Sthompsa	if (run_bbp_init(sc) != 0) {
5988203138Sthompsa		device_printf(sc->sc_dev, "could not initialize BBP\n");
5989203134Sthompsa		goto fail;
5990203134Sthompsa	}
5991203134Sthompsa
5992203134Sthompsa	/* abort TSF synchronization */
5993203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
5994203134Sthompsa	tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
5995203134Sthompsa	    RT2860_TBTT_TIMER_EN);
5996203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
5997203134Sthompsa
5998203134Sthompsa	/* clear RX WCID search table */
5999203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512);
6000203134Sthompsa	/* clear WCID attribute table */
6001203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32);
6002203134Sthompsa
6003209144Sthompsa	/* hostapd sets a key before init. So, don't clear it. */
6004209917Sthompsa	if (sc->cmdq_key_set != RUN_CMDQ_GO) {
6005209144Sthompsa		/* clear shared key table */
6006209144Sthompsa		run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32);
6007209144Sthompsa		/* clear shared key mode */
6008209144Sthompsa		run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4);
6009209144Sthompsa	}
6010209144Sthompsa
6011203134Sthompsa	run_read(sc, RT2860_US_CYC_CNT, &tmp);
6012203134Sthompsa	tmp = (tmp & ~0xff) | 0x1e;
6013203134Sthompsa	run_write(sc, RT2860_US_CYC_CNT, tmp);
6014203134Sthompsa
6015205042Sthompsa	if (sc->mac_rev != 0x0101)
6016203134Sthompsa		run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f);
6017203134Sthompsa
6018203134Sthompsa	run_write(sc, RT2860_WMM_TXOP0_CFG, 0);
6019203134Sthompsa	run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96);
6020203134Sthompsa
6021203134Sthompsa	/* write vendor-specific BBP values (from EEPROM) */
6022260219Skevlo	if (sc->mac_ver < 0x3593) {
6023257955Skevlo		for (i = 0; i < 10; i++) {
6024257955Skevlo			if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff)
6025257955Skevlo				continue;
6026257955Skevlo			run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val);
6027257955Skevlo		}
6028203134Sthompsa	}
6029203134Sthompsa
6030203134Sthompsa	/* select Main antenna for 1T1R devices */
6031257955Skevlo	if (sc->rf_rev == RT3070_RF_3020 || sc->rf_rev == RT5390_RF_5370)
6032203134Sthompsa		run_set_rx_antenna(sc, 0);
6033203134Sthompsa
6034203134Sthompsa	/* send LEDs operating mode to microcontroller */
6035203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]);
6036203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]);
6037203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]);
6038203134Sthompsa
6039257955Skevlo	if (sc->mac_ver >= 0x5390)
6040257955Skevlo		run_rt5390_rf_init(sc);
6041260219Skevlo	else if (sc->mac_ver == 0x3593)
6042260219Skevlo		run_rt3593_rf_init(sc);
6043257955Skevlo	else if (sc->mac_ver >= 0x3070)
6044205042Sthompsa		run_rt3070_rf_init(sc);
6045205042Sthompsa
6046203134Sthompsa	/* disable non-existing Rx chains */
6047203134Sthompsa	run_bbp_read(sc, 3, &bbp3);
6048203134Sthompsa	bbp3 &= ~(1 << 3 | 1 << 4);
6049203134Sthompsa	if (sc->nrxchains == 2)
6050203134Sthompsa		bbp3 |= 1 << 3;
6051203134Sthompsa	else if (sc->nrxchains == 3)
6052203134Sthompsa		bbp3 |= 1 << 4;
6053203134Sthompsa	run_bbp_write(sc, 3, bbp3);
6054203134Sthompsa
6055203134Sthompsa	/* disable non-existing Tx chains */
6056203134Sthompsa	run_bbp_read(sc, 1, &bbp1);
6057203134Sthompsa	if (sc->ntxchains == 1)
6058203134Sthompsa		bbp1 &= ~(1 << 3 | 1 << 4);
6059203134Sthompsa	run_bbp_write(sc, 1, bbp1);
6060203134Sthompsa
6061260219Skevlo	if (sc->mac_ver >= 0x5390)
6062260219Skevlo		run_rt5390_rf_setup(sc);
6063260219Skevlo	else if (sc->mac_ver == 0x3593)
6064260219Skevlo		run_rt3593_rf_setup(sc);
6065260219Skevlo	else if (sc->mac_ver >= 0x3070)
6066205042Sthompsa		run_rt3070_rf_setup(sc);
6067203134Sthompsa
6068203134Sthompsa	/* select default channel */
6069203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
6070203134Sthompsa
6071203134Sthompsa	/* setup initial protection mode */
6072218492Sbschmidt	run_updateprot_cb(ic);
6073203134Sthompsa
6074203134Sthompsa	/* turn radio LED on */
6075203134Sthompsa	run_set_leds(sc, RT2860_LED_RADIO);
6076203134Sthompsa
6077287197Sglebius	sc->sc_flags |= RUN_RUNNING;
6078208019Sthompsa	sc->cmdq_run = RUN_CMDQ_GO;
6079203134Sthompsa
6080209917Sthompsa	for (i = 0; i != RUN_N_XFER; i++)
6081203134Sthompsa		usbd_xfer_set_stall(sc->sc_xfer[i]);
6082203134Sthompsa
6083203134Sthompsa	usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]);
6084203134Sthompsa
6085203134Sthompsa	if (run_txrx_enable(sc) != 0)
6086203134Sthompsa		goto fail;
6087203134Sthompsa
6088203134Sthompsa	return;
6089203134Sthompsa
6090203134Sthompsafail:
6091203134Sthompsa	run_stop(sc);
6092203134Sthompsa}
6093203134Sthompsa
6094203134Sthompsastatic void
6095203134Sthompsarun_stop(void *arg)
6096203134Sthompsa{
6097203134Sthompsa	struct run_softc *sc = (struct run_softc *)arg;
6098203134Sthompsa	uint32_t tmp;
6099203134Sthompsa	int i;
6100203134Sthompsa	int ntries;
6101203134Sthompsa
6102203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
6103203134Sthompsa
6104287197Sglebius	if (sc->sc_flags & RUN_RUNNING)
6105203134Sthompsa		run_set_leds(sc, 0);	/* turn all LEDs off */
6106203134Sthompsa
6107287197Sglebius	sc->sc_flags &= ~RUN_RUNNING;
6108203134Sthompsa
6109208019Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
6110209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set;
6111208019Sthompsa
6112203134Sthompsa	RUN_UNLOCK(sc);
6113203134Sthompsa
6114203134Sthompsa	for(i = 0; i < RUN_N_XFER; i++)
6115203134Sthompsa		usbd_transfer_drain(sc->sc_xfer[i]);
6116203134Sthompsa
6117203134Sthompsa	RUN_LOCK(sc);
6118203134Sthompsa
6119209917Sthompsa	if (sc->rx_m != NULL) {
6120203134Sthompsa		m_free(sc->rx_m);
6121203134Sthompsa		sc->rx_m = NULL;
6122203134Sthompsa	}
6123203134Sthompsa
6124257955Skevlo	/* Disable Tx/Rx DMA. */
6125257955Skevlo	if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6126257955Skevlo		return;
6127257955Skevlo	tmp &= ~(RT2860_RX_DMA_EN | RT2860_TX_DMA_EN);
6128257955Skevlo	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
6129257955Skevlo
6130258643Shselasky	for (ntries = 0; ntries < 100; ntries++) {
6131257955Skevlo		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6132257955Skevlo			return;
6133257955Skevlo		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
6134257955Skevlo				break;
6135257955Skevlo		run_delay(sc, 10);
6136257955Skevlo	}
6137257955Skevlo	if (ntries == 100) {
6138257955Skevlo		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
6139257955Skevlo		return;
6140257955Skevlo	}
6141257955Skevlo
6142203134Sthompsa	/* disable Tx/Rx */
6143203134Sthompsa	run_read(sc, RT2860_MAC_SYS_CTRL, &tmp);
6144203134Sthompsa	tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
6145203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, tmp);
6146203134Sthompsa
6147203134Sthompsa	/* wait for pending Tx to complete */
6148203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
6149209917Sthompsa		if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0) {
6150203134Sthompsa			DPRINTF("Cannot read Tx queue count\n");
6151203134Sthompsa			break;
6152203134Sthompsa		}
6153209917Sthompsa		if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0) {
6154203134Sthompsa			DPRINTF("All Tx cleared\n");
6155203134Sthompsa			break;
6156203134Sthompsa		}
6157203134Sthompsa		run_delay(sc, 10);
6158203134Sthompsa	}
6159209917Sthompsa	if (ntries >= 100)
6160203134Sthompsa		DPRINTF("There are still pending Tx\n");
6161203134Sthompsa	run_delay(sc, 10);
6162203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
6163203134Sthompsa
6164203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST);
6165203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
6166203134Sthompsa
6167203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
6168203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
6169203134Sthompsa}
6170203134Sthompsa
6171203134Sthompsastatic void
6172257429Shselaskyrun_delay(struct run_softc *sc, u_int ms)
6173203134Sthompsa{
6174203134Sthompsa	usb_pause_mtx(mtx_owned(&sc->sc_mtx) ?
6175203134Sthompsa	    &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms));
6176203134Sthompsa}
6177203134Sthompsa
6178203134Sthompsastatic device_method_t run_methods[] = {
6179203134Sthompsa	/* Device interface */
6180203134Sthompsa	DEVMETHOD(device_probe,		run_match),
6181203134Sthompsa	DEVMETHOD(device_attach,	run_attach),
6182203134Sthompsa	DEVMETHOD(device_detach,	run_detach),
6183246614Shselasky	DEVMETHOD_END
6184203134Sthompsa};
6185203134Sthompsa
6186203134Sthompsastatic driver_t run_driver = {
6187233774Shselasky	.name = "run",
6188233774Shselasky	.methods = run_methods,
6189233774Shselasky	.size = sizeof(struct run_softc)
6190203134Sthompsa};
6191203134Sthompsa
6192203134Sthompsastatic devclass_t run_devclass;
6193203134Sthompsa
6194259812SkevloDRIVER_MODULE(run, uhub, run_driver, run_devclass, run_driver_loaded, NULL);
6195212122SthompsaMODULE_DEPEND(run, wlan, 1, 1, 1);
6196212122SthompsaMODULE_DEPEND(run, usb, 1, 1, 1);
6197212122SthompsaMODULE_DEPEND(run, firmware, 1, 1, 1);
6198212122SthompsaMODULE_VERSION(run, 1);
6199