if_run.c revision 287197
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 287197 2015-08-27 08:56:39Z glebius $");
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
91259546Skevlo#define	IEEE80211_HAS_ADDR4(wh)	\
92203134Sthompsa	(((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
93203134Sthompsa
94208019Sthompsa/*
95208019Sthompsa * Because of LOR in run_key_delete(), use atomic instead.
96208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[].
97208019Sthompsa */
98259546Skevlo#define	RUN_CMDQ_GET(c)	(atomic_fetchadd_32((c), 1) & RUN_CMDQ_MASQ)
99208019Sthompsa
100223486Shselaskystatic const STRUCT_USB_HOST_ID run_devs[] = {
101259546Skevlo#define	RUN_DEV(v,p)	{ USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
102259812Skevlo#define	RUN_DEV_EJECT(v,p)	\
103262465Skevlo	{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RUN_EJECT) }
104262465Skevlo#define	RUN_EJECT	1
105209918Sthompsa    RUN_DEV(ABOCOM,		RT2770),
106209918Sthompsa    RUN_DEV(ABOCOM,		RT2870),
107209918Sthompsa    RUN_DEV(ABOCOM,		RT3070),
108209918Sthompsa    RUN_DEV(ABOCOM,		RT3071),
109209918Sthompsa    RUN_DEV(ABOCOM,		RT3072),
110209918Sthompsa    RUN_DEV(ABOCOM2,		RT2870_1),
111209918Sthompsa    RUN_DEV(ACCTON,		RT2770),
112209918Sthompsa    RUN_DEV(ACCTON,		RT2870_1),
113209918Sthompsa    RUN_DEV(ACCTON,		RT2870_2),
114209918Sthompsa    RUN_DEV(ACCTON,		RT2870_3),
115209918Sthompsa    RUN_DEV(ACCTON,		RT2870_4),
116209918Sthompsa    RUN_DEV(ACCTON,		RT2870_5),
117209918Sthompsa    RUN_DEV(ACCTON,		RT3070),
118209918Sthompsa    RUN_DEV(ACCTON,		RT3070_1),
119209918Sthompsa    RUN_DEV(ACCTON,		RT3070_2),
120209918Sthompsa    RUN_DEV(ACCTON,		RT3070_3),
121209918Sthompsa    RUN_DEV(ACCTON,		RT3070_4),
122209918Sthompsa    RUN_DEV(ACCTON,		RT3070_5),
123209918Sthompsa    RUN_DEV(AIRTIES,		RT3070),
124209918Sthompsa    RUN_DEV(ALLWIN,		RT2070),
125209918Sthompsa    RUN_DEV(ALLWIN,		RT2770),
126209918Sthompsa    RUN_DEV(ALLWIN,		RT2870),
127209918Sthompsa    RUN_DEV(ALLWIN,		RT3070),
128209918Sthompsa    RUN_DEV(ALLWIN,		RT3071),
129209918Sthompsa    RUN_DEV(ALLWIN,		RT3072),
130209918Sthompsa    RUN_DEV(ALLWIN,		RT3572),
131209918Sthompsa    RUN_DEV(AMIGO,		RT2870_1),
132209918Sthompsa    RUN_DEV(AMIGO,		RT2870_2),
133209918Sthompsa    RUN_DEV(AMIT,		CGWLUSB2GNR),
134209918Sthompsa    RUN_DEV(AMIT,		RT2870_1),
135209918Sthompsa    RUN_DEV(AMIT2,		RT2870),
136209918Sthompsa    RUN_DEV(ASUS,		RT2870_1),
137209918Sthompsa    RUN_DEV(ASUS,		RT2870_2),
138209918Sthompsa    RUN_DEV(ASUS,		RT2870_3),
139209918Sthompsa    RUN_DEV(ASUS,		RT2870_4),
140209918Sthompsa    RUN_DEV(ASUS,		RT2870_5),
141209918Sthompsa    RUN_DEV(ASUS,		USBN13),
142209918Sthompsa    RUN_DEV(ASUS,		RT3070_1),
143260219Skevlo    RUN_DEV(ASUS,		USBN66),
144239358Shselasky    RUN_DEV(ASUS,		USB_N53),
145209918Sthompsa    RUN_DEV(ASUS2,		USBN11),
146209918Sthompsa    RUN_DEV(AZUREWAVE,		RT2870_1),
147209918Sthompsa    RUN_DEV(AZUREWAVE,		RT2870_2),
148209918Sthompsa    RUN_DEV(AZUREWAVE,		RT3070_1),
149209918Sthompsa    RUN_DEV(AZUREWAVE,		RT3070_2),
150209918Sthompsa    RUN_DEV(AZUREWAVE,		RT3070_3),
151260219Skevlo    RUN_DEV(BELKIN,		F9L1103),
152209918Sthompsa    RUN_DEV(BELKIN,		F5D8053V3),
153209918Sthompsa    RUN_DEV(BELKIN,		F5D8055),
154226534Shselasky    RUN_DEV(BELKIN,		F5D8055V2),
155209918Sthompsa    RUN_DEV(BELKIN,		F6D4050V1),
156256500Shselasky    RUN_DEV(BELKIN,		F6D4050V2),
157209918Sthompsa    RUN_DEV(BELKIN,		RT2870_1),
158209918Sthompsa    RUN_DEV(BELKIN,		RT2870_2),
159226534Shselasky    RUN_DEV(CISCOLINKSYS,	AE1000),
160209918Sthompsa    RUN_DEV(CISCOLINKSYS2,	RT3070),
161209918Sthompsa    RUN_DEV(CISCOLINKSYS3,	RT3070),
162209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_1),
163209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_2),
164209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_3),
165209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_4),
166209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_5),
167209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_6),
168209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_7),
169209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_8),
170209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT3070_1),
171209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT3070_2),
172209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	VIGORN61),
173209918Sthompsa    RUN_DEV(COREGA,		CGWLUSB300GNM),
174209918Sthompsa    RUN_DEV(COREGA,		RT2870_1),
175209918Sthompsa    RUN_DEV(COREGA,		RT2870_2),
176209918Sthompsa    RUN_DEV(COREGA,		RT2870_3),
177209918Sthompsa    RUN_DEV(COREGA,		RT3070),
178209918Sthompsa    RUN_DEV(CYBERTAN,		RT2870),
179209918Sthompsa    RUN_DEV(DLINK,		RT2870),
180209918Sthompsa    RUN_DEV(DLINK,		RT3072),
181255238Sbr    RUN_DEV(DLINK,		DWA127),
182257955Skevlo    RUN_DEV(DLINK,		DWA140B3),
183259032Skevlo    RUN_DEV(DLINK,		DWA160B2),
184267089Skevlo    RUN_DEV(DLINK,		DWA140D1),
185260219Skevlo    RUN_DEV(DLINK,		DWA162),
186209918Sthompsa    RUN_DEV(DLINK2,		DWA130),
187209918Sthompsa    RUN_DEV(DLINK2,		RT2870_1),
188209918Sthompsa    RUN_DEV(DLINK2,		RT2870_2),
189209918Sthompsa    RUN_DEV(DLINK2,		RT3070_1),
190209918Sthompsa    RUN_DEV(DLINK2,		RT3070_2),
191209918Sthompsa    RUN_DEV(DLINK2,		RT3070_3),
192209918Sthompsa    RUN_DEV(DLINK2,		RT3070_4),
193209918Sthompsa    RUN_DEV(DLINK2,		RT3070_5),
194209918Sthompsa    RUN_DEV(DLINK2,		RT3072),
195209918Sthompsa    RUN_DEV(DLINK2,		RT3072_1),
196209918Sthompsa    RUN_DEV(EDIMAX,		EW7717),
197209918Sthompsa    RUN_DEV(EDIMAX,		EW7718),
198260219Skevlo    RUN_DEV(EDIMAX,		EW7733UND),
199209918Sthompsa    RUN_DEV(EDIMAX,		RT2870_1),
200209918Sthompsa    RUN_DEV(ENCORE,		RT3070_1),
201209918Sthompsa    RUN_DEV(ENCORE,		RT3070_2),
202209918Sthompsa    RUN_DEV(ENCORE,		RT3070_3),
203209918Sthompsa    RUN_DEV(GIGABYTE,		GNWB31N),
204209918Sthompsa    RUN_DEV(GIGABYTE,		GNWB32L),
205209918Sthompsa    RUN_DEV(GIGABYTE,		RT2870_1),
206209918Sthompsa    RUN_DEV(GIGASET,		RT3070_1),
207209918Sthompsa    RUN_DEV(GIGASET,		RT3070_2),
208209918Sthompsa    RUN_DEV(GUILLEMOT,		HWNU300),
209209918Sthompsa    RUN_DEV(HAWKING,		HWUN2),
210209918Sthompsa    RUN_DEV(HAWKING,		RT2870_1),
211209918Sthompsa    RUN_DEV(HAWKING,		RT2870_2),
212209918Sthompsa    RUN_DEV(HAWKING,		RT3070),
213209918Sthompsa    RUN_DEV(IODATA,		RT3072_1),
214209918Sthompsa    RUN_DEV(IODATA,		RT3072_2),
215209918Sthompsa    RUN_DEV(IODATA,		RT3072_3),
216209918Sthompsa    RUN_DEV(IODATA,		RT3072_4),
217209918Sthompsa    RUN_DEV(LINKSYS4,		RT3070),
218209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB100),
219209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB54GCV3),
220209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB600N),
221209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB600NV2),
222209918Sthompsa    RUN_DEV(LOGITEC,		RT2870_1),
223209918Sthompsa    RUN_DEV(LOGITEC,		RT2870_2),
224209918Sthompsa    RUN_DEV(LOGITEC,		RT2870_3),
225230333Shselasky    RUN_DEV(LOGITEC,		LANW300NU2),
226238274Shrs    RUN_DEV(LOGITEC,		LANW150NU2),
227248458Shselasky    RUN_DEV(LOGITEC,		LANW300NU2S),
228281745Skevlo    RUN_DEV(MELCO,		WLIUCG300HP),
229209918Sthompsa    RUN_DEV(MELCO,		RT2870_2),
230209918Sthompsa    RUN_DEV(MELCO,		WLIUCAG300N),
231209918Sthompsa    RUN_DEV(MELCO,		WLIUCG300N),
232219257Sdaichi    RUN_DEV(MELCO,		WLIUCG301N),
233209918Sthompsa    RUN_DEV(MELCO,		WLIUCGN),
234227781Shselasky    RUN_DEV(MELCO,		WLIUCGNM),
235281745Skevlo    RUN_DEV(MELCO,		WLIUCG300HPV1),
236238274Shrs    RUN_DEV(MELCO,		WLIUCGNM2),
237209918Sthompsa    RUN_DEV(MOTOROLA4,		RT2770),
238209918Sthompsa    RUN_DEV(MOTOROLA4,		RT3070),
239209918Sthompsa    RUN_DEV(MSI,		RT3070_1),
240209918Sthompsa    RUN_DEV(MSI,		RT3070_2),
241209918Sthompsa    RUN_DEV(MSI,		RT3070_3),
242209918Sthompsa    RUN_DEV(MSI,		RT3070_4),
243209918Sthompsa    RUN_DEV(MSI,		RT3070_5),
244209918Sthompsa    RUN_DEV(MSI,		RT3070_6),
245209918Sthompsa    RUN_DEV(MSI,		RT3070_7),
246209918Sthompsa    RUN_DEV(MSI,		RT3070_8),
247209918Sthompsa    RUN_DEV(MSI,		RT3070_9),
248209918Sthompsa    RUN_DEV(MSI,		RT3070_10),
249209918Sthompsa    RUN_DEV(MSI,		RT3070_11),
250209918Sthompsa    RUN_DEV(OVISLINK,		RT3072),
251209918Sthompsa    RUN_DEV(PARA,		RT3070),
252209918Sthompsa    RUN_DEV(PEGATRON,		RT2870),
253209918Sthompsa    RUN_DEV(PEGATRON,		RT3070),
254209918Sthompsa    RUN_DEV(PEGATRON,		RT3070_2),
255209918Sthompsa    RUN_DEV(PEGATRON,		RT3070_3),
256209918Sthompsa    RUN_DEV(PHILIPS,		RT2870),
257209918Sthompsa    RUN_DEV(PLANEX2,		GWUS300MINIS),
258209918Sthompsa    RUN_DEV(PLANEX2,		GWUSMICRON),
259209918Sthompsa    RUN_DEV(PLANEX2,		RT2870),
260209918Sthompsa    RUN_DEV(PLANEX2,		RT3070),
261209918Sthompsa    RUN_DEV(QCOM,		RT2870),
262209918Sthompsa    RUN_DEV(QUANTA,		RT3070),
263209918Sthompsa    RUN_DEV(RALINK,		RT2070),
264209918Sthompsa    RUN_DEV(RALINK,		RT2770),
265209918Sthompsa    RUN_DEV(RALINK,		RT2870),
266209918Sthompsa    RUN_DEV(RALINK,		RT3070),
267209918Sthompsa    RUN_DEV(RALINK,		RT3071),
268209918Sthompsa    RUN_DEV(RALINK,		RT3072),
269209918Sthompsa    RUN_DEV(RALINK,		RT3370),
270209918Sthompsa    RUN_DEV(RALINK,		RT3572),
271260219Skevlo    RUN_DEV(RALINK,		RT3573),
272257955Skevlo    RUN_DEV(RALINK,		RT5370),
273259032Skevlo    RUN_DEV(RALINK,		RT5572),
274209918Sthompsa    RUN_DEV(RALINK,		RT8070),
275226534Shselasky    RUN_DEV(SAMSUNG,		WIS09ABGN),
276209918Sthompsa    RUN_DEV(SAMSUNG2,		RT2870_1),
277209918Sthompsa    RUN_DEV(SENAO,		RT2870_1),
278209918Sthompsa    RUN_DEV(SENAO,		RT2870_2),
279209918Sthompsa    RUN_DEV(SENAO,		RT2870_3),
280209918Sthompsa    RUN_DEV(SENAO,		RT2870_4),
281209918Sthompsa    RUN_DEV(SENAO,		RT3070),
282209918Sthompsa    RUN_DEV(SENAO,		RT3071),
283209918Sthompsa    RUN_DEV(SENAO,		RT3072_1),
284209918Sthompsa    RUN_DEV(SENAO,		RT3072_2),
285209918Sthompsa    RUN_DEV(SENAO,		RT3072_3),
286209918Sthompsa    RUN_DEV(SENAO,		RT3072_4),
287209918Sthompsa    RUN_DEV(SENAO,		RT3072_5),
288209918Sthompsa    RUN_DEV(SITECOMEU,		RT2770),
289209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_1),
290209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_2),
291209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_3),
292209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_4),
293209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070),
294209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070_2),
295209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070_3),
296209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070_4),
297209918Sthompsa    RUN_DEV(SITECOMEU,		RT3071),
298209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_1),
299209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_2),
300209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_3),
301209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_4),
302209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_5),
303209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_6),
304209918Sthompsa    RUN_DEV(SITECOMEU,		WL608),
305209918Sthompsa    RUN_DEV(SPARKLAN,		RT2870_1),
306209918Sthompsa    RUN_DEV(SPARKLAN,		RT3070),
307209918Sthompsa    RUN_DEV(SWEEX2,		LW153),
308209918Sthompsa    RUN_DEV(SWEEX2,		LW303),
309209918Sthompsa    RUN_DEV(SWEEX2,		LW313),
310209918Sthompsa    RUN_DEV(TOSHIBA,		RT3070),
311209918Sthompsa    RUN_DEV(UMEDIA,		RT2870_1),
312209918Sthompsa    RUN_DEV(ZCOM,		RT2870_1),
313209918Sthompsa    RUN_DEV(ZCOM,		RT2870_2),
314209918Sthompsa    RUN_DEV(ZINWELL,		RT2870_1),
315209918Sthompsa    RUN_DEV(ZINWELL,		RT2870_2),
316209918Sthompsa    RUN_DEV(ZINWELL,		RT3070),
317209918Sthompsa    RUN_DEV(ZINWELL,		RT3072_1),
318209918Sthompsa    RUN_DEV(ZINWELL,		RT3072_2),
319209918Sthompsa    RUN_DEV(ZYXEL,		RT2870_1),
320209918Sthompsa    RUN_DEV(ZYXEL,		RT2870_2),
321263985Shselasky    RUN_DEV(ZYXEL,		RT3070),
322262465Skevlo    RUN_DEV_EJECT(ZYXEL,	NWD2705),
323259812Skevlo    RUN_DEV_EJECT(RALINK,	RT_STOR),
324259812Skevlo#undef RUN_DEV_EJECT
325209918Sthompsa#undef RUN_DEV
326203134Sthompsa};
327203134Sthompsa
328203134Sthompsastatic device_probe_t	run_match;
329203134Sthompsastatic device_attach_t	run_attach;
330203134Sthompsastatic device_detach_t	run_detach;
331203134Sthompsa
332203134Sthompsastatic usb_callback_t	run_bulk_rx_callback;
333203134Sthompsastatic usb_callback_t	run_bulk_tx_callback0;
334203134Sthompsastatic usb_callback_t	run_bulk_tx_callback1;
335203134Sthompsastatic usb_callback_t	run_bulk_tx_callback2;
336203134Sthompsastatic usb_callback_t	run_bulk_tx_callback3;
337203134Sthompsastatic usb_callback_t	run_bulk_tx_callback4;
338203134Sthompsastatic usb_callback_t	run_bulk_tx_callback5;
339203134Sthompsa
340259812Skevlostatic void	run_autoinst(void *, struct usb_device *,
341259812Skevlo		    struct usb_attach_arg *);
342259812Skevlostatic int	run_driver_loaded(struct module *, int, void *);
343203134Sthompsastatic void	run_bulk_tx_callbackN(struct usb_xfer *xfer,
344257429Shselasky		    usb_error_t error, u_int index);
345203134Sthompsastatic struct ieee80211vap *run_vap_create(struct ieee80211com *,
346228621Sbschmidt		    const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
347228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN],
348228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN]);
349203134Sthompsastatic void	run_vap_delete(struct ieee80211vap *);
350208019Sthompsastatic void	run_cmdq_cb(void *, int);
351203134Sthompsastatic void	run_setup_tx_list(struct run_softc *,
352203134Sthompsa		    struct run_endpoint_queue *);
353203134Sthompsastatic void	run_unsetup_tx_list(struct run_softc *,
354203134Sthompsa		    struct run_endpoint_queue *);
355203134Sthompsastatic int	run_load_microcode(struct run_softc *);
356203134Sthompsastatic int	run_reset(struct run_softc *);
357203134Sthompsastatic usb_error_t run_do_request(struct run_softc *,
358203134Sthompsa		    struct usb_device_request *, void *);
359203134Sthompsastatic int	run_read(struct run_softc *, uint16_t, uint32_t *);
360203134Sthompsastatic int	run_read_region_1(struct run_softc *, uint16_t, uint8_t *, int);
361203134Sthompsastatic int	run_write_2(struct run_softc *, uint16_t, uint16_t);
362203134Sthompsastatic int	run_write(struct run_softc *, uint16_t, uint32_t);
363203134Sthompsastatic int	run_write_region_1(struct run_softc *, uint16_t,
364203134Sthompsa		    const uint8_t *, int);
365203134Sthompsastatic int	run_set_region_4(struct run_softc *, uint16_t, uint32_t, int);
366259544Skevlostatic int	run_efuse_read(struct run_softc *, uint16_t, uint16_t *, int);
367203134Sthompsastatic int	run_efuse_read_2(struct run_softc *, uint16_t, uint16_t *);
368203134Sthompsastatic int	run_eeprom_read_2(struct run_softc *, uint16_t, uint16_t *);
369258733Skevlostatic int	run_rt2870_rf_write(struct run_softc *, uint32_t);
370203134Sthompsastatic int	run_rt3070_rf_read(struct run_softc *, uint8_t, uint8_t *);
371203134Sthompsastatic int	run_rt3070_rf_write(struct run_softc *, uint8_t, uint8_t);
372203134Sthompsastatic int	run_bbp_read(struct run_softc *, uint8_t, uint8_t *);
373203134Sthompsastatic int	run_bbp_write(struct run_softc *, uint8_t, uint8_t);
374203134Sthompsastatic int	run_mcu_cmd(struct run_softc *, uint8_t, uint16_t);
375257955Skevlostatic const char *run_get_rf(uint16_t);
376260219Skevlostatic void	run_rt3593_get_txpower(struct run_softc *);
377260219Skevlostatic void	run_get_txpower(struct run_softc *);
378203134Sthompsastatic int	run_read_eeprom(struct run_softc *);
379203134Sthompsastatic struct ieee80211_node *run_node_alloc(struct ieee80211vap *,
380203134Sthompsa			    const uint8_t mac[IEEE80211_ADDR_LEN]);
381203134Sthompsastatic int	run_media_change(struct ifnet *);
382203134Sthompsastatic int	run_newstate(struct ieee80211vap *, enum ieee80211_state, int);
383203134Sthompsastatic int	run_wme_update(struct ieee80211com *);
384208019Sthompsastatic void	run_wme_update_cb(void *);
385203134Sthompsastatic void	run_key_update_begin(struct ieee80211vap *);
386203134Sthompsastatic void	run_key_update_end(struct ieee80211vap *);
387208019Sthompsastatic void	run_key_set_cb(void *);
388208019Sthompsastatic int	run_key_set(struct ieee80211vap *, struct ieee80211_key *,
389257955Skevlo		    const uint8_t mac[IEEE80211_ADDR_LEN]);
390208019Sthompsastatic void	run_key_delete_cb(void *);
391208019Sthompsastatic int	run_key_delete(struct ieee80211vap *, struct ieee80211_key *);
392206358Srpaulostatic void	run_ratectl_to(void *);
393206358Srpaulostatic void	run_ratectl_cb(void *, int);
394208019Sthompsastatic void	run_drain_fifo(void *);
395203134Sthompsastatic void	run_iter_func(void *, struct ieee80211_node *);
396208019Sthompsastatic void	run_newassoc_cb(void *);
397203134Sthompsastatic void	run_newassoc(struct ieee80211_node *, int);
398203134Sthompsastatic void	run_rx_frame(struct run_softc *, struct mbuf *, uint32_t);
399203134Sthompsastatic void	run_tx_free(struct run_endpoint_queue *pq,
400203134Sthompsa		    struct run_tx_data *, int);
401208019Sthompsastatic void	run_set_tx_desc(struct run_softc *, struct run_tx_data *);
402203134Sthompsastatic int	run_tx(struct run_softc *, struct mbuf *,
403203134Sthompsa		    struct ieee80211_node *);
404203134Sthompsastatic int	run_tx_mgt(struct run_softc *, struct mbuf *,
405203134Sthompsa		    struct ieee80211_node *);
406203134Sthompsastatic int	run_sendprot(struct run_softc *, const struct mbuf *,
407203134Sthompsa		    struct ieee80211_node *, int, int);
408203134Sthompsastatic int	run_tx_param(struct run_softc *, struct mbuf *,
409203134Sthompsa		    struct ieee80211_node *,
410203134Sthompsa		    const struct ieee80211_bpf_params *);
411203134Sthompsastatic int	run_raw_xmit(struct ieee80211_node *, struct mbuf *,
412203134Sthompsa		    const struct ieee80211_bpf_params *);
413287197Sglebiusstatic int	run_transmit(struct ieee80211com *, struct mbuf *);
414287197Sglebiusstatic void	run_start(struct run_softc *);
415287197Sglebiusstatic void	run_parent(struct ieee80211com *);
416259544Skevlostatic void	run_iq_calib(struct run_softc *, u_int);
417205042Sthompsastatic void	run_set_agc(struct run_softc *, uint8_t);
418203134Sthompsastatic void	run_select_chan_group(struct run_softc *, int);
419203134Sthompsastatic void	run_set_rx_antenna(struct run_softc *, int);
420203134Sthompsastatic void	run_rt2870_set_chan(struct run_softc *, u_int);
421203134Sthompsastatic void	run_rt3070_set_chan(struct run_softc *, u_int);
422205042Sthompsastatic void	run_rt3572_set_chan(struct run_softc *, u_int);
423260219Skevlostatic void	run_rt3593_set_chan(struct run_softc *, u_int);
424257955Skevlostatic void	run_rt5390_set_chan(struct run_softc *, u_int);
425259032Skevlostatic void	run_rt5592_set_chan(struct run_softc *, u_int);
426203134Sthompsastatic int	run_set_chan(struct run_softc *, struct ieee80211_channel *);
427203134Sthompsastatic void	run_set_channel(struct ieee80211com *);
428203134Sthompsastatic void	run_scan_start(struct ieee80211com *);
429203134Sthompsastatic void	run_scan_end(struct ieee80211com *);
430203134Sthompsastatic void	run_update_beacon(struct ieee80211vap *, int);
431208019Sthompsastatic void	run_update_beacon_cb(void *);
432203134Sthompsastatic void	run_updateprot(struct ieee80211com *);
433218492Sbschmidtstatic void	run_updateprot_cb(void *);
434208019Sthompsastatic void	run_usb_timeout_cb(void *);
435203134Sthompsastatic void	run_reset_livelock(struct run_softc *);
436203134Sthompsastatic void	run_enable_tsf_sync(struct run_softc *);
437203134Sthompsastatic void	run_enable_mrr(struct run_softc *);
438203134Sthompsastatic void	run_set_txpreamble(struct run_softc *);
439203134Sthompsastatic void	run_set_basicrates(struct run_softc *);
440203134Sthompsastatic void	run_set_leds(struct run_softc *, uint16_t);
441203134Sthompsastatic void	run_set_bssid(struct run_softc *, const uint8_t *);
442203134Sthompsastatic void	run_set_macaddr(struct run_softc *, const uint8_t *);
443283540Sglebiusstatic void	run_updateslot(struct ieee80211com *);
444218492Sbschmidtstatic void	run_updateslot_cb(void *);
445283540Sglebiusstatic void	run_update_mcast(struct ieee80211com *);
446203134Sthompsastatic int8_t	run_rssi2dbm(struct run_softc *, uint8_t, uint8_t);
447283540Sglebiusstatic void	run_update_promisc_locked(struct run_softc *);
448283540Sglebiusstatic void	run_update_promisc(struct ieee80211com *);
449257955Skevlostatic void	run_rt5390_bbp_init(struct run_softc *);
450203134Sthompsastatic int	run_bbp_init(struct run_softc *);
451203134Sthompsastatic int	run_rt3070_rf_init(struct run_softc *);
452260219Skevlostatic void	run_rt3593_rf_init(struct run_softc *);
453257955Skevlostatic void	run_rt5390_rf_init(struct run_softc *);
454203134Sthompsastatic int	run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t,
455203134Sthompsa		    uint8_t *);
456205042Sthompsastatic void	run_rt3070_rf_setup(struct run_softc *);
457260219Skevlostatic void	run_rt3593_rf_setup(struct run_softc *);
458260219Skevlostatic void	run_rt5390_rf_setup(struct run_softc *);
459203134Sthompsastatic int	run_txrx_enable(struct run_softc *);
460257955Skevlostatic void	run_adjust_freq_offset(struct run_softc *);
461203134Sthompsastatic void	run_init_locked(struct run_softc *);
462203134Sthompsastatic void	run_stop(void *);
463257429Shselaskystatic void	run_delay(struct run_softc *, u_int);
464203134Sthompsa
465259812Skevlostatic eventhandler_tag run_etag;
466259812Skevlo
467259544Skevlostatic const struct rt2860_rate {
468259544Skevlo	uint8_t		rate;
469259544Skevlo	uint8_t		mcs;
470259544Skevlo	enum		ieee80211_phytype phy;
471259544Skevlo	uint8_t		ctl_ridx;
472259544Skevlo	uint16_t	sp_ack_dur;
473259544Skevlo	uint16_t	lp_ack_dur;
474259544Skevlo} rt2860_rates[] = {
475259544Skevlo	{   2, 0, IEEE80211_T_DS,   0, 314, 314 },
476259544Skevlo	{   4, 1, IEEE80211_T_DS,   1, 258, 162 },
477259544Skevlo	{  11, 2, IEEE80211_T_DS,   2, 223, 127 },
478259544Skevlo	{  22, 3, IEEE80211_T_DS,   3, 213, 117 },
479259544Skevlo	{  12, 0, IEEE80211_T_OFDM, 4,  60,  60 },
480259544Skevlo	{  18, 1, IEEE80211_T_OFDM, 4,  52,  52 },
481259544Skevlo	{  24, 2, IEEE80211_T_OFDM, 6,  48,  48 },
482259544Skevlo	{  36, 3, IEEE80211_T_OFDM, 6,  44,  44 },
483259544Skevlo	{  48, 4, IEEE80211_T_OFDM, 8,  44,  44 },
484259544Skevlo	{  72, 5, IEEE80211_T_OFDM, 8,  40,  40 },
485259544Skevlo	{  96, 6, IEEE80211_T_OFDM, 8,  40,  40 },
486259544Skevlo	{ 108, 7, IEEE80211_T_OFDM, 8,  40,  40 }
487259544Skevlo};
488259544Skevlo
489203134Sthompsastatic const struct {
490208019Sthompsa	uint16_t	reg;
491203134Sthompsa	uint32_t	val;
492203134Sthompsa} rt2870_def_mac[] = {
493203134Sthompsa	RT2870_DEF_MAC
494203134Sthompsa};
495203134Sthompsa
496203134Sthompsastatic const struct {
497203134Sthompsa	uint8_t	reg;
498203134Sthompsa	uint8_t	val;
499203134Sthompsa} rt2860_def_bbp[] = {
500203134Sthompsa	RT2860_DEF_BBP
501257955Skevlo},rt5390_def_bbp[] = {
502257955Skevlo	RT5390_DEF_BBP
503259032Skevlo},rt5592_def_bbp[] = {
504259032Skevlo	RT5592_DEF_BBP
505203134Sthompsa};
506203134Sthompsa
507259032Skevlo/*
508259032Skevlo * Default values for BBP register R196 for RT5592.
509259032Skevlo */
510259032Skevlostatic const uint8_t rt5592_bbp_r196[] = {
511259032Skevlo	0xe0, 0x1f, 0x38, 0x32, 0x08, 0x28, 0x19, 0x0a, 0xff, 0x00,
512259032Skevlo	0x16, 0x10, 0x10, 0x0b, 0x36, 0x2c, 0x26, 0x24, 0x42, 0x36,
513259032Skevlo	0x30, 0x2d, 0x4c, 0x46, 0x3d, 0x40, 0x3e, 0x42, 0x3d, 0x40,
514259032Skevlo	0x3c, 0x34, 0x2c, 0x2f, 0x3c, 0x35, 0x2e, 0x2a, 0x49, 0x41,
515259032Skevlo	0x36, 0x31, 0x30, 0x30, 0x0e, 0x0d, 0x28, 0x21, 0x1c, 0x16,
516259032Skevlo	0x50, 0x4a, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00,
517259032Skevlo	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
518259032Skevlo	0x00, 0x00, 0x7d, 0x14, 0x32, 0x2c, 0x36, 0x4c, 0x43, 0x2c,
519259032Skevlo	0x2e, 0x36, 0x30, 0x6e
520259032Skevlo};
521259032Skevlo
522203134Sthompsastatic const struct rfprog {
523203134Sthompsa	uint8_t		chan;
524203134Sthompsa	uint32_t	r1, r2, r3, r4;
525203134Sthompsa} rt2860_rf2850[] = {
526203134Sthompsa	RT2860_RF2850
527203134Sthompsa};
528203134Sthompsa
529203134Sthompsastruct {
530203134Sthompsa	uint8_t	n, r, k;
531205042Sthompsa} rt3070_freqs[] = {
532205042Sthompsa	RT3070_RF3052
533203134Sthompsa};
534203134Sthompsa
535259032Skevlostatic const struct rt5592_freqs {
536259032Skevlo	uint16_t	n;
537259032Skevlo	uint8_t		k, m, r;
538259032Skevlo} rt5592_freqs_20mhz[] = {
539259032Skevlo	RT5592_RF5592_20MHZ
540259032Skevlo},rt5592_freqs_40mhz[] = {
541259032Skevlo	RT5592_RF5592_40MHZ
542259032Skevlo};
543259032Skevlo
544203134Sthompsastatic const struct {
545203134Sthompsa	uint8_t	reg;
546203134Sthompsa	uint8_t	val;
547203134Sthompsa} rt3070_def_rf[] = {
548203134Sthompsa	RT3070_DEF_RF
549205042Sthompsa},rt3572_def_rf[] = {
550205042Sthompsa	RT3572_DEF_RF
551260219Skevlo},rt3593_def_rf[] = {
552260219Skevlo	RT3593_DEF_RF
553257955Skevlo},rt5390_def_rf[] = {
554257955Skevlo	RT5390_DEF_RF
555257955Skevlo},rt5392_def_rf[] = {
556257955Skevlo	RT5392_DEF_RF
557259032Skevlo},rt5592_def_rf[] = {
558259032Skevlo	RT5592_DEF_RF
559259032Skevlo},rt5592_2ghz_def_rf[] = {
560259032Skevlo	RT5592_2GHZ_DEF_RF
561259032Skevlo},rt5592_5ghz_def_rf[] = {
562259032Skevlo	RT5592_5GHZ_DEF_RF
563203134Sthompsa};
564203134Sthompsa
565259032Skevlostatic const struct {
566259032Skevlo	u_int	firstchan;
567259032Skevlo	u_int	lastchan;
568259032Skevlo	uint8_t	reg;
569259032Skevlo	uint8_t	val;
570259032Skevlo} rt5592_chan_5ghz[] = {
571259032Skevlo	RT5592_CHAN_5GHZ
572259032Skevlo};
573259032Skevlo
574203134Sthompsastatic const struct usb_config run_config[RUN_N_XFER] = {
575203134Sthompsa    [RUN_BULK_TX_BE] = {
576203134Sthompsa	.type = UE_BULK,
577203134Sthompsa	.endpoint = UE_ADDR_ANY,
578203134Sthompsa	.ep_index = 0,
579203134Sthompsa	.direction = UE_DIR_OUT,
580203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
581203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
582203134Sthompsa	.callback = run_bulk_tx_callback0,
583203134Sthompsa	.timeout = 5000,	/* ms */
584203134Sthompsa    },
585203134Sthompsa    [RUN_BULK_TX_BK] = {
586203134Sthompsa	.type = UE_BULK,
587203134Sthompsa	.endpoint = UE_ADDR_ANY,
588203134Sthompsa	.direction = UE_DIR_OUT,
589203134Sthompsa	.ep_index = 1,
590203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
591203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
592203134Sthompsa	.callback = run_bulk_tx_callback1,
593203134Sthompsa	.timeout = 5000,	/* ms */
594203134Sthompsa    },
595203134Sthompsa    [RUN_BULK_TX_VI] = {
596203134Sthompsa	.type = UE_BULK,
597203134Sthompsa	.endpoint = UE_ADDR_ANY,
598203134Sthompsa	.direction = UE_DIR_OUT,
599203134Sthompsa	.ep_index = 2,
600203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
601203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
602203134Sthompsa	.callback = run_bulk_tx_callback2,
603203134Sthompsa	.timeout = 5000,	/* ms */
604203134Sthompsa    },
605203134Sthompsa    [RUN_BULK_TX_VO] = {
606203134Sthompsa	.type = UE_BULK,
607203134Sthompsa	.endpoint = UE_ADDR_ANY,
608203134Sthompsa	.direction = UE_DIR_OUT,
609203134Sthompsa	.ep_index = 3,
610203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
611203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
612203134Sthompsa	.callback = run_bulk_tx_callback3,
613203134Sthompsa	.timeout = 5000,	/* ms */
614203134Sthompsa    },
615203134Sthompsa    [RUN_BULK_TX_HCCA] = {
616203134Sthompsa	.type = UE_BULK,
617203134Sthompsa	.endpoint = UE_ADDR_ANY,
618203134Sthompsa	.direction = UE_DIR_OUT,
619203134Sthompsa	.ep_index = 4,
620203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
621203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
622203134Sthompsa	.callback = run_bulk_tx_callback4,
623203134Sthompsa	.timeout = 5000,	/* ms */
624203134Sthompsa    },
625203134Sthompsa    [RUN_BULK_TX_PRIO] = {
626203134Sthompsa	.type = UE_BULK,
627203134Sthompsa	.endpoint = UE_ADDR_ANY,
628203134Sthompsa	.direction = UE_DIR_OUT,
629203134Sthompsa	.ep_index = 5,
630203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
631203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
632203134Sthompsa	.callback = run_bulk_tx_callback5,
633203134Sthompsa	.timeout = 5000,	/* ms */
634203134Sthompsa    },
635203134Sthompsa    [RUN_BULK_RX] = {
636203134Sthompsa	.type = UE_BULK,
637203134Sthompsa	.endpoint = UE_ADDR_ANY,
638203134Sthompsa	.direction = UE_DIR_IN,
639203134Sthompsa	.bufsize = RUN_MAX_RXSZ,
640203134Sthompsa	.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
641203134Sthompsa	.callback = run_bulk_rx_callback,
642203134Sthompsa    }
643203134Sthompsa};
644203134Sthompsa
645259812Skevlostatic void
646259812Skevlorun_autoinst(void *arg, struct usb_device *udev,
647259812Skevlo    struct usb_attach_arg *uaa)
648259812Skevlo{
649259812Skevlo	struct usb_interface *iface;
650259812Skevlo	struct usb_interface_descriptor *id;
651259812Skevlo
652259812Skevlo	if (uaa->dev_state != UAA_DEV_READY)
653259812Skevlo		return;
654259812Skevlo
655259812Skevlo	iface = usbd_get_iface(udev, 0);
656259812Skevlo	if (iface == NULL)
657259812Skevlo		return;
658259812Skevlo	id = iface->idesc;
659259812Skevlo	if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
660259812Skevlo		return;
661259812Skevlo	if (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa))
662259812Skevlo		return;
663259812Skevlo
664259812Skevlo	if (usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT) == 0)
665259812Skevlo		uaa->dev_state = UAA_DEV_EJECTING;
666259812Skevlo}
667259812Skevlo
668220235Skevlostatic int
669259812Skevlorun_driver_loaded(struct module *mod, int what, void *arg)
670259812Skevlo{
671259812Skevlo	switch (what) {
672259812Skevlo	case MOD_LOAD:
673259812Skevlo		run_etag = EVENTHANDLER_REGISTER(usb_dev_configured,
674259812Skevlo		    run_autoinst, NULL, EVENTHANDLER_PRI_ANY);
675259812Skevlo		break;
676259812Skevlo	case MOD_UNLOAD:
677259812Skevlo		EVENTHANDLER_DEREGISTER(usb_dev_configured, run_etag);
678259812Skevlo		break;
679259812Skevlo	default:
680259812Skevlo		return (EOPNOTSUPP);
681259812Skevlo	}
682259812Skevlo	return (0);
683259812Skevlo}
684259812Skevlo
685259812Skevlostatic int
686203134Sthompsarun_match(device_t self)
687203134Sthompsa{
688203134Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(self);
689203134Sthompsa
690203134Sthompsa	if (uaa->usb_mode != USB_MODE_HOST)
691203134Sthompsa		return (ENXIO);
692203134Sthompsa	if (uaa->info.bConfigIndex != 0)
693203134Sthompsa		return (ENXIO);
694203134Sthompsa	if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX)
695203134Sthompsa		return (ENXIO);
696203134Sthompsa
697203134Sthompsa	return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa));
698203134Sthompsa}
699203134Sthompsa
700203134Sthompsastatic int
701203134Sthompsarun_attach(device_t self)
702203134Sthompsa{
703203134Sthompsa	struct run_softc *sc = device_get_softc(self);
704203134Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(self);
705287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
706205042Sthompsa	uint32_t ver;
707258082Skevlo	int ntries, error;
708203134Sthompsa	uint8_t iface_index, bands;
709203134Sthompsa
710203134Sthompsa	device_set_usb_desc(self);
711203134Sthompsa	sc->sc_udev = uaa->device;
712203134Sthompsa	sc->sc_dev = self;
713262465Skevlo	if (USB_GET_DRIVER_INFO(uaa) != RUN_EJECT)
714262465Skevlo		sc->sc_flags |= RUN_FLAG_FWLOAD_NEEDED;
715203134Sthompsa
716203134Sthompsa	mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev),
717203134Sthompsa	    MTX_NETWORK_LOCK, MTX_DEF);
718287197Sglebius	mbufq_init(&sc->sc_snd, ifqmaxlen);
719203134Sthompsa
720203134Sthompsa	iface_index = RT2860_IFACE_INDEX;
721208019Sthompsa
722203134Sthompsa	error = usbd_transfer_setup(uaa->device, &iface_index,
723203134Sthompsa	    sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx);
724203134Sthompsa	if (error) {
725205042Sthompsa		device_printf(self, "could not allocate USB transfers, "
726203134Sthompsa		    "err=%s\n", usbd_errstr(error));
727203134Sthompsa		goto detach;
728203134Sthompsa	}
729203134Sthompsa
730203134Sthompsa	RUN_LOCK(sc);
731203134Sthompsa
732203134Sthompsa	/* wait for the chip to settle */
733203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
734209917Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0) {
735203134Sthompsa			RUN_UNLOCK(sc);
736203134Sthompsa			goto detach;
737203134Sthompsa		}
738205042Sthompsa		if (ver != 0 && ver != 0xffffffff)
739203134Sthompsa			break;
740203134Sthompsa		run_delay(sc, 10);
741203134Sthompsa	}
742203134Sthompsa	if (ntries == 100) {
743203138Sthompsa		device_printf(sc->sc_dev,
744203138Sthompsa		    "timeout waiting for NIC to initialize\n");
745203134Sthompsa		RUN_UNLOCK(sc);
746203134Sthompsa		goto detach;
747203134Sthompsa	}
748205042Sthompsa	sc->mac_ver = ver >> 16;
749205042Sthompsa	sc->mac_rev = ver & 0xffff;
750203134Sthompsa
751203134Sthompsa	/* retrieve RF rev. no and various other things from EEPROM */
752203134Sthompsa	run_read_eeprom(sc);
753203134Sthompsa
754203138Sthompsa	device_printf(sc->sc_dev,
755203138Sthompsa	    "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n",
756205042Sthompsa	    sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev),
757287197Sglebius	    sc->ntxchains, sc->nrxchains, ether_sprintf(ic->ic_macaddr));
758203134Sthompsa
759203134Sthompsa	RUN_UNLOCK(sc);
760203134Sthompsa
761283537Sglebius	ic->ic_softc = sc;
762283527Sglebius	ic->ic_name = device_get_nameunit(self);
763203134Sthompsa	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
764203134Sthompsa	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
765208019Sthompsa
766203134Sthompsa	/* set device capabilities */
767203134Sthompsa	ic->ic_caps =
768203134Sthompsa	    IEEE80211_C_STA |		/* station mode supported */
769203134Sthompsa	    IEEE80211_C_MONITOR |	/* monitor mode supported */
770203134Sthompsa	    IEEE80211_C_IBSS |
771203134Sthompsa	    IEEE80211_C_HOSTAP |
772208019Sthompsa	    IEEE80211_C_WDS |		/* 4-address traffic works */
773208019Sthompsa	    IEEE80211_C_MBSS |
774203134Sthompsa	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
775203134Sthompsa	    IEEE80211_C_SHSLOT |	/* short slot time supported */
776203134Sthompsa	    IEEE80211_C_WME |		/* WME */
777214894Sbschmidt	    IEEE80211_C_WPA;		/* WPA1|WPA2(RSN) */
778203134Sthompsa
779203134Sthompsa	ic->ic_cryptocaps =
780203134Sthompsa	    IEEE80211_CRYPTO_WEP |
781203134Sthompsa	    IEEE80211_CRYPTO_AES_CCM |
782203134Sthompsa	    IEEE80211_CRYPTO_TKIPMIC |
783203134Sthompsa	    IEEE80211_CRYPTO_TKIP;
784203134Sthompsa
785203134Sthompsa	ic->ic_flags |= IEEE80211_F_DATAPAD;
786203134Sthompsa	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;
787203134Sthompsa
788203134Sthompsa	bands = 0;
789203134Sthompsa	setbit(&bands, IEEE80211_MODE_11B);
790203134Sthompsa	setbit(&bands, IEEE80211_MODE_11G);
791258082Skevlo	if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850 ||
792260219Skevlo	    sc->rf_rev == RT3070_RF_3052 || sc->rf_rev == RT3593_RF_3053 ||
793260219Skevlo	    sc->rf_rev == RT5592_RF_5592)
794258082Skevlo		setbit(&bands, IEEE80211_MODE_11A);
795203134Sthompsa	ieee80211_init_channels(ic, NULL, &bands);
796203134Sthompsa
797287197Sglebius	ieee80211_ifattach(ic);
798203134Sthompsa
799203134Sthompsa	ic->ic_scan_start = run_scan_start;
800203134Sthompsa	ic->ic_scan_end = run_scan_end;
801203134Sthompsa	ic->ic_set_channel = run_set_channel;
802203134Sthompsa	ic->ic_node_alloc = run_node_alloc;
803203134Sthompsa	ic->ic_newassoc = run_newassoc;
804218492Sbschmidt	ic->ic_updateslot = run_updateslot;
805208019Sthompsa	ic->ic_update_mcast = run_update_mcast;
806203134Sthompsa	ic->ic_wme.wme_update = run_wme_update;
807203134Sthompsa	ic->ic_raw_xmit = run_raw_xmit;
808203134Sthompsa	ic->ic_update_promisc = run_update_promisc;
809203134Sthompsa	ic->ic_vap_create = run_vap_create;
810203134Sthompsa	ic->ic_vap_delete = run_vap_delete;
811287197Sglebius	ic->ic_transmit = run_transmit;
812287197Sglebius	ic->ic_parent = run_parent;
813203134Sthompsa
814203134Sthompsa	ieee80211_radiotap_attach(ic,
815203134Sthompsa	    &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
816203134Sthompsa		RUN_TX_RADIOTAP_PRESENT,
817203134Sthompsa	    &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
818203134Sthompsa		RUN_RX_RADIOTAP_PRESENT);
819203134Sthompsa
820208019Sthompsa	TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc);
821208019Sthompsa	TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc);
822257712Shselasky	usb_callout_init_mtx(&sc->ratectl_ch, &sc->sc_mtx, 0);
823208019Sthompsa
824203134Sthompsa	if (bootverbose)
825203134Sthompsa		ieee80211_announce(ic);
826203134Sthompsa
827209917Sthompsa	return (0);
828203134Sthompsa
829203134Sthompsadetach:
830203134Sthompsa	run_detach(self);
831209917Sthompsa	return (ENXIO);
832203134Sthompsa}
833203134Sthompsa
834203134Sthompsastatic int
835203134Sthompsarun_detach(device_t self)
836203134Sthompsa{
837203134Sthompsa	struct run_softc *sc = device_get_softc(self);
838287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
839203134Sthompsa	int i;
840203134Sthompsa
841246614Shselasky	RUN_LOCK(sc);
842246614Shselasky	sc->sc_detached = 1;
843246614Shselasky	RUN_UNLOCK(sc);
844246614Shselasky
845203134Sthompsa	/* stop all USB transfers */
846203134Sthompsa	usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER);
847203134Sthompsa
848203134Sthompsa	RUN_LOCK(sc);
849209144Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
850209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set = RUN_CMDQ_ABORT;
851209144Sthompsa
852203134Sthompsa	/* free TX list, if any */
853203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
854203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
855203134Sthompsa	RUN_UNLOCK(sc);
856203134Sthompsa
857287197Sglebius	if (sc->sc_ic.ic_softc == sc) {
858208019Sthompsa		/* drain tasks */
859208019Sthompsa		usb_callout_drain(&sc->ratectl_ch);
860208019Sthompsa		ieee80211_draintask(ic, &sc->cmdq_task);
861208019Sthompsa		ieee80211_draintask(ic, &sc->ratectl_task);
862203134Sthompsa		ieee80211_ifdetach(ic);
863203134Sthompsa	}
864203134Sthompsa
865287197Sglebius	mbufq_drain(&sc->sc_snd);
866203134Sthompsa	mtx_destroy(&sc->sc_mtx);
867203134Sthompsa
868203134Sthompsa	return (0);
869203134Sthompsa}
870203134Sthompsa
871203134Sthompsastatic struct ieee80211vap *
872228621Sbschmidtrun_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
873228621Sbschmidt    enum ieee80211_opmode opmode, int flags,
874203134Sthompsa    const uint8_t bssid[IEEE80211_ADDR_LEN],
875203134Sthompsa    const uint8_t mac[IEEE80211_ADDR_LEN])
876203134Sthompsa{
877286950Sadrian	struct run_softc *sc = ic->ic_softc;
878203134Sthompsa	struct run_vap *rvp;
879203134Sthompsa	struct ieee80211vap *vap;
880208019Sthompsa	int i;
881203134Sthompsa
882209917Sthompsa	if (sc->rvp_cnt >= RUN_VAP_MAX) {
883287197Sglebius		device_printf(sc->sc_dev, "number of VAPs maxed out\n");
884209917Sthompsa		return (NULL);
885208019Sthompsa	}
886208019Sthompsa
887208019Sthompsa	switch (opmode) {
888208019Sthompsa	case IEEE80211_M_STA:
889208019Sthompsa		/* enable s/w bmiss handling for sta mode */
890208019Sthompsa		flags |= IEEE80211_CLONE_NOBEACONS;
891208019Sthompsa		/* fall though */
892208019Sthompsa	case IEEE80211_M_IBSS:
893208019Sthompsa	case IEEE80211_M_MONITOR:
894208019Sthompsa	case IEEE80211_M_HOSTAP:
895208019Sthompsa	case IEEE80211_M_MBSS:
896208019Sthompsa		/* other than WDS vaps, only one at a time */
897208019Sthompsa		if (!TAILQ_EMPTY(&ic->ic_vaps))
898209917Sthompsa			return (NULL);
899208019Sthompsa		break;
900208019Sthompsa	case IEEE80211_M_WDS:
901208019Sthompsa		TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next){
902208019Sthompsa			if(vap->iv_opmode != IEEE80211_M_HOSTAP)
903208019Sthompsa				continue;
904208019Sthompsa			/* WDS vap's always share the local mac address. */
905208019Sthompsa			flags &= ~IEEE80211_CLONE_BSSID;
906208019Sthompsa			break;
907208019Sthompsa		}
908209917Sthompsa		if (vap == NULL) {
909287197Sglebius			device_printf(sc->sc_dev,
910287197Sglebius			    "wds only supported in ap mode\n");
911209917Sthompsa			return (NULL);
912208019Sthompsa		}
913208019Sthompsa		break;
914208019Sthompsa	default:
915287197Sglebius		device_printf(sc->sc_dev, "unknown opmode %d\n", opmode);
916209917Sthompsa		return (NULL);
917208019Sthompsa	}
918208019Sthompsa
919287197Sglebius	rvp = malloc(sizeof(struct run_vap), M_80211_VAP, M_WAITOK | M_ZERO);
920203134Sthompsa	vap = &rvp->vap;
921203134Sthompsa
922287197Sglebius	if (ieee80211_vap_setup(ic, vap, name, unit, opmode, flags,
923287197Sglebius	    bssid) != 0) {
924257743Shselasky		/* out of memory */
925257743Shselasky		free(rvp, M_80211_VAP);
926257743Shselasky		return (NULL);
927257743Shselasky	}
928257743Shselasky
929203134Sthompsa	vap->iv_key_update_begin = run_key_update_begin;
930203134Sthompsa	vap->iv_key_update_end = run_key_update_end;
931203134Sthompsa	vap->iv_update_beacon = run_update_beacon;
932208019Sthompsa	vap->iv_max_aid = RT2870_WCID_MAX;
933208019Sthompsa	/*
934208019Sthompsa	 * To delete the right key from h/w, we need wcid.
935208019Sthompsa	 * Luckily, there is unused space in ieee80211_key{}, wk_pad,
936208019Sthompsa	 * and matching wcid will be written into there. So, cast
937208019Sthompsa	 * some spells to remove 'const' from ieee80211_key{}
938208019Sthompsa	 */
939208019Sthompsa	vap->iv_key_delete = (void *)run_key_delete;
940208019Sthompsa	vap->iv_key_set = (void *)run_key_set;
941203134Sthompsa
942203134Sthompsa	/* override state transition machine */
943203134Sthompsa	rvp->newstate = vap->iv_newstate;
944203134Sthompsa	vap->iv_newstate = run_newstate;
945203134Sthompsa
946206358Srpaulo	ieee80211_ratectl_init(vap);
947206358Srpaulo	ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */);
948203134Sthompsa
949203134Sthompsa	/* complete setup */
950287197Sglebius	ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status,
951287197Sglebius	    mac);
952208019Sthompsa
953208019Sthompsa	/* make sure id is always unique */
954209917Sthompsa	for (i = 0; i < RUN_VAP_MAX; i++) {
955208019Sthompsa		if((sc->rvp_bmap & 1 << i) == 0){
956208019Sthompsa			sc->rvp_bmap |= 1 << i;
957208019Sthompsa			rvp->rvp_id = i;
958208019Sthompsa			break;
959208019Sthompsa		}
960208019Sthompsa	}
961209917Sthompsa	if (sc->rvp_cnt++ == 0)
962208019Sthompsa		ic->ic_opmode = opmode;
963208019Sthompsa
964209917Sthompsa	if (opmode == IEEE80211_M_HOSTAP)
965209144Sthompsa		sc->cmdq_run = RUN_CMDQ_GO;
966209144Sthompsa
967208019Sthompsa	DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n",
968208019Sthompsa	    rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt);
969208019Sthompsa
970209917Sthompsa	return (vap);
971203134Sthompsa}
972203134Sthompsa
973203134Sthompsastatic void
974203134Sthompsarun_vap_delete(struct ieee80211vap *vap)
975203134Sthompsa{
976203134Sthompsa	struct run_vap *rvp = RUN_VAP(vap);
977203134Sthompsa	struct ieee80211com *ic;
978203134Sthompsa	struct run_softc *sc;
979208019Sthompsa	uint8_t rvp_id;
980203134Sthompsa
981209917Sthompsa	if (vap == NULL)
982203134Sthompsa		return;
983203134Sthompsa
984203134Sthompsa	ic = vap->iv_ic;
985286950Sadrian	sc = ic->ic_softc;
986203134Sthompsa
987205042Sthompsa	RUN_LOCK(sc);
988208019Sthompsa
989218492Sbschmidt	m_freem(rvp->beacon_mbuf);
990218492Sbschmidt	rvp->beacon_mbuf = NULL;
991218492Sbschmidt
992208019Sthompsa	rvp_id = rvp->rvp_id;
993208019Sthompsa	sc->ratectl_run &= ~(1 << rvp_id);
994208019Sthompsa	sc->rvp_bmap &= ~(1 << rvp_id);
995208019Sthompsa	run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128);
996208019Sthompsa	run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512);
997208019Sthompsa	--sc->rvp_cnt;
998208019Sthompsa
999208019Sthompsa	DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n",
1000208019Sthompsa	    vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt);
1001208019Sthompsa
1002205042Sthompsa	RUN_UNLOCK(sc);
1003203134Sthompsa
1004206358Srpaulo	ieee80211_ratectl_deinit(vap);
1005203134Sthompsa	ieee80211_vap_detach(vap);
1006203134Sthompsa	free(rvp, M_80211_VAP);
1007203134Sthompsa}
1008203134Sthompsa
1009208019Sthompsa/*
1010208019Sthompsa * There are numbers of functions need to be called in context thread.
1011208019Sthompsa * Rather than creating taskqueue event for each of those functions,
1012208019Sthompsa * here is all-for-one taskqueue callback function. This function
1013208019Sthompsa * gurantees deferred functions are executed in the same order they
1014208019Sthompsa * were enqueued.
1015208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[].
1016208019Sthompsa */
1017203134Sthompsastatic void
1018208019Sthompsarun_cmdq_cb(void *arg, int pending)
1019208019Sthompsa{
1020208019Sthompsa	struct run_softc *sc = arg;
1021208019Sthompsa	uint8_t i;
1022208019Sthompsa
1023208019Sthompsa	/* call cmdq[].func locked */
1024208019Sthompsa	RUN_LOCK(sc);
1025209917Sthompsa	for (i = sc->cmdq_exec; sc->cmdq[i].func && pending;
1026209917Sthompsa	    i = sc->cmdq_exec, pending--) {
1027208019Sthompsa		DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending);
1028209917Sthompsa		if (sc->cmdq_run == RUN_CMDQ_GO) {
1029208019Sthompsa			/*
1030208019Sthompsa			 * If arg0 is NULL, callback func needs more
1031208019Sthompsa			 * than one arg. So, pass ptr to cmdq struct.
1032208019Sthompsa			 */
1033209917Sthompsa			if (sc->cmdq[i].arg0)
1034208019Sthompsa				sc->cmdq[i].func(sc->cmdq[i].arg0);
1035208019Sthompsa			else
1036208019Sthompsa				sc->cmdq[i].func(&sc->cmdq[i]);
1037208019Sthompsa		}
1038208019Sthompsa		sc->cmdq[i].arg0 = NULL;
1039208019Sthompsa		sc->cmdq[i].func = NULL;
1040208019Sthompsa		sc->cmdq_exec++;
1041208019Sthompsa		sc->cmdq_exec &= RUN_CMDQ_MASQ;
1042208019Sthompsa	}
1043208019Sthompsa	RUN_UNLOCK(sc);
1044208019Sthompsa}
1045208019Sthompsa
1046208019Sthompsastatic void
1047203134Sthompsarun_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
1048203134Sthompsa{
1049203134Sthompsa	struct run_tx_data *data;
1050203134Sthompsa
1051203134Sthompsa	memset(pq, 0, sizeof(*pq));
1052203134Sthompsa
1053203134Sthompsa	STAILQ_INIT(&pq->tx_qh);
1054203134Sthompsa	STAILQ_INIT(&pq->tx_fh);
1055203134Sthompsa
1056203134Sthompsa	for (data = &pq->tx_data[0];
1057203134Sthompsa	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
1058203134Sthompsa		data->sc = sc;
1059203134Sthompsa		STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
1060203134Sthompsa	}
1061203134Sthompsa	pq->tx_nfree = RUN_TX_RING_COUNT;
1062203134Sthompsa}
1063203134Sthompsa
1064203134Sthompsastatic void
1065203134Sthompsarun_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
1066203134Sthompsa{
1067203134Sthompsa	struct run_tx_data *data;
1068203134Sthompsa
1069203134Sthompsa	/* make sure any subsequent use of the queues will fail */
1070203134Sthompsa	pq->tx_nfree = 0;
1071203134Sthompsa	STAILQ_INIT(&pq->tx_fh);
1072203134Sthompsa	STAILQ_INIT(&pq->tx_qh);
1073203134Sthompsa
1074203134Sthompsa	/* free up all node references and mbufs */
1075203134Sthompsa	for (data = &pq->tx_data[0];
1076209917Sthompsa	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
1077203134Sthompsa		if (data->m != NULL) {
1078203134Sthompsa			m_freem(data->m);
1079203134Sthompsa			data->m = NULL;
1080203134Sthompsa		}
1081203134Sthompsa		if (data->ni != NULL) {
1082203134Sthompsa			ieee80211_free_node(data->ni);
1083203134Sthompsa			data->ni = NULL;
1084203134Sthompsa		}
1085203134Sthompsa	}
1086203134Sthompsa}
1087203134Sthompsa
1088220235Skevlostatic int
1089203134Sthompsarun_load_microcode(struct run_softc *sc)
1090203134Sthompsa{
1091203134Sthompsa	usb_device_request_t req;
1092203137Sthompsa	const struct firmware *fw;
1093203134Sthompsa	const u_char *base;
1094203134Sthompsa	uint32_t tmp;
1095203134Sthompsa	int ntries, error;
1096203134Sthompsa	const uint64_t *temp;
1097203134Sthompsa	uint64_t bytes;
1098203134Sthompsa
1099205042Sthompsa	RUN_UNLOCK(sc);
1100203137Sthompsa	fw = firmware_get("runfw");
1101205042Sthompsa	RUN_LOCK(sc);
1102209917Sthompsa	if (fw == NULL) {
1103203138Sthompsa		device_printf(sc->sc_dev,
1104203138Sthompsa		    "failed loadfirmware of file %s\n", "runfw");
1105203134Sthompsa		return ENOENT;
1106203134Sthompsa	}
1107203134Sthompsa
1108203137Sthompsa	if (fw->datasize != 8192) {
1109203138Sthompsa		device_printf(sc->sc_dev,
1110203138Sthompsa		    "invalid firmware size (should be 8KB)\n");
1111203137Sthompsa		error = EINVAL;
1112203137Sthompsa		goto fail;
1113203134Sthompsa	}
1114203134Sthompsa
1115203134Sthompsa	/*
1116203134Sthompsa	 * RT3071/RT3072 use a different firmware
1117203134Sthompsa	 * run-rt2870 (8KB) contains both,
1118203134Sthompsa	 * first half (4KB) is for rt2870,
1119203134Sthompsa	 * last half is for rt3071.
1120203134Sthompsa	 */
1121203137Sthompsa	base = fw->data;
1122205042Sthompsa	if ((sc->mac_ver) != 0x2860 &&
1123205042Sthompsa	    (sc->mac_ver) != 0x2872 &&
1124209917Sthompsa	    (sc->mac_ver) != 0x3070) {
1125203134Sthompsa		base += 4096;
1126205042Sthompsa	}
1127203134Sthompsa
1128203134Sthompsa	/* cheap sanity check */
1129203137Sthompsa	temp = fw->data;
1130203134Sthompsa	bytes = *temp;
1131257712Shselasky	if (bytes != be64toh(0xffffff0210280210ULL)) {
1132203138Sthompsa		device_printf(sc->sc_dev, "firmware checksum failed\n");
1133203137Sthompsa		error = EINVAL;
1134203137Sthompsa		goto fail;
1135203137Sthompsa	}
1136203134Sthompsa
1137203134Sthompsa	/* write microcode image */
1138262465Skevlo	if (sc->sc_flags & RUN_FLAG_FWLOAD_NEEDED) {
1139260219Skevlo		run_write_region_1(sc, RT2870_FW_BASE, base, 4096);
1140260219Skevlo		run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff);
1141260219Skevlo		run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff);
1142260219Skevlo	}
1143203134Sthompsa
1144203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1145203134Sthompsa	req.bRequest = RT2870_RESET;
1146203134Sthompsa	USETW(req.wValue, 8);
1147203134Sthompsa	USETW(req.wIndex, 0);
1148203134Sthompsa	USETW(req.wLength, 0);
1149220235Skevlo	if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL))
1150220235Skevlo	    != 0) {
1151203138Sthompsa		device_printf(sc->sc_dev, "firmware reset failed\n");
1152203137Sthompsa		goto fail;
1153203137Sthompsa	}
1154203134Sthompsa
1155203134Sthompsa	run_delay(sc, 10);
1156203134Sthompsa
1157260219Skevlo	run_write(sc, RT2860_H2M_BBPAGENT, 0);
1158203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
1159260219Skevlo	run_write(sc, RT2860_H2M_INTSRC, 0);
1160205042Sthompsa	if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0)
1161203137Sthompsa		goto fail;
1162203134Sthompsa
1163203134Sthompsa	/* wait until microcontroller is ready */
1164203134Sthompsa	for (ntries = 0; ntries < 1000; ntries++) {
1165260219Skevlo		if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0)
1166203137Sthompsa			goto fail;
1167203134Sthompsa		if (tmp & RT2860_MCU_READY)
1168203134Sthompsa			break;
1169203134Sthompsa		run_delay(sc, 10);
1170203134Sthompsa	}
1171203134Sthompsa	if (ntries == 1000) {
1172203138Sthompsa		device_printf(sc->sc_dev,
1173203138Sthompsa		    "timeout waiting for MCU to initialize\n");
1174203137Sthompsa		error = ETIMEDOUT;
1175203137Sthompsa		goto fail;
1176203134Sthompsa	}
1177233283Sbschmidt	device_printf(sc->sc_dev, "firmware %s ver. %u.%u loaded\n",
1178233283Sbschmidt	    (base == fw->data) ? "RT2870" : "RT3071",
1179233283Sbschmidt	    *(base + 4092), *(base + 4093));
1180203134Sthompsa
1181203137Sthompsafail:
1182203137Sthompsa	firmware_put(fw, FIRMWARE_UNLOAD);
1183203137Sthompsa	return (error);
1184203134Sthompsa}
1185203134Sthompsa
1186258641Shselaskystatic int
1187203134Sthompsarun_reset(struct run_softc *sc)
1188203134Sthompsa{
1189203134Sthompsa	usb_device_request_t req;
1190203134Sthompsa
1191203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1192203134Sthompsa	req.bRequest = RT2870_RESET;
1193203134Sthompsa	USETW(req.wValue, 1);
1194203134Sthompsa	USETW(req.wIndex, 0);
1195203134Sthompsa	USETW(req.wLength, 0);
1196209917Sthompsa	return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL));
1197203134Sthompsa}
1198203134Sthompsa
1199203134Sthompsastatic usb_error_t
1200203134Sthompsarun_do_request(struct run_softc *sc,
1201203134Sthompsa    struct usb_device_request *req, void *data)
1202203134Sthompsa{
1203203134Sthompsa	usb_error_t err;
1204203134Sthompsa	int ntries = 10;
1205203134Sthompsa
1206203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
1207203134Sthompsa
1208203134Sthompsa	while (ntries--) {
1209203134Sthompsa		err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx,
1210203134Sthompsa		    req, data, 0, NULL, 250 /* ms */);
1211203134Sthompsa		if (err == 0)
1212203134Sthompsa			break;
1213203134Sthompsa		DPRINTFN(1, "Control request failed, %s (retrying)\n",
1214203134Sthompsa		    usbd_errstr(err));
1215203134Sthompsa		run_delay(sc, 10);
1216203134Sthompsa	}
1217203134Sthompsa	return (err);
1218203134Sthompsa}
1219203134Sthompsa
1220203134Sthompsastatic int
1221203134Sthompsarun_read(struct run_softc *sc, uint16_t reg, uint32_t *val)
1222203134Sthompsa{
1223203134Sthompsa	uint32_t tmp;
1224203134Sthompsa	int error;
1225203134Sthompsa
1226203134Sthompsa	error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp);
1227203134Sthompsa	if (error == 0)
1228203134Sthompsa		*val = le32toh(tmp);
1229203134Sthompsa	else
1230203134Sthompsa		*val = 0xffffffff;
1231209917Sthompsa	return (error);
1232203134Sthompsa}
1233203134Sthompsa
1234203134Sthompsastatic int
1235203134Sthompsarun_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len)
1236203134Sthompsa{
1237203134Sthompsa	usb_device_request_t req;
1238203134Sthompsa
1239203134Sthompsa	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1240203134Sthompsa	req.bRequest = RT2870_READ_REGION_1;
1241203134Sthompsa	USETW(req.wValue, 0);
1242203134Sthompsa	USETW(req.wIndex, reg);
1243203134Sthompsa	USETW(req.wLength, len);
1244203134Sthompsa
1245209917Sthompsa	return (run_do_request(sc, &req, buf));
1246203134Sthompsa}
1247203134Sthompsa
1248203134Sthompsastatic int
1249203134Sthompsarun_write_2(struct run_softc *sc, uint16_t reg, uint16_t val)
1250203134Sthompsa{
1251203134Sthompsa	usb_device_request_t req;
1252203134Sthompsa
1253203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1254203134Sthompsa	req.bRequest = RT2870_WRITE_2;
1255203134Sthompsa	USETW(req.wValue, val);
1256203134Sthompsa	USETW(req.wIndex, reg);
1257203134Sthompsa	USETW(req.wLength, 0);
1258203134Sthompsa
1259209917Sthompsa	return (run_do_request(sc, &req, NULL));
1260203134Sthompsa}
1261203134Sthompsa
1262203134Sthompsastatic int
1263203134Sthompsarun_write(struct run_softc *sc, uint16_t reg, uint32_t val)
1264203134Sthompsa{
1265203134Sthompsa	int error;
1266203134Sthompsa
1267203134Sthompsa	if ((error = run_write_2(sc, reg, val & 0xffff)) == 0)
1268203134Sthompsa		error = run_write_2(sc, reg + 2, val >> 16);
1269209917Sthompsa	return (error);
1270203134Sthompsa}
1271203134Sthompsa
1272203134Sthompsastatic int
1273203134Sthompsarun_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf,
1274203134Sthompsa    int len)
1275203134Sthompsa{
1276203134Sthompsa#if 1
1277203134Sthompsa	int i, error = 0;
1278203134Sthompsa	/*
1279203134Sthompsa	 * NB: the WRITE_REGION_1 command is not stable on RT2860.
1280203134Sthompsa	 * We thus issue multiple WRITE_2 commands instead.
1281203134Sthompsa	 */
1282203134Sthompsa	KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n"));
1283203134Sthompsa	for (i = 0; i < len && error == 0; i += 2)
1284203134Sthompsa		error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8);
1285209917Sthompsa	return (error);
1286203134Sthompsa#else
1287203134Sthompsa	usb_device_request_t req;
1288257958Skevlo	int error = 0;
1289203134Sthompsa
1290257958Skevlo	/*
1291257958Skevlo	 * NOTE: It appears the WRITE_REGION_1 command cannot be
1292257958Skevlo	 * passed a huge amount of data, which will crash the
1293257958Skevlo	 * firmware. Limit amount of data passed to 64-bytes at a
1294257958Skevlo	 * time.
1295257958Skevlo	 */
1296257958Skevlo	while (len > 0) {
1297257958Skevlo		int delta = 64;
1298257958Skevlo		if (delta > len)
1299257958Skevlo			delta = len;
1300257958Skevlo
1301257958Skevlo		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1302257958Skevlo		req.bRequest = RT2870_WRITE_REGION_1;
1303257958Skevlo		USETW(req.wValue, 0);
1304257958Skevlo		USETW(req.wIndex, reg);
1305257958Skevlo		USETW(req.wLength, delta);
1306257958Skevlo		error = run_do_request(sc, &req, __DECONST(uint8_t *, buf));
1307257958Skevlo		if (error != 0)
1308257958Skevlo			break;
1309257958Skevlo		reg += delta;
1310257958Skevlo		buf += delta;
1311257958Skevlo		len -= delta;
1312257958Skevlo	}
1313257958Skevlo	return (error);
1314203134Sthompsa#endif
1315203134Sthompsa}
1316203134Sthompsa
1317203134Sthompsastatic int
1318203134Sthompsarun_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len)
1319203134Sthompsa{
1320203134Sthompsa	int i, error = 0;
1321203134Sthompsa
1322203134Sthompsa	KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n"));
1323203134Sthompsa	for (i = 0; i < len && error == 0; i += 4)
1324203134Sthompsa		error = run_write(sc, reg + i, val);
1325209917Sthompsa	return (error);
1326203134Sthompsa}
1327203134Sthompsa
1328203134Sthompsastatic int
1329259544Skevlorun_efuse_read(struct run_softc *sc, uint16_t addr, uint16_t *val, int count)
1330203134Sthompsa{
1331203134Sthompsa	uint32_t tmp;
1332203134Sthompsa	uint16_t reg;
1333203134Sthompsa	int error, ntries;
1334203134Sthompsa
1335203134Sthompsa	if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1336209917Sthompsa		return (error);
1337203134Sthompsa
1338261076Shselasky	if (count == 2)
1339261076Shselasky		addr *= 2;
1340203134Sthompsa	/*-
1341203134Sthompsa	 * Read one 16-byte block into registers EFUSE_DATA[0-3]:
1342203134Sthompsa	 * DATA0: F E D C
1343203134Sthompsa	 * DATA1: B A 9 8
1344203134Sthompsa	 * DATA2: 7 6 5 4
1345203134Sthompsa	 * DATA3: 3 2 1 0
1346203134Sthompsa	 */
1347203134Sthompsa	tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK);
1348203134Sthompsa	tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK;
1349203134Sthompsa	run_write(sc, RT3070_EFUSE_CTRL, tmp);
1350203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1351203134Sthompsa		if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1352209917Sthompsa			return (error);
1353203134Sthompsa		if (!(tmp & RT3070_EFSROM_KICK))
1354203134Sthompsa			break;
1355203134Sthompsa		run_delay(sc, 2);
1356203134Sthompsa	}
1357203134Sthompsa	if (ntries == 100)
1358209917Sthompsa		return (ETIMEDOUT);
1359203134Sthompsa
1360261076Shselasky	if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) {
1361261076Shselasky		*val = 0xffff;	/* address not found */
1362209917Sthompsa		return (0);
1363261076Shselasky	}
1364203134Sthompsa	/* determine to which 32-bit register our 16-bit word belongs */
1365203134Sthompsa	reg = RT3070_EFUSE_DATA3 - (addr & 0xc);
1366203134Sthompsa	if ((error = run_read(sc, reg, &tmp)) != 0)
1367209917Sthompsa		return (error);
1368203134Sthompsa
1369261118Skevlo	tmp >>= (8 * (addr & 0x3));
1370261118Skevlo	*val = (addr & 1) ? tmp >> 16 : tmp & 0xffff;
1371261118Skevlo
1372209917Sthompsa	return (0);
1373203134Sthompsa}
1374203134Sthompsa
1375261124Skevlo/* Read 16-bit from eFUSE ROM for RT3xxx. */
1376203134Sthompsastatic int
1377259544Skevlorun_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1378259544Skevlo{
1379259544Skevlo	return (run_efuse_read(sc, addr, val, 2));
1380259544Skevlo}
1381259544Skevlo
1382259544Skevlostatic int
1383203134Sthompsarun_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1384203134Sthompsa{
1385203134Sthompsa	usb_device_request_t req;
1386203134Sthompsa	uint16_t tmp;
1387203134Sthompsa	int error;
1388203134Sthompsa
1389203134Sthompsa	addr *= 2;
1390203134Sthompsa	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1391203134Sthompsa	req.bRequest = RT2870_EEPROM_READ;
1392203134Sthompsa	USETW(req.wValue, 0);
1393203134Sthompsa	USETW(req.wIndex, addr);
1394260219Skevlo	USETW(req.wLength, sizeof(tmp));
1395203134Sthompsa
1396203134Sthompsa	error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp);
1397203134Sthompsa	if (error == 0)
1398203134Sthompsa		*val = le16toh(tmp);
1399203134Sthompsa	else
1400203134Sthompsa		*val = 0xffff;
1401209917Sthompsa	return (error);
1402203134Sthompsa}
1403203134Sthompsa
1404203134Sthompsastatic __inline int
1405203134Sthompsarun_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val)
1406203134Sthompsa{
1407203134Sthompsa	/* either eFUSE ROM or EEPROM */
1408203134Sthompsa	return sc->sc_srom_read(sc, addr, val);
1409203134Sthompsa}
1410203134Sthompsa
1411203134Sthompsastatic int
1412258733Skevlorun_rt2870_rf_write(struct run_softc *sc, uint32_t val)
1413203134Sthompsa{
1414203134Sthompsa	uint32_t tmp;
1415203134Sthompsa	int error, ntries;
1416203134Sthompsa
1417203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1418203134Sthompsa		if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0)
1419209917Sthompsa			return (error);
1420203134Sthompsa		if (!(tmp & RT2860_RF_REG_CTRL))
1421203134Sthompsa			break;
1422203134Sthompsa	}
1423203134Sthompsa	if (ntries == 10)
1424209917Sthompsa		return (ETIMEDOUT);
1425203134Sthompsa
1426258732Skevlo	return (run_write(sc, RT2860_RF_CSR_CFG0, val));
1427203134Sthompsa}
1428203134Sthompsa
1429203134Sthompsastatic int
1430203134Sthompsarun_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1431203134Sthompsa{
1432203134Sthompsa	uint32_t tmp;
1433203134Sthompsa	int error, ntries;
1434203134Sthompsa
1435203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1436203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1437209917Sthompsa			return (error);
1438203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1439203134Sthompsa			break;
1440203134Sthompsa	}
1441203134Sthompsa	if (ntries == 100)
1442209917Sthompsa		return (ETIMEDOUT);
1443203134Sthompsa
1444203134Sthompsa	tmp = RT3070_RF_KICK | reg << 8;
1445203134Sthompsa	if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0)
1446209917Sthompsa		return (error);
1447203134Sthompsa
1448203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1449203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1450209917Sthompsa			return (error);
1451203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1452203134Sthompsa			break;
1453203134Sthompsa	}
1454203134Sthompsa	if (ntries == 100)
1455209917Sthompsa		return (ETIMEDOUT);
1456203134Sthompsa
1457203134Sthompsa	*val = tmp & 0xff;
1458209917Sthompsa	return (0);
1459203134Sthompsa}
1460203134Sthompsa
1461203134Sthompsastatic int
1462203134Sthompsarun_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1463203134Sthompsa{
1464203134Sthompsa	uint32_t tmp;
1465203134Sthompsa	int error, ntries;
1466203134Sthompsa
1467203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1468203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1469209917Sthompsa			return (error);
1470203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1471203134Sthompsa			break;
1472203134Sthompsa	}
1473203134Sthompsa	if (ntries == 10)
1474209917Sthompsa		return (ETIMEDOUT);
1475203134Sthompsa
1476203134Sthompsa	tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val;
1477209917Sthompsa	return (run_write(sc, RT3070_RF_CSR_CFG, tmp));
1478203134Sthompsa}
1479203134Sthompsa
1480203134Sthompsastatic int
1481203134Sthompsarun_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1482203134Sthompsa{
1483203134Sthompsa	uint32_t tmp;
1484203134Sthompsa	int ntries, error;
1485203134Sthompsa
1486203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1487203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1488209917Sthompsa			return (error);
1489203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1490203134Sthompsa			break;
1491203134Sthompsa	}
1492203134Sthompsa	if (ntries == 10)
1493209917Sthompsa		return (ETIMEDOUT);
1494203134Sthompsa
1495203134Sthompsa	tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8;
1496203134Sthompsa	if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0)
1497209917Sthompsa		return (error);
1498203134Sthompsa
1499203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1500203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1501209917Sthompsa			return (error);
1502203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1503203134Sthompsa			break;
1504203134Sthompsa	}
1505203134Sthompsa	if (ntries == 10)
1506209917Sthompsa		return (ETIMEDOUT);
1507203134Sthompsa
1508203134Sthompsa	*val = tmp & 0xff;
1509209917Sthompsa	return (0);
1510203134Sthompsa}
1511203134Sthompsa
1512203134Sthompsastatic int
1513203134Sthompsarun_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1514203134Sthompsa{
1515203134Sthompsa	uint32_t tmp;
1516203134Sthompsa	int ntries, error;
1517203134Sthompsa
1518203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1519203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1520209917Sthompsa			return (error);
1521203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1522203134Sthompsa			break;
1523203134Sthompsa	}
1524203134Sthompsa	if (ntries == 10)
1525209917Sthompsa		return (ETIMEDOUT);
1526203134Sthompsa
1527203134Sthompsa	tmp = RT2860_BBP_CSR_KICK | reg << 8 | val;
1528209917Sthompsa	return (run_write(sc, RT2860_BBP_CSR_CFG, tmp));
1529203134Sthompsa}
1530203134Sthompsa
1531203134Sthompsa/*
1532203134Sthompsa * Send a command to the 8051 microcontroller unit.
1533203134Sthompsa */
1534203134Sthompsastatic int
1535203134Sthompsarun_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg)
1536203134Sthompsa{
1537203134Sthompsa	uint32_t tmp;
1538203134Sthompsa	int error, ntries;
1539203134Sthompsa
1540203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1541203134Sthompsa		if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0)
1542203134Sthompsa			return error;
1543203134Sthompsa		if (!(tmp & RT2860_H2M_BUSY))
1544203134Sthompsa			break;
1545203134Sthompsa	}
1546203134Sthompsa	if (ntries == 100)
1547203134Sthompsa		return ETIMEDOUT;
1548203134Sthompsa
1549203134Sthompsa	tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg;
1550203134Sthompsa	if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0)
1551203134Sthompsa		error = run_write(sc, RT2860_HOST_CMD, cmd);
1552209917Sthompsa	return (error);
1553203134Sthompsa}
1554203134Sthompsa
1555203134Sthompsa/*
1556203134Sthompsa * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word.
1557203134Sthompsa * Used to adjust per-rate Tx power registers.
1558203134Sthompsa */
1559203134Sthompsastatic __inline uint32_t
1560203134Sthompsab4inc(uint32_t b32, int8_t delta)
1561203134Sthompsa{
1562203134Sthompsa	int8_t i, b4;
1563203134Sthompsa
1564203134Sthompsa	for (i = 0; i < 8; i++) {
1565203134Sthompsa		b4 = b32 & 0xf;
1566203134Sthompsa		b4 += delta;
1567203134Sthompsa		if (b4 < 0)
1568203134Sthompsa			b4 = 0;
1569203134Sthompsa		else if (b4 > 0xf)
1570203134Sthompsa			b4 = 0xf;
1571203134Sthompsa		b32 = b32 >> 4 | b4 << 28;
1572203134Sthompsa	}
1573209917Sthompsa	return (b32);
1574203134Sthompsa}
1575203134Sthompsa
1576203134Sthompsastatic const char *
1577257955Skevlorun_get_rf(uint16_t rev)
1578203134Sthompsa{
1579203134Sthompsa	switch (rev) {
1580203134Sthompsa	case RT2860_RF_2820:	return "RT2820";
1581203134Sthompsa	case RT2860_RF_2850:	return "RT2850";
1582203134Sthompsa	case RT2860_RF_2720:	return "RT2720";
1583203134Sthompsa	case RT2860_RF_2750:	return "RT2750";
1584203134Sthompsa	case RT3070_RF_3020:	return "RT3020";
1585203134Sthompsa	case RT3070_RF_2020:	return "RT2020";
1586203134Sthompsa	case RT3070_RF_3021:	return "RT3021";
1587203134Sthompsa	case RT3070_RF_3022:	return "RT3022";
1588203134Sthompsa	case RT3070_RF_3052:	return "RT3052";
1589260219Skevlo	case RT3593_RF_3053:	return "RT3053";
1590259032Skevlo	case RT5592_RF_5592:	return "RT5592";
1591257955Skevlo	case RT5390_RF_5370:	return "RT5370";
1592257955Skevlo	case RT5390_RF_5372:	return "RT5372";
1593203134Sthompsa	}
1594209917Sthompsa	return ("unknown");
1595203134Sthompsa}
1596203134Sthompsa
1597260219Skevlostatic void
1598260219Skevlorun_rt3593_get_txpower(struct run_softc *sc)
1599260219Skevlo{
1600260219Skevlo	uint16_t addr, val;
1601260219Skevlo	int i;
1602260219Skevlo
1603260219Skevlo	/* Read power settings for 2GHz channels. */
1604260219Skevlo	for (i = 0; i < 14; i += 2) {
1605260219Skevlo		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE1 :
1606260219Skevlo		    RT2860_EEPROM_PWR2GHZ_BASE1;
1607260219Skevlo		run_srom_read(sc, addr + i / 2, &val);
1608260219Skevlo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1609260219Skevlo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1610260219Skevlo
1611260219Skevlo		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE2 :
1612260219Skevlo		    RT2860_EEPROM_PWR2GHZ_BASE2;
1613260219Skevlo		run_srom_read(sc, addr + i / 2, &val);
1614260219Skevlo		sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1615260219Skevlo		sc->txpow2[i + 1] = (int8_t)(val >> 8);
1616260219Skevlo
1617260219Skevlo		if (sc->ntxchains == 3) {
1618260219Skevlo			run_srom_read(sc, RT3593_EEPROM_PWR2GHZ_BASE3 + i / 2,
1619260219Skevlo			    &val);
1620260219Skevlo			sc->txpow3[i + 0] = (int8_t)(val & 0xff);
1621260219Skevlo			sc->txpow3[i + 1] = (int8_t)(val >> 8);
1622260219Skevlo		}
1623260219Skevlo	}
1624260219Skevlo	/* Fix broken Tx power entries. */
1625260219Skevlo	for (i = 0; i < 14; i++) {
1626260542Skevlo		if (sc->txpow1[i] > 31)
1627260219Skevlo			sc->txpow1[i] = 5;
1628260542Skevlo		if (sc->txpow2[i] > 31)
1629260219Skevlo			sc->txpow2[i] = 5;
1630260219Skevlo		if (sc->ntxchains == 3) {
1631260542Skevlo			if (sc->txpow3[i] > 31)
1632260219Skevlo				sc->txpow3[i] = 5;
1633260219Skevlo		}
1634260219Skevlo	}
1635260219Skevlo	/* Read power settings for 5GHz channels. */
1636260219Skevlo	for (i = 0; i < 40; i += 2) {
1637260219Skevlo		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1638260219Skevlo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1639260219Skevlo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1640260219Skevlo
1641260219Skevlo		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1642260219Skevlo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1643260219Skevlo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1644260219Skevlo
1645260219Skevlo		if (sc->ntxchains == 3) {
1646260219Skevlo			run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE3 + i / 2,
1647260219Skevlo			    &val);
1648260219Skevlo			sc->txpow3[i + 14] = (int8_t)(val & 0xff);
1649260219Skevlo			sc->txpow3[i + 15] = (int8_t)(val >> 8);
1650260219Skevlo		}
1651260219Skevlo	}
1652260219Skevlo}
1653260219Skevlo
1654260219Skevlostatic void
1655260219Skevlorun_get_txpower(struct run_softc *sc)
1656260219Skevlo{
1657260219Skevlo	uint16_t val;
1658260219Skevlo	int i;
1659260219Skevlo
1660260219Skevlo	/* Read power settings for 2GHz channels. */
1661260219Skevlo	for (i = 0; i < 14; i += 2) {
1662260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val);
1663260219Skevlo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1664260219Skevlo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1665260219Skevlo
1666260219Skevlo		if (sc->mac_ver != 0x5390) {
1667260219Skevlo			run_srom_read(sc,
1668260219Skevlo			    RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val);
1669260219Skevlo			sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1670260219Skevlo			sc->txpow2[i + 1] = (int8_t)(val >> 8);
1671260219Skevlo		}
1672260219Skevlo	}
1673260219Skevlo	/* Fix broken Tx power entries. */
1674260219Skevlo	for (i = 0; i < 14; i++) {
1675260219Skevlo		if (sc->mac_ver >= 0x5390) {
1676260219Skevlo			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 27)
1677260219Skevlo				sc->txpow1[i] = 5;
1678260219Skevlo		} else {
1679260219Skevlo			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31)
1680260219Skevlo				sc->txpow1[i] = 5;
1681260219Skevlo		}
1682260219Skevlo		if (sc->mac_ver > 0x5390) {
1683260219Skevlo			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 27)
1684260219Skevlo				sc->txpow2[i] = 5;
1685260219Skevlo		} else if (sc->mac_ver < 0x5390) {
1686260219Skevlo			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31)
1687260219Skevlo				sc->txpow2[i] = 5;
1688260219Skevlo		}
1689260219Skevlo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1690260219Skevlo		    rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]);
1691260219Skevlo	}
1692260219Skevlo	/* Read power settings for 5GHz channels. */
1693260219Skevlo	for (i = 0; i < 40; i += 2) {
1694260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1695260219Skevlo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1696260219Skevlo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1697260219Skevlo
1698260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1699260219Skevlo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1700260219Skevlo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1701260219Skevlo	}
1702260219Skevlo	/* Fix broken Tx power entries. */
1703260219Skevlo	for (i = 0; i < 40; i++ ) {
1704260219Skevlo		if (sc->mac_ver != 0x5592) {
1705260219Skevlo			if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15)
1706260219Skevlo				sc->txpow1[14 + i] = 5;
1707260219Skevlo			if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15)
1708260219Skevlo				sc->txpow2[14 + i] = 5;
1709260219Skevlo		}
1710260219Skevlo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1711260219Skevlo		    rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i],
1712260219Skevlo		    sc->txpow2[14 + i]);
1713260219Skevlo	}
1714260219Skevlo}
1715260219Skevlo
1716258641Shselaskystatic int
1717203134Sthompsarun_read_eeprom(struct run_softc *sc)
1718203134Sthompsa{
1719287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
1720203134Sthompsa	int8_t delta_2ghz, delta_5ghz;
1721203134Sthompsa	uint32_t tmp;
1722203134Sthompsa	uint16_t val;
1723203134Sthompsa	int ridx, ant, i;
1724203134Sthompsa
1725203134Sthompsa	/* check whether the ROM is eFUSE ROM or EEPROM */
1726203134Sthompsa	sc->sc_srom_read = run_eeprom_read_2;
1727205042Sthompsa	if (sc->mac_ver >= 0x3070) {
1728203134Sthompsa		run_read(sc, RT3070_EFUSE_CTRL, &tmp);
1729203134Sthompsa		DPRINTF("EFUSE_CTRL=0x%08x\n", tmp);
1730261118Skevlo		if ((tmp & RT3070_SEL_EFUSE) || sc->mac_ver == 0x3593)
1731203134Sthompsa			sc->sc_srom_read = run_efuse_read_2;
1732203134Sthompsa	}
1733203134Sthompsa
1734203134Sthompsa	/* read ROM version */
1735203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_VERSION, &val);
1736203134Sthompsa	DPRINTF("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8);
1737203134Sthompsa
1738203134Sthompsa	/* read MAC address */
1739203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC01, &val);
1740287197Sglebius	ic->ic_macaddr[0] = val & 0xff;
1741287197Sglebius	ic->ic_macaddr[1] = val >> 8;
1742203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC23, &val);
1743287197Sglebius	ic->ic_macaddr[2] = val & 0xff;
1744287197Sglebius	ic->ic_macaddr[3] = val >> 8;
1745203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC45, &val);
1746287197Sglebius	ic->ic_macaddr[4] = val & 0xff;
1747287197Sglebius	ic->ic_macaddr[5] = val >> 8;
1748203134Sthompsa
1749260219Skevlo	if (sc->mac_ver < 0x3593) {
1750257955Skevlo		/* read vender BBP settings */
1751205042Sthompsa		for (i = 0; i < 10; i++) {
1752257955Skevlo			run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val);
1753257955Skevlo			sc->bbp[i].val = val & 0xff;
1754257955Skevlo			sc->bbp[i].reg = val >> 8;
1755257955Skevlo			DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg,
1756257955Skevlo			    sc->bbp[i].val);
1757205042Sthompsa		}
1758257955Skevlo		if (sc->mac_ver >= 0x3071) {
1759257955Skevlo			/* read vendor RF settings */
1760257955Skevlo			for (i = 0; i < 10; i++) {
1761257955Skevlo				run_srom_read(sc, RT3071_EEPROM_RF_BASE + i,
1762257955Skevlo				   &val);
1763257955Skevlo				sc->rf[i].val = val & 0xff;
1764257955Skevlo				sc->rf[i].reg = val >> 8;
1765257955Skevlo				DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg,
1766257955Skevlo				    sc->rf[i].val);
1767257955Skevlo			}
1768257955Skevlo		}
1769205042Sthompsa	}
1770203134Sthompsa
1771203134Sthompsa	/* read RF frequency offset from EEPROM */
1772260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1773260219Skevlo	    RT3593_EEPROM_FREQ, &val);
1774203134Sthompsa	sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0;
1775203134Sthompsa	DPRINTF("EEPROM freq offset %d\n", sc->freq & 0xff);
1776203134Sthompsa
1777260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1778260219Skevlo	    RT3593_EEPROM_FREQ_LEDS, &val);
1779205042Sthompsa	if (val >> 8 != 0xff) {
1780203134Sthompsa		/* read LEDs operating mode */
1781205042Sthompsa		sc->leds = val >> 8;
1782260219Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED1 :
1783260219Skevlo		    RT3593_EEPROM_LED1, &sc->led[0]);
1784260219Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED2 :
1785260219Skevlo		    RT3593_EEPROM_LED2, &sc->led[1]);
1786260219Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED3 :
1787260219Skevlo		    RT3593_EEPROM_LED3, &sc->led[2]);
1788203134Sthompsa	} else {
1789203134Sthompsa		/* broken EEPROM, use default settings */
1790203134Sthompsa		sc->leds = 0x01;
1791203134Sthompsa		sc->led[0] = 0x5555;
1792203134Sthompsa		sc->led[1] = 0x2221;
1793203134Sthompsa		sc->led[2] = 0x5627;	/* differs from RT2860 */
1794203134Sthompsa	}
1795203134Sthompsa	DPRINTF("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n",
1796203134Sthompsa	    sc->leds, sc->led[0], sc->led[1], sc->led[2]);
1797203134Sthompsa
1798203134Sthompsa	/* read RF information */
1799259032Skevlo	if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392)
1800257955Skevlo		run_srom_read(sc, 0x00, &val);
1801257955Skevlo	else
1802257955Skevlo		run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1803257955Skevlo
1804203134Sthompsa	if (val == 0xffff) {
1805260219Skevlo		device_printf(sc->sc_dev,
1806260219Skevlo		    "invalid EEPROM antenna info, using default\n");
1807203134Sthompsa		DPRINTF("invalid EEPROM antenna info, using default\n");
1808205042Sthompsa		if (sc->mac_ver == 0x3572) {
1809205042Sthompsa			/* default to RF3052 2T2R */
1810205042Sthompsa			sc->rf_rev = RT3070_RF_3052;
1811205042Sthompsa			sc->ntxchains = 2;
1812205042Sthompsa			sc->nrxchains = 2;
1813205042Sthompsa		} else if (sc->mac_ver >= 0x3070) {
1814203134Sthompsa			/* default to RF3020 1T1R */
1815203134Sthompsa			sc->rf_rev = RT3070_RF_3020;
1816203134Sthompsa			sc->ntxchains = 1;
1817203134Sthompsa			sc->nrxchains = 1;
1818203134Sthompsa		} else {
1819203134Sthompsa			/* default to RF2820 1T2R */
1820203134Sthompsa			sc->rf_rev = RT2860_RF_2820;
1821203134Sthompsa			sc->ntxchains = 1;
1822203134Sthompsa			sc->nrxchains = 2;
1823203134Sthompsa		}
1824203134Sthompsa	} else {
1825259032Skevlo		if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) {
1826257955Skevlo			sc->rf_rev = val;
1827257955Skevlo			run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1828257955Skevlo		} else
1829257955Skevlo			sc->rf_rev = (val >> 8) & 0xf;
1830203134Sthompsa		sc->ntxchains = (val >> 4) & 0xf;
1831203134Sthompsa		sc->nrxchains = val & 0xf;
1832203134Sthompsa	}
1833257955Skevlo	DPRINTF("EEPROM RF rev=0x%04x chains=%dT%dR\n",
1834203134Sthompsa	    sc->rf_rev, sc->ntxchains, sc->nrxchains);
1835203134Sthompsa
1836208019Sthompsa	/* check if RF supports automatic Tx access gain control */
1837203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_CONFIG, &val);
1838203134Sthompsa	DPRINTF("EEPROM CFG 0x%04x\n", val);
1839205042Sthompsa	/* check if driver should patch the DAC issue */
1840205042Sthompsa	if ((val >> 8) != 0xff)
1841205042Sthompsa		sc->patch_dac = (val >> 15) & 1;
1842203134Sthompsa	if ((val & 0xff) != 0xff) {
1843203134Sthompsa		sc->ext_5ghz_lna = (val >> 3) & 1;
1844203134Sthompsa		sc->ext_2ghz_lna = (val >> 2) & 1;
1845205042Sthompsa		/* check if RF supports automatic Tx access gain control */
1846203134Sthompsa		sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1;
1847205042Sthompsa		/* check if we have a hardware radio switch */
1848205042Sthompsa		sc->rfswitch = val & 1;
1849203134Sthompsa	}
1850203134Sthompsa
1851260219Skevlo	/* Read Tx power settings. */
1852260219Skevlo	if (sc->mac_ver == 0x3593)
1853260219Skevlo		run_rt3593_get_txpower(sc);
1854260219Skevlo	else
1855260219Skevlo		run_get_txpower(sc);
1856203134Sthompsa
1857203134Sthompsa	/* read Tx power compensation for each Tx rate */
1858203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val);
1859203134Sthompsa	delta_2ghz = delta_5ghz = 0;
1860203134Sthompsa	if ((val & 0xff) != 0xff && (val & 0x80)) {
1861203134Sthompsa		delta_2ghz = val & 0xf;
1862203134Sthompsa		if (!(val & 0x40))	/* negative number */
1863203134Sthompsa			delta_2ghz = -delta_2ghz;
1864203134Sthompsa	}
1865203134Sthompsa	val >>= 8;
1866203134Sthompsa	if ((val & 0xff) != 0xff && (val & 0x80)) {
1867203134Sthompsa		delta_5ghz = val & 0xf;
1868203134Sthompsa		if (!(val & 0x40))	/* negative number */
1869203134Sthompsa			delta_5ghz = -delta_5ghz;
1870203134Sthompsa	}
1871203134Sthompsa	DPRINTF("power compensation=%d (2GHz), %d (5GHz)\n",
1872203134Sthompsa	    delta_2ghz, delta_5ghz);
1873203134Sthompsa
1874203134Sthompsa	for (ridx = 0; ridx < 5; ridx++) {
1875203134Sthompsa		uint32_t reg;
1876203134Sthompsa
1877208019Sthompsa		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val);
1878208019Sthompsa		reg = val;
1879208019Sthompsa		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val);
1880208019Sthompsa		reg |= (uint32_t)val << 16;
1881203134Sthompsa
1882203134Sthompsa		sc->txpow20mhz[ridx] = reg;
1883203134Sthompsa		sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz);
1884203134Sthompsa		sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz);
1885203134Sthompsa
1886203134Sthompsa		DPRINTF("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, "
1887203134Sthompsa		    "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx],
1888203134Sthompsa		    sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]);
1889203134Sthompsa	}
1890203134Sthompsa
1891260219Skevlo	/* Read RSSI offsets and LNA gains from EEPROM. */
1892260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_2GHZ :
1893260219Skevlo	    RT3593_EEPROM_RSSI1_2GHZ, &val);
1894203134Sthompsa	sc->rssi_2ghz[0] = val & 0xff;	/* Ant A */
1895203134Sthompsa	sc->rssi_2ghz[1] = val >> 8;	/* Ant B */
1896260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_2GHZ :
1897260219Skevlo	    RT3593_EEPROM_RSSI2_2GHZ, &val);
1898205042Sthompsa	if (sc->mac_ver >= 0x3070) {
1899260219Skevlo		if (sc->mac_ver == 0x3593) {
1900260219Skevlo			sc->txmixgain_2ghz = 0;
1901260219Skevlo			sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1902260219Skevlo		} else {
1903260219Skevlo			/*
1904260219Skevlo			 * On RT3070 chips (limited to 2 Rx chains), this ROM
1905260219Skevlo			 * field contains the Tx mixer gain for the 2GHz band.
1906260219Skevlo			 */
1907260219Skevlo			if ((val & 0xff) != 0xff)
1908260219Skevlo				sc->txmixgain_2ghz = val & 0x7;
1909260219Skevlo		}
1910205042Sthompsa		DPRINTF("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz);
1911205042Sthompsa	} else
1912205042Sthompsa		sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1913260219Skevlo	if (sc->mac_ver == 0x3593)
1914260219Skevlo		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
1915203134Sthompsa	sc->lna[2] = val >> 8;		/* channel group 2 */
1916203134Sthompsa
1917260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_5GHZ :
1918260219Skevlo	    RT3593_EEPROM_RSSI1_5GHZ, &val);
1919203134Sthompsa	sc->rssi_5ghz[0] = val & 0xff;	/* Ant A */
1920203134Sthompsa	sc->rssi_5ghz[1] = val >> 8;	/* Ant B */
1921260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_5GHZ :
1922260219Skevlo	    RT3593_EEPROM_RSSI2_5GHZ, &val);
1923205042Sthompsa	if (sc->mac_ver == 0x3572) {
1924205042Sthompsa		/*
1925205042Sthompsa		 * On RT3572 chips (limited to 2 Rx chains), this ROM
1926205042Sthompsa		 * field contains the Tx mixer gain for the 5GHz band.
1927205042Sthompsa		 */
1928205042Sthompsa		if ((val & 0xff) != 0xff)
1929205042Sthompsa			sc->txmixgain_5ghz = val & 0x7;
1930205042Sthompsa		DPRINTF("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz);
1931205042Sthompsa	} else
1932205042Sthompsa		sc->rssi_5ghz[2] = val & 0xff;	/* Ant C */
1933260219Skevlo	if (sc->mac_ver == 0x3593) {
1934260219Skevlo		sc->txmixgain_5ghz = 0;
1935260219Skevlo		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
1936260219Skevlo	}
1937203134Sthompsa	sc->lna[3] = val >> 8;		/* channel group 3 */
1938203134Sthompsa
1939260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LNA :
1940260219Skevlo	    RT3593_EEPROM_LNA, &val);
1941203134Sthompsa	sc->lna[0] = val & 0xff;	/* channel group 0 */
1942203134Sthompsa	sc->lna[1] = val >> 8;		/* channel group 1 */
1943203134Sthompsa
1944203134Sthompsa	/* fix broken 5GHz LNA entries */
1945203134Sthompsa	if (sc->lna[2] == 0 || sc->lna[2] == 0xff) {
1946203134Sthompsa		DPRINTF("invalid LNA for channel group %d\n", 2);
1947203134Sthompsa		sc->lna[2] = sc->lna[1];
1948203134Sthompsa	}
1949203134Sthompsa	if (sc->lna[3] == 0 || sc->lna[3] == 0xff) {
1950203134Sthompsa		DPRINTF("invalid LNA for channel group %d\n", 3);
1951203134Sthompsa		sc->lna[3] = sc->lna[1];
1952203134Sthompsa	}
1953203134Sthompsa
1954203134Sthompsa	/* fix broken RSSI offset entries */
1955203134Sthompsa	for (ant = 0; ant < 3; ant++) {
1956203134Sthompsa		if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) {
1957203134Sthompsa			DPRINTF("invalid RSSI%d offset: %d (2GHz)\n",
1958203134Sthompsa			    ant + 1, sc->rssi_2ghz[ant]);
1959203134Sthompsa			sc->rssi_2ghz[ant] = 0;
1960203134Sthompsa		}
1961203134Sthompsa		if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) {
1962203134Sthompsa			DPRINTF("invalid RSSI%d offset: %d (5GHz)\n",
1963203134Sthompsa			    ant + 1, sc->rssi_5ghz[ant]);
1964203134Sthompsa			sc->rssi_5ghz[ant] = 0;
1965203134Sthompsa		}
1966203134Sthompsa	}
1967209917Sthompsa	return (0);
1968203134Sthompsa}
1969203134Sthompsa
1970218676Shselaskystatic struct ieee80211_node *
1971203134Sthompsarun_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
1972203134Sthompsa{
1973203134Sthompsa	return malloc(sizeof (struct run_node), M_DEVBUF, M_NOWAIT | M_ZERO);
1974203134Sthompsa}
1975203134Sthompsa
1976203134Sthompsastatic int
1977203134Sthompsarun_media_change(struct ifnet *ifp)
1978203134Sthompsa{
1979208019Sthompsa	struct ieee80211vap *vap = ifp->if_softc;
1980208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
1981203134Sthompsa	const struct ieee80211_txparam *tp;
1982286950Sadrian	struct run_softc *sc = ic->ic_softc;
1983203134Sthompsa	uint8_t rate, ridx;
1984203134Sthompsa	int error;
1985203134Sthompsa
1986203134Sthompsa	RUN_LOCK(sc);
1987203134Sthompsa
1988203134Sthompsa	error = ieee80211_media_change(ifp);
1989209917Sthompsa	if (error != ENETRESET) {
1990203134Sthompsa		RUN_UNLOCK(sc);
1991209917Sthompsa		return (error);
1992208019Sthompsa	}
1993203134Sthompsa
1994203134Sthompsa	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
1995203134Sthompsa	if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
1996212127Sthompsa		struct ieee80211_node *ni;
1997212127Sthompsa		struct run_node	*rn;
1998212127Sthompsa
1999203134Sthompsa		rate = ic->ic_sup_rates[ic->ic_curmode].
2000203134Sthompsa		    rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL;
2001203134Sthompsa		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2002203134Sthompsa			if (rt2860_rates[ridx].rate == rate)
2003203134Sthompsa				break;
2004212127Sthompsa		ni = ieee80211_ref_node(vap->iv_bss);
2005212127Sthompsa		rn = (struct run_node *)ni;
2006208019Sthompsa		rn->fix_ridx = ridx;
2007208019Sthompsa		DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx);
2008212127Sthompsa		ieee80211_free_node(ni);
2009203134Sthompsa	}
2010203134Sthompsa
2011208019Sthompsa#if 0
2012203134Sthompsa	if ((ifp->if_flags & IFF_UP) &&
2013287197Sglebius	    (ifp->if_drv_flags &  RUN_RUNNING)){
2014203134Sthompsa		run_init_locked(sc);
2015203134Sthompsa	}
2016208019Sthompsa#endif
2017203134Sthompsa
2018203134Sthompsa	RUN_UNLOCK(sc);
2019203134Sthompsa
2020209917Sthompsa	return (0);
2021203134Sthompsa}
2022203134Sthompsa
2023203134Sthompsastatic int
2024203134Sthompsarun_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
2025203134Sthompsa{
2026203134Sthompsa	const struct ieee80211_txparam *tp;
2027203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2028286950Sadrian	struct run_softc *sc = ic->ic_softc;
2029203134Sthompsa	struct run_vap *rvp = RUN_VAP(vap);
2030203134Sthompsa	enum ieee80211_state ostate;
2031208019Sthompsa	uint32_t sta[3];
2032203134Sthompsa	uint32_t tmp;
2033208019Sthompsa	uint8_t ratectl;
2034208019Sthompsa	uint8_t restart_ratectl = 0;
2035208019Sthompsa	uint8_t bid = 1 << rvp->rvp_id;
2036203134Sthompsa
2037203134Sthompsa	ostate = vap->iv_state;
2038203134Sthompsa	DPRINTF("%s -> %s\n",
2039203134Sthompsa		ieee80211_state_name[ostate],
2040203134Sthompsa		ieee80211_state_name[nstate]);
2041203134Sthompsa
2042203134Sthompsa	IEEE80211_UNLOCK(ic);
2043203134Sthompsa	RUN_LOCK(sc);
2044203134Sthompsa
2045208019Sthompsa	ratectl = sc->ratectl_run; /* remember current state */
2046208019Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
2047208019Sthompsa	usb_callout_stop(&sc->ratectl_ch);
2048203134Sthompsa
2049203134Sthompsa	if (ostate == IEEE80211_S_RUN) {
2050203134Sthompsa		/* turn link LED off */
2051203134Sthompsa		run_set_leds(sc, RT2860_LED_RADIO);
2052203134Sthompsa	}
2053203134Sthompsa
2054203134Sthompsa	switch (nstate) {
2055203134Sthompsa	case IEEE80211_S_INIT:
2056208019Sthompsa		restart_ratectl = 1;
2057208019Sthompsa
2058208019Sthompsa		if (ostate != IEEE80211_S_RUN)
2059208019Sthompsa			break;
2060208019Sthompsa
2061208019Sthompsa		ratectl &= ~bid;
2062208019Sthompsa		sc->runbmap &= ~bid;
2063208019Sthompsa
2064208019Sthompsa		/* abort TSF synchronization if there is no vap running */
2065209917Sthompsa		if (--sc->running == 0) {
2066203134Sthompsa			run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
2067203134Sthompsa			run_write(sc, RT2860_BCN_TIME_CFG,
2068203134Sthompsa			    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
2069203134Sthompsa			    RT2860_TBTT_TIMER_EN));
2070203134Sthompsa		}
2071203134Sthompsa		break;
2072203134Sthompsa
2073203134Sthompsa	case IEEE80211_S_RUN:
2074209917Sthompsa		if (!(sc->runbmap & bid)) {
2075208019Sthompsa			if(sc->running++)
2076208019Sthompsa				restart_ratectl = 1;
2077208019Sthompsa			sc->runbmap |= bid;
2078208019Sthompsa		}
2079203134Sthompsa
2080218492Sbschmidt		m_freem(rvp->beacon_mbuf);
2081218492Sbschmidt		rvp->beacon_mbuf = NULL;
2082218492Sbschmidt
2083209917Sthompsa		switch (vap->iv_opmode) {
2084208019Sthompsa		case IEEE80211_M_HOSTAP:
2085208019Sthompsa		case IEEE80211_M_MBSS:
2086208019Sthompsa			sc->ap_running |= bid;
2087208019Sthompsa			ic->ic_opmode = vap->iv_opmode;
2088208019Sthompsa			run_update_beacon_cb(vap);
2089208019Sthompsa			break;
2090208019Sthompsa		case IEEE80211_M_IBSS:
2091208019Sthompsa			sc->adhoc_running |= bid;
2092209917Sthompsa			if (!sc->ap_running)
2093208019Sthompsa				ic->ic_opmode = vap->iv_opmode;
2094208019Sthompsa			run_update_beacon_cb(vap);
2095208019Sthompsa			break;
2096208019Sthompsa		case IEEE80211_M_STA:
2097208019Sthompsa			sc->sta_running |= bid;
2098209917Sthompsa			if (!sc->ap_running && !sc->adhoc_running)
2099208019Sthompsa				ic->ic_opmode = vap->iv_opmode;
2100208019Sthompsa
2101208019Sthompsa			/* read statistic counters (clear on read) */
2102208019Sthompsa			run_read_region_1(sc, RT2860_TX_STA_CNT0,
2103208019Sthompsa			    (uint8_t *)sta, sizeof sta);
2104208019Sthompsa
2105208019Sthompsa			break;
2106208019Sthompsa		default:
2107208019Sthompsa			ic->ic_opmode = vap->iv_opmode;
2108208019Sthompsa			break;
2109208019Sthompsa		}
2110208019Sthompsa
2111203134Sthompsa		if (vap->iv_opmode != IEEE80211_M_MONITOR) {
2112212127Sthompsa			struct ieee80211_node *ni;
2113212127Sthompsa
2114236439Shselasky			if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) {
2115236439Shselasky				RUN_UNLOCK(sc);
2116236439Shselasky				IEEE80211_LOCK(ic);
2117236439Shselasky				return (-1);
2118236439Shselasky			}
2119283540Sglebius			run_updateslot(ic);
2120203134Sthompsa			run_enable_mrr(sc);
2121203134Sthompsa			run_set_txpreamble(sc);
2122203134Sthompsa			run_set_basicrates(sc);
2123212127Sthompsa			ni = ieee80211_ref_node(vap->iv_bss);
2124287197Sglebius			IEEE80211_ADDR_COPY(ic->ic_macaddr, ni->ni_bssid);
2125203134Sthompsa			run_set_bssid(sc, ni->ni_bssid);
2126212127Sthompsa			ieee80211_free_node(ni);
2127208019Sthompsa			run_enable_tsf_sync(sc);
2128203134Sthompsa
2129208019Sthompsa			/* enable automatic rate adaptation */
2130208019Sthompsa			tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
2131208019Sthompsa			if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
2132208019Sthompsa				ratectl |= bid;
2133203134Sthompsa		}
2134203134Sthompsa
2135203134Sthompsa		/* turn link LED on */
2136203134Sthompsa		run_set_leds(sc, RT2860_LED_RADIO |
2137208019Sthompsa		    (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ?
2138203134Sthompsa		     RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ));
2139203134Sthompsa
2140203134Sthompsa		break;
2141203134Sthompsa	default:
2142203134Sthompsa		DPRINTFN(6, "undefined case\n");
2143203134Sthompsa		break;
2144203134Sthompsa	}
2145203134Sthompsa
2146208019Sthompsa	/* restart amrr for running VAPs */
2147209917Sthompsa	if ((sc->ratectl_run = ratectl) && restart_ratectl)
2148208019Sthompsa		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2149208019Sthompsa
2150203134Sthompsa	RUN_UNLOCK(sc);
2151203134Sthompsa	IEEE80211_LOCK(ic);
2152203134Sthompsa
2153203134Sthompsa	return(rvp->newstate(vap, nstate, arg));
2154203134Sthompsa}
2155203134Sthompsa
2156203134Sthompsa/* ARGSUSED */
2157203134Sthompsastatic void
2158208019Sthompsarun_wme_update_cb(void *arg)
2159203134Sthompsa{
2160203134Sthompsa	struct ieee80211com *ic = arg;
2161286950Sadrian	struct run_softc *sc = ic->ic_softc;
2162203134Sthompsa	struct ieee80211_wme_state *wmesp = &ic->ic_wme;
2163203134Sthompsa	int aci, error = 0;
2164203134Sthompsa
2165208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2166203134Sthompsa
2167203134Sthompsa	/* update MAC TX configuration registers */
2168203134Sthompsa	for (aci = 0; aci < WME_NUM_AC; aci++) {
2169203134Sthompsa		error = run_write(sc, RT2860_EDCA_AC_CFG(aci),
2170203134Sthompsa		    wmesp->wme_params[aci].wmep_logcwmax << 16 |
2171203134Sthompsa		    wmesp->wme_params[aci].wmep_logcwmin << 12 |
2172203134Sthompsa		    wmesp->wme_params[aci].wmep_aifsn  <<  8 |
2173203134Sthompsa		    wmesp->wme_params[aci].wmep_txopLimit);
2174209917Sthompsa		if (error) goto err;
2175203134Sthompsa	}
2176203134Sthompsa
2177203134Sthompsa	/* update SCH/DMA registers too */
2178203134Sthompsa	error = run_write(sc, RT2860_WMM_AIFSN_CFG,
2179203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_aifsn  << 12 |
2180203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_aifsn  <<  8 |
2181203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_aifsn  <<  4 |
2182203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_aifsn);
2183209917Sthompsa	if (error) goto err;
2184203134Sthompsa	error = run_write(sc, RT2860_WMM_CWMIN_CFG,
2185203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_logcwmin << 12 |
2186203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_logcwmin <<  8 |
2187203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_logcwmin <<  4 |
2188203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_logcwmin);
2189209917Sthompsa	if (error) goto err;
2190203134Sthompsa	error = run_write(sc, RT2860_WMM_CWMAX_CFG,
2191203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_logcwmax << 12 |
2192203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_logcwmax <<  8 |
2193203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_logcwmax <<  4 |
2194203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_logcwmax);
2195209917Sthompsa	if (error) goto err;
2196203134Sthompsa	error = run_write(sc, RT2860_WMM_TXOP0_CFG,
2197203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_txopLimit << 16 |
2198203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_txopLimit);
2199209917Sthompsa	if (error) goto err;
2200203134Sthompsa	error = run_write(sc, RT2860_WMM_TXOP1_CFG,
2201203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_txopLimit << 16 |
2202203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_txopLimit);
2203203134Sthompsa
2204203134Sthompsaerr:
2205209917Sthompsa	if (error)
2206203134Sthompsa		DPRINTF("WME update failed\n");
2207203134Sthompsa
2208203134Sthompsa	return;
2209203134Sthompsa}
2210203134Sthompsa
2211208019Sthompsastatic int
2212208019Sthompsarun_wme_update(struct ieee80211com *ic)
2213208019Sthompsa{
2214286950Sadrian	struct run_softc *sc = ic->ic_softc;
2215208019Sthompsa
2216208019Sthompsa	/* sometime called wothout lock */
2217209917Sthompsa	if (mtx_owned(&ic->ic_comlock.mtx)) {
2218208019Sthompsa		uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
2219208019Sthompsa		DPRINTF("cmdq_store=%d\n", i);
2220208019Sthompsa		sc->cmdq[i].func = run_wme_update_cb;
2221208019Sthompsa		sc->cmdq[i].arg0 = ic;
2222208019Sthompsa		ieee80211_runtask(ic, &sc->cmdq_task);
2223209918Sthompsa		return (0);
2224208019Sthompsa	}
2225208019Sthompsa
2226208019Sthompsa	RUN_LOCK(sc);
2227208019Sthompsa	run_wme_update_cb(ic);
2228208019Sthompsa	RUN_UNLOCK(sc);
2229208019Sthompsa
2230208019Sthompsa	/* return whatever, upper layer desn't care anyway */
2231208019Sthompsa	return (0);
2232208019Sthompsa}
2233208019Sthompsa
2234203134Sthompsastatic void
2235203134Sthompsarun_key_update_begin(struct ieee80211vap *vap)
2236203134Sthompsa{
2237203134Sthompsa	/*
2238208019Sthompsa	 * To avoid out-of-order events, both run_key_set() and
2239208019Sthompsa	 * _delete() are deferred and handled by run_cmdq_cb().
2240208019Sthompsa	 * So, there is nothing we need to do here.
2241203134Sthompsa	 */
2242203134Sthompsa}
2243203134Sthompsa
2244203134Sthompsastatic void
2245203134Sthompsarun_key_update_end(struct ieee80211vap *vap)
2246203134Sthompsa{
2247203134Sthompsa	/* null */
2248203134Sthompsa}
2249203134Sthompsa
2250208019Sthompsastatic void
2251208019Sthompsarun_key_set_cb(void *arg)
2252203134Sthompsa{
2253208019Sthompsa	struct run_cmdq *cmdq = arg;
2254208019Sthompsa	struct ieee80211vap *vap = cmdq->arg1;
2255208019Sthompsa	struct ieee80211_key *k = cmdq->k;
2256203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2257286950Sadrian	struct run_softc *sc = ic->ic_softc;
2258203134Sthompsa	struct ieee80211_node *ni;
2259203134Sthompsa	uint32_t attr;
2260203134Sthompsa	uint16_t base, associd;
2261209144Sthompsa	uint8_t mode, wcid, iv[8];
2262203134Sthompsa
2263208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2264203134Sthompsa
2265209917Sthompsa	if (vap->iv_opmode == IEEE80211_M_HOSTAP)
2266208019Sthompsa		ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac);
2267209144Sthompsa	else
2268203134Sthompsa		ni = vap->iv_bss;
2269208019Sthompsa	associd = (ni != NULL) ? ni->ni_associd : 0;
2270203134Sthompsa
2271203134Sthompsa	/* map net80211 cipher to RT2860 security mode */
2272203134Sthompsa	switch (k->wk_cipher->ic_cipher) {
2273203134Sthompsa	case IEEE80211_CIPHER_WEP:
2274203134Sthompsa		if(k->wk_keylen < 8)
2275203134Sthompsa			mode = RT2860_MODE_WEP40;
2276203134Sthompsa		else
2277203134Sthompsa			mode = RT2860_MODE_WEP104;
2278203134Sthompsa		break;
2279203134Sthompsa	case IEEE80211_CIPHER_TKIP:
2280203134Sthompsa		mode = RT2860_MODE_TKIP;
2281203134Sthompsa		break;
2282203134Sthompsa	case IEEE80211_CIPHER_AES_CCM:
2283203134Sthompsa		mode = RT2860_MODE_AES_CCMP;
2284203134Sthompsa		break;
2285203134Sthompsa	default:
2286203134Sthompsa		DPRINTF("undefined case\n");
2287208019Sthompsa		return;
2288203134Sthompsa	}
2289203134Sthompsa
2290208019Sthompsa	DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n",
2291203134Sthompsa	    associd, k->wk_keyix, mode,
2292208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise",
2293208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off",
2294208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off");
2295203134Sthompsa
2296203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2297203134Sthompsa		wcid = 0;	/* NB: update WCID0 for group keys */
2298208019Sthompsa		base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix);
2299203134Sthompsa	} else {
2300245047Shselasky		wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2301245047Shselasky		    1 : RUN_AID2WCID(associd);
2302203134Sthompsa		base = RT2860_PKEY(wcid);
2303203134Sthompsa	}
2304203134Sthompsa
2305203134Sthompsa	if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) {
2306203134Sthompsa		if(run_write_region_1(sc, base, k->wk_key, 16))
2307208019Sthompsa			return;
2308209144Sthompsa		if(run_write_region_1(sc, base + 16, &k->wk_key[16], 8))	/* wk_txmic */
2309208019Sthompsa			return;
2310209144Sthompsa		if(run_write_region_1(sc, base + 24, &k->wk_key[24], 8))	/* wk_rxmic */
2311208019Sthompsa			return;
2312203134Sthompsa	} else {
2313203134Sthompsa		/* roundup len to 16-bit: XXX fix write_region_1() instead */
2314203134Sthompsa		if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1))
2315208019Sthompsa			return;
2316203134Sthompsa	}
2317203134Sthompsa
2318203134Sthompsa	if (!(k->wk_flags & IEEE80211_KEY_GROUP) ||
2319203134Sthompsa	    (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) {
2320203134Sthompsa		/* set initial packet number in IV+EIV */
2321209917Sthompsa		if (k->wk_cipher == IEEE80211_CIPHER_WEP) {
2322203134Sthompsa			memset(iv, 0, sizeof iv);
2323208019Sthompsa			iv[3] = vap->iv_def_txkey << 6;
2324203134Sthompsa		} else {
2325203134Sthompsa			if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) {
2326203134Sthompsa				iv[0] = k->wk_keytsc >> 8;
2327203134Sthompsa				iv[1] = (iv[0] | 0x20) & 0x7f;
2328203134Sthompsa				iv[2] = k->wk_keytsc;
2329203134Sthompsa			} else /* CCMP */ {
2330203134Sthompsa				iv[0] = k->wk_keytsc;
2331203134Sthompsa				iv[1] = k->wk_keytsc >> 8;
2332203134Sthompsa				iv[2] = 0;
2333203134Sthompsa			}
2334203134Sthompsa			iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV;
2335203134Sthompsa			iv[4] = k->wk_keytsc >> 16;
2336203134Sthompsa			iv[5] = k->wk_keytsc >> 24;
2337203134Sthompsa			iv[6] = k->wk_keytsc >> 32;
2338203134Sthompsa			iv[7] = k->wk_keytsc >> 40;
2339203134Sthompsa		}
2340209917Sthompsa		if (run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8))
2341208019Sthompsa			return;
2342203134Sthompsa	}
2343203134Sthompsa
2344203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2345203134Sthompsa		/* install group key */
2346209917Sthompsa		if (run_read(sc, RT2860_SKEY_MODE_0_7, &attr))
2347208019Sthompsa			return;
2348203134Sthompsa		attr &= ~(0xf << (k->wk_keyix * 4));
2349203134Sthompsa		attr |= mode << (k->wk_keyix * 4);
2350209917Sthompsa		if (run_write(sc, RT2860_SKEY_MODE_0_7, attr))
2351208019Sthompsa			return;
2352203134Sthompsa	} else {
2353203134Sthompsa		/* install pairwise key */
2354209917Sthompsa		if (run_read(sc, RT2860_WCID_ATTR(wcid), &attr))
2355208019Sthompsa			return;
2356203134Sthompsa		attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN;
2357209917Sthompsa		if (run_write(sc, RT2860_WCID_ATTR(wcid), attr))
2358208019Sthompsa			return;
2359203134Sthompsa	}
2360203134Sthompsa
2361203134Sthompsa	/* TODO create a pass-thru key entry? */
2362203134Sthompsa
2363208019Sthompsa	/* need wcid to delete the right key later */
2364208019Sthompsa	k->wk_pad = wcid;
2365203134Sthompsa}
2366203134Sthompsa
2367203134Sthompsa/*
2368208019Sthompsa * Don't have to be deferred, but in order to keep order of
2369208019Sthompsa * execution, i.e. with run_key_delete(), defer this and let
2370208019Sthompsa * run_cmdq_cb() maintain the order.
2371208019Sthompsa *
2372203134Sthompsa * return 0 on error
2373203134Sthompsa */
2374203134Sthompsastatic int
2375208019Sthompsarun_key_set(struct ieee80211vap *vap, struct ieee80211_key *k,
2376208019Sthompsa		const uint8_t mac[IEEE80211_ADDR_LEN])
2377203134Sthompsa{
2378203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2379286950Sadrian	struct run_softc *sc = ic->ic_softc;
2380208019Sthompsa	uint32_t i;
2381208019Sthompsa
2382208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
2383208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
2384208019Sthompsa	sc->cmdq[i].func = run_key_set_cb;
2385208019Sthompsa	sc->cmdq[i].arg0 = NULL;
2386208019Sthompsa	sc->cmdq[i].arg1 = vap;
2387208019Sthompsa	sc->cmdq[i].k = k;
2388208019Sthompsa	IEEE80211_ADDR_COPY(sc->cmdq[i].mac, mac);
2389208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
2390208019Sthompsa
2391209144Sthompsa	/*
2392209144Sthompsa	 * To make sure key will be set when hostapd
2393209144Sthompsa	 * calls iv_key_set() before if_init().
2394209144Sthompsa	 */
2395209917Sthompsa	if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
2396209144Sthompsa		RUN_LOCK(sc);
2397209144Sthompsa		sc->cmdq_key_set = RUN_CMDQ_GO;
2398209144Sthompsa		RUN_UNLOCK(sc);
2399209144Sthompsa	}
2400209144Sthompsa
2401209917Sthompsa	return (1);
2402208019Sthompsa}
2403208019Sthompsa
2404208019Sthompsa/*
2405208019Sthompsa * If wlan is destroyed without being brought down i.e. without
2406208019Sthompsa * wlan down or wpa_cli terminate, this function is called after
2407208019Sthompsa * vap is gone. Don't refer it.
2408208019Sthompsa */
2409208019Sthompsastatic void
2410208019Sthompsarun_key_delete_cb(void *arg)
2411208019Sthompsa{
2412208019Sthompsa	struct run_cmdq *cmdq = arg;
2413208019Sthompsa	struct run_softc *sc = cmdq->arg1;
2414208019Sthompsa	struct ieee80211_key *k = &cmdq->key;
2415203134Sthompsa	uint32_t attr;
2416203134Sthompsa	uint8_t wcid;
2417203134Sthompsa
2418208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2419203134Sthompsa
2420203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2421203134Sthompsa		/* remove group key */
2422208019Sthompsa		DPRINTF("removing group key\n");
2423208019Sthompsa		run_read(sc, RT2860_SKEY_MODE_0_7, &attr);
2424203134Sthompsa		attr &= ~(0xf << (k->wk_keyix * 4));
2425208019Sthompsa		run_write(sc, RT2860_SKEY_MODE_0_7, attr);
2426203134Sthompsa	} else {
2427203134Sthompsa		/* remove pairwise key */
2428208019Sthompsa		DPRINTF("removing key for wcid %x\n", k->wk_pad);
2429208019Sthompsa		/* matching wcid was written to wk_pad in run_key_set() */
2430208019Sthompsa		wcid = k->wk_pad;
2431208019Sthompsa		run_read(sc, RT2860_WCID_ATTR(wcid), &attr);
2432203134Sthompsa		attr &= ~0xf;
2433208019Sthompsa		run_write(sc, RT2860_WCID_ATTR(wcid), attr);
2434208019Sthompsa		run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8);
2435203134Sthompsa	}
2436203134Sthompsa
2437208019Sthompsa	k->wk_pad = 0;
2438203134Sthompsa}
2439203134Sthompsa
2440208019Sthompsa/*
2441208019Sthompsa * return 0 on error
2442208019Sthompsa */
2443208019Sthompsastatic int
2444208019Sthompsarun_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k)
2445203134Sthompsa{
2446208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2447286950Sadrian	struct run_softc *sc = ic->ic_softc;
2448208019Sthompsa	struct ieee80211_key *k0;
2449208019Sthompsa	uint32_t i;
2450203134Sthompsa
2451208019Sthompsa	/*
2452208019Sthompsa	 * When called back, key might be gone. So, make a copy
2453208019Sthompsa	 * of some values need to delete keys before deferring.
2454208019Sthompsa	 * But, because of LOR with node lock, cannot use lock here.
2455208019Sthompsa	 * So, use atomic instead.
2456208019Sthompsa	 */
2457208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
2458208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
2459208019Sthompsa	sc->cmdq[i].func = run_key_delete_cb;
2460208019Sthompsa	sc->cmdq[i].arg0 = NULL;
2461208019Sthompsa	sc->cmdq[i].arg1 = sc;
2462208019Sthompsa	k0 = &sc->cmdq[i].key;
2463208019Sthompsa	k0->wk_flags = k->wk_flags;
2464208019Sthompsa	k0->wk_keyix = k->wk_keyix;
2465208019Sthompsa	/* matching wcid was written to wk_pad in run_key_set() */
2466208019Sthompsa	k0->wk_pad = k->wk_pad;
2467208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
2468208019Sthompsa	return (1);	/* return fake success */
2469203134Sthompsa
2470203134Sthompsa}
2471203134Sthompsa
2472203134Sthompsastatic void
2473206358Srpaulorun_ratectl_to(void *arg)
2474203134Sthompsa{
2475208019Sthompsa	struct run_softc *sc = arg;
2476203134Sthompsa
2477203134Sthompsa	/* do it in a process context, so it can go sleep */
2478287197Sglebius	ieee80211_runtask(&sc->sc_ic, &sc->ratectl_task);
2479203134Sthompsa	/* next timeout will be rescheduled in the callback task */
2480203134Sthompsa}
2481203134Sthompsa
2482203134Sthompsa/* ARGSUSED */
2483203134Sthompsastatic void
2484206358Srpaulorun_ratectl_cb(void *arg, int pending)
2485203134Sthompsa{
2486208019Sthompsa	struct run_softc *sc = arg;
2487287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
2488208019Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
2489203134Sthompsa
2490209917Sthompsa	if (vap == NULL)
2491208019Sthompsa		return;
2492208019Sthompsa
2493262795Shselasky	if (sc->rvp_cnt > 1 || vap->iv_opmode != IEEE80211_M_STA) {
2494203134Sthompsa		/*
2495203134Sthompsa		 * run_reset_livelock() doesn't do anything with AMRR,
2496203134Sthompsa		 * but Ralink wants us to call it every 1 sec. So, we
2497203134Sthompsa		 * piggyback here rather than creating another callout.
2498203134Sthompsa		 * Livelock may occur only in HOSTAP or IBSS mode
2499203134Sthompsa		 * (when h/w is sending beacons).
2500203134Sthompsa		 */
2501203134Sthompsa		RUN_LOCK(sc);
2502203134Sthompsa		run_reset_livelock(sc);
2503208019Sthompsa		/* just in case, there are some stats to drain */
2504208019Sthompsa		run_drain_fifo(sc);
2505203134Sthompsa		RUN_UNLOCK(sc);
2506203134Sthompsa	}
2507203134Sthompsa
2508262795Shselasky	ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc);
2509262795Shselasky
2510257712Shselasky	RUN_LOCK(sc);
2511208019Sthompsa	if(sc->ratectl_run != RUN_RATECTL_OFF)
2512208019Sthompsa		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2513257712Shselasky	RUN_UNLOCK(sc);
2514203134Sthompsa}
2515203134Sthompsa
2516203134Sthompsastatic void
2517208019Sthompsarun_drain_fifo(void *arg)
2518203134Sthompsa{
2519208019Sthompsa	struct run_softc *sc = arg;
2520208019Sthompsa	uint32_t stat;
2521218676Shselasky	uint16_t (*wstat)[3];
2522203134Sthompsa	uint8_t wcid, mcs, pid;
2523218676Shselasky	int8_t retry;
2524203134Sthompsa
2525208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2526203134Sthompsa
2527208019Sthompsa	for (;;) {
2528203134Sthompsa		/* drain Tx status FIFO (maxsize = 16) */
2529203134Sthompsa		run_read(sc, RT2860_TX_STAT_FIFO, &stat);
2530208019Sthompsa		DPRINTFN(4, "tx stat 0x%08x\n", stat);
2531209917Sthompsa		if (!(stat & RT2860_TXQ_VLD))
2532208019Sthompsa			break;
2533203134Sthompsa
2534208019Sthompsa		wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff;
2535203134Sthompsa
2536208019Sthompsa		/* if no ACK was requested, no feedback is available */
2537208019Sthompsa		if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX ||
2538208019Sthompsa		    wcid == 0)
2539208019Sthompsa			continue;
2540203134Sthompsa
2541218676Shselasky		/*
2542218676Shselasky		 * Even though each stat is Tx-complete-status like format,
2543218676Shselasky		 * the device can poll stats. Because there is no guarantee
2544218676Shselasky		 * that the referring node is still around when read the stats.
2545218676Shselasky		 * So that, if we use ieee80211_ratectl_tx_update(), we will
2546218676Shselasky		 * have hard time not to refer already freed node.
2547218676Shselasky		 *
2548218676Shselasky		 * To eliminate such page faults, we poll stats in softc.
2549218676Shselasky		 * Then, update the rates later with ieee80211_ratectl_tx_update().
2550218676Shselasky		 */
2551218676Shselasky		wstat = &(sc->wcid_stats[wcid]);
2552218676Shselasky		(*wstat)[RUN_TXCNT]++;
2553218676Shselasky		if (stat & RT2860_TXQ_OK)
2554218676Shselasky			(*wstat)[RUN_SUCCESS]++;
2555218676Shselasky		else
2556287197Sglebius			counter_u64_add(sc->sc_ic.ic_oerrors, 1);
2557218676Shselasky		/*
2558218676Shselasky		 * Check if there were retries, ie if the Tx success rate is
2559218676Shselasky		 * different from the requested rate. Note that it works only
2560218676Shselasky		 * because we do not allow rate fallback from OFDM to CCK.
2561218676Shselasky		 */
2562218676Shselasky		mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f;
2563218676Shselasky		pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf;
2564218676Shselasky		if ((retry = pid -1 - mcs) > 0) {
2565218676Shselasky			(*wstat)[RUN_TXCNT] += retry;
2566218676Shselasky			(*wstat)[RUN_RETRY] += retry;
2567203134Sthompsa		}
2568208019Sthompsa	}
2569208019Sthompsa	DPRINTFN(3, "count=%d\n", sc->fifo_cnt);
2570208019Sthompsa
2571208019Sthompsa	sc->fifo_cnt = 0;
2572208019Sthompsa}
2573208019Sthompsa
2574208019Sthompsastatic void
2575208019Sthompsarun_iter_func(void *arg, struct ieee80211_node *ni)
2576208019Sthompsa{
2577208019Sthompsa	struct run_softc *sc = arg;
2578208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
2579208019Sthompsa	struct run_node *rn = (void *)ni;
2580218676Shselasky	union run_stats sta[2];
2581218676Shselasky	uint16_t (*wstat)[3];
2582218676Shselasky	int txcnt, success, retrycnt, error;
2583208019Sthompsa
2584218676Shselasky	RUN_LOCK(sc);
2585218676Shselasky
2586262795Shselasky	/* Check for special case */
2587262795Shselasky	if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA &&
2588262795Shselasky	    ni != vap->iv_bss)
2589262795Shselasky		goto fail;
2590262795Shselasky
2591209917Sthompsa	if (sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS ||
2592209917Sthompsa	    vap->iv_opmode == IEEE80211_M_STA)) {
2593203134Sthompsa		/* read statistic counters (clear on read) and update AMRR state */
2594203134Sthompsa		error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta,
2595203134Sthompsa		    sizeof sta);
2596203134Sthompsa		if (error != 0)
2597218676Shselasky			goto fail;
2598203134Sthompsa
2599203134Sthompsa		/* count failed TX as errors */
2600287197Sglebius		if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS,
2601287197Sglebius		    le16toh(sta[0].error.fail));
2602203134Sthompsa
2603218676Shselasky		retrycnt = le16toh(sta[1].tx.retry);
2604218676Shselasky		success = le16toh(sta[1].tx.success);
2605218676Shselasky		txcnt = retrycnt + success + le16toh(sta[0].error.fail);
2606203134Sthompsa
2607218676Shselasky		DPRINTFN(3, "retrycnt=%d success=%d failcnt=%d\n",
2608218676Shselasky			retrycnt, success, le16toh(sta[0].error.fail));
2609218676Shselasky	} else {
2610218676Shselasky		wstat = &(sc->wcid_stats[RUN_AID2WCID(ni->ni_associd)]);
2611203134Sthompsa
2612218676Shselasky		if (wstat == &(sc->wcid_stats[0]) ||
2613218676Shselasky		    wstat > &(sc->wcid_stats[RT2870_WCID_MAX]))
2614218676Shselasky			goto fail;
2615208019Sthompsa
2616218676Shselasky		txcnt = (*wstat)[RUN_TXCNT];
2617218676Shselasky		success = (*wstat)[RUN_SUCCESS];
2618218676Shselasky		retrycnt = (*wstat)[RUN_RETRY];
2619218676Shselasky		DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n",
2620218676Shselasky		    retrycnt, txcnt, success);
2621208019Sthompsa
2622218676Shselasky		memset(wstat, 0, sizeof(*wstat));
2623203134Sthompsa	}
2624203134Sthompsa
2625218676Shselasky	ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt);
2626208019Sthompsa	rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0);
2627218676Shselasky
2628218676Shselaskyfail:
2629218676Shselasky	RUN_UNLOCK(sc);
2630218676Shselasky
2631208019Sthompsa	DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx);
2632208019Sthompsa}
2633203134Sthompsa
2634208019Sthompsastatic void
2635208019Sthompsarun_newassoc_cb(void *arg)
2636208019Sthompsa{
2637208019Sthompsa	struct run_cmdq *cmdq = arg;
2638208019Sthompsa	struct ieee80211_node *ni = cmdq->arg1;
2639286950Sadrian	struct run_softc *sc = ni->ni_vap->iv_ic->ic_softc;
2640208019Sthompsa	uint8_t wcid = cmdq->wcid;
2641203134Sthompsa
2642208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2643208019Sthompsa
2644208019Sthompsa	run_write_region_1(sc, RT2860_WCID_ENTRY(wcid),
2645208019Sthompsa	    ni->ni_macaddr, IEEE80211_ADDR_LEN);
2646218676Shselasky
2647218676Shselasky	memset(&(sc->wcid_stats[wcid]), 0, sizeof(sc->wcid_stats[wcid]));
2648203134Sthompsa}
2649203134Sthompsa
2650203134Sthompsastatic void
2651203134Sthompsarun_newassoc(struct ieee80211_node *ni, int isnew)
2652203134Sthompsa{
2653203134Sthompsa	struct run_node *rn = (void *)ni;
2654203134Sthompsa	struct ieee80211_rateset *rs = &ni->ni_rates;
2655208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
2656208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2657286950Sadrian	struct run_softc *sc = ic->ic_softc;
2658203134Sthompsa	uint8_t rate;
2659208019Sthompsa	uint8_t ridx;
2660245047Shselasky	uint8_t wcid;
2661208019Sthompsa	int i, j;
2662203134Sthompsa
2663245047Shselasky	wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2664245047Shselasky	    1 : RUN_AID2WCID(ni->ni_associd);
2665245047Shselasky
2666209917Sthompsa	if (wcid > RT2870_WCID_MAX) {
2667208019Sthompsa		device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid);
2668208019Sthompsa		return;
2669208019Sthompsa	}
2670203134Sthompsa
2671208019Sthompsa	/* only interested in true associations */
2672209917Sthompsa	if (isnew && ni->ni_associd != 0) {
2673208019Sthompsa
2674208019Sthompsa		/*
2675208019Sthompsa		 * This function could is called though timeout function.
2676208019Sthompsa		 * Need to defer.
2677208019Sthompsa		 */
2678208019Sthompsa		uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store);
2679208019Sthompsa		DPRINTF("cmdq_store=%d\n", cnt);
2680208019Sthompsa		sc->cmdq[cnt].func = run_newassoc_cb;
2681208019Sthompsa		sc->cmdq[cnt].arg0 = NULL;
2682208019Sthompsa		sc->cmdq[cnt].arg1 = ni;
2683208019Sthompsa		sc->cmdq[cnt].wcid = wcid;
2684208019Sthompsa		ieee80211_runtask(ic, &sc->cmdq_task);
2685208019Sthompsa	}
2686208019Sthompsa
2687208019Sthompsa	DPRINTF("new assoc isnew=%d associd=%x addr=%s\n",
2688208019Sthompsa	    isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr));
2689208019Sthompsa
2690203134Sthompsa	for (i = 0; i < rs->rs_nrates; i++) {
2691203134Sthompsa		rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
2692203134Sthompsa		/* convert 802.11 rate to hardware rate index */
2693203134Sthompsa		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2694203134Sthompsa			if (rt2860_rates[ridx].rate == rate)
2695203134Sthompsa				break;
2696203134Sthompsa		rn->ridx[i] = ridx;
2697203134Sthompsa		/* determine rate of control response frames */
2698203134Sthompsa		for (j = i; j >= 0; j--) {
2699203134Sthompsa			if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) &&
2700203134Sthompsa			    rt2860_rates[rn->ridx[i]].phy ==
2701203134Sthompsa			    rt2860_rates[rn->ridx[j]].phy)
2702203134Sthompsa				break;
2703203134Sthompsa		}
2704203134Sthompsa		if (j >= 0) {
2705203134Sthompsa			rn->ctl_ridx[i] = rn->ridx[j];
2706203134Sthompsa		} else {
2707203134Sthompsa			/* no basic rate found, use mandatory one */
2708203134Sthompsa			rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx;
2709203134Sthompsa		}
2710203134Sthompsa		DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n",
2711203134Sthompsa		    rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]);
2712203134Sthompsa	}
2713208019Sthompsa	rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate;
2714208019Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2715208019Sthompsa		if (rt2860_rates[ridx].rate == rate)
2716208019Sthompsa			break;
2717208019Sthompsa	rn->mgt_ridx = ridx;
2718208019Sthompsa	DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx);
2719208019Sthompsa
2720262795Shselasky	RUN_LOCK(sc);
2721262795Shselasky	if(sc->ratectl_run != RUN_RATECTL_OFF)
2722262795Shselasky		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2723262795Shselasky	RUN_UNLOCK(sc);
2724203134Sthompsa}
2725203134Sthompsa
2726203134Sthompsa/*
2727203134Sthompsa * Return the Rx chain with the highest RSSI for a given frame.
2728203134Sthompsa */
2729203134Sthompsastatic __inline uint8_t
2730203134Sthompsarun_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi)
2731203134Sthompsa{
2732203134Sthompsa	uint8_t rxchain = 0;
2733203134Sthompsa
2734203134Sthompsa	if (sc->nrxchains > 1) {
2735203134Sthompsa		if (rxwi->rssi[1] > rxwi->rssi[rxchain])
2736203134Sthompsa			rxchain = 1;
2737203134Sthompsa		if (sc->nrxchains > 2)
2738203134Sthompsa			if (rxwi->rssi[2] > rxwi->rssi[rxchain])
2739203134Sthompsa				rxchain = 2;
2740203134Sthompsa	}
2741209917Sthompsa	return (rxchain);
2742203134Sthompsa}
2743203134Sthompsa
2744203134Sthompsastatic void
2745203134Sthompsarun_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen)
2746203134Sthompsa{
2747287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
2748203134Sthompsa	struct ieee80211_frame *wh;
2749203134Sthompsa	struct ieee80211_node *ni;
2750203134Sthompsa	struct rt2870_rxd *rxd;
2751203134Sthompsa	struct rt2860_rxwi *rxwi;
2752203134Sthompsa	uint32_t flags;
2753259032Skevlo	uint16_t len, rxwisize;
2754203134Sthompsa	uint8_t ant, rssi;
2755203134Sthompsa	int8_t nf;
2756203134Sthompsa
2757203134Sthompsa	rxwi = mtod(m, struct rt2860_rxwi *);
2758203134Sthompsa	len = le16toh(rxwi->len) & 0xfff;
2759260219Skevlo	rxwisize = sizeof(struct rt2860_rxwi);
2760260219Skevlo	if (sc->mac_ver == 0x5592)
2761260219Skevlo		rxwisize += sizeof(uint64_t);
2762260219Skevlo	else if (sc->mac_ver == 0x3593)
2763260219Skevlo		rxwisize += sizeof(uint32_t);
2764203134Sthompsa	if (__predict_false(len > dmalen)) {
2765203134Sthompsa		m_freem(m);
2766287197Sglebius		counter_u64_add(ic->ic_ierrors, 1);
2767203134Sthompsa		DPRINTF("bad RXWI length %u > %u\n", len, dmalen);
2768203134Sthompsa		return;
2769203134Sthompsa	}
2770203134Sthompsa	/* Rx descriptor is located at the end */
2771203134Sthompsa	rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen);
2772203134Sthompsa	flags = le32toh(rxd->flags);
2773203134Sthompsa
2774203134Sthompsa	if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) {
2775203134Sthompsa		m_freem(m);
2776287197Sglebius		counter_u64_add(ic->ic_ierrors, 1);
2777203134Sthompsa		DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV");
2778203134Sthompsa		return;
2779203134Sthompsa	}
2780203134Sthompsa
2781259032Skevlo	m->m_data += rxwisize;
2782259032Skevlo	m->m_pkthdr.len = m->m_len -= rxwisize;
2783203134Sthompsa
2784203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
2785203134Sthompsa
2786260444Skevlo	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
2787260444Skevlo		wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
2788203134Sthompsa		m->m_flags |= M_WEP;
2789203134Sthompsa	}
2790203134Sthompsa
2791209917Sthompsa	if (flags & RT2860_RX_L2PAD) {
2792203134Sthompsa		DPRINTFN(8, "received RT2860_RX_L2PAD frame\n");
2793203134Sthompsa		len += 2;
2794203134Sthompsa	}
2795203134Sthompsa
2796208019Sthompsa	ni = ieee80211_find_rxnode(ic,
2797208019Sthompsa	    mtod(m, struct ieee80211_frame_min *));
2798208019Sthompsa
2799203134Sthompsa	if (__predict_false(flags & RT2860_RX_MICERR)) {
2800203134Sthompsa		/* report MIC failures to net80211 for TKIP */
2801209917Sthompsa		if (ni != NULL)
2802259032Skevlo			ieee80211_notify_michael_failure(ni->ni_vap, wh,
2803259032Skevlo			    rxwi->keyidx);
2804203134Sthompsa		m_freem(m);
2805287197Sglebius		counter_u64_add(ic->ic_ierrors, 1);
2806203134Sthompsa		DPRINTF("MIC error. Someone is lying.\n");
2807203134Sthompsa		return;
2808203134Sthompsa	}
2809203134Sthompsa
2810203134Sthompsa	ant = run_maxrssi_chain(sc, rxwi);
2811203134Sthompsa	rssi = rxwi->rssi[ant];
2812203134Sthompsa	nf = run_rssi2dbm(sc, rssi, ant);
2813203134Sthompsa
2814203134Sthompsa	m->m_pkthdr.len = m->m_len = len;
2815203134Sthompsa
2816203134Sthompsa	if (ni != NULL) {
2817203134Sthompsa		(void)ieee80211_input(ni, m, rssi, nf);
2818203134Sthompsa		ieee80211_free_node(ni);
2819203134Sthompsa	} else {
2820203134Sthompsa		(void)ieee80211_input_all(ic, m, rssi, nf);
2821203134Sthompsa	}
2822203134Sthompsa
2823209917Sthompsa	if (__predict_false(ieee80211_radiotap_active(ic))) {
2824203134Sthompsa		struct run_rx_radiotap_header *tap = &sc->sc_rxtap;
2825258643Shselasky		uint16_t phy;
2826203134Sthompsa
2827203134Sthompsa		tap->wr_flags = 0;
2828236439Shselasky		tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
2829236439Shselasky		tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
2830203134Sthompsa		tap->wr_antsignal = rssi;
2831203134Sthompsa		tap->wr_antenna = ant;
2832203134Sthompsa		tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant);
2833203134Sthompsa		tap->wr_rate = 2;	/* in case it can't be found below */
2834203134Sthompsa		phy = le16toh(rxwi->phy);
2835203134Sthompsa		switch (phy & RT2860_PHY_MODE) {
2836203134Sthompsa		case RT2860_PHY_CCK:
2837203134Sthompsa			switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) {
2838203134Sthompsa			case 0:	tap->wr_rate =   2; break;
2839203134Sthompsa			case 1:	tap->wr_rate =   4; break;
2840203134Sthompsa			case 2:	tap->wr_rate =  11; break;
2841203134Sthompsa			case 3:	tap->wr_rate =  22; break;
2842203134Sthompsa			}
2843203134Sthompsa			if (phy & RT2860_PHY_SHPRE)
2844203134Sthompsa				tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
2845203134Sthompsa			break;
2846203134Sthompsa		case RT2860_PHY_OFDM:
2847203134Sthompsa			switch (phy & RT2860_PHY_MCS) {
2848203134Sthompsa			case 0:	tap->wr_rate =  12; break;
2849203134Sthompsa			case 1:	tap->wr_rate =  18; break;
2850203134Sthompsa			case 2:	tap->wr_rate =  24; break;
2851203134Sthompsa			case 3:	tap->wr_rate =  36; break;
2852203134Sthompsa			case 4:	tap->wr_rate =  48; break;
2853203134Sthompsa			case 5:	tap->wr_rate =  72; break;
2854203134Sthompsa			case 6:	tap->wr_rate =  96; break;
2855203134Sthompsa			case 7:	tap->wr_rate = 108; break;
2856203134Sthompsa			}
2857203134Sthompsa			break;
2858203134Sthompsa		}
2859203134Sthompsa	}
2860203134Sthompsa}
2861203134Sthompsa
2862203134Sthompsastatic void
2863203134Sthompsarun_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
2864203134Sthompsa{
2865203134Sthompsa	struct run_softc *sc = usbd_xfer_softc(xfer);
2866287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
2867203134Sthompsa	struct mbuf *m = NULL;
2868203134Sthompsa	struct mbuf *m0;
2869203134Sthompsa	uint32_t dmalen;
2870259032Skevlo	uint16_t rxwisize;
2871203134Sthompsa	int xferlen;
2872203134Sthompsa
2873260219Skevlo	rxwisize = sizeof(struct rt2860_rxwi);
2874260219Skevlo	if (sc->mac_ver == 0x5592)
2875260219Skevlo		rxwisize += sizeof(uint64_t);
2876260219Skevlo	else if (sc->mac_ver == 0x3593)
2877260219Skevlo		rxwisize += sizeof(uint32_t);
2878259032Skevlo
2879203134Sthompsa	usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL);
2880203134Sthompsa
2881203134Sthompsa	switch (USB_GET_STATE(xfer)) {
2882203134Sthompsa	case USB_ST_TRANSFERRED:
2883203134Sthompsa
2884203134Sthompsa		DPRINTFN(15, "rx done, actlen=%d\n", xferlen);
2885203134Sthompsa
2886259032Skevlo		if (xferlen < (int)(sizeof(uint32_t) + rxwisize +
2887259032Skevlo		    sizeof(struct rt2870_rxd))) {
2888203134Sthompsa			DPRINTF("xfer too short %d\n", xferlen);
2889203134Sthompsa			goto tr_setup;
2890203134Sthompsa		}
2891203134Sthompsa
2892203134Sthompsa		m = sc->rx_m;
2893203134Sthompsa		sc->rx_m = NULL;
2894203134Sthompsa
2895203134Sthompsa		/* FALLTHROUGH */
2896203134Sthompsa	case USB_ST_SETUP:
2897203134Sthompsatr_setup:
2898203134Sthompsa		if (sc->rx_m == NULL) {
2899243857Sglebius			sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
2900203134Sthompsa			    MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */);
2901203134Sthompsa		}
2902203134Sthompsa		if (sc->rx_m == NULL) {
2903203134Sthompsa			DPRINTF("could not allocate mbuf - idle with stall\n");
2904287197Sglebius			counter_u64_add(ic->ic_ierrors, 1);
2905203134Sthompsa			usbd_xfer_set_stall(xfer);
2906203134Sthompsa			usbd_xfer_set_frames(xfer, 0);
2907203134Sthompsa		} else {
2908203134Sthompsa			/*
2909203134Sthompsa			 * Directly loading a mbuf cluster into DMA to
2910203134Sthompsa			 * save some data copying. This works because
2911203134Sthompsa			 * there is only one cluster.
2912203134Sthompsa			 */
2913203134Sthompsa			usbd_xfer_set_frame_data(xfer, 0,
2914203134Sthompsa			    mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ);
2915203134Sthompsa			usbd_xfer_set_frames(xfer, 1);
2916203134Sthompsa		}
2917203134Sthompsa		usbd_transfer_submit(xfer);
2918203134Sthompsa		break;
2919203134Sthompsa
2920203134Sthompsa	default:	/* Error */
2921203134Sthompsa		if (error != USB_ERR_CANCELLED) {
2922203134Sthompsa			/* try to clear stall first */
2923203134Sthompsa			usbd_xfer_set_stall(xfer);
2924203134Sthompsa			if (error == USB_ERR_TIMEOUT)
2925203134Sthompsa				device_printf(sc->sc_dev, "device timeout\n");
2926287197Sglebius			counter_u64_add(ic->ic_ierrors, 1);
2927203134Sthompsa			goto tr_setup;
2928203134Sthompsa		}
2929209917Sthompsa		if (sc->rx_m != NULL) {
2930203134Sthompsa			m_freem(sc->rx_m);
2931203134Sthompsa			sc->rx_m = NULL;
2932203134Sthompsa		}
2933203134Sthompsa		break;
2934203134Sthompsa	}
2935203134Sthompsa
2936203134Sthompsa	if (m == NULL)
2937203134Sthompsa		return;
2938203134Sthompsa
2939203134Sthompsa	/* inputting all the frames must be last */
2940203134Sthompsa
2941203134Sthompsa	RUN_UNLOCK(sc);
2942203134Sthompsa
2943203134Sthompsa	m->m_pkthdr.len = m->m_len = xferlen;
2944203134Sthompsa
2945203134Sthompsa	/* HW can aggregate multiple 802.11 frames in a single USB xfer */
2946203134Sthompsa	for(;;) {
2947203134Sthompsa		dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff;
2948203134Sthompsa
2949233774Shselasky		if ((dmalen >= (uint32_t)-8) || (dmalen == 0) ||
2950233774Shselasky		    ((dmalen & 3) != 0)) {
2951203134Sthompsa			DPRINTF("bad DMA length %u\n", dmalen);
2952203134Sthompsa			break;
2953203134Sthompsa		}
2954233774Shselasky		if ((dmalen + 8) > (uint32_t)xferlen) {
2955203134Sthompsa			DPRINTF("bad DMA length %u > %d\n",
2956203134Sthompsa			dmalen + 8, xferlen);
2957203134Sthompsa			break;
2958203134Sthompsa		}
2959203134Sthompsa
2960203134Sthompsa		/* If it is the last one or a single frame, we won't copy. */
2961209917Sthompsa		if ((xferlen -= dmalen + 8) <= 8) {
2962203134Sthompsa			/* trim 32-bit DMA-len header */
2963203134Sthompsa			m->m_data += 4;
2964203134Sthompsa			m->m_pkthdr.len = m->m_len -= 4;
2965203134Sthompsa			run_rx_frame(sc, m, dmalen);
2966257435Shselasky			m = NULL;	/* don't free source buffer */
2967203134Sthompsa			break;
2968203134Sthompsa		}
2969203134Sthompsa
2970203134Sthompsa		/* copy aggregated frames to another mbuf */
2971243857Sglebius		m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
2972203134Sthompsa		if (__predict_false(m0 == NULL)) {
2973203134Sthompsa			DPRINTF("could not allocate mbuf\n");
2974287197Sglebius			counter_u64_add(ic->ic_ierrors, 1);
2975203134Sthompsa			break;
2976203134Sthompsa		}
2977203134Sthompsa		m_copydata(m, 4 /* skip 32-bit DMA-len header */,
2978203134Sthompsa		    dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t));
2979203134Sthompsa		m0->m_pkthdr.len = m0->m_len =
2980203134Sthompsa		    dmalen + sizeof(struct rt2870_rxd);
2981203134Sthompsa		run_rx_frame(sc, m0, dmalen);
2982203134Sthompsa
2983203134Sthompsa		/* update data ptr */
2984203134Sthompsa		m->m_data += dmalen + 8;
2985203134Sthompsa		m->m_pkthdr.len = m->m_len -= dmalen + 8;
2986203134Sthompsa	}
2987203134Sthompsa
2988257435Shselasky	/* make sure we free the source buffer, if any */
2989257435Shselasky	m_freem(m);
2990257435Shselasky
2991203134Sthompsa	RUN_LOCK(sc);
2992203134Sthompsa}
2993203134Sthompsa
2994203134Sthompsastatic void
2995203134Sthompsarun_tx_free(struct run_endpoint_queue *pq,
2996203134Sthompsa    struct run_tx_data *data, int txerr)
2997203134Sthompsa{
2998203134Sthompsa	if (data->m != NULL) {
2999203134Sthompsa		if (data->m->m_flags & M_TXCB)
3000203134Sthompsa			ieee80211_process_callback(data->ni, data->m,
3001203134Sthompsa			    txerr ? ETIMEDOUT : 0);
3002203134Sthompsa		m_freem(data->m);
3003203134Sthompsa		data->m = NULL;
3004203134Sthompsa
3005209917Sthompsa		if (data->ni == NULL) {
3006203134Sthompsa			DPRINTF("no node\n");
3007203134Sthompsa		} else {
3008203134Sthompsa			ieee80211_free_node(data->ni);
3009203134Sthompsa			data->ni = NULL;
3010203134Sthompsa		}
3011203134Sthompsa	}
3012203134Sthompsa
3013203134Sthompsa	STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
3014203134Sthompsa	pq->tx_nfree++;
3015203134Sthompsa}
3016203134Sthompsa
3017203134Sthompsastatic void
3018257429Shselaskyrun_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index)
3019203134Sthompsa{
3020203134Sthompsa	struct run_softc *sc = usbd_xfer_softc(xfer);
3021287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3022203134Sthompsa	struct run_tx_data *data;
3023203134Sthompsa	struct ieee80211vap *vap = NULL;
3024203134Sthompsa	struct usb_page_cache *pc;
3025203134Sthompsa	struct run_endpoint_queue *pq = &sc->sc_epq[index];
3026203134Sthompsa	struct mbuf *m;
3027203134Sthompsa	usb_frlength_t size;
3028203134Sthompsa	int actlen;
3029203134Sthompsa	int sumlen;
3030203134Sthompsa
3031203134Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
3032203134Sthompsa
3033209917Sthompsa	switch (USB_GET_STATE(xfer)) {
3034203134Sthompsa	case USB_ST_TRANSFERRED:
3035203134Sthompsa		DPRINTFN(11, "transfer complete: %d "
3036203134Sthompsa		    "bytes @ index %d\n", actlen, index);
3037203134Sthompsa
3038203134Sthompsa		data = usbd_xfer_get_priv(xfer);
3039203134Sthompsa		run_tx_free(pq, data, 0);
3040203134Sthompsa		usbd_xfer_set_priv(xfer, NULL);
3041203134Sthompsa
3042203134Sthompsa		/* FALLTHROUGH */
3043203134Sthompsa	case USB_ST_SETUP:
3044203134Sthompsatr_setup:
3045203134Sthompsa		data = STAILQ_FIRST(&pq->tx_qh);
3046209917Sthompsa		if (data == NULL)
3047203134Sthompsa			break;
3048203134Sthompsa
3049203134Sthompsa		STAILQ_REMOVE_HEAD(&pq->tx_qh, next);
3050203134Sthompsa
3051203134Sthompsa		m = data->m;
3052261330Shselasky		size = (sc->mac_ver == 0x5592) ?
3053261330Shselasky		    sizeof(data->desc) + sizeof(uint32_t) : sizeof(data->desc);
3054261076Shselasky		if ((m->m_pkthdr.len +
3055261330Shselasky		    size + 3 + 8) > RUN_MAX_TXSZ) {
3056203134Sthompsa			DPRINTF("data overflow, %u bytes\n",
3057203134Sthompsa			    m->m_pkthdr.len);
3058203134Sthompsa			run_tx_free(pq, data, 1);
3059203134Sthompsa			goto tr_setup;
3060203134Sthompsa		}
3061203134Sthompsa
3062203134Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
3063203134Sthompsa		usbd_copy_in(pc, 0, &data->desc, size);
3064203134Sthompsa		usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len);
3065228508Shselasky		size += m->m_pkthdr.len;
3066228508Shselasky		/*
3067228508Shselasky		 * Align end on a 4-byte boundary, pad 8 bytes (CRC +
3068228508Shselasky		 * 4-byte padding), and be sure to zero those trailing
3069228508Shselasky		 * bytes:
3070228508Shselasky		 */
3071228508Shselasky		usbd_frame_zero(pc, size, ((-size) & 3) + 8);
3072228508Shselasky		size += ((-size) & 3) + 8;
3073203134Sthompsa
3074203134Sthompsa		vap = data->ni->ni_vap;
3075203134Sthompsa		if (ieee80211_radiotap_active_vap(vap)) {
3076203134Sthompsa			struct run_tx_radiotap_header *tap = &sc->sc_txtap;
3077259032Skevlo			struct rt2860_txwi *txwi =
3078208019Sthompsa			    (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd));
3079203134Sthompsa			tap->wt_flags = 0;
3080203134Sthompsa			tap->wt_rate = rt2860_rates[data->ridx].rate;
3081236439Shselasky			tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
3082236439Shselasky			tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
3083203134Sthompsa			tap->wt_hwqueue = index;
3084208019Sthompsa			if (le16toh(txwi->phy) & RT2860_PHY_SHPRE)
3085203134Sthompsa				tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
3086203134Sthompsa
3087203134Sthompsa			ieee80211_radiotap_tx(vap, m);
3088203134Sthompsa		}
3089203134Sthompsa
3090228508Shselasky		DPRINTFN(11, "sending frame len=%u/%u  @ index %d\n",
3091228508Shselasky		    m->m_pkthdr.len, size, index);
3092203134Sthompsa
3093228508Shselasky		usbd_xfer_set_frame_len(xfer, 0, size);
3094203134Sthompsa		usbd_xfer_set_priv(xfer, data);
3095203134Sthompsa		usbd_transfer_submit(xfer);
3096287197Sglebius		run_start(sc);
3097203134Sthompsa
3098203134Sthompsa		break;
3099203134Sthompsa
3100203134Sthompsa	default:
3101203134Sthompsa		DPRINTF("USB transfer error, %s\n",
3102203134Sthompsa		    usbd_errstr(error));
3103203134Sthompsa
3104203134Sthompsa		data = usbd_xfer_get_priv(xfer);
3105203134Sthompsa
3106203134Sthompsa		if (data != NULL) {
3107208019Sthompsa			if(data->ni != NULL)
3108208019Sthompsa				vap = data->ni->ni_vap;
3109203134Sthompsa			run_tx_free(pq, data, error);
3110203134Sthompsa			usbd_xfer_set_priv(xfer, NULL);
3111203134Sthompsa		}
3112287197Sglebius
3113209917Sthompsa		if (vap == NULL)
3114208019Sthompsa			vap = TAILQ_FIRST(&ic->ic_vaps);
3115203134Sthompsa
3116203134Sthompsa		if (error != USB_ERR_CANCELLED) {
3117203134Sthompsa			if (error == USB_ERR_TIMEOUT) {
3118203134Sthompsa				device_printf(sc->sc_dev, "device timeout\n");
3119208019Sthompsa				uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3120208019Sthompsa				DPRINTF("cmdq_store=%d\n", i);
3121208019Sthompsa				sc->cmdq[i].func = run_usb_timeout_cb;
3122208019Sthompsa				sc->cmdq[i].arg0 = vap;
3123208019Sthompsa				ieee80211_runtask(ic, &sc->cmdq_task);
3124203134Sthompsa			}
3125203134Sthompsa
3126203134Sthompsa			/*
3127203134Sthompsa			 * Try to clear stall first, also if other
3128203134Sthompsa			 * errors occur, hence clearing stall
3129203134Sthompsa			 * introduces a 50 ms delay:
3130203134Sthompsa			 */
3131203134Sthompsa			usbd_xfer_set_stall(xfer);
3132203134Sthompsa			goto tr_setup;
3133203134Sthompsa		}
3134203134Sthompsa		break;
3135203134Sthompsa	}
3136203134Sthompsa}
3137203134Sthompsa
3138203134Sthompsastatic void
3139203134Sthompsarun_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error)
3140203134Sthompsa{
3141203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 0);
3142203134Sthompsa}
3143203134Sthompsa
3144203134Sthompsastatic void
3145203134Sthompsarun_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error)
3146203134Sthompsa{
3147203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 1);
3148203134Sthompsa}
3149203134Sthompsa
3150203134Sthompsastatic void
3151203134Sthompsarun_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error)
3152203134Sthompsa{
3153203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 2);
3154203134Sthompsa}
3155203134Sthompsa
3156203134Sthompsastatic void
3157203134Sthompsarun_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error)
3158203134Sthompsa{
3159203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 3);
3160203134Sthompsa}
3161203134Sthompsa
3162203134Sthompsastatic void
3163203134Sthompsarun_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error)
3164203134Sthompsa{
3165203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 4);
3166203134Sthompsa}
3167203134Sthompsa
3168203134Sthompsastatic void
3169203134Sthompsarun_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error)
3170203134Sthompsa{
3171203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 5);
3172203134Sthompsa}
3173203134Sthompsa
3174203134Sthompsastatic void
3175208019Sthompsarun_set_tx_desc(struct run_softc *sc, struct run_tx_data *data)
3176203134Sthompsa{
3177203134Sthompsa	struct mbuf *m = data->m;
3178287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3179208019Sthompsa	struct ieee80211vap *vap = data->ni->ni_vap;
3180203134Sthompsa	struct ieee80211_frame *wh;
3181203134Sthompsa	struct rt2870_txd *txd;
3182203134Sthompsa	struct rt2860_txwi *txwi;
3183259032Skevlo	uint16_t xferlen, txwisize;
3184208019Sthompsa	uint16_t mcs;
3185203134Sthompsa	uint8_t ridx = data->ridx;
3186208019Sthompsa	uint8_t pad;
3187203134Sthompsa
3188203134Sthompsa	/* get MCS code from rate index */
3189208019Sthompsa	mcs = rt2860_rates[ridx].mcs;
3190203134Sthompsa
3191259032Skevlo	txwisize = (sc->mac_ver == 0x5592) ?
3192259032Skevlo	    sizeof(*txwi) + sizeof(uint32_t) : sizeof(*txwi);
3193259032Skevlo	xferlen = txwisize + m->m_pkthdr.len;
3194203134Sthompsa
3195203134Sthompsa	/* roundup to 32-bit alignment */
3196203134Sthompsa	xferlen = (xferlen + 3) & ~3;
3197203134Sthompsa
3198203134Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3199203134Sthompsa	txd->len = htole16(xferlen);
3200203134Sthompsa
3201208019Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3202208019Sthompsa
3203208019Sthompsa	/*
3204208019Sthompsa	 * Ether both are true or both are false, the header
3205208019Sthompsa	 * are nicely aligned to 32-bit. So, no L2 padding.
3206208019Sthompsa	 */
3207208019Sthompsa	if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh))
3208208019Sthompsa		pad = 0;
3209208019Sthompsa	else
3210208019Sthompsa		pad = 2;
3211208019Sthompsa
3212203134Sthompsa	/* setup TX Wireless Information */
3213203134Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3214203134Sthompsa	txwi->len = htole16(m->m_pkthdr.len - pad);
3215203134Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_DS) {
3216270192Skevlo		mcs |= RT2860_PHY_CCK;
3217203134Sthompsa		if (ridx != RT2860_RIDX_CCK1 &&
3218203134Sthompsa		    (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
3219203134Sthompsa			mcs |= RT2860_PHY_SHPRE;
3220203134Sthompsa	} else
3221270192Skevlo		mcs |= RT2860_PHY_OFDM;
3222270192Skevlo	txwi->phy = htole16(mcs);
3223203134Sthompsa
3224203134Sthompsa	/* check if RTS/CTS or CTS-to-self protection is required */
3225203134Sthompsa	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3226203134Sthompsa	    (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold ||
3227203134Sthompsa	     ((ic->ic_flags & IEEE80211_F_USEPROT) &&
3228203134Sthompsa	      rt2860_rates[ridx].phy == IEEE80211_T_OFDM)))
3229208019Sthompsa		txwi->txop |= RT2860_TX_TXOP_HT;
3230203134Sthompsa	else
3231208019Sthompsa		txwi->txop |= RT2860_TX_TXOP_BACKOFF;
3232209144Sthompsa
3233209917Sthompsa	if (vap->iv_opmode != IEEE80211_M_STA && !IEEE80211_QOS_HAS_SEQ(wh))
3234209144Sthompsa		txwi->xflags |= RT2860_TX_NSEQ;
3235203134Sthompsa}
3236203134Sthompsa
3237203134Sthompsa/* This function must be called locked */
3238203134Sthompsastatic int
3239203134Sthompsarun_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3240203134Sthompsa{
3241287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3242208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
3243203134Sthompsa	struct ieee80211_frame *wh;
3244208019Sthompsa	struct ieee80211_channel *chan;
3245203134Sthompsa	const struct ieee80211_txparam *tp;
3246208019Sthompsa	struct run_node *rn = (void *)ni;
3247203134Sthompsa	struct run_tx_data *data;
3248208019Sthompsa	struct rt2870_txd *txd;
3249208019Sthompsa	struct rt2860_txwi *txwi;
3250203134Sthompsa	uint16_t qos;
3251203134Sthompsa	uint16_t dur;
3252208019Sthompsa	uint16_t qid;
3253203134Sthompsa	uint8_t type;
3254203134Sthompsa	uint8_t tid;
3255208019Sthompsa	uint8_t ridx;
3256208019Sthompsa	uint8_t ctl_ridx;
3257203134Sthompsa	uint8_t qflags;
3258203134Sthompsa	uint8_t xflags = 0;
3259203134Sthompsa	int hasqos;
3260203134Sthompsa
3261203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3262203134Sthompsa
3263203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3264203134Sthompsa
3265203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3266203134Sthompsa
3267203134Sthompsa	/*
3268203134Sthompsa	 * There are 7 bulk endpoints: 1 for RX
3269203134Sthompsa	 * and 6 for TX (4 EDCAs + HCCA + Prio).
3270203134Sthompsa	 * Update 03-14-2009:  some devices like the Planex GW-US300MiniS
3271203134Sthompsa	 * seem to have only 4 TX bulk endpoints (Fukaumi Naoki).
3272203134Sthompsa	 */
3273203134Sthompsa	if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) {
3274203134Sthompsa		uint8_t *frm;
3275203134Sthompsa
3276203134Sthompsa		if(IEEE80211_HAS_ADDR4(wh))
3277203134Sthompsa			frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos;
3278203134Sthompsa		else
3279203134Sthompsa			frm =((struct ieee80211_qosframe *)wh)->i_qos;
3280203134Sthompsa
3281203134Sthompsa		qos = le16toh(*(const uint16_t *)frm);
3282203134Sthompsa		tid = qos & IEEE80211_QOS_TID;
3283203134Sthompsa		qid = TID_TO_WME_AC(tid);
3284203134Sthompsa	} else {
3285203134Sthompsa		qos = 0;
3286203134Sthompsa		tid = 0;
3287203134Sthompsa		qid = WME_AC_BE;
3288203134Sthompsa	}
3289203134Sthompsa	qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA;
3290203134Sthompsa
3291203134Sthompsa	DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n",
3292203134Sthompsa	    qos, qid, tid, qflags);
3293203134Sthompsa
3294208019Sthompsa	chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan;
3295208019Sthompsa	tp = &vap->iv_txparms[ieee80211_chan2mode(chan)];
3296203134Sthompsa
3297203134Sthompsa	/* pickup a rate index */
3298203134Sthompsa	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
3299270192Skevlo	    type != IEEE80211_FC0_TYPE_DATA || m->m_flags & M_EAPOL) {
3300203134Sthompsa		ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
3301203134Sthompsa		    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
3302203134Sthompsa		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3303203134Sthompsa	} else {
3304208019Sthompsa		if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
3305208019Sthompsa			ridx = rn->fix_ridx;
3306208019Sthompsa		else
3307208019Sthompsa			ridx = rn->amrr_ridx;
3308203134Sthompsa		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3309203134Sthompsa	}
3310203134Sthompsa
3311203134Sthompsa	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3312203134Sthompsa	    (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) !=
3313203134Sthompsa	     IEEE80211_QOS_ACKPOLICY_NOACK)) {
3314209144Sthompsa		xflags |= RT2860_TX_ACK;
3315203134Sthompsa		if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
3316208019Sthompsa			dur = rt2860_rates[ctl_ridx].sp_ack_dur;
3317203134Sthompsa		else
3318208019Sthompsa			dur = rt2860_rates[ctl_ridx].lp_ack_dur;
3319258919Shselasky		USETW(wh->i_dur, dur);
3320203134Sthompsa	}
3321203134Sthompsa
3322203134Sthompsa	/* reserve slots for mgmt packets, just in case */
3323203134Sthompsa	if (sc->sc_epq[qid].tx_nfree < 3) {
3324203134Sthompsa		DPRINTFN(10, "tx ring %d is full\n", qid);
3325203134Sthompsa		return (-1);
3326203134Sthompsa	}
3327203134Sthompsa
3328203134Sthompsa	data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh);
3329203134Sthompsa	STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next);
3330203134Sthompsa	sc->sc_epq[qid].tx_nfree--;
3331203134Sthompsa
3332208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3333208019Sthompsa	txd->flags = qflags;
3334208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3335208019Sthompsa	txwi->xflags = xflags;
3336259032Skevlo	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
3337245047Shselasky		txwi->wcid = 0;
3338259032Skevlo	else
3339245047Shselasky		txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
3340245047Shselasky		    1 : RUN_AID2WCID(ni->ni_associd);
3341259032Skevlo
3342208019Sthompsa	/* clear leftover garbage bits */
3343208019Sthompsa	txwi->flags = 0;
3344208019Sthompsa	txwi->txop = 0;
3345208019Sthompsa
3346203134Sthompsa	data->m = m;
3347203134Sthompsa	data->ni = ni;
3348203134Sthompsa	data->ridx = ridx;
3349203134Sthompsa
3350208019Sthompsa	run_set_tx_desc(sc, data);
3351203134Sthompsa
3352208019Sthompsa	/*
3353208019Sthompsa	 * The chip keeps track of 2 kind of Tx stats,
3354208019Sthompsa	 *  * TX_STAT_FIFO, for per WCID stats, and
3355208019Sthompsa	 *  * TX_STA_CNT0 for all-TX-in-one stats.
3356208019Sthompsa	 *
3357208019Sthompsa	 * To use FIFO stats, we need to store MCS into the driver-private
3358208019Sthompsa 	 * PacketID field. So that, we can tell whose stats when we read them.
3359208019Sthompsa 	 * We add 1 to the MCS because setting the PacketID field to 0 means
3360208019Sthompsa 	 * that we don't want feedback in TX_STAT_FIFO.
3361208019Sthompsa 	 * And, that's what we want for STA mode, since TX_STA_CNT0 does the job.
3362208019Sthompsa 	 *
3363208019Sthompsa 	 * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx().
3364208019Sthompsa 	 */
3365209917Sthompsa	if (sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP ||
3366209917Sthompsa	    vap->iv_opmode == IEEE80211_M_MBSS) {
3367208019Sthompsa		uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf;
3368208019Sthompsa		txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT);
3369208019Sthompsa
3370208019Sthompsa		/*
3371208019Sthompsa		 * Unlike PCI based devices, we don't get any interrupt from
3372208019Sthompsa		 * USB devices, so we simulate FIFO-is-full interrupt here.
3373208019Sthompsa		 * Ralink recomends to drain FIFO stats every 100 ms, but 16 slots
3374208019Sthompsa		 * quickly get fulled. To prevent overflow, increment a counter on
3375208019Sthompsa		 * every FIFO stat request, so we know how many slots are left.
3376208019Sthompsa		 * We do this only in HOSTAP or multiple vap mode since FIFO stats
3377208019Sthompsa		 * are used only in those modes.
3378208019Sthompsa		 * We just drain stats. AMRR gets updated every 1 sec by
3379208019Sthompsa		 * run_ratectl_cb() via callout.
3380208019Sthompsa		 * Call it early. Otherwise overflow.
3381208019Sthompsa		 */
3382209917Sthompsa		if (sc->fifo_cnt++ == 10) {
3383208019Sthompsa			/*
3384208019Sthompsa			 * With multiple vaps or if_bridge, if_start() is called
3385208019Sthompsa			 * with a non-sleepable lock, tcpinp. So, need to defer.
3386208019Sthompsa			 */
3387208019Sthompsa			uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3388208019Sthompsa			DPRINTFN(6, "cmdq_store=%d\n", i);
3389208019Sthompsa			sc->cmdq[i].func = run_drain_fifo;
3390208019Sthompsa			sc->cmdq[i].arg0 = sc;
3391208019Sthompsa			ieee80211_runtask(ic, &sc->cmdq_task);
3392208019Sthompsa		}
3393208019Sthompsa	}
3394208019Sthompsa
3395203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next);
3396203134Sthompsa
3397203134Sthompsa	usbd_transfer_start(sc->sc_xfer[qid]);
3398203134Sthompsa
3399258840Skevlo	DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n",
3400259032Skevlo	    m->m_pkthdr.len + (int)(sizeof(struct rt2870_txd) +
3401259046Shselasky	    sizeof(struct rt2860_txwi)), rt2860_rates[ridx].rate, qid);
3402203134Sthompsa
3403203134Sthompsa	return (0);
3404203134Sthompsa}
3405203134Sthompsa
3406203134Sthompsastatic int
3407203134Sthompsarun_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3408203134Sthompsa{
3409287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3410208019Sthompsa	struct run_node *rn = (void *)ni;
3411203134Sthompsa	struct run_tx_data *data;
3412203134Sthompsa	struct ieee80211_frame *wh;
3413208019Sthompsa	struct rt2870_txd *txd;
3414208019Sthompsa	struct rt2860_txwi *txwi;
3415203134Sthompsa	uint16_t dur;
3416208019Sthompsa	uint8_t ridx = rn->mgt_ridx;
3417203134Sthompsa	uint8_t type;
3418203134Sthompsa	uint8_t xflags = 0;
3419208019Sthompsa	uint8_t wflags = 0;
3420203134Sthompsa
3421203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3422203134Sthompsa
3423203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3424203134Sthompsa
3425203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3426203134Sthompsa
3427208019Sthompsa	/* tell hardware to add timestamp for probe responses */
3428208019Sthompsa	if ((wh->i_fc[0] &
3429208019Sthompsa	    (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
3430208019Sthompsa	    (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
3431208019Sthompsa		wflags |= RT2860_TX_TS;
3432208019Sthompsa	else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3433203134Sthompsa		xflags |= RT2860_TX_ACK;
3434203134Sthompsa
3435208019Sthompsa		dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate,
3436203134Sthompsa		    ic->ic_flags & IEEE80211_F_SHPREAMBLE);
3437258919Shselasky		USETW(wh->i_dur, dur);
3438203134Sthompsa	}
3439203134Sthompsa
3440287197Sglebius	if (sc->sc_epq[0].tx_nfree == 0)
3441203134Sthompsa		/* let caller free mbuf */
3442203134Sthompsa		return (EIO);
3443203134Sthompsa	data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3444203134Sthompsa	STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3445203134Sthompsa	sc->sc_epq[0].tx_nfree--;
3446203134Sthompsa
3447208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3448208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3449208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3450208019Sthompsa	txwi->wcid = 0xff;
3451208019Sthompsa	txwi->flags = wflags;
3452208019Sthompsa	txwi->xflags = xflags;
3453208019Sthompsa	txwi->txop = 0;	/* clear leftover garbage bits */
3454208019Sthompsa
3455203134Sthompsa	data->m = m;
3456203134Sthompsa	data->ni = ni;
3457203134Sthompsa	data->ridx = ridx;
3458203134Sthompsa
3459208019Sthompsa	run_set_tx_desc(sc, data);
3460203134Sthompsa
3461203134Sthompsa	DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len +
3462258840Skevlo	    (int)(sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi)),
3463208019Sthompsa	    rt2860_rates[ridx].rate);
3464203134Sthompsa
3465203134Sthompsa	STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3466203134Sthompsa
3467203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3468203134Sthompsa
3469203134Sthompsa	return (0);
3470203134Sthompsa}
3471203134Sthompsa
3472203134Sthompsastatic int
3473203134Sthompsarun_sendprot(struct run_softc *sc,
3474203134Sthompsa    const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate)
3475203134Sthompsa{
3476203134Sthompsa	struct ieee80211com *ic = ni->ni_ic;
3477203134Sthompsa	struct ieee80211_frame *wh;
3478203134Sthompsa	struct run_tx_data *data;
3479208019Sthompsa	struct rt2870_txd *txd;
3480208019Sthompsa	struct rt2860_txwi *txwi;
3481203134Sthompsa	struct mbuf *mprot;
3482203134Sthompsa	int ridx;
3483203134Sthompsa	int protrate;
3484203134Sthompsa	int ackrate;
3485203134Sthompsa	int pktlen;
3486203134Sthompsa	int isshort;
3487203134Sthompsa	uint16_t dur;
3488203134Sthompsa	uint8_t type;
3489208019Sthompsa	uint8_t wflags = 0;
3490208019Sthompsa	uint8_t xflags = 0;
3491203134Sthompsa
3492203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3493203134Sthompsa
3494203134Sthompsa	KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY,
3495203134Sthompsa	    ("protection %d", prot));
3496203134Sthompsa
3497203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3498203134Sthompsa	pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
3499203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3500203134Sthompsa
3501203134Sthompsa	protrate = ieee80211_ctl_rate(ic->ic_rt, rate);
3502203134Sthompsa	ackrate = ieee80211_ack_rate(ic->ic_rt, rate);
3503203134Sthompsa
3504203134Sthompsa	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
3505209189Sjkim	dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort)
3506203134Sthompsa	    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3507203134Sthompsa	wflags = RT2860_TX_FRAG;
3508203134Sthompsa
3509203134Sthompsa	/* check that there are free slots before allocating the mbuf */
3510287197Sglebius	if (sc->sc_epq[0].tx_nfree == 0)
3511203134Sthompsa		/* let caller free mbuf */
3512203134Sthompsa		return (ENOBUFS);
3513203134Sthompsa
3514203134Sthompsa	if (prot == IEEE80211_PROT_RTSCTS) {
3515203134Sthompsa		/* NB: CTS is the same size as an ACK */
3516203134Sthompsa		dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3517208019Sthompsa		xflags |= RT2860_TX_ACK;
3518203134Sthompsa		mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur);
3519203134Sthompsa	} else {
3520203134Sthompsa		mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur);
3521203134Sthompsa	}
3522203134Sthompsa	if (mprot == NULL) {
3523287197Sglebius		if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1);
3524203134Sthompsa		DPRINTF("could not allocate mbuf\n");
3525203134Sthompsa		return (ENOBUFS);
3526203134Sthompsa	}
3527203134Sthompsa
3528203134Sthompsa        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3529203134Sthompsa        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3530203134Sthompsa        sc->sc_epq[0].tx_nfree--;
3531203134Sthompsa
3532208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3533208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3534208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3535208019Sthompsa	txwi->wcid = 0xff;
3536208019Sthompsa	txwi->flags = wflags;
3537208019Sthompsa	txwi->xflags = xflags;
3538208019Sthompsa	txwi->txop = 0;	/* clear leftover garbage bits */
3539208019Sthompsa
3540203134Sthompsa	data->m = mprot;
3541203134Sthompsa	data->ni = ieee80211_ref_node(ni);
3542203134Sthompsa
3543203134Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3544203134Sthompsa		if (rt2860_rates[ridx].rate == protrate)
3545203134Sthompsa			break;
3546203134Sthompsa	data->ridx = ridx;
3547203134Sthompsa
3548208019Sthompsa	run_set_tx_desc(sc, data);
3549203134Sthompsa
3550203134Sthompsa        DPRINTFN(1, "sending prot len=%u rate=%u\n",
3551203134Sthompsa            m->m_pkthdr.len, rate);
3552203134Sthompsa
3553203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3554203134Sthompsa
3555203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3556203134Sthompsa
3557203134Sthompsa	return (0);
3558203134Sthompsa}
3559203134Sthompsa
3560203134Sthompsastatic int
3561203134Sthompsarun_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
3562203134Sthompsa    const struct ieee80211_bpf_params *params)
3563203134Sthompsa{
3564203134Sthompsa	struct ieee80211com *ic = ni->ni_ic;
3565203134Sthompsa	struct ieee80211_frame *wh;
3566203134Sthompsa	struct run_tx_data *data;
3567208019Sthompsa	struct rt2870_txd *txd;
3568208019Sthompsa	struct rt2860_txwi *txwi;
3569203134Sthompsa	uint8_t type;
3570208019Sthompsa	uint8_t ridx;
3571208019Sthompsa	uint8_t rate;
3572208019Sthompsa	uint8_t opflags = 0;
3573208019Sthompsa	uint8_t xflags = 0;
3574203134Sthompsa	int error;
3575203134Sthompsa
3576203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3577203134Sthompsa
3578203134Sthompsa	KASSERT(params != NULL, ("no raw xmit params"));
3579203134Sthompsa
3580203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3581203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3582203134Sthompsa
3583203134Sthompsa	rate = params->ibp_rate0;
3584203134Sthompsa	if (!ieee80211_isratevalid(ic->ic_rt, rate)) {
3585203134Sthompsa		/* let caller free mbuf */
3586203134Sthompsa		return (EINVAL);
3587203134Sthompsa	}
3588203134Sthompsa
3589203134Sthompsa	if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0)
3590208019Sthompsa		xflags |= RT2860_TX_ACK;
3591203134Sthompsa	if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) {
3592203134Sthompsa		error = run_sendprot(sc, m, ni,
3593203134Sthompsa		    params->ibp_flags & IEEE80211_BPF_RTS ?
3594203134Sthompsa			IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY,
3595203134Sthompsa		    rate);
3596203134Sthompsa		if (error) {
3597203134Sthompsa			/* let caller free mbuf */
3598209917Sthompsa			return error;
3599203134Sthompsa		}
3600203134Sthompsa		opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS;
3601203134Sthompsa	}
3602203134Sthompsa
3603203134Sthompsa	if (sc->sc_epq[0].tx_nfree == 0) {
3604203134Sthompsa		/* let caller free mbuf */
3605203134Sthompsa		DPRINTF("sending raw frame, but tx ring is full\n");
3606203134Sthompsa		return (EIO);
3607203134Sthompsa	}
3608203134Sthompsa        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3609203134Sthompsa        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3610203134Sthompsa        sc->sc_epq[0].tx_nfree--;
3611203134Sthompsa
3612208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3613208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3614208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3615208019Sthompsa	txwi->wcid = 0xff;
3616208019Sthompsa	txwi->xflags = xflags;
3617208019Sthompsa	txwi->txop = opflags;
3618208019Sthompsa	txwi->flags = 0;	/* clear leftover garbage bits */
3619208019Sthompsa
3620203134Sthompsa        data->m = m;
3621203134Sthompsa        data->ni = ni;
3622203134Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3623203134Sthompsa		if (rt2860_rates[ridx].rate == rate)
3624203134Sthompsa			break;
3625203134Sthompsa	data->ridx = ridx;
3626203134Sthompsa
3627208019Sthompsa        run_set_tx_desc(sc, data);
3628203134Sthompsa
3629203134Sthompsa        DPRINTFN(10, "sending raw frame len=%u rate=%u\n",
3630203134Sthompsa            m->m_pkthdr.len, rate);
3631203134Sthompsa
3632203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3633203134Sthompsa
3634203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3635203134Sthompsa
3636209917Sthompsa        return (0);
3637203134Sthompsa}
3638203134Sthompsa
3639203134Sthompsastatic int
3640203134Sthompsarun_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
3641203134Sthompsa    const struct ieee80211_bpf_params *params)
3642203134Sthompsa{
3643286950Sadrian	struct run_softc *sc = ni->ni_ic->ic_softc;
3644208019Sthompsa	int error = 0;
3645208019Sthompsa
3646203134Sthompsa	RUN_LOCK(sc);
3647203134Sthompsa
3648203134Sthompsa	/* prevent management frames from being sent if we're not ready */
3649287197Sglebius	if (!(sc->sc_flags & RUN_RUNNING)) {
3650287197Sglebius		error = ENETDOWN;
3651208019Sthompsa		goto done;
3652203134Sthompsa	}
3653203134Sthompsa
3654203134Sthompsa	if (params == NULL) {
3655203134Sthompsa		/* tx mgt packet */
3656209917Sthompsa		if ((error = run_tx_mgt(sc, m, ni)) != 0) {
3657203134Sthompsa			DPRINTF("mgt tx failed\n");
3658208019Sthompsa			goto done;
3659203134Sthompsa		}
3660203134Sthompsa	} else {
3661203134Sthompsa		/* tx raw packet with param */
3662209917Sthompsa		if ((error = run_tx_param(sc, m, ni, params)) != 0) {
3663203134Sthompsa			DPRINTF("tx with param failed\n");
3664208019Sthompsa			goto done;
3665203134Sthompsa		}
3666203134Sthompsa	}
3667203134Sthompsa
3668208019Sthompsadone:
3669203134Sthompsa	RUN_UNLOCK(sc);
3670203134Sthompsa
3671209917Sthompsa	if (error != 0) {
3672208019Sthompsa		if(m != NULL)
3673208019Sthompsa			m_freem(m);
3674208019Sthompsa		ieee80211_free_node(ni);
3675208019Sthompsa	}
3676203134Sthompsa
3677203134Sthompsa	return (error);
3678203134Sthompsa}
3679203134Sthompsa
3680287197Sglebiusstatic int
3681287197Sglebiusrun_transmit(struct ieee80211com *ic, struct mbuf *m)
3682287197Sglebius{
3683287197Sglebius	struct run_softc *sc = ic->ic_softc;
3684287197Sglebius	int error;
3685287197Sglebius
3686287197Sglebius	RUN_LOCK(sc);
3687287197Sglebius	if ((sc->sc_flags & RUN_RUNNING) == 0) {
3688287197Sglebius		RUN_UNLOCK(sc);
3689287197Sglebius		return (ENXIO);
3690287197Sglebius	}
3691287197Sglebius	error = mbufq_enqueue(&sc->sc_snd, m);
3692287197Sglebius	if (error) {
3693287197Sglebius		RUN_UNLOCK(sc);
3694287197Sglebius		return (error);
3695287197Sglebius	}
3696287197Sglebius	run_start(sc);
3697287197Sglebius	RUN_UNLOCK(sc);
3698287197Sglebius
3699287197Sglebius	return (0);
3700287197Sglebius}
3701287197Sglebius
3702203134Sthompsastatic void
3703287197Sglebiusrun_start(struct run_softc *sc)
3704203134Sthompsa{
3705203134Sthompsa	struct ieee80211_node *ni;
3706203134Sthompsa	struct mbuf *m;
3707203134Sthompsa
3708287197Sglebius	RUN_LOCK_ASSERT(sc, MA_OWNED);
3709203134Sthompsa
3710287197Sglebius	if ((sc->sc_flags & RUN_RUNNING) == 0)
3711203134Sthompsa		return;
3712203134Sthompsa
3713287197Sglebius	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
3714203134Sthompsa		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
3715203134Sthompsa		if (run_tx(sc, m, ni) != 0) {
3716287197Sglebius			mbufq_prepend(&sc->sc_snd, m);
3717203134Sthompsa			break;
3718203134Sthompsa		}
3719203134Sthompsa	}
3720203134Sthompsa}
3721203134Sthompsa
3722287197Sglebiusstatic void
3723287197Sglebiusrun_parent(struct ieee80211com *ic)
3724203134Sthompsa{
3725286950Sadrian	struct run_softc *sc = ic->ic_softc;
3726208019Sthompsa	int startall = 0;
3727203134Sthompsa
3728246614Shselasky	RUN_LOCK(sc);
3729287197Sglebius	if (sc->sc_detached) {
3730203134Sthompsa		RUN_UNLOCK(sc);
3731287197Sglebius		return;
3732203134Sthompsa	}
3733203134Sthompsa
3734287197Sglebius	if (ic->ic_nrunning > 0) {
3735287197Sglebius		if (!(sc->sc_flags & RUN_RUNNING)) {
3736287197Sglebius			startall = 1;
3737287197Sglebius			run_init_locked(sc);
3738287197Sglebius		} else
3739287197Sglebius			run_update_promisc_locked(sc);
3740287197Sglebius	} else if ((sc->sc_flags & RUN_RUNNING) && sc->rvp_cnt <= 1)
3741287197Sglebius		run_stop(sc);
3742287197Sglebius	RUN_UNLOCK(sc);
3743287197Sglebius	if (startall)
3744287197Sglebius		ieee80211_start_all(ic);
3745203134Sthompsa}
3746203134Sthompsa
3747203134Sthompsastatic void
3748259544Skevlorun_iq_calib(struct run_softc *sc, u_int chan)
3749259544Skevlo{
3750259544Skevlo	uint16_t val;
3751259544Skevlo
3752259544Skevlo	/* Tx0 IQ gain. */
3753259544Skevlo	run_bbp_write(sc, 158, 0x2c);
3754259544Skevlo	if (chan <= 14)
3755259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX0_2GHZ, &val, 1);
3756259544Skevlo	else if (chan <= 64) {
3757259544Skevlo		run_efuse_read(sc,
3758259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5GHZ,
3759259544Skevlo		    &val, 1);
3760259544Skevlo	} else if (chan <= 138) {
3761259544Skevlo		run_efuse_read(sc,
3762259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5GHZ,
3763259544Skevlo		    &val, 1);
3764259544Skevlo	} else if (chan <= 165) {
3765259544Skevlo		run_efuse_read(sc,
3766259544Skevlo	    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5GHZ,
3767259544Skevlo		    &val, 1);
3768259544Skevlo	} else
3769259544Skevlo		val = 0;
3770259547Skevlo	run_bbp_write(sc, 159, val);
3771259544Skevlo
3772259544Skevlo	/* Tx0 IQ phase. */
3773259544Skevlo	run_bbp_write(sc, 158, 0x2d);
3774259544Skevlo	if (chan <= 14) {
3775259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX0_2GHZ,
3776259544Skevlo		    &val, 1);
3777259544Skevlo	} else if (chan <= 64) {
3778259544Skevlo		run_efuse_read(sc,
3779259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5GHZ,
3780259544Skevlo		    &val, 1);
3781259544Skevlo	} else if (chan <= 138) {
3782259544Skevlo		run_efuse_read(sc,
3783259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5GHZ,
3784259544Skevlo		    &val, 1);
3785259544Skevlo	} else if (chan <= 165) {
3786259544Skevlo		run_efuse_read(sc,
3787259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5GHZ,
3788259544Skevlo		    &val, 1);
3789259544Skevlo	} else
3790259544Skevlo		val = 0;
3791259547Skevlo	run_bbp_write(sc, 159, val);
3792259544Skevlo
3793259544Skevlo	/* Tx1 IQ gain. */
3794259544Skevlo	run_bbp_write(sc, 158, 0x4a);
3795259544Skevlo	if (chan <= 14) {
3796259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX1_2GHZ,
3797259544Skevlo		    &val, 1);
3798259544Skevlo	} else if (chan <= 64) {
3799259544Skevlo		run_efuse_read(sc,
3800259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5GHZ,
3801259544Skevlo		    &val, 1);
3802259544Skevlo	} else if (chan <= 138) {
3803259544Skevlo		run_efuse_read(sc,
3804259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5GHZ,
3805259544Skevlo		    &val, 1);
3806259544Skevlo	} else if (chan <= 165) {
3807259544Skevlo		run_efuse_read(sc,
3808259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5GHZ,
3809259544Skevlo		    &val, 1);
3810259544Skevlo	} else
3811259544Skevlo		val = 0;
3812259547Skevlo	run_bbp_write(sc, 159, val);
3813259544Skevlo
3814259544Skevlo	/* Tx1 IQ phase. */
3815259544Skevlo	run_bbp_write(sc, 158, 0x4b);
3816259544Skevlo	if (chan <= 14) {
3817259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX1_2GHZ,
3818259544Skevlo		    &val, 1);
3819259544Skevlo	} else if (chan <= 64) {
3820259544Skevlo		run_efuse_read(sc,
3821259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5GHZ,
3822259544Skevlo		    &val, 1);
3823259544Skevlo	} else if (chan <= 138) {
3824259544Skevlo		run_efuse_read(sc,
3825259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5GHZ,
3826259544Skevlo		    &val, 1);
3827259544Skevlo	} else if (chan <= 165) {
3828259544Skevlo		run_efuse_read(sc,
3829259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5GHZ,
3830259544Skevlo		    &val, 1);
3831259544Skevlo	} else
3832259544Skevlo		val = 0;
3833259547Skevlo	run_bbp_write(sc, 159, val);
3834259544Skevlo
3835259544Skevlo	/* RF IQ compensation control. */
3836259544Skevlo	run_bbp_write(sc, 158, 0x04);
3837259544Skevlo	run_efuse_read(sc, RT5390_EEPROM_RF_IQ_COMPENSATION_CTL,
3838259544Skevlo	    &val, 1);
3839259547Skevlo	run_bbp_write(sc, 159, val);
3840259544Skevlo
3841259544Skevlo	/* RF IQ imbalance compensation control. */
3842259544Skevlo	run_bbp_write(sc, 158, 0x03);
3843259544Skevlo	run_efuse_read(sc,
3844259544Skevlo	    RT5390_EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CTL, &val, 1);
3845259547Skevlo	run_bbp_write(sc, 159, val);
3846259544Skevlo}
3847259544Skevlo
3848259544Skevlostatic void
3849205042Sthompsarun_set_agc(struct run_softc *sc, uint8_t agc)
3850205042Sthompsa{
3851205042Sthompsa	uint8_t bbp;
3852205042Sthompsa
3853205042Sthompsa	if (sc->mac_ver == 0x3572) {
3854205042Sthompsa		run_bbp_read(sc, 27, &bbp);
3855205042Sthompsa		bbp &= ~(0x3 << 5);
3856205042Sthompsa		run_bbp_write(sc, 27, bbp | 0 << 5);	/* select Rx0 */
3857205042Sthompsa		run_bbp_write(sc, 66, agc);
3858205042Sthompsa		run_bbp_write(sc, 27, bbp | 1 << 5);	/* select Rx1 */
3859205042Sthompsa		run_bbp_write(sc, 66, agc);
3860205042Sthompsa	} else
3861205042Sthompsa		run_bbp_write(sc, 66, agc);
3862205042Sthompsa}
3863205042Sthompsa
3864205042Sthompsastatic void
3865203134Sthompsarun_select_chan_group(struct run_softc *sc, int group)
3866203134Sthompsa{
3867203134Sthompsa	uint32_t tmp;
3868205042Sthompsa	uint8_t agc;
3869203134Sthompsa
3870203134Sthompsa	run_bbp_write(sc, 62, 0x37 - sc->lna[group]);
3871203134Sthompsa	run_bbp_write(sc, 63, 0x37 - sc->lna[group]);
3872203134Sthompsa	run_bbp_write(sc, 64, 0x37 - sc->lna[group]);
3873258082Skevlo	if (sc->mac_ver < 0x3572)
3874257955Skevlo		run_bbp_write(sc, 86, 0x00);
3875203134Sthompsa
3876260219Skevlo	if (sc->mac_ver == 0x3593) {
3877260219Skevlo		run_bbp_write(sc, 77, 0x98);
3878260219Skevlo		run_bbp_write(sc, 83, (group == 0) ? 0x8a : 0x9a);
3879260219Skevlo	}
3880260219Skevlo
3881203134Sthompsa	if (group == 0) {
3882203134Sthompsa		if (sc->ext_2ghz_lna) {
3883257955Skevlo			if (sc->mac_ver >= 0x5390)
3884257955Skevlo				run_bbp_write(sc, 75, 0x52);
3885257955Skevlo			else {
3886257955Skevlo				run_bbp_write(sc, 82, 0x62);
3887257955Skevlo				run_bbp_write(sc, 75, 0x46);
3888257955Skevlo			}
3889203134Sthompsa		} else {
3890259032Skevlo			if (sc->mac_ver == 0x5592) {
3891259032Skevlo				run_bbp_write(sc, 79, 0x1c);
3892259032Skevlo				run_bbp_write(sc, 80, 0x0e);
3893259032Skevlo				run_bbp_write(sc, 81, 0x3a);
3894259032Skevlo				run_bbp_write(sc, 82, 0x62);
3895259032Skevlo
3896259032Skevlo				run_bbp_write(sc, 195, 0x80);
3897259032Skevlo				run_bbp_write(sc, 196, 0xe0);
3898259032Skevlo				run_bbp_write(sc, 195, 0x81);
3899259032Skevlo				run_bbp_write(sc, 196, 0x1f);
3900259032Skevlo				run_bbp_write(sc, 195, 0x82);
3901259032Skevlo				run_bbp_write(sc, 196, 0x38);
3902259032Skevlo				run_bbp_write(sc, 195, 0x83);
3903259032Skevlo				run_bbp_write(sc, 196, 0x32);
3904259032Skevlo				run_bbp_write(sc, 195, 0x85);
3905259032Skevlo				run_bbp_write(sc, 196, 0x28);
3906259032Skevlo				run_bbp_write(sc, 195, 0x86);
3907259032Skevlo				run_bbp_write(sc, 196, 0x19);
3908259032Skevlo			} else if (sc->mac_ver >= 0x5390)
3909257955Skevlo				run_bbp_write(sc, 75, 0x50);
3910257955Skevlo			else {
3911260219Skevlo				run_bbp_write(sc, 82,
3912260219Skevlo				    (sc->mac_ver == 0x3593) ? 0x62 : 0x84);
3913257955Skevlo				run_bbp_write(sc, 75, 0x50);
3914257955Skevlo			}
3915203134Sthompsa		}
3916203134Sthompsa	} else {
3917259032Skevlo		if (sc->mac_ver == 0x5592) {
3918259032Skevlo			run_bbp_write(sc, 79, 0x18);
3919259032Skevlo			run_bbp_write(sc, 80, 0x08);
3920259032Skevlo			run_bbp_write(sc, 81, 0x38);
3921259032Skevlo			run_bbp_write(sc, 82, 0x92);
3922259032Skevlo
3923259032Skevlo			run_bbp_write(sc, 195, 0x80);
3924259032Skevlo			run_bbp_write(sc, 196, 0xf0);
3925259032Skevlo			run_bbp_write(sc, 195, 0x81);
3926259032Skevlo			run_bbp_write(sc, 196, 0x1e);
3927259032Skevlo			run_bbp_write(sc, 195, 0x82);
3928259032Skevlo			run_bbp_write(sc, 196, 0x28);
3929259032Skevlo			run_bbp_write(sc, 195, 0x83);
3930259032Skevlo			run_bbp_write(sc, 196, 0x20);
3931259032Skevlo			run_bbp_write(sc, 195, 0x85);
3932259032Skevlo			run_bbp_write(sc, 196, 0x7f);
3933259032Skevlo			run_bbp_write(sc, 195, 0x86);
3934259032Skevlo			run_bbp_write(sc, 196, 0x7f);
3935259032Skevlo		} else if (sc->mac_ver == 0x3572)
3936205042Sthompsa			run_bbp_write(sc, 82, 0x94);
3937205042Sthompsa		else
3938260219Skevlo			run_bbp_write(sc, 82,
3939260219Skevlo			    (sc->mac_ver == 0x3593) ? 0x82 : 0xf2);
3940205042Sthompsa		if (sc->ext_5ghz_lna)
3941203134Sthompsa			run_bbp_write(sc, 75, 0x46);
3942205042Sthompsa		else
3943203134Sthompsa			run_bbp_write(sc, 75, 0x50);
3944203134Sthompsa	}
3945203134Sthompsa
3946203134Sthompsa	run_read(sc, RT2860_TX_BAND_CFG, &tmp);
3947203134Sthompsa	tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P);
3948203134Sthompsa	tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P;
3949203134Sthompsa	run_write(sc, RT2860_TX_BAND_CFG, tmp);
3950203134Sthompsa
3951203134Sthompsa	/* enable appropriate Power Amplifiers and Low Noise Amplifiers */
3952208019Sthompsa	tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN;
3953260219Skevlo	if (sc->mac_ver == 0x3593)
3954260219Skevlo		tmp |= 1 << 29 | 1 << 28;
3955208019Sthompsa	if (sc->nrxchains > 1)
3956208019Sthompsa		tmp |= RT2860_LNA_PE1_EN;
3957203134Sthompsa	if (group == 0) {	/* 2GHz */
3958208019Sthompsa		tmp |= RT2860_PA_PE_G0_EN;
3959203134Sthompsa		if (sc->ntxchains > 1)
3960203134Sthompsa			tmp |= RT2860_PA_PE_G1_EN;
3961260219Skevlo		if (sc->mac_ver == 0x3593) {
3962260219Skevlo			if (sc->ntxchains > 2)
3963260219Skevlo				tmp |= 1 << 25;
3964260219Skevlo		}
3965203134Sthompsa	} else {		/* 5GHz */
3966208019Sthompsa		tmp |= RT2860_PA_PE_A0_EN;
3967203134Sthompsa		if (sc->ntxchains > 1)
3968203134Sthompsa			tmp |= RT2860_PA_PE_A1_EN;
3969203134Sthompsa	}
3970205042Sthompsa	if (sc->mac_ver == 0x3572) {
3971205042Sthompsa		run_rt3070_rf_write(sc, 8, 0x00);
3972205042Sthompsa		run_write(sc, RT2860_TX_PIN_CFG, tmp);
3973205042Sthompsa		run_rt3070_rf_write(sc, 8, 0x80);
3974205042Sthompsa	} else
3975205042Sthompsa		run_write(sc, RT2860_TX_PIN_CFG, tmp);
3976203134Sthompsa
3977259032Skevlo	if (sc->mac_ver == 0x5592) {
3978259032Skevlo		run_bbp_write(sc, 195, 0x8d);
3979259032Skevlo		run_bbp_write(sc, 196, 0x1a);
3980259032Skevlo	}
3981259032Skevlo
3982260219Skevlo	if (sc->mac_ver == 0x3593) {
3983260219Skevlo		run_read(sc, RT2860_GPIO_CTRL, &tmp);
3984260219Skevlo		tmp &= ~0x01010000;
3985260219Skevlo		if (group == 0)
3986260219Skevlo			tmp |= 0x00010000;
3987260219Skevlo		tmp = (tmp & ~0x00009090) | 0x00000090;
3988260219Skevlo		run_write(sc, RT2860_GPIO_CTRL, tmp);
3989260219Skevlo	}
3990260219Skevlo
3991203134Sthompsa	/* set initial AGC value */
3992205042Sthompsa	if (group == 0) {	/* 2GHz band */
3993205042Sthompsa		if (sc->mac_ver >= 0x3070)
3994205042Sthompsa			agc = 0x1c + sc->lna[0] * 2;
3995205042Sthompsa		else
3996205042Sthompsa			agc = 0x2e + sc->lna[0];
3997205042Sthompsa	} else {		/* 5GHz band */
3998259032Skevlo		if (sc->mac_ver == 0x5592)
3999259032Skevlo			agc = 0x24 + sc->lna[group] * 2;
4000260219Skevlo		else if (sc->mac_ver == 0x3572 || sc->mac_ver == 0x3593)
4001205042Sthompsa			agc = 0x22 + (sc->lna[group] * 5) / 3;
4002205042Sthompsa		else
4003205042Sthompsa			agc = 0x32 + (sc->lna[group] * 5) / 3;
4004205042Sthompsa	}
4005205042Sthompsa	run_set_agc(sc, agc);
4006203134Sthompsa}
4007203134Sthompsa
4008203134Sthompsastatic void
4009257429Shselaskyrun_rt2870_set_chan(struct run_softc *sc, u_int chan)
4010203134Sthompsa{
4011203134Sthompsa	const struct rfprog *rfprog = rt2860_rf2850;
4012203134Sthompsa	uint32_t r2, r3, r4;
4013203134Sthompsa	int8_t txpow1, txpow2;
4014203134Sthompsa	int i;
4015203134Sthompsa
4016203134Sthompsa	/* find the settings for this channel (we know it exists) */
4017203134Sthompsa	for (i = 0; rfprog[i].chan != chan; i++);
4018203134Sthompsa
4019203134Sthompsa	r2 = rfprog[i].r2;
4020203134Sthompsa	if (sc->ntxchains == 1)
4021258732Skevlo		r2 |= 1 << 14;		/* 1T: disable Tx chain 2 */
4022203134Sthompsa	if (sc->nrxchains == 1)
4023258732Skevlo		r2 |= 1 << 17 | 1 << 6;	/* 1R: disable Rx chains 2 & 3 */
4024203134Sthompsa	else if (sc->nrxchains == 2)
4025258732Skevlo		r2 |= 1 << 6;		/* 2R: disable Rx chain 3 */
4026203134Sthompsa
4027203134Sthompsa	/* use Tx power values from EEPROM */
4028203134Sthompsa	txpow1 = sc->txpow1[i];
4029203134Sthompsa	txpow2 = sc->txpow2[i];
4030258732Skevlo
4031258732Skevlo	/* Initialize RF R3 and R4. */
4032258732Skevlo	r3 = rfprog[i].r3 & 0xffffc1ff;
4033258732Skevlo	r4 = (rfprog[i].r4 & ~(0x001f87c0)) | (sc->freq << 15);
4034203134Sthompsa	if (chan > 14) {
4035258732Skevlo		if (txpow1 >= 0) {
4036258732Skevlo			txpow1 = (txpow1 > 0xf) ? (0xf) : (txpow1);
4037258732Skevlo			r3 |= (txpow1 << 10) | (1 << 9);
4038258732Skevlo		} else {
4039258732Skevlo			txpow1 += 7;
4040258732Skevlo
4041258732Skevlo			/* txpow1 is not possible larger than 15. */
4042258732Skevlo			r3 |= (txpow1 << 10);
4043258732Skevlo		}
4044258732Skevlo		if (txpow2 >= 0) {
4045258732Skevlo			txpow2 = (txpow2 > 0xf) ? (0xf) : (txpow2);
4046258921Shselasky			r4 |= (txpow2 << 7) | (1 << 6);
4047258732Skevlo		} else {
4048258732Skevlo			txpow2 += 7;
4049258732Skevlo			r4 |= (txpow2 << 7);
4050258732Skevlo		}
4051258732Skevlo	} else {
4052258732Skevlo		/* Set Tx0 power. */
4053258732Skevlo		r3 |= (txpow1 << 9);
4054258732Skevlo
4055258732Skevlo		/* Set frequency offset and Tx1 power. */
4056258732Skevlo		r4 |= (txpow2 << 6);
4057203134Sthompsa	}
4058203134Sthompsa
4059258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4060258733Skevlo	run_rt2870_rf_write(sc, r2);
4061258733Skevlo	run_rt2870_rf_write(sc, r3 & ~(1 << 2));
4062258733Skevlo	run_rt2870_rf_write(sc, r4);
4063203134Sthompsa
4064203134Sthompsa	run_delay(sc, 10);
4065203134Sthompsa
4066258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4067258733Skevlo	run_rt2870_rf_write(sc, r2);
4068258733Skevlo	run_rt2870_rf_write(sc, r3 | (1 << 2));
4069258733Skevlo	run_rt2870_rf_write(sc, r4);
4070203134Sthompsa
4071203134Sthompsa	run_delay(sc, 10);
4072203134Sthompsa
4073258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4074258733Skevlo	run_rt2870_rf_write(sc, r2);
4075258733Skevlo	run_rt2870_rf_write(sc, r3 & ~(1 << 2));
4076258733Skevlo	run_rt2870_rf_write(sc, r4);
4077203134Sthompsa}
4078203134Sthompsa
4079203134Sthompsastatic void
4080257429Shselaskyrun_rt3070_set_chan(struct run_softc *sc, u_int chan)
4081203134Sthompsa{
4082203134Sthompsa	int8_t txpow1, txpow2;
4083203134Sthompsa	uint8_t rf;
4084205042Sthompsa	int i;
4085203134Sthompsa
4086205042Sthompsa	/* find the settings for this channel (we know it exists) */
4087205042Sthompsa	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4088205042Sthompsa
4089203134Sthompsa	/* use Tx power values from EEPROM */
4090205042Sthompsa	txpow1 = sc->txpow1[i];
4091205042Sthompsa	txpow2 = sc->txpow2[i];
4092203134Sthompsa
4093205042Sthompsa	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
4094256720Skevlo
4095256720Skevlo	/* RT3370/RT3390: RF R3 [7:4] is not reserved bits. */
4096256720Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4097256720Skevlo	rf = (rf & ~0x0f) | rt3070_freqs[i].k;
4098256720Skevlo	run_rt3070_rf_write(sc, 3, rf);
4099256720Skevlo
4100203134Sthompsa	run_rt3070_rf_read(sc, 6, &rf);
4101205042Sthompsa	rf = (rf & ~0x03) | rt3070_freqs[i].r;
4102203134Sthompsa	run_rt3070_rf_write(sc, 6, rf);
4103203134Sthompsa
4104203134Sthompsa	/* set Tx0 power */
4105203134Sthompsa	run_rt3070_rf_read(sc, 12, &rf);
4106203134Sthompsa	rf = (rf & ~0x1f) | txpow1;
4107203134Sthompsa	run_rt3070_rf_write(sc, 12, rf);
4108203134Sthompsa
4109203134Sthompsa	/* set Tx1 power */
4110203134Sthompsa	run_rt3070_rf_read(sc, 13, &rf);
4111203134Sthompsa	rf = (rf & ~0x1f) | txpow2;
4112203134Sthompsa	run_rt3070_rf_write(sc, 13, rf);
4113203134Sthompsa
4114203134Sthompsa	run_rt3070_rf_read(sc, 1, &rf);
4115203134Sthompsa	rf &= ~0xfc;
4116203134Sthompsa	if (sc->ntxchains == 1)
4117203134Sthompsa		rf |= 1 << 7 | 1 << 5;	/* 1T: disable Tx chains 2 & 3 */
4118203134Sthompsa	else if (sc->ntxchains == 2)
4119203134Sthompsa		rf |= 1 << 7;		/* 2T: disable Tx chain 3 */
4120203134Sthompsa	if (sc->nrxchains == 1)
4121203134Sthompsa		rf |= 1 << 6 | 1 << 4;	/* 1R: disable Rx chains 2 & 3 */
4122203134Sthompsa	else if (sc->nrxchains == 2)
4123203134Sthompsa		rf |= 1 << 6;		/* 2R: disable Rx chain 3 */
4124203134Sthompsa	run_rt3070_rf_write(sc, 1, rf);
4125203134Sthompsa
4126203134Sthompsa	/* set RF offset */
4127203134Sthompsa	run_rt3070_rf_read(sc, 23, &rf);
4128203134Sthompsa	rf = (rf & ~0x7f) | sc->freq;
4129203134Sthompsa	run_rt3070_rf_write(sc, 23, rf);
4130203134Sthompsa
4131203134Sthompsa	/* program RF filter */
4132205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf);	/* Tx */
4133205042Sthompsa	rf = (rf & ~0x3f) | sc->rf24_20mhz;
4134205042Sthompsa	run_rt3070_rf_write(sc, 24, rf);
4135205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);	/* Rx */
4136205042Sthompsa	rf = (rf & ~0x3f) | sc->rf24_20mhz;
4137205042Sthompsa	run_rt3070_rf_write(sc, 31, rf);
4138203134Sthompsa
4139203134Sthompsa	/* enable RF tuning */
4140203134Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4141203134Sthompsa	run_rt3070_rf_write(sc, 7, rf | 0x01);
4142203134Sthompsa}
4143203134Sthompsa
4144203134Sthompsastatic void
4145205042Sthompsarun_rt3572_set_chan(struct run_softc *sc, u_int chan)
4146205042Sthompsa{
4147205042Sthompsa	int8_t txpow1, txpow2;
4148205042Sthompsa	uint32_t tmp;
4149205042Sthompsa	uint8_t rf;
4150205042Sthompsa	int i;
4151205042Sthompsa
4152205042Sthompsa	/* find the settings for this channel (we know it exists) */
4153205042Sthompsa	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4154205042Sthompsa
4155205042Sthompsa	/* use Tx power values from EEPROM */
4156205042Sthompsa	txpow1 = sc->txpow1[i];
4157205042Sthompsa	txpow2 = sc->txpow2[i];
4158205042Sthompsa
4159205042Sthompsa	if (chan <= 14) {
4160205042Sthompsa		run_bbp_write(sc, 25, sc->bbp25);
4161205042Sthompsa		run_bbp_write(sc, 26, sc->bbp26);
4162205042Sthompsa	} else {
4163205042Sthompsa		/* enable IQ phase correction */
4164205042Sthompsa		run_bbp_write(sc, 25, 0x09);
4165205042Sthompsa		run_bbp_write(sc, 26, 0xff);
4166205042Sthompsa	}
4167205042Sthompsa
4168205042Sthompsa	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
4169205042Sthompsa	run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k);
4170205042Sthompsa	run_rt3070_rf_read(sc, 6, &rf);
4171205042Sthompsa	rf  = (rf & ~0x0f) | rt3070_freqs[i].r;
4172205042Sthompsa	rf |= (chan <= 14) ? 0x08 : 0x04;
4173205042Sthompsa	run_rt3070_rf_write(sc, 6, rf);
4174205042Sthompsa
4175205042Sthompsa	/* set PLL mode */
4176205042Sthompsa	run_rt3070_rf_read(sc, 5, &rf);
4177205042Sthompsa	rf &= ~(0x08 | 0x04);
4178205042Sthompsa	rf |= (chan <= 14) ? 0x04 : 0x08;
4179205042Sthompsa	run_rt3070_rf_write(sc, 5, rf);
4180205042Sthompsa
4181205042Sthompsa	/* set Tx power for chain 0 */
4182205042Sthompsa	if (chan <= 14)
4183205042Sthompsa		rf = 0x60 | txpow1;
4184205042Sthompsa	else
4185205042Sthompsa		rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3);
4186205042Sthompsa	run_rt3070_rf_write(sc, 12, rf);
4187205042Sthompsa
4188205042Sthompsa	/* set Tx power for chain 1 */
4189205042Sthompsa	if (chan <= 14)
4190205042Sthompsa		rf = 0x60 | txpow2;
4191205042Sthompsa	else
4192205042Sthompsa		rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3);
4193205042Sthompsa	run_rt3070_rf_write(sc, 13, rf);
4194205042Sthompsa
4195205042Sthompsa	/* set Tx/Rx streams */
4196205042Sthompsa	run_rt3070_rf_read(sc, 1, &rf);
4197205042Sthompsa	rf &= ~0xfc;
4198205042Sthompsa	if (sc->ntxchains == 1)
4199205042Sthompsa		rf |= 1 << 7 | 1 << 5;  /* 1T: disable Tx chains 2 & 3 */
4200205042Sthompsa	else if (sc->ntxchains == 2)
4201205042Sthompsa		rf |= 1 << 7;           /* 2T: disable Tx chain 3 */
4202205042Sthompsa	if (sc->nrxchains == 1)
4203205042Sthompsa		rf |= 1 << 6 | 1 << 4;  /* 1R: disable Rx chains 2 & 3 */
4204205042Sthompsa	else if (sc->nrxchains == 2)
4205205042Sthompsa		rf |= 1 << 6;           /* 2R: disable Rx chain 3 */
4206205042Sthompsa	run_rt3070_rf_write(sc, 1, rf);
4207205042Sthompsa
4208205042Sthompsa	/* set RF offset */
4209205042Sthompsa	run_rt3070_rf_read(sc, 23, &rf);
4210205042Sthompsa	rf = (rf & ~0x7f) | sc->freq;
4211205042Sthompsa	run_rt3070_rf_write(sc, 23, rf);
4212205042Sthompsa
4213205042Sthompsa	/* program RF filter */
4214205042Sthompsa	rf = sc->rf24_20mhz;
4215205042Sthompsa	run_rt3070_rf_write(sc, 24, rf);	/* Tx */
4216205042Sthompsa	run_rt3070_rf_write(sc, 31, rf);	/* Rx */
4217205042Sthompsa
4218205042Sthompsa	/* enable RF tuning */
4219205042Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4220205042Sthompsa	rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14);
4221205042Sthompsa	run_rt3070_rf_write(sc, 7, rf);
4222205042Sthompsa
4223205042Sthompsa	/* TSSI */
4224205042Sthompsa	rf = (chan <= 14) ? 0xc3 : 0xc0;
4225205042Sthompsa	run_rt3070_rf_write(sc, 9, rf);
4226205042Sthompsa
4227205042Sthompsa	/* set loop filter 1 */
4228205042Sthompsa	run_rt3070_rf_write(sc, 10, 0xf1);
4229205042Sthompsa	/* set loop filter 2 */
4230205042Sthompsa	run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00);
4231205042Sthompsa
4232205042Sthompsa	/* set tx_mx2_ic */
4233205042Sthompsa	run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43);
4234205042Sthompsa	/* set tx_mx1_ic */
4235205042Sthompsa	if (chan <= 14)
4236205042Sthompsa		rf = 0x48 | sc->txmixgain_2ghz;
4237205042Sthompsa	else
4238205042Sthompsa		rf = 0x78 | sc->txmixgain_5ghz;
4239205042Sthompsa	run_rt3070_rf_write(sc, 16, rf);
4240205042Sthompsa
4241205042Sthompsa	/* set tx_lo1 */
4242205042Sthompsa	run_rt3070_rf_write(sc, 17, 0x23);
4243205042Sthompsa	/* set tx_lo2 */
4244205042Sthompsa	if (chan <= 14)
4245205042Sthompsa		rf = 0x93;
4246205042Sthompsa	else if (chan <= 64)
4247205042Sthompsa		rf = 0xb7;
4248205042Sthompsa	else if (chan <= 128)
4249205042Sthompsa		rf = 0x74;
4250205042Sthompsa	else
4251205042Sthompsa		rf = 0x72;
4252205042Sthompsa	run_rt3070_rf_write(sc, 19, rf);
4253205042Sthompsa
4254205042Sthompsa	/* set rx_lo1 */
4255205042Sthompsa	if (chan <= 14)
4256205042Sthompsa		rf = 0xb3;
4257205042Sthompsa	else if (chan <= 64)
4258205042Sthompsa		rf = 0xf6;
4259205042Sthompsa	else if (chan <= 128)
4260205042Sthompsa		rf = 0xf4;
4261205042Sthompsa	else
4262205042Sthompsa		rf = 0xf3;
4263205042Sthompsa	run_rt3070_rf_write(sc, 20, rf);
4264205042Sthompsa
4265205042Sthompsa	/* set pfd_delay */
4266205042Sthompsa	if (chan <= 14)
4267205042Sthompsa		rf = 0x15;
4268205042Sthompsa	else if (chan <= 64)
4269205042Sthompsa		rf = 0x3d;
4270205042Sthompsa	else
4271205042Sthompsa		rf = 0x01;
4272205042Sthompsa	run_rt3070_rf_write(sc, 25, rf);
4273205042Sthompsa
4274205042Sthompsa	/* set rx_lo2 */
4275205042Sthompsa	run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87);
4276205042Sthompsa	/* set ldo_rf_vc */
4277205042Sthompsa	run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01);
4278205042Sthompsa	/* set drv_cc */
4279205042Sthompsa	run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f);
4280205042Sthompsa
4281205042Sthompsa	run_read(sc, RT2860_GPIO_CTRL, &tmp);
4282205042Sthompsa	tmp &= ~0x8080;
4283205042Sthompsa	if (chan <= 14)
4284205042Sthompsa		tmp |= 0x80;
4285205042Sthompsa	run_write(sc, RT2860_GPIO_CTRL, tmp);
4286205042Sthompsa
4287205042Sthompsa	/* enable RF tuning */
4288205042Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4289205042Sthompsa	run_rt3070_rf_write(sc, 7, rf | 0x01);
4290205042Sthompsa
4291205042Sthompsa	run_delay(sc, 2);
4292205042Sthompsa}
4293205042Sthompsa
4294205042Sthompsastatic void
4295260219Skevlorun_rt3593_set_chan(struct run_softc *sc, u_int chan)
4296260219Skevlo{
4297260219Skevlo	int8_t txpow1, txpow2, txpow3;
4298260219Skevlo	uint8_t h20mhz, rf;
4299260219Skevlo	int i;
4300260219Skevlo
4301260219Skevlo	/* find the settings for this channel (we know it exists) */
4302260219Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4303260219Skevlo
4304260219Skevlo	/* use Tx power values from EEPROM */
4305260219Skevlo	txpow1 = sc->txpow1[i];
4306260219Skevlo	txpow2 = sc->txpow2[i];
4307260219Skevlo	txpow3 = (sc->ntxchains == 3) ? sc->txpow3[i] : 0;
4308260219Skevlo
4309260219Skevlo	if (chan <= 14) {
4310260219Skevlo		run_bbp_write(sc, 25, sc->bbp25);
4311260219Skevlo		run_bbp_write(sc, 26, sc->bbp26);
4312260219Skevlo	} else {
4313260219Skevlo		/* Enable IQ phase correction. */
4314260219Skevlo		run_bbp_write(sc, 25, 0x09);
4315260219Skevlo		run_bbp_write(sc, 26, 0xff);
4316260219Skevlo	}
4317260219Skevlo
4318260219Skevlo	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
4319260219Skevlo	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
4320260219Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4321260219Skevlo	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
4322260219Skevlo	run_rt3070_rf_write(sc, 11, rf);
4323260219Skevlo
4324260219Skevlo	/* Set pll_idoh. */
4325260219Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4326260219Skevlo	rf &= ~0x4c;
4327260219Skevlo	rf |= (chan <= 14) ? 0x44 : 0x48;
4328260219Skevlo	run_rt3070_rf_write(sc, 11, rf);
4329260219Skevlo
4330260219Skevlo	if (chan <= 14)
4331260219Skevlo		rf = txpow1 & 0x1f;
4332260219Skevlo	else
4333260219Skevlo		rf = 0x40 | ((txpow1 & 0x18) << 1) | (txpow1 & 0x07);
4334260219Skevlo	run_rt3070_rf_write(sc, 53, rf);
4335260219Skevlo
4336260219Skevlo	if (chan <= 14)
4337260219Skevlo		rf = txpow2 & 0x1f;
4338260219Skevlo	else
4339260219Skevlo		rf = 0x40 | ((txpow2 & 0x18) << 1) | (txpow2 & 0x07);
4340260219Skevlo	run_rt3070_rf_write(sc, 55, rf);
4341260219Skevlo
4342260219Skevlo	if (chan <= 14)
4343260219Skevlo		rf = txpow3 & 0x1f;
4344260219Skevlo	else
4345260219Skevlo		rf = 0x40 | ((txpow3 & 0x18) << 1) | (txpow3 & 0x07);
4346260219Skevlo	run_rt3070_rf_write(sc, 54, rf);
4347260219Skevlo
4348260219Skevlo	rf = RT3070_RF_BLOCK | RT3070_PLL_PD;
4349260219Skevlo	if (sc->ntxchains == 3)
4350260219Skevlo		rf |= RT3070_TX0_PD | RT3070_TX1_PD | RT3070_TX2_PD;
4351260219Skevlo	else
4352260219Skevlo		rf |= RT3070_TX0_PD | RT3070_TX1_PD;
4353260219Skevlo	rf |= RT3070_RX0_PD | RT3070_RX1_PD | RT3070_RX2_PD;
4354260219Skevlo	run_rt3070_rf_write(sc, 1, rf);
4355260219Skevlo
4356260219Skevlo	run_adjust_freq_offset(sc);
4357260219Skevlo
4358260219Skevlo	run_rt3070_rf_write(sc, 31, (chan <= 14) ? 0xa0 : 0x80);
4359260219Skevlo
4360260219Skevlo	h20mhz = (sc->rf24_20mhz & 0x20) >> 5;
4361260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
4362260219Skevlo	rf = (rf & ~0x06) | (h20mhz << 1) | (h20mhz << 2);
4363260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
4364260219Skevlo
4365260219Skevlo	run_rt3070_rf_read(sc, 36, &rf);
4366260219Skevlo	if (chan <= 14)
4367260219Skevlo		rf |= 0x80;
4368260219Skevlo	else
4369260219Skevlo		rf &= ~0x80;
4370260219Skevlo	run_rt3070_rf_write(sc, 36, rf);
4371260219Skevlo
4372260219Skevlo	/* Set vcolo_bs. */
4373260219Skevlo	run_rt3070_rf_write(sc, 34, (chan <= 14) ? 0x3c : 0x20);
4374260219Skevlo	/* Set pfd_delay. */
4375260219Skevlo	run_rt3070_rf_write(sc, 12, (chan <= 14) ? 0x1a : 0x12);
4376260219Skevlo
4377260219Skevlo	/* Set vco bias current control. */
4378260219Skevlo	run_rt3070_rf_read(sc, 6, &rf);
4379260219Skevlo	rf &= ~0xc0;
4380260219Skevlo	if (chan <= 14)
4381260219Skevlo		rf |= 0x40;
4382260219Skevlo	else if (chan <= 128)
4383260219Skevlo		rf |= 0x80;
4384260219Skevlo	else
4385260219Skevlo		rf |= 0x40;
4386260219Skevlo	run_rt3070_rf_write(sc, 6, rf);
4387260219Skevlo
4388260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
4389260219Skevlo	rf = (rf & ~0x18) | 0x10;
4390260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
4391260219Skevlo
4392260219Skevlo	run_rt3070_rf_write(sc, 10, (chan <= 14) ? 0xd3 : 0xd8);
4393260219Skevlo	run_rt3070_rf_write(sc, 13, (chan <= 14) ? 0x12 : 0x23);
4394260219Skevlo
4395260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4396260219Skevlo	rf = (rf & ~0x03) | 0x01;
4397260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4398260219Skevlo	/* Set tx_mx1_cc. */
4399260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4400260219Skevlo	rf &= ~0x1c;
4401260219Skevlo	rf |= (chan <= 14) ? 0x14 : 0x10;
4402260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4403260219Skevlo	/* Set tx_mx1_ic. */
4404260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4405260219Skevlo	rf &= ~0xe0;
4406260219Skevlo	rf |= (chan <= 14) ? 0x60 : 0x40;
4407260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4408260219Skevlo	/* Set tx_lo1_ic. */
4409260219Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4410260219Skevlo	rf &= ~0x1c;
4411260219Skevlo	rf |= (chan <= 14) ? 0x0c : 0x08;
4412260219Skevlo	run_rt3070_rf_write(sc, 49, rf);
4413260219Skevlo	/* Set tx_lo1_en. */
4414260219Skevlo	run_rt3070_rf_read(sc, 50, &rf);
4415260219Skevlo	run_rt3070_rf_write(sc, 50, rf & ~0x20);
4416260219Skevlo	/* Set drv_cc. */
4417260219Skevlo	run_rt3070_rf_read(sc, 57, &rf);
4418260219Skevlo	rf &= ~0xfc;
4419260219Skevlo	rf |= (chan <= 14) ?  0x6c : 0x3c;
4420260219Skevlo	run_rt3070_rf_write(sc, 57, rf);
4421260219Skevlo	/* Set rx_mix1_ic, rxa_lnactr, lna_vc, lna_inbias_en and lna_en. */
4422260219Skevlo	run_rt3070_rf_write(sc, 44, (chan <= 14) ? 0x93 : 0x9b);
4423260219Skevlo	/* Set drv_gnd_a, tx_vga_cc_a and tx_mx2_gain. */
4424260219Skevlo	run_rt3070_rf_write(sc, 52, (chan <= 14) ? 0x45 : 0x05);
4425260219Skevlo	/* Enable VCO calibration. */
4426260219Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4427260219Skevlo	rf &= ~RT5390_VCOCAL;
4428260219Skevlo	rf |= (chan <= 14) ? RT5390_VCOCAL : 0xbe;
4429260219Skevlo	run_rt3070_rf_write(sc, 3, rf);
4430260219Skevlo
4431260219Skevlo	if (chan <= 14)
4432260219Skevlo		rf = 0x23;
4433260219Skevlo	else if (chan <= 64)
4434260219Skevlo		rf = 0x36;
4435260219Skevlo	else if (chan <= 128)
4436260219Skevlo		rf = 0x32;
4437260219Skevlo	else
4438260219Skevlo		rf = 0x30;
4439260219Skevlo	run_rt3070_rf_write(sc, 39, rf);
4440260219Skevlo	if (chan <= 14)
4441260219Skevlo		rf = 0xbb;
4442260219Skevlo	else if (chan <= 64)
4443260219Skevlo		rf = 0xeb;
4444260219Skevlo	else if (chan <= 128)
4445260219Skevlo		rf = 0xb3;
4446260219Skevlo	else
4447260219Skevlo		rf = 0x9b;
4448260219Skevlo	run_rt3070_rf_write(sc, 45, rf);
4449260219Skevlo
4450260219Skevlo	/* Set FEQ/AEQ control. */
4451260219Skevlo	run_bbp_write(sc, 105, 0x34);
4452260219Skevlo}
4453260219Skevlo
4454260219Skevlostatic void
4455257955Skevlorun_rt5390_set_chan(struct run_softc *sc, u_int chan)
4456257955Skevlo{
4457257955Skevlo	int8_t txpow1, txpow2;
4458257955Skevlo	uint8_t rf;
4459257955Skevlo	int i;
4460257955Skevlo
4461257955Skevlo	/* find the settings for this channel (we know it exists) */
4462257955Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4463257955Skevlo
4464257955Skevlo	/* use Tx power values from EEPROM */
4465257955Skevlo	txpow1 = sc->txpow1[i];
4466257955Skevlo	txpow2 = sc->txpow2[i];
4467257955Skevlo
4468257955Skevlo	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
4469257955Skevlo	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
4470257955Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4471257955Skevlo	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
4472257955Skevlo	run_rt3070_rf_write(sc, 11, rf);
4473257955Skevlo
4474257955Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4475257955Skevlo	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
4476257955Skevlo	/* The valid range of the RF R49 is 0x00 to 0x27. */
4477257955Skevlo	if ((rf & 0x3f) > 0x27)
4478257955Skevlo		rf = (rf & ~0x3f) | 0x27;
4479257955Skevlo	run_rt3070_rf_write(sc, 49, rf);
4480257955Skevlo
4481257955Skevlo	if (sc->mac_ver == 0x5392) {
4482257955Skevlo		run_rt3070_rf_read(sc, 50, &rf);
4483257955Skevlo		rf = (rf & ~0x3f) | (txpow2 & 0x3f);
4484257955Skevlo		/* The valid range of the RF R50 is 0x00 to 0x27. */
4485257955Skevlo		if ((rf & 0x3f) > 0x27)
4486257955Skevlo			rf = (rf & ~0x3f) | 0x27;
4487257955Skevlo		run_rt3070_rf_write(sc, 50, rf);
4488257955Skevlo	}
4489257955Skevlo
4490257955Skevlo	run_rt3070_rf_read(sc, 1, &rf);
4491257955Skevlo	rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD;
4492257955Skevlo	if (sc->mac_ver == 0x5392)
4493257955Skevlo		rf |= RT3070_RX1_PD | RT3070_TX1_PD;
4494257955Skevlo	run_rt3070_rf_write(sc, 1, rf);
4495257955Skevlo
4496257955Skevlo	if (sc->mac_ver != 0x5392) {
4497257955Skevlo		run_rt3070_rf_read(sc, 2, &rf);
4498257955Skevlo		rf |= 0x80;
4499257955Skevlo		run_rt3070_rf_write(sc, 2, rf);
4500257955Skevlo		run_delay(sc, 10);
4501257955Skevlo		rf &= 0x7f;
4502257955Skevlo		run_rt3070_rf_write(sc, 2, rf);
4503257955Skevlo	}
4504257955Skevlo
4505257955Skevlo	run_adjust_freq_offset(sc);
4506257955Skevlo
4507257955Skevlo	if (sc->mac_ver == 0x5392) {
4508257955Skevlo		/* Fix for RT5392C. */
4509257955Skevlo		if (sc->mac_rev >= 0x0223) {
4510259030Skevlo			if (chan <= 4)
4511257955Skevlo				rf = 0x0f;
4512259030Skevlo			else if (chan >= 5 && chan <= 7)
4513257955Skevlo				rf = 0x0e;
4514259030Skevlo			else
4515257955Skevlo				rf = 0x0d;
4516257955Skevlo			run_rt3070_rf_write(sc, 23, rf);
4517257955Skevlo
4518259030Skevlo			if (chan <= 4)
4519257955Skevlo				rf = 0x0c;
4520257955Skevlo			else if (chan == 5)
4521257955Skevlo				rf = 0x0b;
4522259030Skevlo			else if (chan >= 6 && chan <= 7)
4523257955Skevlo				rf = 0x0a;
4524259030Skevlo			else if (chan >= 8 && chan <= 10)
4525257955Skevlo				rf = 0x09;
4526259030Skevlo			else
4527257955Skevlo				rf = 0x08;
4528257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4529257955Skevlo		} else {
4530259030Skevlo			if (chan <= 11)
4531257955Skevlo				rf = 0x0f;
4532259030Skevlo			else
4533257955Skevlo				rf = 0x0b;
4534257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4535257955Skevlo		}
4536257955Skevlo	} else {
4537257955Skevlo		/* Fix for RT5390F. */
4538257955Skevlo		if (sc->mac_rev >= 0x0502) {
4539259030Skevlo			if (chan <= 11)
4540257955Skevlo				rf = 0x43;
4541259030Skevlo			else
4542257955Skevlo				rf = 0x23;
4543257955Skevlo			run_rt3070_rf_write(sc, 55, rf);
4544257955Skevlo
4545259030Skevlo			if (chan <= 11)
4546257955Skevlo				rf = 0x0f;
4547257955Skevlo			else if (chan == 12)
4548257955Skevlo				rf = 0x0d;
4549259030Skevlo			else
4550257955Skevlo				rf = 0x0b;
4551257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4552257955Skevlo		} else {
4553257955Skevlo			run_rt3070_rf_write(sc, 55, 0x44);
4554257955Skevlo			run_rt3070_rf_write(sc, 59, 0x8f);
4555257955Skevlo		}
4556257955Skevlo	}
4557257955Skevlo
4558257955Skevlo	/* Enable VCO calibration. */
4559257955Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4560257955Skevlo	rf |= RT5390_VCOCAL;
4561257955Skevlo	run_rt3070_rf_write(sc, 3, rf);
4562257955Skevlo}
4563257955Skevlo
4564257955Skevlostatic void
4565259032Skevlorun_rt5592_set_chan(struct run_softc *sc, u_int chan)
4566259032Skevlo{
4567259032Skevlo	const struct rt5592_freqs *freqs;
4568259032Skevlo	uint32_t tmp;
4569259032Skevlo	uint8_t reg, rf, txpow_bound;
4570259032Skevlo	int8_t txpow1, txpow2;
4571259032Skevlo	int i;
4572259032Skevlo
4573259032Skevlo	run_read(sc, RT5592_DEBUG_INDEX, &tmp);
4574259032Skevlo	freqs = (tmp & RT5592_SEL_XTAL) ?
4575259032Skevlo	    rt5592_freqs_40mhz : rt5592_freqs_20mhz;
4576259032Skevlo
4577259032Skevlo	/* find the settings for this channel (we know it exists) */
4578259032Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++, freqs++);
4579259032Skevlo
4580259032Skevlo	/* use Tx power values from EEPROM */
4581259032Skevlo	txpow1 = sc->txpow1[i];
4582259032Skevlo	txpow2 = sc->txpow2[i];
4583259032Skevlo
4584259032Skevlo	run_read(sc, RT3070_LDO_CFG0, &tmp);
4585259032Skevlo	tmp &= ~0x1c000000;
4586259032Skevlo	if (chan > 14)
4587259032Skevlo		tmp |= 0x14000000;
4588259032Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
4589259032Skevlo
4590259032Skevlo	/* N setting. */
4591259032Skevlo	run_rt3070_rf_write(sc, 8, freqs->n & 0xff);
4592259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4593259032Skevlo	rf &= ~(1 << 4);
4594259032Skevlo	rf |= ((freqs->n & 0x0100) >> 8) << 4;
4595259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4596259032Skevlo
4597259032Skevlo	/* K setting. */
4598259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4599259032Skevlo	rf &= ~0x0f;
4600259032Skevlo	rf |= (freqs->k & 0x0f);
4601259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4602259032Skevlo
4603259032Skevlo	/* Mode setting. */
4604259032Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4605259032Skevlo	rf &= ~0x0c;
4606259032Skevlo	rf |= ((freqs->m - 0x8) & 0x3) << 2;
4607259032Skevlo	run_rt3070_rf_write(sc, 11, rf);
4608259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4609259032Skevlo	rf &= ~(1 << 7);
4610259032Skevlo	rf |= (((freqs->m - 0x8) & 0x4) >> 2) << 7;
4611259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4612259032Skevlo
4613259032Skevlo	/* R setting. */
4614259032Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4615259032Skevlo	rf &= ~0x03;
4616259032Skevlo	rf |= (freqs->r - 0x1);
4617259032Skevlo	run_rt3070_rf_write(sc, 11, rf);
4618259032Skevlo
4619259032Skevlo	if (chan <= 14) {
4620259032Skevlo		/* Initialize RF registers for 2GHZ. */
4621259032Skevlo		for (i = 0; i < nitems(rt5592_2ghz_def_rf); i++) {
4622259032Skevlo			run_rt3070_rf_write(sc, rt5592_2ghz_def_rf[i].reg,
4623259032Skevlo			    rt5592_2ghz_def_rf[i].val);
4624259032Skevlo		}
4625259032Skevlo
4626259032Skevlo		rf = (chan <= 10) ? 0x07 : 0x06;
4627259032Skevlo		run_rt3070_rf_write(sc, 23, rf);
4628259032Skevlo		run_rt3070_rf_write(sc, 59, rf);
4629259032Skevlo
4630259032Skevlo		run_rt3070_rf_write(sc, 55, 0x43);
4631259032Skevlo
4632259032Skevlo		/*
4633259032Skevlo		 * RF R49/R50 Tx power ALC code.
4634259032Skevlo		 * G-band bit<7:6>=1:0, bit<5:0> range from 0x0 ~ 0x27.
4635259032Skevlo		 */
4636259032Skevlo		reg = 2;
4637259032Skevlo		txpow_bound = 0x27;
4638259032Skevlo	} else {
4639259032Skevlo		/* Initialize RF registers for 5GHZ. */
4640259032Skevlo		for (i = 0; i < nitems(rt5592_5ghz_def_rf); i++) {
4641259032Skevlo			run_rt3070_rf_write(sc, rt5592_5ghz_def_rf[i].reg,
4642259032Skevlo			    rt5592_5ghz_def_rf[i].val);
4643259032Skevlo		}
4644259032Skevlo		for (i = 0; i < nitems(rt5592_chan_5ghz); i++) {
4645259032Skevlo			if (chan >= rt5592_chan_5ghz[i].firstchan &&
4646259032Skevlo			    chan <= rt5592_chan_5ghz[i].lastchan) {
4647259032Skevlo				run_rt3070_rf_write(sc, rt5592_chan_5ghz[i].reg,
4648259032Skevlo				    rt5592_chan_5ghz[i].val);
4649259032Skevlo			}
4650259032Skevlo		}
4651259032Skevlo
4652259032Skevlo		/*
4653259032Skevlo		 * RF R49/R50 Tx power ALC code.
4654259032Skevlo		 * A-band bit<7:6>=1:1, bit<5:0> range from 0x0 ~ 0x2b.
4655259032Skevlo		 */
4656259032Skevlo		reg = 3;
4657259032Skevlo		txpow_bound = 0x2b;
4658259032Skevlo	}
4659259032Skevlo
4660259032Skevlo	/* RF R49 ch0 Tx power ALC code. */
4661259032Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4662259032Skevlo	rf &= ~0xc0;
4663259032Skevlo	rf |= (reg << 6);
4664259032Skevlo	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
4665259032Skevlo	if ((rf & 0x3f) > txpow_bound)
4666259032Skevlo		rf = (rf & ~0x3f) | txpow_bound;
4667259032Skevlo	run_rt3070_rf_write(sc, 49, rf);
4668259032Skevlo
4669259032Skevlo	/* RF R50 ch1 Tx power ALC code. */
4670259032Skevlo	run_rt3070_rf_read(sc, 50, &rf);
4671259032Skevlo	rf &= ~(1 << 7 | 1 << 6);
4672259032Skevlo	rf |= (reg << 6);
4673259032Skevlo	rf = (rf & ~0x3f) | (txpow2 & 0x3f);
4674259032Skevlo	if ((rf & 0x3f) > txpow_bound)
4675259032Skevlo		rf = (rf & ~0x3f) | txpow_bound;
4676259032Skevlo	run_rt3070_rf_write(sc, 50, rf);
4677259032Skevlo
4678259032Skevlo	/* Enable RF_BLOCK, PLL_PD, RX0_PD, and TX0_PD. */
4679259032Skevlo	run_rt3070_rf_read(sc, 1, &rf);
4680259032Skevlo	rf |= (RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD);
4681259032Skevlo	if (sc->ntxchains > 1)
4682259032Skevlo		rf |= RT3070_TX1_PD;
4683259032Skevlo	if (sc->nrxchains > 1)
4684259032Skevlo		rf |= RT3070_RX1_PD;
4685259032Skevlo	run_rt3070_rf_write(sc, 1, rf);
4686259032Skevlo
4687259032Skevlo	run_rt3070_rf_write(sc, 6, 0xe4);
4688259032Skevlo
4689259032Skevlo	run_rt3070_rf_write(sc, 30, 0x10);
4690259032Skevlo	run_rt3070_rf_write(sc, 31, 0x80);
4691259032Skevlo	run_rt3070_rf_write(sc, 32, 0x80);
4692259032Skevlo
4693259032Skevlo	run_adjust_freq_offset(sc);
4694259032Skevlo
4695259032Skevlo	/* Enable VCO calibration. */
4696259032Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4697259032Skevlo	rf |= RT5390_VCOCAL;
4698259032Skevlo	run_rt3070_rf_write(sc, 3, rf);
4699259032Skevlo}
4700259032Skevlo
4701259032Skevlostatic void
4702203134Sthompsarun_set_rx_antenna(struct run_softc *sc, int aux)
4703203134Sthompsa{
4704203134Sthompsa	uint32_t tmp;
4705257955Skevlo	uint8_t bbp152;
4706203134Sthompsa
4707203134Sthompsa	if (aux) {
4708257955Skevlo		if (sc->rf_rev == RT5390_RF_5370) {
4709257955Skevlo			run_bbp_read(sc, 152, &bbp152);
4710257955Skevlo			run_bbp_write(sc, 152, bbp152 & ~0x80);
4711259030Skevlo		} else {
4712257955Skevlo			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0);
4713257955Skevlo			run_read(sc, RT2860_GPIO_CTRL, &tmp);
4714257955Skevlo			run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08);
4715257955Skevlo		}
4716203134Sthompsa	} else {
4717257955Skevlo		if (sc->rf_rev == RT5390_RF_5370) {
4718257955Skevlo			run_bbp_read(sc, 152, &bbp152);
4719257955Skevlo			run_bbp_write(sc, 152, bbp152 | 0x80);
4720259030Skevlo		} else {
4721257955Skevlo			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1);
4722257955Skevlo			run_read(sc, RT2860_GPIO_CTRL, &tmp);
4723257955Skevlo			run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808);
4724257955Skevlo		}
4725203134Sthompsa	}
4726203134Sthompsa}
4727203134Sthompsa
4728203134Sthompsastatic int
4729203134Sthompsarun_set_chan(struct run_softc *sc, struct ieee80211_channel *c)
4730203134Sthompsa{
4731287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4732257429Shselasky	u_int chan, group;
4733203134Sthompsa
4734203134Sthompsa	chan = ieee80211_chan2ieee(ic, c);
4735203134Sthompsa	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
4736209917Sthompsa		return (EINVAL);
4737203134Sthompsa
4738259032Skevlo	if (sc->mac_ver == 0x5592)
4739259032Skevlo		run_rt5592_set_chan(sc, chan);
4740259032Skevlo	else if (sc->mac_ver >= 0x5390)
4741257955Skevlo		run_rt5390_set_chan(sc, chan);
4742260219Skevlo	else if (sc->mac_ver == 0x3593)
4743260219Skevlo		run_rt3593_set_chan(sc, chan);
4744257955Skevlo	else if (sc->mac_ver == 0x3572)
4745205042Sthompsa		run_rt3572_set_chan(sc, chan);
4746205042Sthompsa	else if (sc->mac_ver >= 0x3070)
4747203134Sthompsa		run_rt3070_set_chan(sc, chan);
4748203134Sthompsa	else
4749203134Sthompsa		run_rt2870_set_chan(sc, chan);
4750203134Sthompsa
4751203134Sthompsa	/* determine channel group */
4752203134Sthompsa	if (chan <= 14)
4753203134Sthompsa		group = 0;
4754203134Sthompsa	else if (chan <= 64)
4755203134Sthompsa		group = 1;
4756203134Sthompsa	else if (chan <= 128)
4757203134Sthompsa		group = 2;
4758203134Sthompsa	else
4759203134Sthompsa		group = 3;
4760203134Sthompsa
4761203134Sthompsa	/* XXX necessary only when group has changed! */
4762203134Sthompsa	run_select_chan_group(sc, group);
4763203134Sthompsa
4764203134Sthompsa	run_delay(sc, 10);
4765203134Sthompsa
4766259545Skevlo	/* Perform IQ calibration. */
4767259544Skevlo	if (sc->mac_ver >= 0x5392)
4768259544Skevlo		run_iq_calib(sc, chan);
4769259544Skevlo
4770209917Sthompsa	return (0);
4771203134Sthompsa}
4772203134Sthompsa
4773203134Sthompsastatic void
4774203134Sthompsarun_set_channel(struct ieee80211com *ic)
4775203134Sthompsa{
4776286950Sadrian	struct run_softc *sc = ic->ic_softc;
4777203134Sthompsa
4778203134Sthompsa	RUN_LOCK(sc);
4779203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
4780203134Sthompsa	RUN_UNLOCK(sc);
4781203134Sthompsa
4782203134Sthompsa	return;
4783203134Sthompsa}
4784203134Sthompsa
4785203134Sthompsastatic void
4786203134Sthompsarun_scan_start(struct ieee80211com *ic)
4787203134Sthompsa{
4788286950Sadrian	struct run_softc *sc = ic->ic_softc;
4789203134Sthompsa	uint32_t tmp;
4790203134Sthompsa
4791203134Sthompsa	RUN_LOCK(sc);
4792203134Sthompsa
4793203134Sthompsa	/* abort TSF synchronization */
4794203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
4795203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG,
4796203134Sthompsa	    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
4797203134Sthompsa	    RT2860_TBTT_TIMER_EN));
4798287197Sglebius	run_set_bssid(sc, ieee80211broadcastaddr);
4799203134Sthompsa
4800203134Sthompsa	RUN_UNLOCK(sc);
4801203134Sthompsa
4802203134Sthompsa	return;
4803203134Sthompsa}
4804203134Sthompsa
4805203134Sthompsastatic void
4806203134Sthompsarun_scan_end(struct ieee80211com *ic)
4807203134Sthompsa{
4808286950Sadrian	struct run_softc *sc = ic->ic_softc;
4809203134Sthompsa
4810203134Sthompsa	RUN_LOCK(sc);
4811203134Sthompsa
4812203134Sthompsa	run_enable_tsf_sync(sc);
4813203134Sthompsa	/* XXX keep local copy */
4814287197Sglebius	run_set_bssid(sc, ic->ic_macaddr);
4815203134Sthompsa
4816203134Sthompsa	RUN_UNLOCK(sc);
4817203134Sthompsa
4818203134Sthompsa	return;
4819203134Sthompsa}
4820203134Sthompsa
4821208019Sthompsa/*
4822208019Sthompsa * Could be called from ieee80211_node_timeout()
4823208019Sthompsa * (non-sleepable thread)
4824208019Sthompsa */
4825208019Sthompsastatic void
4826208019Sthompsarun_update_beacon(struct ieee80211vap *vap, int item)
4827203134Sthompsa{
4828208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4829286950Sadrian	struct run_softc *sc = ic->ic_softc;
4830218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4831218492Sbschmidt	int mcast = 0;
4832208019Sthompsa	uint32_t i;
4833208019Sthompsa
4834218492Sbschmidt	KASSERT(vap != NULL, ("no beacon"));
4835218492Sbschmidt
4836218492Sbschmidt	switch (item) {
4837218492Sbschmidt	case IEEE80211_BEACON_ERP:
4838283540Sglebius		run_updateslot(ic);
4839218492Sbschmidt		break;
4840218492Sbschmidt	case IEEE80211_BEACON_HTINFO:
4841218492Sbschmidt		run_updateprot(ic);
4842218492Sbschmidt		break;
4843218492Sbschmidt	case IEEE80211_BEACON_TIM:
4844218492Sbschmidt		mcast = 1;	/*TODO*/
4845218492Sbschmidt		break;
4846218492Sbschmidt	default:
4847218492Sbschmidt		break;
4848218492Sbschmidt	}
4849218492Sbschmidt
4850218492Sbschmidt	setbit(rvp->bo.bo_flags, item);
4851273448Skevlo	if (rvp->beacon_mbuf == NULL) {
4852273448Skevlo		rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss,
4853273448Skevlo		    &rvp->bo);
4854273448Skevlo		if (rvp->beacon_mbuf == NULL)
4855273448Skevlo			return;
4856273448Skevlo	}
4857218492Sbschmidt	ieee80211_beacon_update(vap->iv_bss, &rvp->bo, rvp->beacon_mbuf, mcast);
4858218492Sbschmidt
4859208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
4860208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
4861208019Sthompsa	sc->cmdq[i].func = run_update_beacon_cb;
4862208019Sthompsa	sc->cmdq[i].arg0 = vap;
4863208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
4864208019Sthompsa
4865208019Sthompsa	return;
4866203134Sthompsa}
4867203134Sthompsa
4868203134Sthompsastatic void
4869208019Sthompsarun_update_beacon_cb(void *arg)
4870203134Sthompsa{
4871208019Sthompsa	struct ieee80211vap *vap = arg;
4872218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4873203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4874286950Sadrian	struct run_softc *sc = ic->ic_softc;
4875203134Sthompsa	struct rt2860_txwi txwi;
4876203134Sthompsa	struct mbuf *m;
4877259032Skevlo	uint16_t txwisize;
4878208019Sthompsa	uint8_t ridx;
4879203134Sthompsa
4880209917Sthompsa	if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC)
4881208019Sthompsa		return;
4882236439Shselasky	if (ic->ic_bsschan == IEEE80211_CHAN_ANYC)
4883236439Shselasky		return;
4884208019Sthompsa
4885218492Sbschmidt	/*
4886218492Sbschmidt	 * No need to call ieee80211_beacon_update(), run_update_beacon()
4887218492Sbschmidt	 * is taking care of apropriate calls.
4888218492Sbschmidt	 */
4889218492Sbschmidt	if (rvp->beacon_mbuf == NULL) {
4890218492Sbschmidt		rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss,
4891218492Sbschmidt		    &rvp->bo);
4892218492Sbschmidt		if (rvp->beacon_mbuf == NULL)
4893218492Sbschmidt			return;
4894218492Sbschmidt	}
4895218492Sbschmidt	m = rvp->beacon_mbuf;
4896203134Sthompsa
4897259032Skevlo	memset(&txwi, 0, sizeof(txwi));
4898203134Sthompsa	txwi.wcid = 0xff;
4899203134Sthompsa	txwi.len = htole16(m->m_pkthdr.len);
4900259032Skevlo
4901203134Sthompsa	/* send beacons at the lowest available rate */
4902208019Sthompsa	ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
4903208019Sthompsa	    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
4904208019Sthompsa	txwi.phy = htole16(rt2860_rates[ridx].mcs);
4905208019Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM)
4906259032Skevlo		txwi.phy |= htole16(RT2860_PHY_OFDM);
4907203134Sthompsa	txwi.txop = RT2860_TX_TXOP_HT;
4908203134Sthompsa	txwi.flags = RT2860_TX_TS;
4909209144Sthompsa	txwi.xflags = RT2860_TX_NSEQ;
4910203134Sthompsa
4911259032Skevlo	txwisize = (sc->mac_ver == 0x5592) ?
4912259032Skevlo	    sizeof(txwi) + sizeof(uint32_t) : sizeof(txwi);
4913259032Skevlo	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id), (uint8_t *)&txwi,
4914259032Skevlo	    txwisize);
4915259032Skevlo	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id) + txwisize,
4916259032Skevlo	    mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1);
4917203134Sthompsa}
4918203134Sthompsa
4919203134Sthompsastatic void
4920203134Sthompsarun_updateprot(struct ieee80211com *ic)
4921203134Sthompsa{
4922286950Sadrian	struct run_softc *sc = ic->ic_softc;
4923218492Sbschmidt	uint32_t i;
4924218492Sbschmidt
4925218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
4926218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
4927218492Sbschmidt	sc->cmdq[i].func = run_updateprot_cb;
4928218492Sbschmidt	sc->cmdq[i].arg0 = ic;
4929218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
4930218492Sbschmidt}
4931218492Sbschmidt
4932218492Sbschmidtstatic void
4933218492Sbschmidtrun_updateprot_cb(void *arg)
4934218492Sbschmidt{
4935218492Sbschmidt	struct ieee80211com *ic = arg;
4936286950Sadrian	struct run_softc *sc = ic->ic_softc;
4937203134Sthompsa	uint32_t tmp;
4938203134Sthompsa
4939203134Sthompsa	tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL;
4940203134Sthompsa	/* setup protection frame rate (MCS code) */
4941203134Sthompsa	tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ?
4942270192Skevlo	    rt2860_rates[RT2860_RIDX_OFDM6].mcs | RT2860_PHY_OFDM :
4943203134Sthompsa	    rt2860_rates[RT2860_RIDX_CCK11].mcs;
4944203134Sthompsa
4945203134Sthompsa	/* CCK frames don't require protection */
4946203134Sthompsa	run_write(sc, RT2860_CCK_PROT_CFG, tmp);
4947203134Sthompsa	if (ic->ic_flags & IEEE80211_F_USEPROT) {
4948203134Sthompsa		if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
4949203134Sthompsa			tmp |= RT2860_PROT_CTRL_RTS_CTS;
4950203134Sthompsa		else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
4951203134Sthompsa			tmp |= RT2860_PROT_CTRL_CTS;
4952203134Sthompsa	}
4953203134Sthompsa	run_write(sc, RT2860_OFDM_PROT_CFG, tmp);
4954203134Sthompsa}
4955203134Sthompsa
4956203134Sthompsastatic void
4957208019Sthompsarun_usb_timeout_cb(void *arg)
4958203134Sthompsa{
4959208019Sthompsa	struct ieee80211vap *vap = arg;
4960286950Sadrian	struct run_softc *sc = vap->iv_ic->ic_softc;
4961203134Sthompsa
4962208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
4963203134Sthompsa
4964203134Sthompsa	if(vap->iv_state == IEEE80211_S_RUN &&
4965203134Sthompsa	    vap->iv_opmode != IEEE80211_M_STA)
4966203134Sthompsa		run_reset_livelock(sc);
4967209917Sthompsa	else if (vap->iv_state == IEEE80211_S_SCAN) {
4968203134Sthompsa		DPRINTF("timeout caused by scan\n");
4969203134Sthompsa		/* cancel bgscan */
4970203134Sthompsa		ieee80211_cancel_scan(vap);
4971203134Sthompsa	} else
4972203134Sthompsa		DPRINTF("timeout by unknown cause\n");
4973203134Sthompsa}
4974203134Sthompsa
4975203134Sthompsastatic void
4976203134Sthompsarun_reset_livelock(struct run_softc *sc)
4977203134Sthompsa{
4978203134Sthompsa	uint32_t tmp;
4979203134Sthompsa
4980208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
4981208019Sthompsa
4982203134Sthompsa	/*
4983203134Sthompsa	 * In IBSS or HostAP modes (when the hardware sends beacons), the MAC
4984203134Sthompsa	 * can run into a livelock and start sending CTS-to-self frames like
4985203134Sthompsa	 * crazy if protection is enabled.  Reset MAC/BBP for a while
4986203134Sthompsa	 */
4987203134Sthompsa	run_read(sc, RT2860_DEBUG, &tmp);
4988208019Sthompsa	DPRINTFN(3, "debug reg %08x\n", tmp);
4989209917Sthompsa	if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) {
4990203134Sthompsa		DPRINTF("CTS-to-self livelock detected\n");
4991203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST);
4992203134Sthompsa		run_delay(sc, 1);
4993203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL,
4994203134Sthompsa		    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
4995203134Sthompsa	}
4996203134Sthompsa}
4997203134Sthompsa
4998203134Sthompsastatic void
4999283540Sglebiusrun_update_promisc_locked(struct run_softc *sc)
5000203134Sthompsa{
5001203134Sthompsa        uint32_t tmp;
5002203134Sthompsa
5003203134Sthompsa	run_read(sc, RT2860_RX_FILTR_CFG, &tmp);
5004203134Sthompsa
5005203134Sthompsa	tmp |= RT2860_DROP_UC_NOME;
5006287197Sglebius        if (sc->sc_ic.ic_promisc > 0)
5007203134Sthompsa		tmp &= ~RT2860_DROP_UC_NOME;
5008203134Sthompsa
5009203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5010203134Sthompsa
5011287197Sglebius        DPRINTF("%s promiscuous mode\n", (sc->sc_ic.ic_promisc > 0) ?
5012203134Sthompsa            "entering" : "leaving");
5013203134Sthompsa}
5014203134Sthompsa
5015203134Sthompsastatic void
5016283540Sglebiusrun_update_promisc(struct ieee80211com *ic)
5017203134Sthompsa{
5018283540Sglebius	struct run_softc *sc = ic->ic_softc;
5019203134Sthompsa
5020287197Sglebius	if ((sc->sc_flags & RUN_RUNNING) == 0)
5021203134Sthompsa		return;
5022203134Sthompsa
5023203134Sthompsa	RUN_LOCK(sc);
5024283540Sglebius	run_update_promisc_locked(sc);
5025203134Sthompsa	RUN_UNLOCK(sc);
5026203134Sthompsa}
5027203134Sthompsa
5028203134Sthompsastatic void
5029203134Sthompsarun_enable_tsf_sync(struct run_softc *sc)
5030203134Sthompsa{
5031287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5032203134Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
5033203134Sthompsa	uint32_t tmp;
5034203134Sthompsa
5035257955Skevlo	DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id,
5036257955Skevlo	    ic->ic_opmode);
5037208019Sthompsa
5038203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
5039203134Sthompsa	tmp &= ~0x1fffff;
5040203134Sthompsa	tmp |= vap->iv_bss->ni_intval * 16;
5041203134Sthompsa	tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN;
5042203134Sthompsa
5043208019Sthompsa	if (ic->ic_opmode == IEEE80211_M_STA) {
5044203134Sthompsa		/*
5045203134Sthompsa		 * Local TSF is always updated with remote TSF on beacon
5046203134Sthompsa		 * reception.
5047203134Sthompsa		 */
5048203134Sthompsa		tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT;
5049208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_IBSS) {
5050203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5051203134Sthompsa	        /*
5052203134Sthompsa	         * Local TSF is updated with remote TSF on beacon reception
5053203134Sthompsa	         * only if the remote TSF is greater than local TSF.
5054203134Sthompsa	         */
5055203134Sthompsa	        tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT;
5056208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
5057208019Sthompsa		    ic->ic_opmode == IEEE80211_M_MBSS) {
5058203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5059203134Sthompsa	        /* SYNC with nobody */
5060203134Sthompsa	        tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT;
5061208019Sthompsa	} else {
5062203134Sthompsa		DPRINTF("Enabling TSF failed. undefined opmode\n");
5063208019Sthompsa		return;
5064208019Sthompsa	}
5065203134Sthompsa
5066203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
5067203134Sthompsa}
5068203134Sthompsa
5069203134Sthompsastatic void
5070203134Sthompsarun_enable_mrr(struct run_softc *sc)
5071203134Sthompsa{
5072259546Skevlo#define	CCK(mcs)	(mcs)
5073259546Skevlo#define	OFDM(mcs)	(1 << 3 | (mcs))
5074203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG0,
5075203134Sthompsa	    OFDM(6) << 28 |	/* 54->48 */
5076203134Sthompsa	    OFDM(5) << 24 |	/* 48->36 */
5077203134Sthompsa	    OFDM(4) << 20 |	/* 36->24 */
5078203134Sthompsa	    OFDM(3) << 16 |	/* 24->18 */
5079203134Sthompsa	    OFDM(2) << 12 |	/* 18->12 */
5080203134Sthompsa	    OFDM(1) <<  8 |	/* 12-> 9 */
5081203134Sthompsa	    OFDM(0) <<  4 |	/*  9-> 6 */
5082203134Sthompsa	    OFDM(0));		/*  6-> 6 */
5083203134Sthompsa
5084203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG1,
5085203134Sthompsa	    CCK(2) << 12 |	/* 11->5.5 */
5086203134Sthompsa	    CCK(1) <<  8 |	/* 5.5-> 2 */
5087203134Sthompsa	    CCK(0) <<  4 |	/*   2-> 1 */
5088203134Sthompsa	    CCK(0));		/*   1-> 1 */
5089203134Sthompsa#undef OFDM
5090203134Sthompsa#undef CCK
5091203134Sthompsa}
5092203134Sthompsa
5093203134Sthompsastatic void
5094203134Sthompsarun_set_txpreamble(struct run_softc *sc)
5095203134Sthompsa{
5096287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5097203134Sthompsa	uint32_t tmp;
5098203134Sthompsa
5099203134Sthompsa	run_read(sc, RT2860_AUTO_RSP_CFG, &tmp);
5100203134Sthompsa	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
5101203134Sthompsa		tmp |= RT2860_CCK_SHORT_EN;
5102203134Sthompsa	else
5103203134Sthompsa		tmp &= ~RT2860_CCK_SHORT_EN;
5104203134Sthompsa	run_write(sc, RT2860_AUTO_RSP_CFG, tmp);
5105203134Sthompsa}
5106203134Sthompsa
5107203134Sthompsastatic void
5108203134Sthompsarun_set_basicrates(struct run_softc *sc)
5109203134Sthompsa{
5110287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5111203134Sthompsa
5112203134Sthompsa	/* set basic rates mask */
5113203134Sthompsa	if (ic->ic_curmode == IEEE80211_MODE_11B)
5114203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003);
5115203134Sthompsa	else if (ic->ic_curmode == IEEE80211_MODE_11A)
5116203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150);
5117203134Sthompsa	else	/* 11g */
5118203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f);
5119203134Sthompsa}
5120203134Sthompsa
5121203134Sthompsastatic void
5122203134Sthompsarun_set_leds(struct run_softc *sc, uint16_t which)
5123203134Sthompsa{
5124203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS,
5125203134Sthompsa	    which | (sc->leds & 0x7f));
5126203134Sthompsa}
5127203134Sthompsa
5128203134Sthompsastatic void
5129203134Sthompsarun_set_bssid(struct run_softc *sc, const uint8_t *bssid)
5130203134Sthompsa{
5131203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW0,
5132203134Sthompsa	    bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24);
5133203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW1,
5134203134Sthompsa	    bssid[4] | bssid[5] << 8);
5135203134Sthompsa}
5136203134Sthompsa
5137203134Sthompsastatic void
5138203134Sthompsarun_set_macaddr(struct run_softc *sc, const uint8_t *addr)
5139203134Sthompsa{
5140203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW0,
5141203134Sthompsa	    addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24);
5142203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW1,
5143203134Sthompsa	    addr[4] | addr[5] << 8 | 0xff << 16);
5144203134Sthompsa}
5145203134Sthompsa
5146203134Sthompsastatic void
5147283540Sglebiusrun_updateslot(struct ieee80211com *ic)
5148203134Sthompsa{
5149283540Sglebius	struct run_softc *sc = ic->ic_softc;
5150218492Sbschmidt	uint32_t i;
5151218492Sbschmidt
5152218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
5153218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
5154218492Sbschmidt	sc->cmdq[i].func = run_updateslot_cb;
5155287197Sglebius	sc->cmdq[i].arg0 = ic;
5156218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
5157218492Sbschmidt
5158218492Sbschmidt	return;
5159218492Sbschmidt}
5160218492Sbschmidt
5161218492Sbschmidt/* ARGSUSED */
5162218492Sbschmidtstatic void
5163218492Sbschmidtrun_updateslot_cb(void *arg)
5164218492Sbschmidt{
5165287197Sglebius	struct ieee80211com *ic = arg;
5166286950Sadrian	struct run_softc *sc = ic->ic_softc;
5167203134Sthompsa	uint32_t tmp;
5168203134Sthompsa
5169203134Sthompsa	run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp);
5170203134Sthompsa	tmp &= ~0xff;
5171203134Sthompsa	tmp |= (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
5172203134Sthompsa	run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp);
5173203134Sthompsa}
5174203134Sthompsa
5175208019Sthompsastatic void
5176283540Sglebiusrun_update_mcast(struct ieee80211com *ic)
5177208019Sthompsa{
5178208019Sthompsa}
5179208019Sthompsa
5180203134Sthompsastatic int8_t
5181203134Sthompsarun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain)
5182203134Sthompsa{
5183287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5184203134Sthompsa	struct ieee80211_channel *c = ic->ic_curchan;
5185203134Sthompsa	int delta;
5186203134Sthompsa
5187203134Sthompsa	if (IEEE80211_IS_CHAN_5GHZ(c)) {
5188257429Shselasky		u_int chan = ieee80211_chan2ieee(ic, c);
5189203134Sthompsa		delta = sc->rssi_5ghz[rxchain];
5190203134Sthompsa
5191203134Sthompsa		/* determine channel group */
5192203134Sthompsa		if (chan <= 64)
5193203134Sthompsa			delta -= sc->lna[1];
5194203134Sthompsa		else if (chan <= 128)
5195203134Sthompsa			delta -= sc->lna[2];
5196203134Sthompsa		else
5197203134Sthompsa			delta -= sc->lna[3];
5198203134Sthompsa	} else
5199203134Sthompsa		delta = sc->rssi_2ghz[rxchain] - sc->lna[0];
5200203134Sthompsa
5201209917Sthompsa	return (-12 - delta - rssi);
5202203134Sthompsa}
5203203134Sthompsa
5204257955Skevlostatic void
5205257955Skevlorun_rt5390_bbp_init(struct run_softc *sc)
5206257955Skevlo{
5207257955Skevlo	int i;
5208259032Skevlo	uint8_t bbp;
5209257955Skevlo
5210259032Skevlo	/* Apply maximum likelihood detection for 2 stream case. */
5211259032Skevlo	run_bbp_read(sc, 105, &bbp);
5212259032Skevlo	if (sc->nrxchains > 1)
5213259032Skevlo		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5214259032Skevlo
5215257955Skevlo	/* Avoid data lost and CRC error. */
5216259032Skevlo	run_bbp_read(sc, 4, &bbp);
5217259031Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5218257955Skevlo
5219259032Skevlo	if (sc->mac_ver == 0x5592) {
5220259032Skevlo		for (i = 0; i < nitems(rt5592_def_bbp); i++) {
5221259032Skevlo			run_bbp_write(sc, rt5592_def_bbp[i].reg,
5222259032Skevlo			    rt5592_def_bbp[i].val);
5223259032Skevlo		}
5224259032Skevlo		for (i = 0; i < nitems(rt5592_bbp_r196); i++) {
5225259032Skevlo			run_bbp_write(sc, 195, i + 0x80);
5226259032Skevlo			run_bbp_write(sc, 196, rt5592_bbp_r196[i]);
5227259032Skevlo		}
5228259032Skevlo	} else {
5229259032Skevlo		for (i = 0; i < nitems(rt5390_def_bbp); i++) {
5230259032Skevlo			run_bbp_write(sc, rt5390_def_bbp[i].reg,
5231259032Skevlo			    rt5390_def_bbp[i].val);
5232259032Skevlo		}
5233257955Skevlo	}
5234257955Skevlo	if (sc->mac_ver == 0x5392) {
5235257955Skevlo		run_bbp_write(sc, 88, 0x90);
5236257955Skevlo		run_bbp_write(sc, 95, 0x9a);
5237257955Skevlo		run_bbp_write(sc, 98, 0x12);
5238257955Skevlo		run_bbp_write(sc, 106, 0x12);
5239257955Skevlo		run_bbp_write(sc, 134, 0xd0);
5240257955Skevlo		run_bbp_write(sc, 135, 0xf6);
5241257955Skevlo		run_bbp_write(sc, 148, 0x84);
5242257955Skevlo	}
5243257955Skevlo
5244259032Skevlo	run_bbp_read(sc, 152, &bbp);
5245259032Skevlo	run_bbp_write(sc, 152, bbp | 0x80);
5246259032Skevlo
5247259032Skevlo	/* Fix BBP254 for RT5592C. */
5248259032Skevlo	if (sc->mac_ver == 0x5592 && sc->mac_rev >= 0x0221) {
5249259032Skevlo		run_bbp_read(sc, 254, &bbp);
5250259032Skevlo		run_bbp_write(sc, 254, bbp | 0x80);
5251259032Skevlo	}
5252259032Skevlo
5253257955Skevlo	/* Disable hardware antenna diversity. */
5254257955Skevlo	if (sc->mac_ver == 0x5390)
5255257955Skevlo		run_bbp_write(sc, 154, 0);
5256259032Skevlo
5257259032Skevlo	/* Initialize Rx CCK/OFDM frequency offset report. */
5258259032Skevlo	run_bbp_write(sc, 142, 1);
5259259032Skevlo	run_bbp_write(sc, 143, 57);
5260257955Skevlo}
5261257955Skevlo
5262203134Sthompsastatic int
5263203134Sthompsarun_bbp_init(struct run_softc *sc)
5264203134Sthompsa{
5265203134Sthompsa	int i, error, ntries;
5266203134Sthompsa	uint8_t bbp0;
5267203134Sthompsa
5268203134Sthompsa	/* wait for BBP to wake up */
5269203134Sthompsa	for (ntries = 0; ntries < 20; ntries++) {
5270203134Sthompsa		if ((error = run_bbp_read(sc, 0, &bbp0)) != 0)
5271203134Sthompsa			return error;
5272203134Sthompsa		if (bbp0 != 0 && bbp0 != 0xff)
5273203134Sthompsa			break;
5274203134Sthompsa	}
5275203134Sthompsa	if (ntries == 20)
5276209917Sthompsa		return (ETIMEDOUT);
5277203134Sthompsa
5278203134Sthompsa	/* initialize BBP registers to default values */
5279257955Skevlo	if (sc->mac_ver >= 0x5390)
5280257955Skevlo		run_rt5390_bbp_init(sc);
5281257955Skevlo	else {
5282257955Skevlo		for (i = 0; i < nitems(rt2860_def_bbp); i++) {
5283257955Skevlo			run_bbp_write(sc, rt2860_def_bbp[i].reg,
5284257955Skevlo			    rt2860_def_bbp[i].val);
5285257955Skevlo		}
5286203134Sthompsa	}
5287203134Sthompsa
5288260219Skevlo	if (sc->mac_ver == 0x3593) {
5289260219Skevlo		run_bbp_write(sc, 79, 0x13);
5290260219Skevlo		run_bbp_write(sc, 80, 0x05);
5291260219Skevlo		run_bbp_write(sc, 81, 0x33);
5292260219Skevlo		run_bbp_write(sc, 86, 0x46);
5293260219Skevlo		run_bbp_write(sc, 137, 0x0f);
5294260219Skevlo	}
5295260219Skevlo
5296203134Sthompsa	/* fix BBP84 for RT2860E */
5297205042Sthompsa	if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101)
5298205042Sthompsa		run_bbp_write(sc, 84, 0x19);
5299203134Sthompsa
5300260219Skevlo	if (sc->mac_ver >= 0x3070 && (sc->mac_ver != 0x3593 &&
5301260219Skevlo	    sc->mac_ver != 0x5592)) {
5302203134Sthompsa		run_bbp_write(sc, 79, 0x13);
5303203134Sthompsa		run_bbp_write(sc, 80, 0x05);
5304203134Sthompsa		run_bbp_write(sc, 81, 0x33);
5305205042Sthompsa	} else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) {
5306203134Sthompsa		run_bbp_write(sc, 69, 0x16);
5307203134Sthompsa		run_bbp_write(sc, 73, 0x12);
5308203134Sthompsa	}
5309209917Sthompsa	return (0);
5310203134Sthompsa}
5311203134Sthompsa
5312203134Sthompsastatic int
5313203134Sthompsarun_rt3070_rf_init(struct run_softc *sc)
5314203134Sthompsa{
5315203134Sthompsa	uint32_t tmp;
5316256722Skevlo	uint8_t bbp4, mingain, rf, target;
5317203134Sthompsa	int i;
5318203134Sthompsa
5319203134Sthompsa	run_rt3070_rf_read(sc, 30, &rf);
5320203134Sthompsa	/* toggle RF R30 bit 7 */
5321203134Sthompsa	run_rt3070_rf_write(sc, 30, rf | 0x80);
5322203134Sthompsa	run_delay(sc, 10);
5323203134Sthompsa	run_rt3070_rf_write(sc, 30, rf & ~0x80);
5324203134Sthompsa
5325203134Sthompsa	/* initialize RF registers to default value */
5326205042Sthompsa	if (sc->mac_ver == 0x3572) {
5327257955Skevlo		for (i = 0; i < nitems(rt3572_def_rf); i++) {
5328205042Sthompsa			run_rt3070_rf_write(sc, rt3572_def_rf[i].reg,
5329205042Sthompsa			    rt3572_def_rf[i].val);
5330205042Sthompsa		}
5331205042Sthompsa	} else {
5332257955Skevlo		for (i = 0; i < nitems(rt3070_def_rf); i++) {
5333205042Sthompsa			run_rt3070_rf_write(sc, rt3070_def_rf[i].reg,
5334205042Sthompsa			    rt3070_def_rf[i].val);
5335205042Sthompsa		}
5336203134Sthompsa	}
5337205042Sthompsa
5338256721Skevlo	if (sc->mac_ver == 0x3070 && sc->mac_rev < 0x0201) {
5339256721Skevlo		/*
5340256721Skevlo		 * Change voltage from 1.2V to 1.35V for RT3070.
5341256721Skevlo		 * The DAC issue (RT3070_LDO_CFG0) has been fixed
5342256721Skevlo		 * in RT3070(F).
5343256721Skevlo		 */
5344203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5345203134Sthompsa		tmp = (tmp & ~0x0f000000) | 0x0d000000;
5346203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5347203134Sthompsa
5348205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5349203134Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5350203134Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5351203134Sthompsa		run_rt3070_rf_write(sc, 31, 0x14);
5352203134Sthompsa
5353203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5354203134Sthompsa		tmp &= ~0x1f000000;
5355205042Sthompsa		if (sc->mac_rev < 0x0211)
5356205042Sthompsa			tmp |= 0x0d000000;	/* 1.3V */
5357203134Sthompsa		else
5358205042Sthompsa			tmp |= 0x01000000;	/* 1.2V */
5359203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5360203134Sthompsa
5361203134Sthompsa		/* patch LNA_PE_G1 */
5362203134Sthompsa		run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5363203134Sthompsa		run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20);
5364208019Sthompsa
5365209917Sthompsa	} else if (sc->mac_ver == 0x3572) {
5366205042Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5367205042Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5368205042Sthompsa
5369208019Sthompsa		/* increase voltage from 1.2V to 1.35V */
5370208019Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5371208019Sthompsa		tmp = (tmp & ~0x1f000000) | 0x0d000000;
5372208019Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5373203134Sthompsa
5374209917Sthompsa		if (sc->mac_rev < 0x0211 || !sc->patch_dac) {
5375203134Sthompsa			run_delay(sc, 1);	/* wait for 1msec */
5376205042Sthompsa			/* decrease voltage back to 1.2V */
5377203134Sthompsa			tmp = (tmp & ~0x1f000000) | 0x01000000;
5378203134Sthompsa			run_write(sc, RT3070_LDO_CFG0, tmp);
5379203134Sthompsa		}
5380203134Sthompsa	}
5381203134Sthompsa
5382203134Sthompsa	/* select 20MHz bandwidth */
5383203134Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5384203134Sthompsa	run_rt3070_rf_write(sc, 31, rf & ~0x20);
5385203134Sthompsa
5386203134Sthompsa	/* calibrate filter for 20MHz bandwidth */
5387203134Sthompsa	sc->rf24_20mhz = 0x1f;	/* default value */
5388205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13;
5389205042Sthompsa	run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz);
5390203134Sthompsa
5391203134Sthompsa	/* select 40MHz bandwidth */
5392203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5393256721Skevlo	run_bbp_write(sc, 4, (bbp4 & ~0x18) | 0x10);
5394205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5395205042Sthompsa	run_rt3070_rf_write(sc, 31, rf | 0x20);
5396203134Sthompsa
5397203134Sthompsa	/* calibrate filter for 40MHz bandwidth */
5398203134Sthompsa	sc->rf24_40mhz = 0x2f;	/* default value */
5399205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15;
5400205042Sthompsa	run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz);
5401203134Sthompsa
5402203134Sthompsa	/* go back to 20MHz bandwidth */
5403203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5404203134Sthompsa	run_bbp_write(sc, 4, bbp4 & ~0x18);
5405203134Sthompsa
5406205042Sthompsa	if (sc->mac_ver == 0x3572) {
5407205042Sthompsa		/* save default BBP registers 25 and 26 values */
5408205042Sthompsa		run_bbp_read(sc, 25, &sc->bbp25);
5409205042Sthompsa		run_bbp_read(sc, 26, &sc->bbp26);
5410256721Skevlo	} else if (sc->mac_rev < 0x0201 || sc->mac_rev < 0x0211)
5411203134Sthompsa		run_rt3070_rf_write(sc, 27, 0x03);
5412203134Sthompsa
5413203134Sthompsa	run_read(sc, RT3070_OPT_14, &tmp);
5414203134Sthompsa	run_write(sc, RT3070_OPT_14, tmp | 1);
5415203134Sthompsa
5416205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5417205042Sthompsa		run_rt3070_rf_read(sc, 17, &rf);
5418205042Sthompsa		rf &= ~RT3070_TX_LO1;
5419205042Sthompsa		if ((sc->mac_ver == 0x3070 ||
5420205042Sthompsa		     (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) &&
5421205042Sthompsa		    !sc->ext_2ghz_lna)
5422205042Sthompsa			rf |= 0x20;	/* fix for long range Rx issue */
5423256722Skevlo		mingain = (sc->mac_ver == 0x3070) ? 1 : 2;
5424256722Skevlo		if (sc->txmixgain_2ghz >= mingain)
5425205042Sthompsa			rf = (rf & ~0x7) | sc->txmixgain_2ghz;
5426205042Sthompsa		run_rt3070_rf_write(sc, 17, rf);
5427205042Sthompsa	}
5428205042Sthompsa
5429270643Skevlo	if (sc->mac_ver == 0x3071) {
5430203134Sthompsa		run_rt3070_rf_read(sc, 1, &rf);
5431203134Sthompsa		rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD);
5432203134Sthompsa		rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD;
5433203134Sthompsa		run_rt3070_rf_write(sc, 1, rf);
5434203134Sthompsa
5435203134Sthompsa		run_rt3070_rf_read(sc, 15, &rf);
5436203134Sthompsa		run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2);
5437203134Sthompsa
5438203134Sthompsa		run_rt3070_rf_read(sc, 20, &rf);
5439203134Sthompsa		run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1);
5440203134Sthompsa
5441203134Sthompsa		run_rt3070_rf_read(sc, 21, &rf);
5442203134Sthompsa		run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2);
5443205042Sthompsa	}
5444203134Sthompsa
5445205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5446205042Sthompsa		/* fix Tx to Rx IQ glitch by raising RF voltage */
5447203134Sthompsa		run_rt3070_rf_read(sc, 27, &rf);
5448203134Sthompsa		rf &= ~0x77;
5449205042Sthompsa		if (sc->mac_rev < 0x0211)
5450203134Sthompsa			rf |= 0x03;
5451203134Sthompsa		run_rt3070_rf_write(sc, 27, rf);
5452203134Sthompsa	}
5453209917Sthompsa	return (0);
5454203134Sthompsa}
5455203134Sthompsa
5456257955Skevlostatic void
5457260219Skevlorun_rt3593_rf_init(struct run_softc *sc)
5458260219Skevlo{
5459260219Skevlo	uint32_t tmp;
5460260219Skevlo	uint8_t rf;
5461260219Skevlo	int i;
5462260219Skevlo
5463260219Skevlo	/* Disable the GPIO bits 4 and 7 for LNA PE control. */
5464260219Skevlo	run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5465260219Skevlo	tmp &= ~(1 << 4 | 1 << 7);
5466260219Skevlo	run_write(sc, RT3070_GPIO_SWITCH, tmp);
5467260219Skevlo
5468260219Skevlo	/* Initialize RF registers to default value. */
5469260219Skevlo	for (i = 0; i < nitems(rt3593_def_rf); i++) {
5470260219Skevlo		run_rt3070_rf_write(sc, rt3593_def_rf[i].reg,
5471260219Skevlo		    rt3593_def_rf[i].val);
5472260219Skevlo	}
5473260219Skevlo
5474260219Skevlo	/* Toggle RF R2 to initiate calibration. */
5475260219Skevlo	run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5476260219Skevlo
5477260219Skevlo	/* Initialize RF frequency offset. */
5478260219Skevlo	run_adjust_freq_offset(sc);
5479260219Skevlo
5480260219Skevlo	run_rt3070_rf_read(sc, 18, &rf);
5481260219Skevlo	run_rt3070_rf_write(sc, 18, rf | RT3593_AUTOTUNE_BYPASS);
5482260219Skevlo
5483260219Skevlo	/*
5484260219Skevlo	 * Increase voltage from 1.2V to 1.35V, wait for 1 msec to
5485260219Skevlo	 * decrease voltage back to 1.2V.
5486260219Skevlo	 */
5487260219Skevlo	run_read(sc, RT3070_LDO_CFG0, &tmp);
5488260219Skevlo	tmp = (tmp & ~0x1f000000) | 0x0d000000;
5489260219Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5490260219Skevlo	run_delay(sc, 1);
5491260219Skevlo	tmp = (tmp & ~0x1f000000) | 0x01000000;
5492260219Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5493260219Skevlo
5494260219Skevlo	sc->rf24_20mhz = 0x1f;
5495260219Skevlo	sc->rf24_40mhz = 0x2f;
5496260219Skevlo
5497260219Skevlo	/* Save default BBP registers 25 and 26 values. */
5498260219Skevlo	run_bbp_read(sc, 25, &sc->bbp25);
5499260219Skevlo	run_bbp_read(sc, 26, &sc->bbp26);
5500260219Skevlo
5501260219Skevlo	run_read(sc, RT3070_OPT_14, &tmp);
5502260219Skevlo	run_write(sc, RT3070_OPT_14, tmp | 1);
5503260219Skevlo}
5504260219Skevlo
5505260219Skevlostatic void
5506257955Skevlorun_rt5390_rf_init(struct run_softc *sc)
5507257955Skevlo{
5508257955Skevlo	uint32_t tmp;
5509257955Skevlo	uint8_t rf;
5510257955Skevlo	int i;
5511257955Skevlo
5512259030Skevlo	/* Toggle RF R2 to initiate calibration. */
5513259030Skevlo	if (sc->mac_ver == 0x5390) {
5514257955Skevlo		run_rt3070_rf_read(sc, 2, &rf);
5515259031Skevlo		run_rt3070_rf_write(sc, 2, rf | RT5390_RESCAL);
5516257955Skevlo		run_delay(sc, 10);
5517259031Skevlo		run_rt3070_rf_write(sc, 2, rf & ~RT5390_RESCAL);
5518259030Skevlo	} else {
5519259031Skevlo		run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5520259030Skevlo		run_delay(sc, 10);
5521257955Skevlo	}
5522257955Skevlo
5523257955Skevlo	/* Initialize RF registers to default value. */
5524259032Skevlo	if (sc->mac_ver == 0x5592) {
5525259032Skevlo		for (i = 0; i < nitems(rt5592_def_rf); i++) {
5526259032Skevlo			run_rt3070_rf_write(sc, rt5592_def_rf[i].reg,
5527259032Skevlo			    rt5592_def_rf[i].val);
5528259032Skevlo		}
5529259032Skevlo		/* Initialize RF frequency offset. */
5530259032Skevlo		run_adjust_freq_offset(sc);
5531259032Skevlo	} else if (sc->mac_ver == 0x5392) {
5532257955Skevlo		for (i = 0; i < nitems(rt5392_def_rf); i++) {
5533257955Skevlo			run_rt3070_rf_write(sc, rt5392_def_rf[i].reg,
5534257955Skevlo			    rt5392_def_rf[i].val);
5535257955Skevlo		}
5536257955Skevlo		if (sc->mac_rev >= 0x0223) {
5537257955Skevlo			run_rt3070_rf_write(sc, 23, 0x0f);
5538257955Skevlo			run_rt3070_rf_write(sc, 24, 0x3e);
5539257955Skevlo			run_rt3070_rf_write(sc, 51, 0x32);
5540257955Skevlo			run_rt3070_rf_write(sc, 53, 0x22);
5541257955Skevlo			run_rt3070_rf_write(sc, 56, 0xc1);
5542257955Skevlo			run_rt3070_rf_write(sc, 59, 0x0f);
5543257955Skevlo		}
5544257955Skevlo	} else {
5545257955Skevlo		for (i = 0; i < nitems(rt5390_def_rf); i++) {
5546257955Skevlo			run_rt3070_rf_write(sc, rt5390_def_rf[i].reg,
5547257955Skevlo			    rt5390_def_rf[i].val);
5548257955Skevlo		}
5549257955Skevlo		if (sc->mac_rev >= 0x0502) {
5550257955Skevlo			run_rt3070_rf_write(sc, 6, 0xe0);
5551257955Skevlo			run_rt3070_rf_write(sc, 25, 0x80);
5552257955Skevlo			run_rt3070_rf_write(sc, 46, 0x73);
5553257955Skevlo			run_rt3070_rf_write(sc, 53, 0x00);
5554257955Skevlo			run_rt3070_rf_write(sc, 56, 0x42);
5555257955Skevlo			run_rt3070_rf_write(sc, 61, 0xd1);
5556257955Skevlo		}
5557257955Skevlo	}
5558257955Skevlo
5559257955Skevlo	sc->rf24_20mhz = 0x1f;	/* default value */
5560259032Skevlo	sc->rf24_40mhz = (sc->mac_ver == 0x5592) ? 0 : 0x2f;
5561257955Skevlo
5562257955Skevlo	if (sc->mac_rev < 0x0211)
5563257955Skevlo		run_rt3070_rf_write(sc, 27, 0x3);
5564257955Skevlo
5565257955Skevlo	run_read(sc, RT3070_OPT_14, &tmp);
5566257955Skevlo	run_write(sc, RT3070_OPT_14, tmp | 1);
5567257955Skevlo}
5568257955Skevlo
5569203134Sthompsastatic int
5570203134Sthompsarun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target,
5571203134Sthompsa    uint8_t *val)
5572203134Sthompsa{
5573203134Sthompsa	uint8_t rf22, rf24;
5574203134Sthompsa	uint8_t bbp55_pb, bbp55_sb, delta;
5575203134Sthompsa	int ntries;
5576203134Sthompsa
5577203134Sthompsa	/* program filter */
5578205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf24);
5579205042Sthompsa	rf24 = (rf24 & 0xc0) | init;	/* initial filter value */
5580203134Sthompsa	run_rt3070_rf_write(sc, 24, rf24);
5581203134Sthompsa
5582203134Sthompsa	/* enable baseband loopback mode */
5583203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5584203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 | 0x01);
5585203134Sthompsa
5586203134Sthompsa	/* set power and frequency of passband test tone */
5587203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5588203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5589203134Sthompsa		/* transmit test tone */
5590203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5591203134Sthompsa		run_delay(sc, 10);
5592203134Sthompsa		/* read received power */
5593203134Sthompsa		run_bbp_read(sc, 55, &bbp55_pb);
5594203134Sthompsa		if (bbp55_pb != 0)
5595203134Sthompsa			break;
5596203134Sthompsa	}
5597203134Sthompsa	if (ntries == 100)
5598257955Skevlo		return (ETIMEDOUT);
5599203134Sthompsa
5600203134Sthompsa	/* set power and frequency of stopband test tone */
5601203134Sthompsa	run_bbp_write(sc, 24, 0x06);
5602203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5603203134Sthompsa		/* transmit test tone */
5604203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5605203134Sthompsa		run_delay(sc, 10);
5606203134Sthompsa		/* read received power */
5607203134Sthompsa		run_bbp_read(sc, 55, &bbp55_sb);
5608203134Sthompsa
5609203134Sthompsa		delta = bbp55_pb - bbp55_sb;
5610203134Sthompsa		if (delta > target)
5611203134Sthompsa			break;
5612203134Sthompsa
5613203134Sthompsa		/* reprogram filter */
5614203134Sthompsa		rf24++;
5615203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5616203134Sthompsa	}
5617203134Sthompsa	if (ntries < 100) {
5618203134Sthompsa		if (rf24 != init)
5619203134Sthompsa			rf24--;	/* backtrack */
5620203134Sthompsa		*val = rf24;
5621203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5622203134Sthompsa	}
5623203134Sthompsa
5624203134Sthompsa	/* restore initial state */
5625203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5626203134Sthompsa
5627203134Sthompsa	/* disable baseband loopback mode */
5628203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5629203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 & ~0x01);
5630203134Sthompsa
5631209917Sthompsa	return (0);
5632203134Sthompsa}
5633203134Sthompsa
5634205042Sthompsastatic void
5635205042Sthompsarun_rt3070_rf_setup(struct run_softc *sc)
5636205042Sthompsa{
5637205042Sthompsa	uint8_t bbp, rf;
5638205042Sthompsa	int i;
5639205042Sthompsa
5640260219Skevlo	if (sc->mac_ver == 0x3572) {
5641205042Sthompsa		/* enable DC filter */
5642205042Sthompsa		if (sc->mac_rev >= 0x0201)
5643205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5644205042Sthompsa
5645205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5646205042Sthompsa		if (sc->ntxchains == 1)
5647205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5648205042Sthompsa		if (sc->nrxchains == 1)
5649205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5650205042Sthompsa		run_bbp_write(sc, 138, bbp);
5651205042Sthompsa
5652205042Sthompsa		if (sc->mac_rev >= 0x0211) {
5653205042Sthompsa			/* improve power consumption */
5654205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5655205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5656205042Sthompsa		}
5657205042Sthompsa
5658205042Sthompsa		run_rt3070_rf_read(sc, 16, &rf);
5659205042Sthompsa		rf = (rf & ~0x07) | sc->txmixgain_2ghz;
5660205042Sthompsa		run_rt3070_rf_write(sc, 16, rf);
5661205042Sthompsa
5662205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5663257409Skevlo		if (sc->mac_rev >= 0x0211) {
5664257409Skevlo			/* enable DC filter */
5665205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5666205042Sthompsa
5667257409Skevlo			/* improve power consumption */
5668257409Skevlo			run_bbp_read(sc, 31, &bbp);
5669257409Skevlo			run_bbp_write(sc, 31, bbp & ~0x03);
5670257409Skevlo		}
5671257409Skevlo
5672205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5673205042Sthompsa		if (sc->ntxchains == 1)
5674205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5675205042Sthompsa		if (sc->nrxchains == 1)
5676205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5677205042Sthompsa		run_bbp_write(sc, 138, bbp);
5678205042Sthompsa
5679205042Sthompsa		run_write(sc, RT2860_TX_SW_CFG1, 0);
5680205042Sthompsa		if (sc->mac_rev < 0x0211) {
5681205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2,
5682205042Sthompsa			    sc->patch_dac ? 0x2c : 0x0f);
5683205042Sthompsa		} else
5684205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5685205042Sthompsa
5686205042Sthompsa	} else if (sc->mac_ver == 0x3070) {
5687205042Sthompsa		if (sc->mac_rev >= 0x0201) {
5688205042Sthompsa			/* enable DC filter */
5689205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5690205042Sthompsa
5691205042Sthompsa			/* improve power consumption */
5692205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5693205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5694205042Sthompsa		}
5695205042Sthompsa
5696256955Skevlo		if (sc->mac_rev < 0x0201) {
5697205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG1, 0);
5698205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0x2c);
5699205042Sthompsa		} else
5700205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5701205042Sthompsa	}
5702205042Sthompsa
5703205042Sthompsa	/* initialize RF registers from ROM for >=RT3071*/
5704260219Skevlo	if (sc->mac_ver >= 0x3071) {
5705205042Sthompsa		for (i = 0; i < 10; i++) {
5706205042Sthompsa			if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff)
5707205042Sthompsa				continue;
5708205042Sthompsa			run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val);
5709205042Sthompsa		}
5710205042Sthompsa	}
5711205042Sthompsa}
5712205042Sthompsa
5713260219Skevlostatic void
5714260219Skevlorun_rt3593_rf_setup(struct run_softc *sc)
5715260219Skevlo{
5716260219Skevlo	uint8_t bbp, rf;
5717260219Skevlo
5718260219Skevlo	if (sc->mac_rev >= 0x0211) {
5719260219Skevlo		/* Enable DC filter. */
5720260219Skevlo		run_bbp_write(sc, 103, 0xc0);
5721260219Skevlo	}
5722260219Skevlo	run_write(sc, RT2860_TX_SW_CFG1, 0);
5723260219Skevlo	if (sc->mac_rev < 0x0211) {
5724260219Skevlo		run_write(sc, RT2860_TX_SW_CFG2,
5725260219Skevlo		    sc->patch_dac ? 0x2c : 0x0f);
5726260219Skevlo	} else
5727260219Skevlo		run_write(sc, RT2860_TX_SW_CFG2, 0);
5728260219Skevlo
5729260219Skevlo	run_rt3070_rf_read(sc, 50, &rf);
5730260219Skevlo	run_rt3070_rf_write(sc, 50, rf & ~RT3593_TX_LO2);
5731260219Skevlo
5732260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
5733260219Skevlo	rf = (rf & ~(RT3593_TX_LO1 | 0x0c)) |
5734260219Skevlo	    ((sc->txmixgain_2ghz & 0x07) << 2);
5735260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
5736260219Skevlo
5737260219Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5738260219Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5739260219Skevlo
5740260219Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5741260219Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5742260219Skevlo
5743260219Skevlo	run_rt3070_rf_read(sc, 1, &rf);
5744260219Skevlo	run_rt3070_rf_write(sc, 1, rf & ~(RT3070_RF_BLOCK | RT3070_PLL_PD));
5745260219Skevlo
5746260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5747260219Skevlo	rf = (rf & ~0x18) | 0x10;
5748260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
5749260219Skevlo
5750260219Skevlo	/* Apply maximum likelihood detection for 2 stream case. */
5751260219Skevlo	run_bbp_read(sc, 105, &bbp);
5752260219Skevlo	if (sc->nrxchains > 1)
5753260219Skevlo		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5754260219Skevlo
5755260219Skevlo	/* Avoid data lost and CRC error. */
5756260219Skevlo	run_bbp_read(sc, 4, &bbp);
5757260219Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5758260219Skevlo
5759260219Skevlo	run_bbp_write(sc, 92, 0x02);
5760260219Skevlo	run_bbp_write(sc, 82, 0x82);
5761260219Skevlo	run_bbp_write(sc, 106, 0x05);
5762260219Skevlo	run_bbp_write(sc, 104, 0x92);
5763260219Skevlo	run_bbp_write(sc, 88, 0x90);
5764260219Skevlo	run_bbp_write(sc, 148, 0xc8);
5765260219Skevlo	run_bbp_write(sc, 47, 0x48);
5766260219Skevlo	run_bbp_write(sc, 120, 0x50);
5767260219Skevlo
5768260219Skevlo	run_bbp_write(sc, 163, 0x9d);
5769260219Skevlo
5770260219Skevlo	/* SNR mapping. */
5771260219Skevlo	run_bbp_write(sc, 142, 0x06);
5772260219Skevlo	run_bbp_write(sc, 143, 0xa0);
5773260219Skevlo	run_bbp_write(sc, 142, 0x07);
5774260219Skevlo	run_bbp_write(sc, 143, 0xa1);
5775260219Skevlo	run_bbp_write(sc, 142, 0x08);
5776260219Skevlo	run_bbp_write(sc, 143, 0xa2);
5777260219Skevlo
5778260219Skevlo	run_bbp_write(sc, 31, 0x08);
5779260219Skevlo	run_bbp_write(sc, 68, 0x0b);
5780260219Skevlo	run_bbp_write(sc, 105, 0x04);
5781260219Skevlo}
5782260219Skevlo
5783260219Skevlostatic void
5784260219Skevlorun_rt5390_rf_setup(struct run_softc *sc)
5785260219Skevlo{
5786260219Skevlo	uint8_t bbp, rf;
5787260219Skevlo
5788260219Skevlo	if (sc->mac_rev >= 0x0211) {
5789260219Skevlo		/* Enable DC filter. */
5790260219Skevlo		run_bbp_write(sc, 103, 0xc0);
5791260219Skevlo
5792260219Skevlo		if (sc->mac_ver != 0x5592) {
5793260219Skevlo			/* Improve power consumption. */
5794260219Skevlo			run_bbp_read(sc, 31, &bbp);
5795260219Skevlo			run_bbp_write(sc, 31, bbp & ~0x03);
5796260219Skevlo		}
5797260219Skevlo	}
5798260219Skevlo
5799260219Skevlo	run_bbp_read(sc, 138, &bbp);
5800260219Skevlo	if (sc->ntxchains == 1)
5801260219Skevlo		bbp |= 0x20;	/* turn off DAC1 */
5802260219Skevlo	if (sc->nrxchains == 1)
5803260219Skevlo		bbp &= ~0x02;	/* turn off ADC1 */
5804260219Skevlo	run_bbp_write(sc, 138, bbp);
5805260219Skevlo
5806260219Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5807260219Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5808260219Skevlo
5809260219Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5810260219Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5811260219Skevlo
5812260219Skevlo	/* Avoid data lost and CRC error. */
5813260219Skevlo	run_bbp_read(sc, 4, &bbp);
5814260219Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5815260219Skevlo
5816260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5817260219Skevlo	rf = (rf & ~0x18) | 0x10;
5818260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
5819260219Skevlo
5820260219Skevlo	if (sc->mac_ver != 0x5592) {
5821260219Skevlo		run_write(sc, RT2860_TX_SW_CFG1, 0);
5822260219Skevlo		if (sc->mac_rev < 0x0211) {
5823260219Skevlo			run_write(sc, RT2860_TX_SW_CFG2,
5824260219Skevlo			    sc->patch_dac ? 0x2c : 0x0f);
5825260219Skevlo		} else
5826260219Skevlo			run_write(sc, RT2860_TX_SW_CFG2, 0);
5827260219Skevlo	}
5828260219Skevlo}
5829260219Skevlo
5830203134Sthompsastatic int
5831203134Sthompsarun_txrx_enable(struct run_softc *sc)
5832203134Sthompsa{
5833287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5834203134Sthompsa	uint32_t tmp;
5835203134Sthompsa	int error, ntries;
5836203134Sthompsa
5837203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN);
5838203134Sthompsa	for (ntries = 0; ntries < 200; ntries++) {
5839203134Sthompsa		if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0)
5840257955Skevlo			return (error);
5841203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5842203134Sthompsa			break;
5843203134Sthompsa		run_delay(sc, 50);
5844203134Sthompsa	}
5845203134Sthompsa	if (ntries == 200)
5846257955Skevlo		return (ETIMEDOUT);
5847203134Sthompsa
5848203134Sthompsa	run_delay(sc, 50);
5849203134Sthompsa
5850203134Sthompsa	tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE;
5851203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
5852203134Sthompsa
5853203134Sthompsa	/* enable Rx bulk aggregation (set timeout and limit) */
5854203134Sthompsa	tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN |
5855203134Sthompsa	    RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2);
5856203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, tmp);
5857203134Sthompsa
5858203134Sthompsa	/* set Rx filter */
5859203134Sthompsa	tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR;
5860203134Sthompsa	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
5861203134Sthompsa		tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL |
5862203134Sthompsa		    RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK |
5863203134Sthompsa		    RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV |
5864203134Sthompsa		    RT2860_DROP_CFACK | RT2860_DROP_CFEND;
5865203134Sthompsa		if (ic->ic_opmode == IEEE80211_M_STA)
5866203134Sthompsa			tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL;
5867203134Sthompsa	}
5868203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5869203134Sthompsa
5870203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
5871203134Sthompsa	    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
5872203134Sthompsa
5873209917Sthompsa	return (0);
5874203134Sthompsa}
5875203134Sthompsa
5876203134Sthompsastatic void
5877259030Skevlorun_adjust_freq_offset(struct run_softc *sc)
5878257955Skevlo{
5879257955Skevlo	uint8_t rf, tmp;
5880257955Skevlo
5881257955Skevlo	run_rt3070_rf_read(sc, 17, &rf);
5882257955Skevlo	tmp = rf;
5883257955Skevlo	rf = (rf & ~0x7f) | (sc->freq & 0x7f);
5884257955Skevlo	rf = MIN(rf, 0x5f);
5885257955Skevlo
5886257955Skevlo	if (tmp != rf)
5887257955Skevlo		run_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf);
5888257955Skevlo}
5889257955Skevlo
5890257955Skevlostatic void
5891203134Sthompsarun_init_locked(struct run_softc *sc)
5892203134Sthompsa{
5893287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5894287197Sglebius	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
5895203134Sthompsa	uint32_t tmp;
5896203134Sthompsa	uint8_t bbp1, bbp3;
5897203134Sthompsa	int i;
5898203134Sthompsa	int ridx;
5899203134Sthompsa	int ntries;
5900203134Sthompsa
5901209917Sthompsa	if (ic->ic_nrunning > 1)
5902208019Sthompsa		return;
5903208019Sthompsa
5904203134Sthompsa	run_stop(sc);
5905203134Sthompsa
5906233283Sbschmidt	if (run_load_microcode(sc) != 0) {
5907233283Sbschmidt		device_printf(sc->sc_dev, "could not load 8051 microcode\n");
5908233283Sbschmidt		goto fail;
5909233283Sbschmidt	}
5910233283Sbschmidt
5911203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5912203134Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0)
5913203134Sthompsa			goto fail;
5914203134Sthompsa		if (tmp != 0 && tmp != 0xffffffff)
5915203134Sthompsa			break;
5916203134Sthompsa		run_delay(sc, 10);
5917203134Sthompsa	}
5918203134Sthompsa	if (ntries == 100)
5919203134Sthompsa		goto fail;
5920203134Sthompsa
5921203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
5922203134Sthompsa		run_setup_tx_list(sc, &sc->sc_epq[i]);
5923203134Sthompsa
5924287197Sglebius	run_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr);
5925203134Sthompsa
5926203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5927203134Sthompsa		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
5928203134Sthompsa			goto fail;
5929203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5930203134Sthompsa			break;
5931203134Sthompsa		run_delay(sc, 10);
5932203134Sthompsa	}
5933203134Sthompsa	if (ntries == 100) {
5934203138Sthompsa		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
5935203134Sthompsa		goto fail;
5936203134Sthompsa	}
5937203134Sthompsa	tmp &= 0xff0;
5938203134Sthompsa	tmp |= RT2860_TX_WB_DDONE;
5939203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
5940203134Sthompsa
5941203134Sthompsa	/* turn off PME_OEN to solve high-current issue */
5942203134Sthompsa	run_read(sc, RT2860_SYS_CTRL, &tmp);
5943203134Sthompsa	run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN);
5944203134Sthompsa
5945203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
5946203134Sthompsa	    RT2860_BBP_HRST | RT2860_MAC_SRST);
5947203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
5948203134Sthompsa
5949203134Sthompsa	if (run_reset(sc) != 0) {
5950203138Sthompsa		device_printf(sc->sc_dev, "could not reset chipset\n");
5951203134Sthompsa		goto fail;
5952203134Sthompsa	}
5953203134Sthompsa
5954203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
5955203134Sthompsa
5956203134Sthompsa	/* init Tx power for all Tx rates (from EEPROM) */
5957203134Sthompsa	for (ridx = 0; ridx < 5; ridx++) {
5958203134Sthompsa		if (sc->txpow20mhz[ridx] == 0xffffffff)
5959203134Sthompsa			continue;
5960203134Sthompsa		run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]);
5961203134Sthompsa	}
5962203134Sthompsa
5963257955Skevlo	for (i = 0; i < nitems(rt2870_def_mac); i++)
5964203134Sthompsa		run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val);
5965203134Sthompsa	run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273);
5966203134Sthompsa	run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344);
5967203134Sthompsa	run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa);
5968203134Sthompsa
5969259030Skevlo	if (sc->mac_ver >= 0x5390) {
5970259030Skevlo		run_write(sc, RT2860_TX_SW_CFG0,
5971259030Skevlo		    4 << RT2860_DLY_PAPE_EN_SHIFT | 4);
5972259030Skevlo		if (sc->mac_ver >= 0x5392) {
5973259030Skevlo			run_write(sc, RT2860_MAX_LEN_CFG, 0x00002fff);
5974259032Skevlo			if (sc->mac_ver == 0x5592) {
5975259032Skevlo				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcba980);
5976259032Skevlo				run_write(sc, RT2860_TXOP_HLDR_ET, 0x00000082);
5977259032Skevlo			} else {
5978259032Skevlo				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcb4980);
5979259032Skevlo				run_write(sc, RT2860_LG_FBK_CFG0, 0xedcba322);
5980259032Skevlo			}
5981259030Skevlo		}
5982260219Skevlo	} else if (sc->mac_ver == 0x3593) {
5983260219Skevlo		run_write(sc, RT2860_TX_SW_CFG0,
5984260219Skevlo		    4 << RT2860_DLY_PAPE_EN_SHIFT | 2);
5985257955Skevlo	} else if (sc->mac_ver >= 0x3070) {
5986203134Sthompsa		/* set delay of PA_PE assertion to 1us (unit of 0.25us) */
5987203134Sthompsa		run_write(sc, RT2860_TX_SW_CFG0,
5988203134Sthompsa		    4 << RT2860_DLY_PAPE_EN_SHIFT);
5989203134Sthompsa	}
5990203134Sthompsa
5991203134Sthompsa	/* wait while MAC is busy */
5992203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5993203134Sthompsa		if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0)
5994203134Sthompsa			goto fail;
5995203134Sthompsa		if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY)))
5996203134Sthompsa			break;
5997203134Sthompsa		run_delay(sc, 10);
5998203134Sthompsa	}
5999203134Sthompsa	if (ntries == 100)
6000203134Sthompsa		goto fail;
6001203134Sthompsa
6002203134Sthompsa	/* clear Host to MCU mailbox */
6003203134Sthompsa	run_write(sc, RT2860_H2M_BBPAGENT, 0);
6004203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
6005203134Sthompsa	run_delay(sc, 10);
6006203134Sthompsa
6007203134Sthompsa	if (run_bbp_init(sc) != 0) {
6008203138Sthompsa		device_printf(sc->sc_dev, "could not initialize BBP\n");
6009203134Sthompsa		goto fail;
6010203134Sthompsa	}
6011203134Sthompsa
6012203134Sthompsa	/* abort TSF synchronization */
6013203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
6014203134Sthompsa	tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
6015203134Sthompsa	    RT2860_TBTT_TIMER_EN);
6016203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
6017203134Sthompsa
6018203134Sthompsa	/* clear RX WCID search table */
6019203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512);
6020203134Sthompsa	/* clear WCID attribute table */
6021203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32);
6022203134Sthompsa
6023209144Sthompsa	/* hostapd sets a key before init. So, don't clear it. */
6024209917Sthompsa	if (sc->cmdq_key_set != RUN_CMDQ_GO) {
6025209144Sthompsa		/* clear shared key table */
6026209144Sthompsa		run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32);
6027209144Sthompsa		/* clear shared key mode */
6028209144Sthompsa		run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4);
6029209144Sthompsa	}
6030209144Sthompsa
6031203134Sthompsa	run_read(sc, RT2860_US_CYC_CNT, &tmp);
6032203134Sthompsa	tmp = (tmp & ~0xff) | 0x1e;
6033203134Sthompsa	run_write(sc, RT2860_US_CYC_CNT, tmp);
6034203134Sthompsa
6035205042Sthompsa	if (sc->mac_rev != 0x0101)
6036203134Sthompsa		run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f);
6037203134Sthompsa
6038203134Sthompsa	run_write(sc, RT2860_WMM_TXOP0_CFG, 0);
6039203134Sthompsa	run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96);
6040203134Sthompsa
6041203134Sthompsa	/* write vendor-specific BBP values (from EEPROM) */
6042260219Skevlo	if (sc->mac_ver < 0x3593) {
6043257955Skevlo		for (i = 0; i < 10; i++) {
6044257955Skevlo			if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff)
6045257955Skevlo				continue;
6046257955Skevlo			run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val);
6047257955Skevlo		}
6048203134Sthompsa	}
6049203134Sthompsa
6050203134Sthompsa	/* select Main antenna for 1T1R devices */
6051257955Skevlo	if (sc->rf_rev == RT3070_RF_3020 || sc->rf_rev == RT5390_RF_5370)
6052203134Sthompsa		run_set_rx_antenna(sc, 0);
6053203134Sthompsa
6054203134Sthompsa	/* send LEDs operating mode to microcontroller */
6055203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]);
6056203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]);
6057203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]);
6058203134Sthompsa
6059257955Skevlo	if (sc->mac_ver >= 0x5390)
6060257955Skevlo		run_rt5390_rf_init(sc);
6061260219Skevlo	else if (sc->mac_ver == 0x3593)
6062260219Skevlo		run_rt3593_rf_init(sc);
6063257955Skevlo	else if (sc->mac_ver >= 0x3070)
6064205042Sthompsa		run_rt3070_rf_init(sc);
6065205042Sthompsa
6066203134Sthompsa	/* disable non-existing Rx chains */
6067203134Sthompsa	run_bbp_read(sc, 3, &bbp3);
6068203134Sthompsa	bbp3 &= ~(1 << 3 | 1 << 4);
6069203134Sthompsa	if (sc->nrxchains == 2)
6070203134Sthompsa		bbp3 |= 1 << 3;
6071203134Sthompsa	else if (sc->nrxchains == 3)
6072203134Sthompsa		bbp3 |= 1 << 4;
6073203134Sthompsa	run_bbp_write(sc, 3, bbp3);
6074203134Sthompsa
6075203134Sthompsa	/* disable non-existing Tx chains */
6076203134Sthompsa	run_bbp_read(sc, 1, &bbp1);
6077203134Sthompsa	if (sc->ntxchains == 1)
6078203134Sthompsa		bbp1 &= ~(1 << 3 | 1 << 4);
6079203134Sthompsa	run_bbp_write(sc, 1, bbp1);
6080203134Sthompsa
6081260219Skevlo	if (sc->mac_ver >= 0x5390)
6082260219Skevlo		run_rt5390_rf_setup(sc);
6083260219Skevlo	else if (sc->mac_ver == 0x3593)
6084260219Skevlo		run_rt3593_rf_setup(sc);
6085260219Skevlo	else if (sc->mac_ver >= 0x3070)
6086205042Sthompsa		run_rt3070_rf_setup(sc);
6087203134Sthompsa
6088203134Sthompsa	/* select default channel */
6089203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
6090203134Sthompsa
6091203134Sthompsa	/* setup initial protection mode */
6092218492Sbschmidt	run_updateprot_cb(ic);
6093203134Sthompsa
6094203134Sthompsa	/* turn radio LED on */
6095203134Sthompsa	run_set_leds(sc, RT2860_LED_RADIO);
6096203134Sthompsa
6097287197Sglebius	sc->sc_flags |= RUN_RUNNING;
6098208019Sthompsa	sc->cmdq_run = RUN_CMDQ_GO;
6099203134Sthompsa
6100209917Sthompsa	for (i = 0; i != RUN_N_XFER; i++)
6101203134Sthompsa		usbd_xfer_set_stall(sc->sc_xfer[i]);
6102203134Sthompsa
6103203134Sthompsa	usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]);
6104203134Sthompsa
6105203134Sthompsa	if (run_txrx_enable(sc) != 0)
6106203134Sthompsa		goto fail;
6107203134Sthompsa
6108203134Sthompsa	return;
6109203134Sthompsa
6110203134Sthompsafail:
6111203134Sthompsa	run_stop(sc);
6112203134Sthompsa}
6113203134Sthompsa
6114203134Sthompsastatic void
6115203134Sthompsarun_stop(void *arg)
6116203134Sthompsa{
6117203134Sthompsa	struct run_softc *sc = (struct run_softc *)arg;
6118203134Sthompsa	uint32_t tmp;
6119203134Sthompsa	int i;
6120203134Sthompsa	int ntries;
6121203134Sthompsa
6122203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
6123203134Sthompsa
6124287197Sglebius	if (sc->sc_flags & RUN_RUNNING)
6125203134Sthompsa		run_set_leds(sc, 0);	/* turn all LEDs off */
6126203134Sthompsa
6127287197Sglebius	sc->sc_flags &= ~RUN_RUNNING;
6128203134Sthompsa
6129208019Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
6130209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set;
6131208019Sthompsa
6132203134Sthompsa	RUN_UNLOCK(sc);
6133203134Sthompsa
6134203134Sthompsa	for(i = 0; i < RUN_N_XFER; i++)
6135203134Sthompsa		usbd_transfer_drain(sc->sc_xfer[i]);
6136203134Sthompsa
6137203134Sthompsa	RUN_LOCK(sc);
6138203134Sthompsa
6139209917Sthompsa	if (sc->rx_m != NULL) {
6140203134Sthompsa		m_free(sc->rx_m);
6141203134Sthompsa		sc->rx_m = NULL;
6142203134Sthompsa	}
6143203134Sthompsa
6144257955Skevlo	/* Disable Tx/Rx DMA. */
6145257955Skevlo	if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6146257955Skevlo		return;
6147257955Skevlo	tmp &= ~(RT2860_RX_DMA_EN | RT2860_TX_DMA_EN);
6148257955Skevlo	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
6149257955Skevlo
6150258643Shselasky	for (ntries = 0; ntries < 100; ntries++) {
6151257955Skevlo		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6152257955Skevlo			return;
6153257955Skevlo		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
6154257955Skevlo				break;
6155257955Skevlo		run_delay(sc, 10);
6156257955Skevlo	}
6157257955Skevlo	if (ntries == 100) {
6158257955Skevlo		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
6159257955Skevlo		return;
6160257955Skevlo	}
6161257955Skevlo
6162203134Sthompsa	/* disable Tx/Rx */
6163203134Sthompsa	run_read(sc, RT2860_MAC_SYS_CTRL, &tmp);
6164203134Sthompsa	tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
6165203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, tmp);
6166203134Sthompsa
6167203134Sthompsa	/* wait for pending Tx to complete */
6168203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
6169209917Sthompsa		if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0) {
6170203134Sthompsa			DPRINTF("Cannot read Tx queue count\n");
6171203134Sthompsa			break;
6172203134Sthompsa		}
6173209917Sthompsa		if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0) {
6174203134Sthompsa			DPRINTF("All Tx cleared\n");
6175203134Sthompsa			break;
6176203134Sthompsa		}
6177203134Sthompsa		run_delay(sc, 10);
6178203134Sthompsa	}
6179209917Sthompsa	if (ntries >= 100)
6180203134Sthompsa		DPRINTF("There are still pending Tx\n");
6181203134Sthompsa	run_delay(sc, 10);
6182203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
6183203134Sthompsa
6184203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST);
6185203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
6186203134Sthompsa
6187203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
6188203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
6189203134Sthompsa}
6190203134Sthompsa
6191203134Sthompsastatic void
6192257429Shselaskyrun_delay(struct run_softc *sc, u_int ms)
6193203134Sthompsa{
6194203134Sthompsa	usb_pause_mtx(mtx_owned(&sc->sc_mtx) ?
6195203134Sthompsa	    &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms));
6196203134Sthompsa}
6197203134Sthompsa
6198203134Sthompsastatic device_method_t run_methods[] = {
6199203134Sthompsa	/* Device interface */
6200203134Sthompsa	DEVMETHOD(device_probe,		run_match),
6201203134Sthompsa	DEVMETHOD(device_attach,	run_attach),
6202203134Sthompsa	DEVMETHOD(device_detach,	run_detach),
6203246614Shselasky	DEVMETHOD_END
6204203134Sthompsa};
6205203134Sthompsa
6206203134Sthompsastatic driver_t run_driver = {
6207233774Shselasky	.name = "run",
6208233774Shselasky	.methods = run_methods,
6209233774Shselasky	.size = sizeof(struct run_softc)
6210203134Sthompsa};
6211203134Sthompsa
6212203134Sthompsastatic devclass_t run_devclass;
6213203134Sthompsa
6214259812SkevloDRIVER_MODULE(run, uhub, run_driver, run_devclass, run_driver_loaded, NULL);
6215212122SthompsaMODULE_DEPEND(run, wlan, 1, 1, 1);
6216212122SthompsaMODULE_DEPEND(run, usb, 1, 1, 1);
6217212122SthompsaMODULE_DEPEND(run, firmware, 1, 1, 1);
6218212122SthompsaMODULE_VERSION(run, 1);
6219