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: stable/11/sys/dev/usb/wlan/if_run.c 346006 2019-04-07 13:26:45Z avos $");
22203134Sthompsa
23203134Sthompsa/*-
24257955Skevlo * Ralink Technology RT2700U/RT2800U/RT3000U/RT3900E chipset driver.
25203134Sthompsa * http://www.ralinktech.com/
26203134Sthompsa */
27203134Sthompsa
28203134Sthompsa#include <sys/param.h>
29203134Sthompsa#include <sys/sockio.h>
30203134Sthompsa#include <sys/sysctl.h>
31203134Sthompsa#include <sys/lock.h>
32203134Sthompsa#include <sys/mutex.h>
33203134Sthompsa#include <sys/mbuf.h>
34203134Sthompsa#include <sys/kernel.h>
35203134Sthompsa#include <sys/socket.h>
36203134Sthompsa#include <sys/systm.h>
37203134Sthompsa#include <sys/malloc.h>
38203134Sthompsa#include <sys/module.h>
39203134Sthompsa#include <sys/bus.h>
40203134Sthompsa#include <sys/endian.h>
41203134Sthompsa#include <sys/linker.h>
42203134Sthompsa#include <sys/firmware.h>
43203134Sthompsa#include <sys/kdb.h>
44203134Sthompsa
45203134Sthompsa#include <net/bpf.h>
46203134Sthompsa#include <net/if.h>
47257176Sglebius#include <net/if_var.h>
48203134Sthompsa#include <net/if_arp.h>
49203134Sthompsa#include <net/ethernet.h>
50203134Sthompsa#include <net/if_dl.h>
51203134Sthompsa#include <net/if_media.h>
52203134Sthompsa#include <net/if_types.h>
53203134Sthompsa
54203134Sthompsa#include <netinet/in.h>
55203134Sthompsa#include <netinet/in_systm.h>
56203134Sthompsa#include <netinet/in_var.h>
57203134Sthompsa#include <netinet/if_ether.h>
58203134Sthompsa#include <netinet/ip.h>
59203134Sthompsa
60203134Sthompsa#include <net80211/ieee80211_var.h>
61203134Sthompsa#include <net80211/ieee80211_regdomain.h>
62203134Sthompsa#include <net80211/ieee80211_radiotap.h>
63206358Srpaulo#include <net80211/ieee80211_ratectl.h>
64203134Sthompsa
65203134Sthompsa#include <dev/usb/usb.h>
66203134Sthompsa#include <dev/usb/usbdi.h>
67203134Sthompsa#include "usbdevs.h"
68203134Sthompsa
69259546Skevlo#define	USB_DEBUG_VAR	run_debug
70203134Sthompsa#include <dev/usb/usb_debug.h>
71259812Skevlo#include <dev/usb/usb_msctest.h>
72203134Sthompsa
73220235Skevlo#include <dev/usb/wlan/if_runreg.h>
74220235Skevlo#include <dev/usb/wlan/if_runvar.h>
75203134Sthompsa
76207077Sthompsa#ifdef	USB_DEBUG
77259546Skevlo#define	RUN_DEBUG
78203134Sthompsa#endif
79203134Sthompsa
80203134Sthompsa#ifdef	RUN_DEBUG
81203134Sthompsaint run_debug = 0;
82227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, run, CTLFLAG_RW, 0, "USB run");
83276701ShselaskySYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RWTUN, &run_debug, 0,
84203134Sthompsa    "run debug level");
85203134Sthompsa#endif
86203134Sthompsa
87287552Skevlo#define	IEEE80211_HAS_ADDR4(wh)	IEEE80211_IS_DSTODS(wh)
88203134Sthompsa
89208019Sthompsa/*
90208019Sthompsa * Because of LOR in run_key_delete(), use atomic instead.
91208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[].
92208019Sthompsa */
93259546Skevlo#define	RUN_CMDQ_GET(c)	(atomic_fetchadd_32((c), 1) & RUN_CMDQ_MASQ)
94208019Sthompsa
95223486Shselaskystatic const STRUCT_USB_HOST_ID run_devs[] = {
96259546Skevlo#define	RUN_DEV(v,p)	{ USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
97259812Skevlo#define	RUN_DEV_EJECT(v,p)	\
98262465Skevlo	{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RUN_EJECT) }
99262465Skevlo#define	RUN_EJECT	1
100209918Sthompsa    RUN_DEV(ABOCOM,		RT2770),
101209918Sthompsa    RUN_DEV(ABOCOM,		RT2870),
102209918Sthompsa    RUN_DEV(ABOCOM,		RT3070),
103209918Sthompsa    RUN_DEV(ABOCOM,		RT3071),
104209918Sthompsa    RUN_DEV(ABOCOM,		RT3072),
105209918Sthompsa    RUN_DEV(ABOCOM2,		RT2870_1),
106209918Sthompsa    RUN_DEV(ACCTON,		RT2770),
107209918Sthompsa    RUN_DEV(ACCTON,		RT2870_1),
108209918Sthompsa    RUN_DEV(ACCTON,		RT2870_2),
109209918Sthompsa    RUN_DEV(ACCTON,		RT2870_3),
110209918Sthompsa    RUN_DEV(ACCTON,		RT2870_4),
111209918Sthompsa    RUN_DEV(ACCTON,		RT2870_5),
112209918Sthompsa    RUN_DEV(ACCTON,		RT3070),
113209918Sthompsa    RUN_DEV(ACCTON,		RT3070_1),
114209918Sthompsa    RUN_DEV(ACCTON,		RT3070_2),
115209918Sthompsa    RUN_DEV(ACCTON,		RT3070_3),
116209918Sthompsa    RUN_DEV(ACCTON,		RT3070_4),
117209918Sthompsa    RUN_DEV(ACCTON,		RT3070_5),
118209918Sthompsa    RUN_DEV(AIRTIES,		RT3070),
119209918Sthompsa    RUN_DEV(ALLWIN,		RT2070),
120209918Sthompsa    RUN_DEV(ALLWIN,		RT2770),
121209918Sthompsa    RUN_DEV(ALLWIN,		RT2870),
122209918Sthompsa    RUN_DEV(ALLWIN,		RT3070),
123209918Sthompsa    RUN_DEV(ALLWIN,		RT3071),
124209918Sthompsa    RUN_DEV(ALLWIN,		RT3072),
125209918Sthompsa    RUN_DEV(ALLWIN,		RT3572),
126209918Sthompsa    RUN_DEV(AMIGO,		RT2870_1),
127209918Sthompsa    RUN_DEV(AMIGO,		RT2870_2),
128209918Sthompsa    RUN_DEV(AMIT,		CGWLUSB2GNR),
129209918Sthompsa    RUN_DEV(AMIT,		RT2870_1),
130209918Sthompsa    RUN_DEV(AMIT2,		RT2870),
131209918Sthompsa    RUN_DEV(ASUS,		RT2870_1),
132209918Sthompsa    RUN_DEV(ASUS,		RT2870_2),
133209918Sthompsa    RUN_DEV(ASUS,		RT2870_3),
134209918Sthompsa    RUN_DEV(ASUS,		RT2870_4),
135209918Sthompsa    RUN_DEV(ASUS,		RT2870_5),
136209918Sthompsa    RUN_DEV(ASUS,		USBN13),
137209918Sthompsa    RUN_DEV(ASUS,		RT3070_1),
138260219Skevlo    RUN_DEV(ASUS,		USBN66),
139239358Shselasky    RUN_DEV(ASUS,		USB_N53),
140209918Sthompsa    RUN_DEV(ASUS2,		USBN11),
141209918Sthompsa    RUN_DEV(AZUREWAVE,		RT2870_1),
142209918Sthompsa    RUN_DEV(AZUREWAVE,		RT2870_2),
143209918Sthompsa    RUN_DEV(AZUREWAVE,		RT3070_1),
144209918Sthompsa    RUN_DEV(AZUREWAVE,		RT3070_2),
145209918Sthompsa    RUN_DEV(AZUREWAVE,		RT3070_3),
146260219Skevlo    RUN_DEV(BELKIN,		F9L1103),
147209918Sthompsa    RUN_DEV(BELKIN,		F5D8053V3),
148209918Sthompsa    RUN_DEV(BELKIN,		F5D8055),
149226534Shselasky    RUN_DEV(BELKIN,		F5D8055V2),
150209918Sthompsa    RUN_DEV(BELKIN,		F6D4050V1),
151256500Shselasky    RUN_DEV(BELKIN,		F6D4050V2),
152209918Sthompsa    RUN_DEV(BELKIN,		RT2870_1),
153209918Sthompsa    RUN_DEV(BELKIN,		RT2870_2),
154226534Shselasky    RUN_DEV(CISCOLINKSYS,	AE1000),
155209918Sthompsa    RUN_DEV(CISCOLINKSYS2,	RT3070),
156209918Sthompsa    RUN_DEV(CISCOLINKSYS3,	RT3070),
157209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_1),
158209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_2),
159209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_3),
160209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_4),
161209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_5),
162209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_6),
163209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_7),
164209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_8),
165209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT3070_1),
166209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT3070_2),
167209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	VIGORN61),
168209918Sthompsa    RUN_DEV(COREGA,		CGWLUSB300GNM),
169209918Sthompsa    RUN_DEV(COREGA,		RT2870_1),
170209918Sthompsa    RUN_DEV(COREGA,		RT2870_2),
171209918Sthompsa    RUN_DEV(COREGA,		RT2870_3),
172209918Sthompsa    RUN_DEV(COREGA,		RT3070),
173209918Sthompsa    RUN_DEV(CYBERTAN,		RT2870),
174209918Sthompsa    RUN_DEV(DLINK,		RT2870),
175209918Sthompsa    RUN_DEV(DLINK,		RT3072),
176255238Sbr    RUN_DEV(DLINK,		DWA127),
177257955Skevlo    RUN_DEV(DLINK,		DWA140B3),
178259032Skevlo    RUN_DEV(DLINK,		DWA160B2),
179267089Skevlo    RUN_DEV(DLINK,		DWA140D1),
180260219Skevlo    RUN_DEV(DLINK,		DWA162),
181209918Sthompsa    RUN_DEV(DLINK2,		DWA130),
182209918Sthompsa    RUN_DEV(DLINK2,		RT2870_1),
183209918Sthompsa    RUN_DEV(DLINK2,		RT2870_2),
184209918Sthompsa    RUN_DEV(DLINK2,		RT3070_1),
185209918Sthompsa    RUN_DEV(DLINK2,		RT3070_2),
186209918Sthompsa    RUN_DEV(DLINK2,		RT3070_3),
187209918Sthompsa    RUN_DEV(DLINK2,		RT3070_4),
188209918Sthompsa    RUN_DEV(DLINK2,		RT3070_5),
189209918Sthompsa    RUN_DEV(DLINK2,		RT3072),
190209918Sthompsa    RUN_DEV(DLINK2,		RT3072_1),
191209918Sthompsa    RUN_DEV(EDIMAX,		EW7717),
192209918Sthompsa    RUN_DEV(EDIMAX,		EW7718),
193260219Skevlo    RUN_DEV(EDIMAX,		EW7733UND),
194209918Sthompsa    RUN_DEV(EDIMAX,		RT2870_1),
195209918Sthompsa    RUN_DEV(ENCORE,		RT3070_1),
196209918Sthompsa    RUN_DEV(ENCORE,		RT3070_2),
197209918Sthompsa    RUN_DEV(ENCORE,		RT3070_3),
198209918Sthompsa    RUN_DEV(GIGABYTE,		GNWB31N),
199209918Sthompsa    RUN_DEV(GIGABYTE,		GNWB32L),
200209918Sthompsa    RUN_DEV(GIGABYTE,		RT2870_1),
201209918Sthompsa    RUN_DEV(GIGASET,		RT3070_1),
202209918Sthompsa    RUN_DEV(GIGASET,		RT3070_2),
203209918Sthompsa    RUN_DEV(GUILLEMOT,		HWNU300),
204209918Sthompsa    RUN_DEV(HAWKING,		HWUN2),
205209918Sthompsa    RUN_DEV(HAWKING,		RT2870_1),
206209918Sthompsa    RUN_DEV(HAWKING,		RT2870_2),
207209918Sthompsa    RUN_DEV(HAWKING,		RT3070),
208209918Sthompsa    RUN_DEV(IODATA,		RT3072_1),
209209918Sthompsa    RUN_DEV(IODATA,		RT3072_2),
210209918Sthompsa    RUN_DEV(IODATA,		RT3072_3),
211209918Sthompsa    RUN_DEV(IODATA,		RT3072_4),
212209918Sthompsa    RUN_DEV(LINKSYS4,		RT3070),
213209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB100),
214209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB54GCV3),
215209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB600N),
216209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB600NV2),
217209918Sthompsa    RUN_DEV(LOGITEC,		RT2870_1),
218209918Sthompsa    RUN_DEV(LOGITEC,		RT2870_2),
219209918Sthompsa    RUN_DEV(LOGITEC,		RT2870_3),
220230333Shselasky    RUN_DEV(LOGITEC,		LANW300NU2),
221238274Shrs    RUN_DEV(LOGITEC,		LANW150NU2),
222248458Shselasky    RUN_DEV(LOGITEC,		LANW300NU2S),
223281745Skevlo    RUN_DEV(MELCO,		WLIUCG300HP),
224209918Sthompsa    RUN_DEV(MELCO,		RT2870_2),
225209918Sthompsa    RUN_DEV(MELCO,		WLIUCAG300N),
226209918Sthompsa    RUN_DEV(MELCO,		WLIUCG300N),
227219257Sdaichi    RUN_DEV(MELCO,		WLIUCG301N),
228209918Sthompsa    RUN_DEV(MELCO,		WLIUCGN),
229227781Shselasky    RUN_DEV(MELCO,		WLIUCGNM),
230281745Skevlo    RUN_DEV(MELCO,		WLIUCG300HPV1),
231238274Shrs    RUN_DEV(MELCO,		WLIUCGNM2),
232209918Sthompsa    RUN_DEV(MOTOROLA4,		RT2770),
233209918Sthompsa    RUN_DEV(MOTOROLA4,		RT3070),
234209918Sthompsa    RUN_DEV(MSI,		RT3070_1),
235209918Sthompsa    RUN_DEV(MSI,		RT3070_2),
236209918Sthompsa    RUN_DEV(MSI,		RT3070_3),
237209918Sthompsa    RUN_DEV(MSI,		RT3070_4),
238209918Sthompsa    RUN_DEV(MSI,		RT3070_5),
239209918Sthompsa    RUN_DEV(MSI,		RT3070_6),
240209918Sthompsa    RUN_DEV(MSI,		RT3070_7),
241209918Sthompsa    RUN_DEV(MSI,		RT3070_8),
242209918Sthompsa    RUN_DEV(MSI,		RT3070_9),
243209918Sthompsa    RUN_DEV(MSI,		RT3070_10),
244209918Sthompsa    RUN_DEV(MSI,		RT3070_11),
245289028Sgavin    RUN_DEV(NETGEAR,		WNDA4100),
246209918Sthompsa    RUN_DEV(OVISLINK,		RT3072),
247209918Sthompsa    RUN_DEV(PARA,		RT3070),
248209918Sthompsa    RUN_DEV(PEGATRON,		RT2870),
249209918Sthompsa    RUN_DEV(PEGATRON,		RT3070),
250209918Sthompsa    RUN_DEV(PEGATRON,		RT3070_2),
251209918Sthompsa    RUN_DEV(PEGATRON,		RT3070_3),
252209918Sthompsa    RUN_DEV(PHILIPS,		RT2870),
253209918Sthompsa    RUN_DEV(PLANEX2,		GWUS300MINIS),
254209918Sthompsa    RUN_DEV(PLANEX2,		GWUSMICRON),
255209918Sthompsa    RUN_DEV(PLANEX2,		RT2870),
256209918Sthompsa    RUN_DEV(PLANEX2,		RT3070),
257209918Sthompsa    RUN_DEV(QCOM,		RT2870),
258209918Sthompsa    RUN_DEV(QUANTA,		RT3070),
259209918Sthompsa    RUN_DEV(RALINK,		RT2070),
260209918Sthompsa    RUN_DEV(RALINK,		RT2770),
261209918Sthompsa    RUN_DEV(RALINK,		RT2870),
262209918Sthompsa    RUN_DEV(RALINK,		RT3070),
263209918Sthompsa    RUN_DEV(RALINK,		RT3071),
264209918Sthompsa    RUN_DEV(RALINK,		RT3072),
265209918Sthompsa    RUN_DEV(RALINK,		RT3370),
266209918Sthompsa    RUN_DEV(RALINK,		RT3572),
267260219Skevlo    RUN_DEV(RALINK,		RT3573),
268257955Skevlo    RUN_DEV(RALINK,		RT5370),
269259032Skevlo    RUN_DEV(RALINK,		RT5572),
270209918Sthompsa    RUN_DEV(RALINK,		RT8070),
271226534Shselasky    RUN_DEV(SAMSUNG,		WIS09ABGN),
272209918Sthompsa    RUN_DEV(SAMSUNG2,		RT2870_1),
273209918Sthompsa    RUN_DEV(SENAO,		RT2870_1),
274209918Sthompsa    RUN_DEV(SENAO,		RT2870_2),
275209918Sthompsa    RUN_DEV(SENAO,		RT2870_3),
276209918Sthompsa    RUN_DEV(SENAO,		RT2870_4),
277209918Sthompsa    RUN_DEV(SENAO,		RT3070),
278209918Sthompsa    RUN_DEV(SENAO,		RT3071),
279209918Sthompsa    RUN_DEV(SENAO,		RT3072_1),
280209918Sthompsa    RUN_DEV(SENAO,		RT3072_2),
281209918Sthompsa    RUN_DEV(SENAO,		RT3072_3),
282209918Sthompsa    RUN_DEV(SENAO,		RT3072_4),
283209918Sthompsa    RUN_DEV(SENAO,		RT3072_5),
284209918Sthompsa    RUN_DEV(SITECOMEU,		RT2770),
285209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_1),
286209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_2),
287209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_3),
288209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_4),
289209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070),
290209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070_2),
291209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070_3),
292209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070_4),
293209918Sthompsa    RUN_DEV(SITECOMEU,		RT3071),
294209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_1),
295209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_2),
296209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_3),
297209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_4),
298209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_5),
299209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_6),
300209918Sthompsa    RUN_DEV(SITECOMEU,		WL608),
301209918Sthompsa    RUN_DEV(SPARKLAN,		RT2870_1),
302209918Sthompsa    RUN_DEV(SPARKLAN,		RT3070),
303209918Sthompsa    RUN_DEV(SWEEX2,		LW153),
304209918Sthompsa    RUN_DEV(SWEEX2,		LW303),
305209918Sthompsa    RUN_DEV(SWEEX2,		LW313),
306209918Sthompsa    RUN_DEV(TOSHIBA,		RT3070),
307209918Sthompsa    RUN_DEV(UMEDIA,		RT2870_1),
308209918Sthompsa    RUN_DEV(ZCOM,		RT2870_1),
309209918Sthompsa    RUN_DEV(ZCOM,		RT2870_2),
310209918Sthompsa    RUN_DEV(ZINWELL,		RT2870_1),
311209918Sthompsa    RUN_DEV(ZINWELL,		RT2870_2),
312209918Sthompsa    RUN_DEV(ZINWELL,		RT3070),
313209918Sthompsa    RUN_DEV(ZINWELL,		RT3072_1),
314209918Sthompsa    RUN_DEV(ZINWELL,		RT3072_2),
315209918Sthompsa    RUN_DEV(ZYXEL,		RT2870_1),
316209918Sthompsa    RUN_DEV(ZYXEL,		RT2870_2),
317263985Shselasky    RUN_DEV(ZYXEL,		RT3070),
318262465Skevlo    RUN_DEV_EJECT(ZYXEL,	NWD2705),
319259812Skevlo    RUN_DEV_EJECT(RALINK,	RT_STOR),
320259812Skevlo#undef RUN_DEV_EJECT
321209918Sthompsa#undef RUN_DEV
322203134Sthompsa};
323203134Sthompsa
324203134Sthompsastatic device_probe_t	run_match;
325203134Sthompsastatic device_attach_t	run_attach;
326203134Sthompsastatic device_detach_t	run_detach;
327203134Sthompsa
328203134Sthompsastatic usb_callback_t	run_bulk_rx_callback;
329203134Sthompsastatic usb_callback_t	run_bulk_tx_callback0;
330203134Sthompsastatic usb_callback_t	run_bulk_tx_callback1;
331203134Sthompsastatic usb_callback_t	run_bulk_tx_callback2;
332203134Sthompsastatic usb_callback_t	run_bulk_tx_callback3;
333203134Sthompsastatic usb_callback_t	run_bulk_tx_callback4;
334203134Sthompsastatic usb_callback_t	run_bulk_tx_callback5;
335203134Sthompsa
336259812Skevlostatic void	run_autoinst(void *, struct usb_device *,
337259812Skevlo		    struct usb_attach_arg *);
338259812Skevlostatic int	run_driver_loaded(struct module *, int, void *);
339203134Sthompsastatic void	run_bulk_tx_callbackN(struct usb_xfer *xfer,
340257429Shselasky		    usb_error_t error, u_int index);
341203134Sthompsastatic struct ieee80211vap *run_vap_create(struct ieee80211com *,
342228621Sbschmidt		    const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
343228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN],
344228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN]);
345203134Sthompsastatic void	run_vap_delete(struct ieee80211vap *);
346208019Sthompsastatic void	run_cmdq_cb(void *, int);
347203134Sthompsastatic void	run_setup_tx_list(struct run_softc *,
348203134Sthompsa		    struct run_endpoint_queue *);
349203134Sthompsastatic void	run_unsetup_tx_list(struct run_softc *,
350203134Sthompsa		    struct run_endpoint_queue *);
351203134Sthompsastatic int	run_load_microcode(struct run_softc *);
352203134Sthompsastatic int	run_reset(struct run_softc *);
353203134Sthompsastatic usb_error_t run_do_request(struct run_softc *,
354203134Sthompsa		    struct usb_device_request *, void *);
355203134Sthompsastatic int	run_read(struct run_softc *, uint16_t, uint32_t *);
356203134Sthompsastatic int	run_read_region_1(struct run_softc *, uint16_t, uint8_t *, int);
357203134Sthompsastatic int	run_write_2(struct run_softc *, uint16_t, uint16_t);
358203134Sthompsastatic int	run_write(struct run_softc *, uint16_t, uint32_t);
359203134Sthompsastatic int	run_write_region_1(struct run_softc *, uint16_t,
360203134Sthompsa		    const uint8_t *, int);
361203134Sthompsastatic int	run_set_region_4(struct run_softc *, uint16_t, uint32_t, int);
362259544Skevlostatic int	run_efuse_read(struct run_softc *, uint16_t, uint16_t *, int);
363203134Sthompsastatic int	run_efuse_read_2(struct run_softc *, uint16_t, uint16_t *);
364203134Sthompsastatic int	run_eeprom_read_2(struct run_softc *, uint16_t, uint16_t *);
365258733Skevlostatic int	run_rt2870_rf_write(struct run_softc *, uint32_t);
366203134Sthompsastatic int	run_rt3070_rf_read(struct run_softc *, uint8_t, uint8_t *);
367203134Sthompsastatic int	run_rt3070_rf_write(struct run_softc *, uint8_t, uint8_t);
368203134Sthompsastatic int	run_bbp_read(struct run_softc *, uint8_t, uint8_t *);
369203134Sthompsastatic int	run_bbp_write(struct run_softc *, uint8_t, uint8_t);
370203134Sthompsastatic int	run_mcu_cmd(struct run_softc *, uint8_t, uint16_t);
371257955Skevlostatic const char *run_get_rf(uint16_t);
372260219Skevlostatic void	run_rt3593_get_txpower(struct run_softc *);
373260219Skevlostatic void	run_get_txpower(struct run_softc *);
374203134Sthompsastatic int	run_read_eeprom(struct run_softc *);
375203134Sthompsastatic struct ieee80211_node *run_node_alloc(struct ieee80211vap *,
376203134Sthompsa			    const uint8_t mac[IEEE80211_ADDR_LEN]);
377203134Sthompsastatic int	run_media_change(struct ifnet *);
378203134Sthompsastatic int	run_newstate(struct ieee80211vap *, enum ieee80211_state, int);
379203134Sthompsastatic int	run_wme_update(struct ieee80211com *);
380208019Sthompsastatic void	run_key_set_cb(void *);
381288635Sadrianstatic int	run_key_set(struct ieee80211vap *, struct ieee80211_key *);
382208019Sthompsastatic void	run_key_delete_cb(void *);
383208019Sthompsastatic int	run_key_delete(struct ieee80211vap *, struct ieee80211_key *);
384206358Srpaulostatic void	run_ratectl_to(void *);
385206358Srpaulostatic void	run_ratectl_cb(void *, int);
386208019Sthompsastatic void	run_drain_fifo(void *);
387203134Sthompsastatic void	run_iter_func(void *, struct ieee80211_node *);
388208019Sthompsastatic void	run_newassoc_cb(void *);
389203134Sthompsastatic void	run_newassoc(struct ieee80211_node *, int);
390288603Sadrianstatic void	run_recv_mgmt(struct ieee80211_node *, struct mbuf *, int,
391288603Sadrian		    const struct ieee80211_rx_stats *, int, int);
392203134Sthompsastatic void	run_rx_frame(struct run_softc *, struct mbuf *, uint32_t);
393203134Sthompsastatic void	run_tx_free(struct run_endpoint_queue *pq,
394203134Sthompsa		    struct run_tx_data *, int);
395208019Sthompsastatic void	run_set_tx_desc(struct run_softc *, struct run_tx_data *);
396203134Sthompsastatic int	run_tx(struct run_softc *, struct mbuf *,
397203134Sthompsa		    struct ieee80211_node *);
398203134Sthompsastatic int	run_tx_mgt(struct run_softc *, struct mbuf *,
399203134Sthompsa		    struct ieee80211_node *);
400203134Sthompsastatic int	run_sendprot(struct run_softc *, const struct mbuf *,
401203134Sthompsa		    struct ieee80211_node *, int, int);
402203134Sthompsastatic int	run_tx_param(struct run_softc *, struct mbuf *,
403203134Sthompsa		    struct ieee80211_node *,
404203134Sthompsa		    const struct ieee80211_bpf_params *);
405203134Sthompsastatic int	run_raw_xmit(struct ieee80211_node *, struct mbuf *,
406203134Sthompsa		    const struct ieee80211_bpf_params *);
407287197Sglebiusstatic int	run_transmit(struct ieee80211com *, struct mbuf *);
408287197Sglebiusstatic void	run_start(struct run_softc *);
409287197Sglebiusstatic void	run_parent(struct ieee80211com *);
410259544Skevlostatic void	run_iq_calib(struct run_softc *, u_int);
411205042Sthompsastatic void	run_set_agc(struct run_softc *, uint8_t);
412203134Sthompsastatic void	run_select_chan_group(struct run_softc *, int);
413203134Sthompsastatic void	run_set_rx_antenna(struct run_softc *, int);
414203134Sthompsastatic void	run_rt2870_set_chan(struct run_softc *, u_int);
415203134Sthompsastatic void	run_rt3070_set_chan(struct run_softc *, u_int);
416205042Sthompsastatic void	run_rt3572_set_chan(struct run_softc *, u_int);
417260219Skevlostatic void	run_rt3593_set_chan(struct run_softc *, u_int);
418257955Skevlostatic void	run_rt5390_set_chan(struct run_softc *, u_int);
419259032Skevlostatic void	run_rt5592_set_chan(struct run_softc *, u_int);
420203134Sthompsastatic int	run_set_chan(struct run_softc *, struct ieee80211_channel *);
421203134Sthompsastatic void	run_set_channel(struct ieee80211com *);
422300748Savosstatic void	run_getradiocaps(struct ieee80211com *, int, int *,
423300748Savos		    struct ieee80211_channel[]);
424203134Sthompsastatic void	run_scan_start(struct ieee80211com *);
425203134Sthompsastatic void	run_scan_end(struct ieee80211com *);
426203134Sthompsastatic void	run_update_beacon(struct ieee80211vap *, int);
427208019Sthompsastatic void	run_update_beacon_cb(void *);
428203134Sthompsastatic void	run_updateprot(struct ieee80211com *);
429218492Sbschmidtstatic void	run_updateprot_cb(void *);
430208019Sthompsastatic void	run_usb_timeout_cb(void *);
431203134Sthompsastatic void	run_reset_livelock(struct run_softc *);
432203134Sthompsastatic void	run_enable_tsf_sync(struct run_softc *);
433287555Skevlostatic void	run_enable_tsf(struct run_softc *);
434345752Savosstatic void	run_disable_tsf(struct run_softc *);
435287554Skevlostatic void	run_get_tsf(struct run_softc *, uint64_t *);
436203134Sthompsastatic void	run_enable_mrr(struct run_softc *);
437203134Sthompsastatic void	run_set_txpreamble(struct run_softc *);
438203134Sthompsastatic void	run_set_basicrates(struct run_softc *);
439203134Sthompsastatic void	run_set_leds(struct run_softc *, uint16_t);
440203134Sthompsastatic void	run_set_bssid(struct run_softc *, const uint8_t *);
441203134Sthompsastatic void	run_set_macaddr(struct run_softc *, const uint8_t *);
442283540Sglebiusstatic void	run_updateslot(struct ieee80211com *);
443218492Sbschmidtstatic void	run_updateslot_cb(void *);
444283540Sglebiusstatic void	run_update_mcast(struct ieee80211com *);
445203134Sthompsastatic int8_t	run_rssi2dbm(struct run_softc *, uint8_t, uint8_t);
446283540Sglebiusstatic void	run_update_promisc_locked(struct run_softc *);
447283540Sglebiusstatic void	run_update_promisc(struct ieee80211com *);
448257955Skevlostatic void	run_rt5390_bbp_init(struct run_softc *);
449203134Sthompsastatic int	run_bbp_init(struct run_softc *);
450203134Sthompsastatic int	run_rt3070_rf_init(struct run_softc *);
451260219Skevlostatic void	run_rt3593_rf_init(struct run_softc *);
452257955Skevlostatic void	run_rt5390_rf_init(struct run_softc *);
453203134Sthompsastatic int	run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t,
454203134Sthompsa		    uint8_t *);
455205042Sthompsastatic void	run_rt3070_rf_setup(struct run_softc *);
456260219Skevlostatic void	run_rt3593_rf_setup(struct run_softc *);
457260219Skevlostatic void	run_rt5390_rf_setup(struct run_softc *);
458203134Sthompsastatic int	run_txrx_enable(struct run_softc *);
459257955Skevlostatic void	run_adjust_freq_offset(struct run_softc *);
460203134Sthompsastatic void	run_init_locked(struct run_softc *);
461203134Sthompsastatic void	run_stop(void *);
462257429Shselaskystatic void	run_delay(struct run_softc *, u_int);
463203134Sthompsa
464259812Skevlostatic eventhandler_tag run_etag;
465259812Skevlo
466259544Skevlostatic const struct rt2860_rate {
467259544Skevlo	uint8_t		rate;
468259544Skevlo	uint8_t		mcs;
469259544Skevlo	enum		ieee80211_phytype phy;
470259544Skevlo	uint8_t		ctl_ridx;
471259544Skevlo	uint16_t	sp_ack_dur;
472259544Skevlo	uint16_t	lp_ack_dur;
473259544Skevlo} rt2860_rates[] = {
474259544Skevlo	{   2, 0, IEEE80211_T_DS,   0, 314, 314 },
475259544Skevlo	{   4, 1, IEEE80211_T_DS,   1, 258, 162 },
476259544Skevlo	{  11, 2, IEEE80211_T_DS,   2, 223, 127 },
477259544Skevlo	{  22, 3, IEEE80211_T_DS,   3, 213, 117 },
478259544Skevlo	{  12, 0, IEEE80211_T_OFDM, 4,  60,  60 },
479259544Skevlo	{  18, 1, IEEE80211_T_OFDM, 4,  52,  52 },
480259544Skevlo	{  24, 2, IEEE80211_T_OFDM, 6,  48,  48 },
481259544Skevlo	{  36, 3, IEEE80211_T_OFDM, 6,  44,  44 },
482259544Skevlo	{  48, 4, IEEE80211_T_OFDM, 8,  44,  44 },
483259544Skevlo	{  72, 5, IEEE80211_T_OFDM, 8,  40,  40 },
484259544Skevlo	{  96, 6, IEEE80211_T_OFDM, 8,  40,  40 },
485259544Skevlo	{ 108, 7, IEEE80211_T_OFDM, 8,  40,  40 }
486259544Skevlo};
487259544Skevlo
488203134Sthompsastatic const struct {
489208019Sthompsa	uint16_t	reg;
490203134Sthompsa	uint32_t	val;
491203134Sthompsa} rt2870_def_mac[] = {
492203134Sthompsa	RT2870_DEF_MAC
493203134Sthompsa};
494203134Sthompsa
495203134Sthompsastatic const struct {
496203134Sthompsa	uint8_t	reg;
497203134Sthompsa	uint8_t	val;
498203134Sthompsa} rt2860_def_bbp[] = {
499203134Sthompsa	RT2860_DEF_BBP
500257955Skevlo},rt5390_def_bbp[] = {
501257955Skevlo	RT5390_DEF_BBP
502259032Skevlo},rt5592_def_bbp[] = {
503259032Skevlo	RT5592_DEF_BBP
504203134Sthompsa};
505203134Sthompsa
506259032Skevlo/*
507259032Skevlo * Default values for BBP register R196 for RT5592.
508259032Skevlo */
509259032Skevlostatic const uint8_t rt5592_bbp_r196[] = {
510259032Skevlo	0xe0, 0x1f, 0x38, 0x32, 0x08, 0x28, 0x19, 0x0a, 0xff, 0x00,
511259032Skevlo	0x16, 0x10, 0x10, 0x0b, 0x36, 0x2c, 0x26, 0x24, 0x42, 0x36,
512259032Skevlo	0x30, 0x2d, 0x4c, 0x46, 0x3d, 0x40, 0x3e, 0x42, 0x3d, 0x40,
513259032Skevlo	0x3c, 0x34, 0x2c, 0x2f, 0x3c, 0x35, 0x2e, 0x2a, 0x49, 0x41,
514259032Skevlo	0x36, 0x31, 0x30, 0x30, 0x0e, 0x0d, 0x28, 0x21, 0x1c, 0x16,
515259032Skevlo	0x50, 0x4a, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00,
516259032Skevlo	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
517259032Skevlo	0x00, 0x00, 0x7d, 0x14, 0x32, 0x2c, 0x36, 0x4c, 0x43, 0x2c,
518259032Skevlo	0x2e, 0x36, 0x30, 0x6e
519259032Skevlo};
520259032Skevlo
521203134Sthompsastatic const struct rfprog {
522203134Sthompsa	uint8_t		chan;
523203134Sthompsa	uint32_t	r1, r2, r3, r4;
524203134Sthompsa} rt2860_rf2850[] = {
525203134Sthompsa	RT2860_RF2850
526203134Sthompsa};
527203134Sthompsa
528203134Sthompsastruct {
529203134Sthompsa	uint8_t	n, r, k;
530205042Sthompsa} rt3070_freqs[] = {
531205042Sthompsa	RT3070_RF3052
532203134Sthompsa};
533203134Sthompsa
534259032Skevlostatic const struct rt5592_freqs {
535259032Skevlo	uint16_t	n;
536259032Skevlo	uint8_t		k, m, r;
537259032Skevlo} rt5592_freqs_20mhz[] = {
538259032Skevlo	RT5592_RF5592_20MHZ
539259032Skevlo},rt5592_freqs_40mhz[] = {
540259032Skevlo	RT5592_RF5592_40MHZ
541259032Skevlo};
542259032Skevlo
543203134Sthompsastatic const struct {
544203134Sthompsa	uint8_t	reg;
545203134Sthompsa	uint8_t	val;
546203134Sthompsa} rt3070_def_rf[] = {
547203134Sthompsa	RT3070_DEF_RF
548205042Sthompsa},rt3572_def_rf[] = {
549205042Sthompsa	RT3572_DEF_RF
550260219Skevlo},rt3593_def_rf[] = {
551260219Skevlo	RT3593_DEF_RF
552257955Skevlo},rt5390_def_rf[] = {
553257955Skevlo	RT5390_DEF_RF
554257955Skevlo},rt5392_def_rf[] = {
555257955Skevlo	RT5392_DEF_RF
556259032Skevlo},rt5592_def_rf[] = {
557259032Skevlo	RT5592_DEF_RF
558259032Skevlo},rt5592_2ghz_def_rf[] = {
559259032Skevlo	RT5592_2GHZ_DEF_RF
560259032Skevlo},rt5592_5ghz_def_rf[] = {
561259032Skevlo	RT5592_5GHZ_DEF_RF
562203134Sthompsa};
563203134Sthompsa
564259032Skevlostatic const struct {
565259032Skevlo	u_int	firstchan;
566259032Skevlo	u_int	lastchan;
567259032Skevlo	uint8_t	reg;
568259032Skevlo	uint8_t	val;
569259032Skevlo} rt5592_chan_5ghz[] = {
570259032Skevlo	RT5592_CHAN_5GHZ
571259032Skevlo};
572259032Skevlo
573203134Sthompsastatic const struct usb_config run_config[RUN_N_XFER] = {
574203134Sthompsa    [RUN_BULK_TX_BE] = {
575203134Sthompsa	.type = UE_BULK,
576203134Sthompsa	.endpoint = UE_ADDR_ANY,
577203134Sthompsa	.ep_index = 0,
578203134Sthompsa	.direction = UE_DIR_OUT,
579203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
580203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
581203134Sthompsa	.callback = run_bulk_tx_callback0,
582203134Sthompsa	.timeout = 5000,	/* ms */
583203134Sthompsa    },
584203134Sthompsa    [RUN_BULK_TX_BK] = {
585203134Sthompsa	.type = UE_BULK,
586203134Sthompsa	.endpoint = UE_ADDR_ANY,
587203134Sthompsa	.direction = UE_DIR_OUT,
588203134Sthompsa	.ep_index = 1,
589203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
590203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
591203134Sthompsa	.callback = run_bulk_tx_callback1,
592203134Sthompsa	.timeout = 5000,	/* ms */
593203134Sthompsa    },
594203134Sthompsa    [RUN_BULK_TX_VI] = {
595203134Sthompsa	.type = UE_BULK,
596203134Sthompsa	.endpoint = UE_ADDR_ANY,
597203134Sthompsa	.direction = UE_DIR_OUT,
598203134Sthompsa	.ep_index = 2,
599203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
600203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
601203134Sthompsa	.callback = run_bulk_tx_callback2,
602203134Sthompsa	.timeout = 5000,	/* ms */
603203134Sthompsa    },
604203134Sthompsa    [RUN_BULK_TX_VO] = {
605203134Sthompsa	.type = UE_BULK,
606203134Sthompsa	.endpoint = UE_ADDR_ANY,
607203134Sthompsa	.direction = UE_DIR_OUT,
608203134Sthompsa	.ep_index = 3,
609203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
610203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
611203134Sthompsa	.callback = run_bulk_tx_callback3,
612203134Sthompsa	.timeout = 5000,	/* ms */
613203134Sthompsa    },
614203134Sthompsa    [RUN_BULK_TX_HCCA] = {
615203134Sthompsa	.type = UE_BULK,
616203134Sthompsa	.endpoint = UE_ADDR_ANY,
617203134Sthompsa	.direction = UE_DIR_OUT,
618203134Sthompsa	.ep_index = 4,
619203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
620203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
621203134Sthompsa	.callback = run_bulk_tx_callback4,
622203134Sthompsa	.timeout = 5000,	/* ms */
623203134Sthompsa    },
624203134Sthompsa    [RUN_BULK_TX_PRIO] = {
625203134Sthompsa	.type = UE_BULK,
626203134Sthompsa	.endpoint = UE_ADDR_ANY,
627203134Sthompsa	.direction = UE_DIR_OUT,
628203134Sthompsa	.ep_index = 5,
629203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
630203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
631203134Sthompsa	.callback = run_bulk_tx_callback5,
632203134Sthompsa	.timeout = 5000,	/* ms */
633203134Sthompsa    },
634203134Sthompsa    [RUN_BULK_RX] = {
635203134Sthompsa	.type = UE_BULK,
636203134Sthompsa	.endpoint = UE_ADDR_ANY,
637203134Sthompsa	.direction = UE_DIR_IN,
638203134Sthompsa	.bufsize = RUN_MAX_RXSZ,
639203134Sthompsa	.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
640203134Sthompsa	.callback = run_bulk_rx_callback,
641203134Sthompsa    }
642203134Sthompsa};
643203134Sthompsa
644259812Skevlostatic void
645259812Skevlorun_autoinst(void *arg, struct usb_device *udev,
646259812Skevlo    struct usb_attach_arg *uaa)
647259812Skevlo{
648259812Skevlo	struct usb_interface *iface;
649259812Skevlo	struct usb_interface_descriptor *id;
650259812Skevlo
651259812Skevlo	if (uaa->dev_state != UAA_DEV_READY)
652259812Skevlo		return;
653259812Skevlo
654259812Skevlo	iface = usbd_get_iface(udev, 0);
655259812Skevlo	if (iface == NULL)
656259812Skevlo		return;
657259812Skevlo	id = iface->idesc;
658259812Skevlo	if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
659259812Skevlo		return;
660259812Skevlo	if (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa))
661259812Skevlo		return;
662259812Skevlo
663259812Skevlo	if (usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT) == 0)
664259812Skevlo		uaa->dev_state = UAA_DEV_EJECTING;
665259812Skevlo}
666259812Skevlo
667220235Skevlostatic int
668259812Skevlorun_driver_loaded(struct module *mod, int what, void *arg)
669259812Skevlo{
670259812Skevlo	switch (what) {
671259812Skevlo	case MOD_LOAD:
672259812Skevlo		run_etag = EVENTHANDLER_REGISTER(usb_dev_configured,
673259812Skevlo		    run_autoinst, NULL, EVENTHANDLER_PRI_ANY);
674259812Skevlo		break;
675259812Skevlo	case MOD_UNLOAD:
676259812Skevlo		EVENTHANDLER_DEREGISTER(usb_dev_configured, run_etag);
677259812Skevlo		break;
678259812Skevlo	default:
679259812Skevlo		return (EOPNOTSUPP);
680259812Skevlo	}
681259812Skevlo	return (0);
682259812Skevlo}
683259812Skevlo
684259812Skevlostatic int
685203134Sthompsarun_match(device_t self)
686203134Sthompsa{
687203134Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(self);
688203134Sthompsa
689203134Sthompsa	if (uaa->usb_mode != USB_MODE_HOST)
690203134Sthompsa		return (ENXIO);
691203134Sthompsa	if (uaa->info.bConfigIndex != 0)
692203134Sthompsa		return (ENXIO);
693203134Sthompsa	if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX)
694203134Sthompsa		return (ENXIO);
695203134Sthompsa
696203134Sthompsa	return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa));
697203134Sthompsa}
698203134Sthompsa
699203134Sthompsastatic int
700203134Sthompsarun_attach(device_t self)
701203134Sthompsa{
702203134Sthompsa	struct run_softc *sc = device_get_softc(self);
703203134Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(self);
704287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
705205042Sthompsa	uint32_t ver;
706293339Savos	uint8_t iface_index;
707258082Skevlo	int ntries, error;
708203134Sthompsa
709203134Sthompsa	device_set_usb_desc(self);
710203134Sthompsa	sc->sc_udev = uaa->device;
711203134Sthompsa	sc->sc_dev = self;
712262465Skevlo	if (USB_GET_DRIVER_INFO(uaa) != RUN_EJECT)
713262465Skevlo		sc->sc_flags |= RUN_FLAG_FWLOAD_NEEDED;
714203134Sthompsa
715203134Sthompsa	mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev),
716203134Sthompsa	    MTX_NETWORK_LOCK, MTX_DEF);
717287197Sglebius	mbufq_init(&sc->sc_snd, ifqmaxlen);
718203134Sthompsa
719203134Sthompsa	iface_index = RT2860_IFACE_INDEX;
720208019Sthompsa
721203134Sthompsa	error = usbd_transfer_setup(uaa->device, &iface_index,
722203134Sthompsa	    sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx);
723203134Sthompsa	if (error) {
724205042Sthompsa		device_printf(self, "could not allocate USB transfers, "
725203134Sthompsa		    "err=%s\n", usbd_errstr(error));
726203134Sthompsa		goto detach;
727203134Sthompsa	}
728203134Sthompsa
729203134Sthompsa	RUN_LOCK(sc);
730203134Sthompsa
731203134Sthompsa	/* wait for the chip to settle */
732203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
733209917Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0) {
734203134Sthompsa			RUN_UNLOCK(sc);
735203134Sthompsa			goto detach;
736203134Sthompsa		}
737205042Sthompsa		if (ver != 0 && ver != 0xffffffff)
738203134Sthompsa			break;
739203134Sthompsa		run_delay(sc, 10);
740203134Sthompsa	}
741203134Sthompsa	if (ntries == 100) {
742203138Sthompsa		device_printf(sc->sc_dev,
743203138Sthompsa		    "timeout waiting for NIC to initialize\n");
744203134Sthompsa		RUN_UNLOCK(sc);
745203134Sthompsa		goto detach;
746203134Sthompsa	}
747205042Sthompsa	sc->mac_ver = ver >> 16;
748205042Sthompsa	sc->mac_rev = ver & 0xffff;
749203134Sthompsa
750203134Sthompsa	/* retrieve RF rev. no and various other things from EEPROM */
751203134Sthompsa	run_read_eeprom(sc);
752203134Sthompsa
753203138Sthompsa	device_printf(sc->sc_dev,
754203138Sthompsa	    "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n",
755205042Sthompsa	    sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev),
756287197Sglebius	    sc->ntxchains, sc->nrxchains, ether_sprintf(ic->ic_macaddr));
757203134Sthompsa
758203134Sthompsa	RUN_UNLOCK(sc);
759203134Sthompsa
760283537Sglebius	ic->ic_softc = sc;
761283527Sglebius	ic->ic_name = device_get_nameunit(self);
762203134Sthompsa	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
763203134Sthompsa	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
764208019Sthompsa
765203134Sthompsa	/* set device capabilities */
766203134Sthompsa	ic->ic_caps =
767203134Sthompsa	    IEEE80211_C_STA |		/* station mode supported */
768203134Sthompsa	    IEEE80211_C_MONITOR |	/* monitor mode supported */
769203134Sthompsa	    IEEE80211_C_IBSS |
770203134Sthompsa	    IEEE80211_C_HOSTAP |
771208019Sthompsa	    IEEE80211_C_WDS |		/* 4-address traffic works */
772208019Sthompsa	    IEEE80211_C_MBSS |
773203134Sthompsa	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
774203134Sthompsa	    IEEE80211_C_SHSLOT |	/* short slot time supported */
775203134Sthompsa	    IEEE80211_C_WME |		/* WME */
776214894Sbschmidt	    IEEE80211_C_WPA;		/* WPA1|WPA2(RSN) */
777203134Sthompsa
778203134Sthompsa	ic->ic_cryptocaps =
779203134Sthompsa	    IEEE80211_CRYPTO_WEP |
780203134Sthompsa	    IEEE80211_CRYPTO_AES_CCM |
781203134Sthompsa	    IEEE80211_CRYPTO_TKIPMIC |
782203134Sthompsa	    IEEE80211_CRYPTO_TKIP;
783203134Sthompsa
784203134Sthompsa	ic->ic_flags |= IEEE80211_F_DATAPAD;
785203134Sthompsa	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;
786203134Sthompsa
787300748Savos	run_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans,
788300748Savos	    ic->ic_channels);
789203134Sthompsa
790287197Sglebius	ieee80211_ifattach(ic);
791203134Sthompsa
792203134Sthompsa	ic->ic_scan_start = run_scan_start;
793203134Sthompsa	ic->ic_scan_end = run_scan_end;
794203134Sthompsa	ic->ic_set_channel = run_set_channel;
795300748Savos	ic->ic_getradiocaps = run_getradiocaps;
796203134Sthompsa	ic->ic_node_alloc = run_node_alloc;
797203134Sthompsa	ic->ic_newassoc = run_newassoc;
798218492Sbschmidt	ic->ic_updateslot = run_updateslot;
799208019Sthompsa	ic->ic_update_mcast = run_update_mcast;
800203134Sthompsa	ic->ic_wme.wme_update = run_wme_update;
801203134Sthompsa	ic->ic_raw_xmit = run_raw_xmit;
802203134Sthompsa	ic->ic_update_promisc = run_update_promisc;
803203134Sthompsa	ic->ic_vap_create = run_vap_create;
804203134Sthompsa	ic->ic_vap_delete = run_vap_delete;
805287197Sglebius	ic->ic_transmit = run_transmit;
806287197Sglebius	ic->ic_parent = run_parent;
807203134Sthompsa
808203134Sthompsa	ieee80211_radiotap_attach(ic,
809203134Sthompsa	    &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
810203134Sthompsa		RUN_TX_RADIOTAP_PRESENT,
811203134Sthompsa	    &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
812203134Sthompsa		RUN_RX_RADIOTAP_PRESENT);
813203134Sthompsa
814208019Sthompsa	TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc);
815208019Sthompsa	TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc);
816257712Shselasky	usb_callout_init_mtx(&sc->ratectl_ch, &sc->sc_mtx, 0);
817208019Sthompsa
818203134Sthompsa	if (bootverbose)
819203134Sthompsa		ieee80211_announce(ic);
820203134Sthompsa
821209917Sthompsa	return (0);
822203134Sthompsa
823203134Sthompsadetach:
824203134Sthompsa	run_detach(self);
825209917Sthompsa	return (ENXIO);
826203134Sthompsa}
827203134Sthompsa
828288649Sadrianstatic void
829288649Sadrianrun_drain_mbufq(struct run_softc *sc)
830288649Sadrian{
831288649Sadrian	struct mbuf *m;
832288649Sadrian	struct ieee80211_node *ni;
833288649Sadrian
834288649Sadrian	RUN_LOCK_ASSERT(sc, MA_OWNED);
835288649Sadrian	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
836288649Sadrian		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
837288649Sadrian		m->m_pkthdr.rcvif = NULL;
838288649Sadrian		ieee80211_free_node(ni);
839288649Sadrian		m_freem(m);
840288649Sadrian	}
841288649Sadrian}
842288649Sadrian
843203134Sthompsastatic int
844203134Sthompsarun_detach(device_t self)
845203134Sthompsa{
846203134Sthompsa	struct run_softc *sc = device_get_softc(self);
847287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
848203134Sthompsa	int i;
849203134Sthompsa
850246614Shselasky	RUN_LOCK(sc);
851246614Shselasky	sc->sc_detached = 1;
852246614Shselasky	RUN_UNLOCK(sc);
853246614Shselasky
854203134Sthompsa	/* stop all USB transfers */
855203134Sthompsa	usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER);
856203134Sthompsa
857203134Sthompsa	RUN_LOCK(sc);
858209144Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
859209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set = RUN_CMDQ_ABORT;
860209144Sthompsa
861203134Sthompsa	/* free TX list, if any */
862203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
863203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
864288649Sadrian
865288649Sadrian	/* Free TX queue */
866288649Sadrian	run_drain_mbufq(sc);
867203134Sthompsa	RUN_UNLOCK(sc);
868203134Sthompsa
869287197Sglebius	if (sc->sc_ic.ic_softc == sc) {
870208019Sthompsa		/* drain tasks */
871208019Sthompsa		usb_callout_drain(&sc->ratectl_ch);
872208019Sthompsa		ieee80211_draintask(ic, &sc->cmdq_task);
873208019Sthompsa		ieee80211_draintask(ic, &sc->ratectl_task);
874203134Sthompsa		ieee80211_ifdetach(ic);
875203134Sthompsa	}
876203134Sthompsa
877203134Sthompsa	mtx_destroy(&sc->sc_mtx);
878203134Sthompsa
879203134Sthompsa	return (0);
880203134Sthompsa}
881203134Sthompsa
882203134Sthompsastatic struct ieee80211vap *
883228621Sbschmidtrun_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
884228621Sbschmidt    enum ieee80211_opmode opmode, int flags,
885203134Sthompsa    const uint8_t bssid[IEEE80211_ADDR_LEN],
886203134Sthompsa    const uint8_t mac[IEEE80211_ADDR_LEN])
887203134Sthompsa{
888286950Sadrian	struct run_softc *sc = ic->ic_softc;
889203134Sthompsa	struct run_vap *rvp;
890203134Sthompsa	struct ieee80211vap *vap;
891208019Sthompsa	int i;
892203134Sthompsa
893209917Sthompsa	if (sc->rvp_cnt >= RUN_VAP_MAX) {
894287197Sglebius		device_printf(sc->sc_dev, "number of VAPs maxed out\n");
895209917Sthompsa		return (NULL);
896208019Sthompsa	}
897208019Sthompsa
898208019Sthompsa	switch (opmode) {
899208019Sthompsa	case IEEE80211_M_STA:
900208019Sthompsa		/* enable s/w bmiss handling for sta mode */
901208019Sthompsa		flags |= IEEE80211_CLONE_NOBEACONS;
902208019Sthompsa		/* fall though */
903208019Sthompsa	case IEEE80211_M_IBSS:
904208019Sthompsa	case IEEE80211_M_MONITOR:
905208019Sthompsa	case IEEE80211_M_HOSTAP:
906208019Sthompsa	case IEEE80211_M_MBSS:
907208019Sthompsa		/* other than WDS vaps, only one at a time */
908208019Sthompsa		if (!TAILQ_EMPTY(&ic->ic_vaps))
909209917Sthompsa			return (NULL);
910208019Sthompsa		break;
911208019Sthompsa	case IEEE80211_M_WDS:
912208019Sthompsa		TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next){
913208019Sthompsa			if(vap->iv_opmode != IEEE80211_M_HOSTAP)
914208019Sthompsa				continue;
915208019Sthompsa			/* WDS vap's always share the local mac address. */
916208019Sthompsa			flags &= ~IEEE80211_CLONE_BSSID;
917208019Sthompsa			break;
918208019Sthompsa		}
919209917Sthompsa		if (vap == NULL) {
920287197Sglebius			device_printf(sc->sc_dev,
921287197Sglebius			    "wds only supported in ap mode\n");
922209917Sthompsa			return (NULL);
923208019Sthompsa		}
924208019Sthompsa		break;
925208019Sthompsa	default:
926287197Sglebius		device_printf(sc->sc_dev, "unknown opmode %d\n", opmode);
927209917Sthompsa		return (NULL);
928208019Sthompsa	}
929208019Sthompsa
930287197Sglebius	rvp = malloc(sizeof(struct run_vap), M_80211_VAP, M_WAITOK | M_ZERO);
931203134Sthompsa	vap = &rvp->vap;
932203134Sthompsa
933287197Sglebius	if (ieee80211_vap_setup(ic, vap, name, unit, opmode, flags,
934287197Sglebius	    bssid) != 0) {
935257743Shselasky		/* out of memory */
936257743Shselasky		free(rvp, M_80211_VAP);
937257743Shselasky		return (NULL);
938257743Shselasky	}
939257743Shselasky
940203134Sthompsa	vap->iv_update_beacon = run_update_beacon;
941208019Sthompsa	vap->iv_max_aid = RT2870_WCID_MAX;
942208019Sthompsa	/*
943208019Sthompsa	 * To delete the right key from h/w, we need wcid.
944208019Sthompsa	 * Luckily, there is unused space in ieee80211_key{}, wk_pad,
945208019Sthompsa	 * and matching wcid will be written into there. So, cast
946208019Sthompsa	 * some spells to remove 'const' from ieee80211_key{}
947208019Sthompsa	 */
948208019Sthompsa	vap->iv_key_delete = (void *)run_key_delete;
949208019Sthompsa	vap->iv_key_set = (void *)run_key_set;
950203134Sthompsa
951203134Sthompsa	/* override state transition machine */
952203134Sthompsa	rvp->newstate = vap->iv_newstate;
953203134Sthompsa	vap->iv_newstate = run_newstate;
954288603Sadrian	if (opmode == IEEE80211_M_IBSS) {
955288603Sadrian		rvp->recv_mgmt = vap->iv_recv_mgmt;
956288603Sadrian		vap->iv_recv_mgmt = run_recv_mgmt;
957288603Sadrian	}
958203134Sthompsa
959206358Srpaulo	ieee80211_ratectl_init(vap);
960206358Srpaulo	ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */);
961203134Sthompsa
962203134Sthompsa	/* complete setup */
963287197Sglebius	ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status,
964287197Sglebius	    mac);
965208019Sthompsa
966208019Sthompsa	/* make sure id is always unique */
967209917Sthompsa	for (i = 0; i < RUN_VAP_MAX; i++) {
968208019Sthompsa		if((sc->rvp_bmap & 1 << i) == 0){
969208019Sthompsa			sc->rvp_bmap |= 1 << i;
970208019Sthompsa			rvp->rvp_id = i;
971208019Sthompsa			break;
972208019Sthompsa		}
973208019Sthompsa	}
974209917Sthompsa	if (sc->rvp_cnt++ == 0)
975208019Sthompsa		ic->ic_opmode = opmode;
976208019Sthompsa
977209917Sthompsa	if (opmode == IEEE80211_M_HOSTAP)
978209144Sthompsa		sc->cmdq_run = RUN_CMDQ_GO;
979209144Sthompsa
980208019Sthompsa	DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n",
981208019Sthompsa	    rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt);
982208019Sthompsa
983209917Sthompsa	return (vap);
984203134Sthompsa}
985203134Sthompsa
986203134Sthompsastatic void
987203134Sthompsarun_vap_delete(struct ieee80211vap *vap)
988203134Sthompsa{
989203134Sthompsa	struct run_vap *rvp = RUN_VAP(vap);
990203134Sthompsa	struct ieee80211com *ic;
991203134Sthompsa	struct run_softc *sc;
992208019Sthompsa	uint8_t rvp_id;
993203134Sthompsa
994209917Sthompsa	if (vap == NULL)
995203134Sthompsa		return;
996203134Sthompsa
997203134Sthompsa	ic = vap->iv_ic;
998286950Sadrian	sc = ic->ic_softc;
999203134Sthompsa
1000205042Sthompsa	RUN_LOCK(sc);
1001208019Sthompsa
1002218492Sbschmidt	m_freem(rvp->beacon_mbuf);
1003218492Sbschmidt	rvp->beacon_mbuf = NULL;
1004218492Sbschmidt
1005208019Sthompsa	rvp_id = rvp->rvp_id;
1006208019Sthompsa	sc->ratectl_run &= ~(1 << rvp_id);
1007208019Sthompsa	sc->rvp_bmap &= ~(1 << rvp_id);
1008208019Sthompsa	run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128);
1009208019Sthompsa	run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512);
1010208019Sthompsa	--sc->rvp_cnt;
1011208019Sthompsa
1012208019Sthompsa	DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n",
1013208019Sthompsa	    vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt);
1014208019Sthompsa
1015205042Sthompsa	RUN_UNLOCK(sc);
1016203134Sthompsa
1017206358Srpaulo	ieee80211_ratectl_deinit(vap);
1018203134Sthompsa	ieee80211_vap_detach(vap);
1019203134Sthompsa	free(rvp, M_80211_VAP);
1020203134Sthompsa}
1021203134Sthompsa
1022208019Sthompsa/*
1023208019Sthompsa * There are numbers of functions need to be called in context thread.
1024208019Sthompsa * Rather than creating taskqueue event for each of those functions,
1025208019Sthompsa * here is all-for-one taskqueue callback function. This function
1026298932Spfg * guarantees deferred functions are executed in the same order they
1027208019Sthompsa * were enqueued.
1028208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[].
1029208019Sthompsa */
1030203134Sthompsastatic void
1031208019Sthompsarun_cmdq_cb(void *arg, int pending)
1032208019Sthompsa{
1033208019Sthompsa	struct run_softc *sc = arg;
1034208019Sthompsa	uint8_t i;
1035208019Sthompsa
1036208019Sthompsa	/* call cmdq[].func locked */
1037208019Sthompsa	RUN_LOCK(sc);
1038209917Sthompsa	for (i = sc->cmdq_exec; sc->cmdq[i].func && pending;
1039209917Sthompsa	    i = sc->cmdq_exec, pending--) {
1040208019Sthompsa		DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending);
1041209917Sthompsa		if (sc->cmdq_run == RUN_CMDQ_GO) {
1042208019Sthompsa			/*
1043208019Sthompsa			 * If arg0 is NULL, callback func needs more
1044208019Sthompsa			 * than one arg. So, pass ptr to cmdq struct.
1045208019Sthompsa			 */
1046209917Sthompsa			if (sc->cmdq[i].arg0)
1047208019Sthompsa				sc->cmdq[i].func(sc->cmdq[i].arg0);
1048208019Sthompsa			else
1049208019Sthompsa				sc->cmdq[i].func(&sc->cmdq[i]);
1050208019Sthompsa		}
1051208019Sthompsa		sc->cmdq[i].arg0 = NULL;
1052208019Sthompsa		sc->cmdq[i].func = NULL;
1053208019Sthompsa		sc->cmdq_exec++;
1054208019Sthompsa		sc->cmdq_exec &= RUN_CMDQ_MASQ;
1055208019Sthompsa	}
1056208019Sthompsa	RUN_UNLOCK(sc);
1057208019Sthompsa}
1058208019Sthompsa
1059208019Sthompsastatic void
1060203134Sthompsarun_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
1061203134Sthompsa{
1062203134Sthompsa	struct run_tx_data *data;
1063203134Sthompsa
1064203134Sthompsa	memset(pq, 0, sizeof(*pq));
1065203134Sthompsa
1066203134Sthompsa	STAILQ_INIT(&pq->tx_qh);
1067203134Sthompsa	STAILQ_INIT(&pq->tx_fh);
1068203134Sthompsa
1069203134Sthompsa	for (data = &pq->tx_data[0];
1070203134Sthompsa	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
1071203134Sthompsa		data->sc = sc;
1072203134Sthompsa		STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
1073203134Sthompsa	}
1074203134Sthompsa	pq->tx_nfree = RUN_TX_RING_COUNT;
1075203134Sthompsa}
1076203134Sthompsa
1077203134Sthompsastatic void
1078203134Sthompsarun_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
1079203134Sthompsa{
1080203134Sthompsa	struct run_tx_data *data;
1081203134Sthompsa
1082203134Sthompsa	/* make sure any subsequent use of the queues will fail */
1083203134Sthompsa	pq->tx_nfree = 0;
1084203134Sthompsa	STAILQ_INIT(&pq->tx_fh);
1085203134Sthompsa	STAILQ_INIT(&pq->tx_qh);
1086203134Sthompsa
1087203134Sthompsa	/* free up all node references and mbufs */
1088203134Sthompsa	for (data = &pq->tx_data[0];
1089209917Sthompsa	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
1090203134Sthompsa		if (data->m != NULL) {
1091203134Sthompsa			m_freem(data->m);
1092203134Sthompsa			data->m = NULL;
1093203134Sthompsa		}
1094203134Sthompsa		if (data->ni != NULL) {
1095203134Sthompsa			ieee80211_free_node(data->ni);
1096203134Sthompsa			data->ni = NULL;
1097203134Sthompsa		}
1098203134Sthompsa	}
1099203134Sthompsa}
1100203134Sthompsa
1101220235Skevlostatic int
1102203134Sthompsarun_load_microcode(struct run_softc *sc)
1103203134Sthompsa{
1104203134Sthompsa	usb_device_request_t req;
1105203137Sthompsa	const struct firmware *fw;
1106203134Sthompsa	const u_char *base;
1107203134Sthompsa	uint32_t tmp;
1108203134Sthompsa	int ntries, error;
1109203134Sthompsa	const uint64_t *temp;
1110203134Sthompsa	uint64_t bytes;
1111203134Sthompsa
1112205042Sthompsa	RUN_UNLOCK(sc);
1113203137Sthompsa	fw = firmware_get("runfw");
1114205042Sthompsa	RUN_LOCK(sc);
1115209917Sthompsa	if (fw == NULL) {
1116203138Sthompsa		device_printf(sc->sc_dev,
1117203138Sthompsa		    "failed loadfirmware of file %s\n", "runfw");
1118203134Sthompsa		return ENOENT;
1119203134Sthompsa	}
1120203134Sthompsa
1121203137Sthompsa	if (fw->datasize != 8192) {
1122203138Sthompsa		device_printf(sc->sc_dev,
1123203138Sthompsa		    "invalid firmware size (should be 8KB)\n");
1124203137Sthompsa		error = EINVAL;
1125203137Sthompsa		goto fail;
1126203134Sthompsa	}
1127203134Sthompsa
1128203134Sthompsa	/*
1129203134Sthompsa	 * RT3071/RT3072 use a different firmware
1130203134Sthompsa	 * run-rt2870 (8KB) contains both,
1131203134Sthompsa	 * first half (4KB) is for rt2870,
1132203134Sthompsa	 * last half is for rt3071.
1133203134Sthompsa	 */
1134203137Sthompsa	base = fw->data;
1135205042Sthompsa	if ((sc->mac_ver) != 0x2860 &&
1136205042Sthompsa	    (sc->mac_ver) != 0x2872 &&
1137209917Sthompsa	    (sc->mac_ver) != 0x3070) {
1138203134Sthompsa		base += 4096;
1139205042Sthompsa	}
1140203134Sthompsa
1141203134Sthompsa	/* cheap sanity check */
1142203137Sthompsa	temp = fw->data;
1143203134Sthompsa	bytes = *temp;
1144257712Shselasky	if (bytes != be64toh(0xffffff0210280210ULL)) {
1145203138Sthompsa		device_printf(sc->sc_dev, "firmware checksum failed\n");
1146203137Sthompsa		error = EINVAL;
1147203137Sthompsa		goto fail;
1148203137Sthompsa	}
1149203134Sthompsa
1150203134Sthompsa	/* write microcode image */
1151262465Skevlo	if (sc->sc_flags & RUN_FLAG_FWLOAD_NEEDED) {
1152260219Skevlo		run_write_region_1(sc, RT2870_FW_BASE, base, 4096);
1153260219Skevlo		run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff);
1154260219Skevlo		run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff);
1155260219Skevlo	}
1156203134Sthompsa
1157203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1158203134Sthompsa	req.bRequest = RT2870_RESET;
1159203134Sthompsa	USETW(req.wValue, 8);
1160203134Sthompsa	USETW(req.wIndex, 0);
1161203134Sthompsa	USETW(req.wLength, 0);
1162220235Skevlo	if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL))
1163220235Skevlo	    != 0) {
1164203138Sthompsa		device_printf(sc->sc_dev, "firmware reset failed\n");
1165203137Sthompsa		goto fail;
1166203137Sthompsa	}
1167203134Sthompsa
1168203134Sthompsa	run_delay(sc, 10);
1169203134Sthompsa
1170260219Skevlo	run_write(sc, RT2860_H2M_BBPAGENT, 0);
1171203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
1172260219Skevlo	run_write(sc, RT2860_H2M_INTSRC, 0);
1173205042Sthompsa	if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0)
1174203137Sthompsa		goto fail;
1175203134Sthompsa
1176203134Sthompsa	/* wait until microcontroller is ready */
1177203134Sthompsa	for (ntries = 0; ntries < 1000; ntries++) {
1178260219Skevlo		if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0)
1179203137Sthompsa			goto fail;
1180203134Sthompsa		if (tmp & RT2860_MCU_READY)
1181203134Sthompsa			break;
1182203134Sthompsa		run_delay(sc, 10);
1183203134Sthompsa	}
1184203134Sthompsa	if (ntries == 1000) {
1185203138Sthompsa		device_printf(sc->sc_dev,
1186203138Sthompsa		    "timeout waiting for MCU to initialize\n");
1187203137Sthompsa		error = ETIMEDOUT;
1188203137Sthompsa		goto fail;
1189203134Sthompsa	}
1190233283Sbschmidt	device_printf(sc->sc_dev, "firmware %s ver. %u.%u loaded\n",
1191233283Sbschmidt	    (base == fw->data) ? "RT2870" : "RT3071",
1192233283Sbschmidt	    *(base + 4092), *(base + 4093));
1193203134Sthompsa
1194203137Sthompsafail:
1195203137Sthompsa	firmware_put(fw, FIRMWARE_UNLOAD);
1196203137Sthompsa	return (error);
1197203134Sthompsa}
1198203134Sthompsa
1199258641Shselaskystatic int
1200203134Sthompsarun_reset(struct run_softc *sc)
1201203134Sthompsa{
1202203134Sthompsa	usb_device_request_t req;
1203203134Sthompsa
1204203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1205203134Sthompsa	req.bRequest = RT2870_RESET;
1206203134Sthompsa	USETW(req.wValue, 1);
1207203134Sthompsa	USETW(req.wIndex, 0);
1208203134Sthompsa	USETW(req.wLength, 0);
1209209917Sthompsa	return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL));
1210203134Sthompsa}
1211203134Sthompsa
1212203134Sthompsastatic usb_error_t
1213203134Sthompsarun_do_request(struct run_softc *sc,
1214203134Sthompsa    struct usb_device_request *req, void *data)
1215203134Sthompsa{
1216203134Sthompsa	usb_error_t err;
1217203134Sthompsa	int ntries = 10;
1218203134Sthompsa
1219203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
1220203134Sthompsa
1221203134Sthompsa	while (ntries--) {
1222203134Sthompsa		err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx,
1223203134Sthompsa		    req, data, 0, NULL, 250 /* ms */);
1224203134Sthompsa		if (err == 0)
1225203134Sthompsa			break;
1226203134Sthompsa		DPRINTFN(1, "Control request failed, %s (retrying)\n",
1227203134Sthompsa		    usbd_errstr(err));
1228203134Sthompsa		run_delay(sc, 10);
1229203134Sthompsa	}
1230203134Sthompsa	return (err);
1231203134Sthompsa}
1232203134Sthompsa
1233203134Sthompsastatic int
1234203134Sthompsarun_read(struct run_softc *sc, uint16_t reg, uint32_t *val)
1235203134Sthompsa{
1236203134Sthompsa	uint32_t tmp;
1237203134Sthompsa	int error;
1238203134Sthompsa
1239203134Sthompsa	error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp);
1240203134Sthompsa	if (error == 0)
1241203134Sthompsa		*val = le32toh(tmp);
1242203134Sthompsa	else
1243203134Sthompsa		*val = 0xffffffff;
1244209917Sthompsa	return (error);
1245203134Sthompsa}
1246203134Sthompsa
1247203134Sthompsastatic int
1248203134Sthompsarun_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len)
1249203134Sthompsa{
1250203134Sthompsa	usb_device_request_t req;
1251203134Sthompsa
1252203134Sthompsa	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1253203134Sthompsa	req.bRequest = RT2870_READ_REGION_1;
1254203134Sthompsa	USETW(req.wValue, 0);
1255203134Sthompsa	USETW(req.wIndex, reg);
1256203134Sthompsa	USETW(req.wLength, len);
1257203134Sthompsa
1258209917Sthompsa	return (run_do_request(sc, &req, buf));
1259203134Sthompsa}
1260203134Sthompsa
1261203134Sthompsastatic int
1262203134Sthompsarun_write_2(struct run_softc *sc, uint16_t reg, uint16_t val)
1263203134Sthompsa{
1264203134Sthompsa	usb_device_request_t req;
1265203134Sthompsa
1266203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1267203134Sthompsa	req.bRequest = RT2870_WRITE_2;
1268203134Sthompsa	USETW(req.wValue, val);
1269203134Sthompsa	USETW(req.wIndex, reg);
1270203134Sthompsa	USETW(req.wLength, 0);
1271203134Sthompsa
1272209917Sthompsa	return (run_do_request(sc, &req, NULL));
1273203134Sthompsa}
1274203134Sthompsa
1275203134Sthompsastatic int
1276203134Sthompsarun_write(struct run_softc *sc, uint16_t reg, uint32_t val)
1277203134Sthompsa{
1278203134Sthompsa	int error;
1279203134Sthompsa
1280203134Sthompsa	if ((error = run_write_2(sc, reg, val & 0xffff)) == 0)
1281203134Sthompsa		error = run_write_2(sc, reg + 2, val >> 16);
1282209917Sthompsa	return (error);
1283203134Sthompsa}
1284203134Sthompsa
1285203134Sthompsastatic int
1286203134Sthompsarun_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf,
1287203134Sthompsa    int len)
1288203134Sthompsa{
1289203134Sthompsa#if 1
1290203134Sthompsa	int i, error = 0;
1291203134Sthompsa	/*
1292203134Sthompsa	 * NB: the WRITE_REGION_1 command is not stable on RT2860.
1293203134Sthompsa	 * We thus issue multiple WRITE_2 commands instead.
1294203134Sthompsa	 */
1295203134Sthompsa	KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n"));
1296203134Sthompsa	for (i = 0; i < len && error == 0; i += 2)
1297203134Sthompsa		error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8);
1298209917Sthompsa	return (error);
1299203134Sthompsa#else
1300203134Sthompsa	usb_device_request_t req;
1301257958Skevlo	int error = 0;
1302203134Sthompsa
1303257958Skevlo	/*
1304257958Skevlo	 * NOTE: It appears the WRITE_REGION_1 command cannot be
1305257958Skevlo	 * passed a huge amount of data, which will crash the
1306257958Skevlo	 * firmware. Limit amount of data passed to 64-bytes at a
1307257958Skevlo	 * time.
1308257958Skevlo	 */
1309257958Skevlo	while (len > 0) {
1310257958Skevlo		int delta = 64;
1311257958Skevlo		if (delta > len)
1312257958Skevlo			delta = len;
1313257958Skevlo
1314257958Skevlo		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1315257958Skevlo		req.bRequest = RT2870_WRITE_REGION_1;
1316257958Skevlo		USETW(req.wValue, 0);
1317257958Skevlo		USETW(req.wIndex, reg);
1318257958Skevlo		USETW(req.wLength, delta);
1319257958Skevlo		error = run_do_request(sc, &req, __DECONST(uint8_t *, buf));
1320257958Skevlo		if (error != 0)
1321257958Skevlo			break;
1322257958Skevlo		reg += delta;
1323257958Skevlo		buf += delta;
1324257958Skevlo		len -= delta;
1325257958Skevlo	}
1326257958Skevlo	return (error);
1327203134Sthompsa#endif
1328203134Sthompsa}
1329203134Sthompsa
1330203134Sthompsastatic int
1331203134Sthompsarun_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len)
1332203134Sthompsa{
1333203134Sthompsa	int i, error = 0;
1334203134Sthompsa
1335203134Sthompsa	KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n"));
1336203134Sthompsa	for (i = 0; i < len && error == 0; i += 4)
1337203134Sthompsa		error = run_write(sc, reg + i, val);
1338209917Sthompsa	return (error);
1339203134Sthompsa}
1340203134Sthompsa
1341203134Sthompsastatic int
1342259544Skevlorun_efuse_read(struct run_softc *sc, uint16_t addr, uint16_t *val, int count)
1343203134Sthompsa{
1344203134Sthompsa	uint32_t tmp;
1345203134Sthompsa	uint16_t reg;
1346203134Sthompsa	int error, ntries;
1347203134Sthompsa
1348203134Sthompsa	if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1349209917Sthompsa		return (error);
1350203134Sthompsa
1351261076Shselasky	if (count == 2)
1352261076Shselasky		addr *= 2;
1353203134Sthompsa	/*-
1354203134Sthompsa	 * Read one 16-byte block into registers EFUSE_DATA[0-3]:
1355203134Sthompsa	 * DATA0: F E D C
1356203134Sthompsa	 * DATA1: B A 9 8
1357203134Sthompsa	 * DATA2: 7 6 5 4
1358203134Sthompsa	 * DATA3: 3 2 1 0
1359203134Sthompsa	 */
1360203134Sthompsa	tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK);
1361203134Sthompsa	tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK;
1362203134Sthompsa	run_write(sc, RT3070_EFUSE_CTRL, tmp);
1363203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1364203134Sthompsa		if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1365209917Sthompsa			return (error);
1366203134Sthompsa		if (!(tmp & RT3070_EFSROM_KICK))
1367203134Sthompsa			break;
1368203134Sthompsa		run_delay(sc, 2);
1369203134Sthompsa	}
1370203134Sthompsa	if (ntries == 100)
1371209917Sthompsa		return (ETIMEDOUT);
1372203134Sthompsa
1373261076Shselasky	if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) {
1374261076Shselasky		*val = 0xffff;	/* address not found */
1375209917Sthompsa		return (0);
1376261076Shselasky	}
1377203134Sthompsa	/* determine to which 32-bit register our 16-bit word belongs */
1378203134Sthompsa	reg = RT3070_EFUSE_DATA3 - (addr & 0xc);
1379203134Sthompsa	if ((error = run_read(sc, reg, &tmp)) != 0)
1380209917Sthompsa		return (error);
1381203134Sthompsa
1382261118Skevlo	tmp >>= (8 * (addr & 0x3));
1383261118Skevlo	*val = (addr & 1) ? tmp >> 16 : tmp & 0xffff;
1384261118Skevlo
1385209917Sthompsa	return (0);
1386203134Sthompsa}
1387203134Sthompsa
1388261124Skevlo/* Read 16-bit from eFUSE ROM for RT3xxx. */
1389203134Sthompsastatic int
1390259544Skevlorun_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1391259544Skevlo{
1392259544Skevlo	return (run_efuse_read(sc, addr, val, 2));
1393259544Skevlo}
1394259544Skevlo
1395259544Skevlostatic int
1396203134Sthompsarun_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1397203134Sthompsa{
1398203134Sthompsa	usb_device_request_t req;
1399203134Sthompsa	uint16_t tmp;
1400203134Sthompsa	int error;
1401203134Sthompsa
1402203134Sthompsa	addr *= 2;
1403203134Sthompsa	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1404203134Sthompsa	req.bRequest = RT2870_EEPROM_READ;
1405203134Sthompsa	USETW(req.wValue, 0);
1406203134Sthompsa	USETW(req.wIndex, addr);
1407260219Skevlo	USETW(req.wLength, sizeof(tmp));
1408203134Sthompsa
1409203134Sthompsa	error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp);
1410203134Sthompsa	if (error == 0)
1411203134Sthompsa		*val = le16toh(tmp);
1412203134Sthompsa	else
1413203134Sthompsa		*val = 0xffff;
1414209917Sthompsa	return (error);
1415203134Sthompsa}
1416203134Sthompsa
1417203134Sthompsastatic __inline int
1418203134Sthompsarun_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val)
1419203134Sthompsa{
1420203134Sthompsa	/* either eFUSE ROM or EEPROM */
1421203134Sthompsa	return sc->sc_srom_read(sc, addr, val);
1422203134Sthompsa}
1423203134Sthompsa
1424203134Sthompsastatic int
1425258733Skevlorun_rt2870_rf_write(struct run_softc *sc, uint32_t val)
1426203134Sthompsa{
1427203134Sthompsa	uint32_t tmp;
1428203134Sthompsa	int error, ntries;
1429203134Sthompsa
1430203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1431203134Sthompsa		if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0)
1432209917Sthompsa			return (error);
1433203134Sthompsa		if (!(tmp & RT2860_RF_REG_CTRL))
1434203134Sthompsa			break;
1435203134Sthompsa	}
1436203134Sthompsa	if (ntries == 10)
1437209917Sthompsa		return (ETIMEDOUT);
1438203134Sthompsa
1439258732Skevlo	return (run_write(sc, RT2860_RF_CSR_CFG0, val));
1440203134Sthompsa}
1441203134Sthompsa
1442203134Sthompsastatic int
1443203134Sthompsarun_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1444203134Sthompsa{
1445203134Sthompsa	uint32_t tmp;
1446203134Sthompsa	int error, ntries;
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	tmp = RT3070_RF_KICK | reg << 8;
1458203134Sthompsa	if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0)
1459209917Sthompsa		return (error);
1460203134Sthompsa
1461203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1462203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1463209917Sthompsa			return (error);
1464203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1465203134Sthompsa			break;
1466203134Sthompsa	}
1467203134Sthompsa	if (ntries == 100)
1468209917Sthompsa		return (ETIMEDOUT);
1469203134Sthompsa
1470203134Sthompsa	*val = tmp & 0xff;
1471209917Sthompsa	return (0);
1472203134Sthompsa}
1473203134Sthompsa
1474203134Sthompsastatic int
1475203134Sthompsarun_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1476203134Sthompsa{
1477203134Sthompsa	uint32_t tmp;
1478203134Sthompsa	int error, ntries;
1479203134Sthompsa
1480203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1481203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1482209917Sthompsa			return (error);
1483203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1484203134Sthompsa			break;
1485203134Sthompsa	}
1486203134Sthompsa	if (ntries == 10)
1487209917Sthompsa		return (ETIMEDOUT);
1488203134Sthompsa
1489203134Sthompsa	tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val;
1490209917Sthompsa	return (run_write(sc, RT3070_RF_CSR_CFG, tmp));
1491203134Sthompsa}
1492203134Sthompsa
1493203134Sthompsastatic int
1494203134Sthompsarun_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1495203134Sthompsa{
1496203134Sthompsa	uint32_t tmp;
1497203134Sthompsa	int ntries, 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	tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8;
1509203134Sthompsa	if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0)
1510209917Sthompsa		return (error);
1511203134Sthompsa
1512203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1513203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1514209917Sthompsa			return (error);
1515203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1516203134Sthompsa			break;
1517203134Sthompsa	}
1518203134Sthompsa	if (ntries == 10)
1519209917Sthompsa		return (ETIMEDOUT);
1520203134Sthompsa
1521203134Sthompsa	*val = tmp & 0xff;
1522209917Sthompsa	return (0);
1523203134Sthompsa}
1524203134Sthompsa
1525203134Sthompsastatic int
1526203134Sthompsarun_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1527203134Sthompsa{
1528203134Sthompsa	uint32_t tmp;
1529203134Sthompsa	int ntries, error;
1530203134Sthompsa
1531203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1532203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1533209917Sthompsa			return (error);
1534203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1535203134Sthompsa			break;
1536203134Sthompsa	}
1537203134Sthompsa	if (ntries == 10)
1538209917Sthompsa		return (ETIMEDOUT);
1539203134Sthompsa
1540203134Sthompsa	tmp = RT2860_BBP_CSR_KICK | reg << 8 | val;
1541209917Sthompsa	return (run_write(sc, RT2860_BBP_CSR_CFG, tmp));
1542203134Sthompsa}
1543203134Sthompsa
1544203134Sthompsa/*
1545203134Sthompsa * Send a command to the 8051 microcontroller unit.
1546203134Sthompsa */
1547203134Sthompsastatic int
1548203134Sthompsarun_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg)
1549203134Sthompsa{
1550203134Sthompsa	uint32_t tmp;
1551203134Sthompsa	int error, ntries;
1552203134Sthompsa
1553203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1554203134Sthompsa		if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0)
1555203134Sthompsa			return error;
1556203134Sthompsa		if (!(tmp & RT2860_H2M_BUSY))
1557203134Sthompsa			break;
1558203134Sthompsa	}
1559203134Sthompsa	if (ntries == 100)
1560203134Sthompsa		return ETIMEDOUT;
1561203134Sthompsa
1562203134Sthompsa	tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg;
1563203134Sthompsa	if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0)
1564203134Sthompsa		error = run_write(sc, RT2860_HOST_CMD, cmd);
1565209917Sthompsa	return (error);
1566203134Sthompsa}
1567203134Sthompsa
1568203134Sthompsa/*
1569203134Sthompsa * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word.
1570203134Sthompsa * Used to adjust per-rate Tx power registers.
1571203134Sthompsa */
1572203134Sthompsastatic __inline uint32_t
1573203134Sthompsab4inc(uint32_t b32, int8_t delta)
1574203134Sthompsa{
1575203134Sthompsa	int8_t i, b4;
1576203134Sthompsa
1577203134Sthompsa	for (i = 0; i < 8; i++) {
1578203134Sthompsa		b4 = b32 & 0xf;
1579203134Sthompsa		b4 += delta;
1580203134Sthompsa		if (b4 < 0)
1581203134Sthompsa			b4 = 0;
1582203134Sthompsa		else if (b4 > 0xf)
1583203134Sthompsa			b4 = 0xf;
1584203134Sthompsa		b32 = b32 >> 4 | b4 << 28;
1585203134Sthompsa	}
1586209917Sthompsa	return (b32);
1587203134Sthompsa}
1588203134Sthompsa
1589203134Sthompsastatic const char *
1590257955Skevlorun_get_rf(uint16_t rev)
1591203134Sthompsa{
1592203134Sthompsa	switch (rev) {
1593203134Sthompsa	case RT2860_RF_2820:	return "RT2820";
1594203134Sthompsa	case RT2860_RF_2850:	return "RT2850";
1595203134Sthompsa	case RT2860_RF_2720:	return "RT2720";
1596203134Sthompsa	case RT2860_RF_2750:	return "RT2750";
1597203134Sthompsa	case RT3070_RF_3020:	return "RT3020";
1598203134Sthompsa	case RT3070_RF_2020:	return "RT2020";
1599203134Sthompsa	case RT3070_RF_3021:	return "RT3021";
1600203134Sthompsa	case RT3070_RF_3022:	return "RT3022";
1601203134Sthompsa	case RT3070_RF_3052:	return "RT3052";
1602260219Skevlo	case RT3593_RF_3053:	return "RT3053";
1603259032Skevlo	case RT5592_RF_5592:	return "RT5592";
1604257955Skevlo	case RT5390_RF_5370:	return "RT5370";
1605257955Skevlo	case RT5390_RF_5372:	return "RT5372";
1606203134Sthompsa	}
1607209917Sthompsa	return ("unknown");
1608203134Sthompsa}
1609203134Sthompsa
1610260219Skevlostatic void
1611260219Skevlorun_rt3593_get_txpower(struct run_softc *sc)
1612260219Skevlo{
1613260219Skevlo	uint16_t addr, val;
1614260219Skevlo	int i;
1615260219Skevlo
1616260219Skevlo	/* Read power settings for 2GHz channels. */
1617260219Skevlo	for (i = 0; i < 14; i += 2) {
1618260219Skevlo		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE1 :
1619260219Skevlo		    RT2860_EEPROM_PWR2GHZ_BASE1;
1620260219Skevlo		run_srom_read(sc, addr + i / 2, &val);
1621260219Skevlo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1622260219Skevlo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1623260219Skevlo
1624260219Skevlo		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE2 :
1625260219Skevlo		    RT2860_EEPROM_PWR2GHZ_BASE2;
1626260219Skevlo		run_srom_read(sc, addr + i / 2, &val);
1627260219Skevlo		sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1628260219Skevlo		sc->txpow2[i + 1] = (int8_t)(val >> 8);
1629260219Skevlo
1630260219Skevlo		if (sc->ntxchains == 3) {
1631260219Skevlo			run_srom_read(sc, RT3593_EEPROM_PWR2GHZ_BASE3 + i / 2,
1632260219Skevlo			    &val);
1633260219Skevlo			sc->txpow3[i + 0] = (int8_t)(val & 0xff);
1634260219Skevlo			sc->txpow3[i + 1] = (int8_t)(val >> 8);
1635260219Skevlo		}
1636260219Skevlo	}
1637260219Skevlo	/* Fix broken Tx power entries. */
1638260219Skevlo	for (i = 0; i < 14; i++) {
1639260542Skevlo		if (sc->txpow1[i] > 31)
1640260219Skevlo			sc->txpow1[i] = 5;
1641260542Skevlo		if (sc->txpow2[i] > 31)
1642260219Skevlo			sc->txpow2[i] = 5;
1643260219Skevlo		if (sc->ntxchains == 3) {
1644260542Skevlo			if (sc->txpow3[i] > 31)
1645260219Skevlo				sc->txpow3[i] = 5;
1646260219Skevlo		}
1647260219Skevlo	}
1648260219Skevlo	/* Read power settings for 5GHz channels. */
1649260219Skevlo	for (i = 0; i < 40; i += 2) {
1650260219Skevlo		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1651260219Skevlo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1652260219Skevlo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1653260219Skevlo
1654260219Skevlo		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1655260219Skevlo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1656260219Skevlo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1657260219Skevlo
1658260219Skevlo		if (sc->ntxchains == 3) {
1659260219Skevlo			run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE3 + i / 2,
1660260219Skevlo			    &val);
1661260219Skevlo			sc->txpow3[i + 14] = (int8_t)(val & 0xff);
1662260219Skevlo			sc->txpow3[i + 15] = (int8_t)(val >> 8);
1663260219Skevlo		}
1664260219Skevlo	}
1665260219Skevlo}
1666260219Skevlo
1667260219Skevlostatic void
1668260219Skevlorun_get_txpower(struct run_softc *sc)
1669260219Skevlo{
1670260219Skevlo	uint16_t val;
1671260219Skevlo	int i;
1672260219Skevlo
1673260219Skevlo	/* Read power settings for 2GHz channels. */
1674260219Skevlo	for (i = 0; i < 14; i += 2) {
1675260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val);
1676260219Skevlo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1677260219Skevlo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1678260219Skevlo
1679260219Skevlo		if (sc->mac_ver != 0x5390) {
1680260219Skevlo			run_srom_read(sc,
1681260219Skevlo			    RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val);
1682260219Skevlo			sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1683260219Skevlo			sc->txpow2[i + 1] = (int8_t)(val >> 8);
1684260219Skevlo		}
1685260219Skevlo	}
1686260219Skevlo	/* Fix broken Tx power entries. */
1687260219Skevlo	for (i = 0; i < 14; i++) {
1688260219Skevlo		if (sc->mac_ver >= 0x5390) {
1689288666Skevlo			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 39)
1690260219Skevlo				sc->txpow1[i] = 5;
1691260219Skevlo		} else {
1692260219Skevlo			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31)
1693260219Skevlo				sc->txpow1[i] = 5;
1694260219Skevlo		}
1695260219Skevlo		if (sc->mac_ver > 0x5390) {
1696288666Skevlo			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 39)
1697260219Skevlo				sc->txpow2[i] = 5;
1698260219Skevlo		} else if (sc->mac_ver < 0x5390) {
1699260219Skevlo			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31)
1700260219Skevlo				sc->txpow2[i] = 5;
1701260219Skevlo		}
1702260219Skevlo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1703260219Skevlo		    rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]);
1704260219Skevlo	}
1705260219Skevlo	/* Read power settings for 5GHz channels. */
1706260219Skevlo	for (i = 0; i < 40; i += 2) {
1707260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1708260219Skevlo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1709260219Skevlo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1710260219Skevlo
1711260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1712260219Skevlo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1713260219Skevlo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1714260219Skevlo	}
1715260219Skevlo	/* Fix broken Tx power entries. */
1716260219Skevlo	for (i = 0; i < 40; i++ ) {
1717260219Skevlo		if (sc->mac_ver != 0x5592) {
1718260219Skevlo			if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15)
1719260219Skevlo				sc->txpow1[14 + i] = 5;
1720260219Skevlo			if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15)
1721260219Skevlo				sc->txpow2[14 + i] = 5;
1722260219Skevlo		}
1723260219Skevlo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1724260219Skevlo		    rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i],
1725260219Skevlo		    sc->txpow2[14 + i]);
1726260219Skevlo	}
1727260219Skevlo}
1728260219Skevlo
1729258641Shselaskystatic int
1730203134Sthompsarun_read_eeprom(struct run_softc *sc)
1731203134Sthompsa{
1732287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
1733203134Sthompsa	int8_t delta_2ghz, delta_5ghz;
1734203134Sthompsa	uint32_t tmp;
1735203134Sthompsa	uint16_t val;
1736203134Sthompsa	int ridx, ant, i;
1737203134Sthompsa
1738203134Sthompsa	/* check whether the ROM is eFUSE ROM or EEPROM */
1739203134Sthompsa	sc->sc_srom_read = run_eeprom_read_2;
1740205042Sthompsa	if (sc->mac_ver >= 0x3070) {
1741203134Sthompsa		run_read(sc, RT3070_EFUSE_CTRL, &tmp);
1742203134Sthompsa		DPRINTF("EFUSE_CTRL=0x%08x\n", tmp);
1743261118Skevlo		if ((tmp & RT3070_SEL_EFUSE) || sc->mac_ver == 0x3593)
1744203134Sthompsa			sc->sc_srom_read = run_efuse_read_2;
1745203134Sthompsa	}
1746203134Sthompsa
1747203134Sthompsa	/* read ROM version */
1748203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_VERSION, &val);
1749287853Skevlo	DPRINTF("EEPROM rev=%d, FAE=%d\n", val >> 8, val & 0xff);
1750203134Sthompsa
1751203134Sthompsa	/* read MAC address */
1752203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC01, &val);
1753287197Sglebius	ic->ic_macaddr[0] = val & 0xff;
1754287197Sglebius	ic->ic_macaddr[1] = val >> 8;
1755203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC23, &val);
1756287197Sglebius	ic->ic_macaddr[2] = val & 0xff;
1757287197Sglebius	ic->ic_macaddr[3] = val >> 8;
1758203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC45, &val);
1759287197Sglebius	ic->ic_macaddr[4] = val & 0xff;
1760287197Sglebius	ic->ic_macaddr[5] = val >> 8;
1761203134Sthompsa
1762260219Skevlo	if (sc->mac_ver < 0x3593) {
1763257955Skevlo		/* read vender BBP settings */
1764205042Sthompsa		for (i = 0; i < 10; i++) {
1765257955Skevlo			run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val);
1766257955Skevlo			sc->bbp[i].val = val & 0xff;
1767257955Skevlo			sc->bbp[i].reg = val >> 8;
1768257955Skevlo			DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg,
1769257955Skevlo			    sc->bbp[i].val);
1770205042Sthompsa		}
1771257955Skevlo		if (sc->mac_ver >= 0x3071) {
1772257955Skevlo			/* read vendor RF settings */
1773257955Skevlo			for (i = 0; i < 10; i++) {
1774257955Skevlo				run_srom_read(sc, RT3071_EEPROM_RF_BASE + i,
1775257955Skevlo				   &val);
1776257955Skevlo				sc->rf[i].val = val & 0xff;
1777257955Skevlo				sc->rf[i].reg = val >> 8;
1778257955Skevlo				DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg,
1779257955Skevlo				    sc->rf[i].val);
1780257955Skevlo			}
1781257955Skevlo		}
1782205042Sthompsa	}
1783203134Sthompsa
1784203134Sthompsa	/* read RF frequency offset from EEPROM */
1785260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1786260219Skevlo	    RT3593_EEPROM_FREQ, &val);
1787203134Sthompsa	sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0;
1788203134Sthompsa	DPRINTF("EEPROM freq offset %d\n", sc->freq & 0xff);
1789203134Sthompsa
1790260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1791260219Skevlo	    RT3593_EEPROM_FREQ_LEDS, &val);
1792205042Sthompsa	if (val >> 8 != 0xff) {
1793203134Sthompsa		/* read LEDs operating mode */
1794205042Sthompsa		sc->leds = val >> 8;
1795260219Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED1 :
1796260219Skevlo		    RT3593_EEPROM_LED1, &sc->led[0]);
1797260219Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED2 :
1798260219Skevlo		    RT3593_EEPROM_LED2, &sc->led[1]);
1799260219Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED3 :
1800260219Skevlo		    RT3593_EEPROM_LED3, &sc->led[2]);
1801203134Sthompsa	} else {
1802203134Sthompsa		/* broken EEPROM, use default settings */
1803203134Sthompsa		sc->leds = 0x01;
1804203134Sthompsa		sc->led[0] = 0x5555;
1805203134Sthompsa		sc->led[1] = 0x2221;
1806203134Sthompsa		sc->led[2] = 0x5627;	/* differs from RT2860 */
1807203134Sthompsa	}
1808203134Sthompsa	DPRINTF("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n",
1809203134Sthompsa	    sc->leds, sc->led[0], sc->led[1], sc->led[2]);
1810203134Sthompsa
1811203134Sthompsa	/* read RF information */
1812259032Skevlo	if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392)
1813257955Skevlo		run_srom_read(sc, 0x00, &val);
1814257955Skevlo	else
1815257955Skevlo		run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1816257955Skevlo
1817203134Sthompsa	if (val == 0xffff) {
1818260219Skevlo		device_printf(sc->sc_dev,
1819260219Skevlo		    "invalid EEPROM antenna info, using default\n");
1820203134Sthompsa		DPRINTF("invalid EEPROM antenna info, using default\n");
1821205042Sthompsa		if (sc->mac_ver == 0x3572) {
1822205042Sthompsa			/* default to RF3052 2T2R */
1823205042Sthompsa			sc->rf_rev = RT3070_RF_3052;
1824205042Sthompsa			sc->ntxchains = 2;
1825205042Sthompsa			sc->nrxchains = 2;
1826205042Sthompsa		} else if (sc->mac_ver >= 0x3070) {
1827203134Sthompsa			/* default to RF3020 1T1R */
1828203134Sthompsa			sc->rf_rev = RT3070_RF_3020;
1829203134Sthompsa			sc->ntxchains = 1;
1830203134Sthompsa			sc->nrxchains = 1;
1831203134Sthompsa		} else {
1832203134Sthompsa			/* default to RF2820 1T2R */
1833203134Sthompsa			sc->rf_rev = RT2860_RF_2820;
1834203134Sthompsa			sc->ntxchains = 1;
1835203134Sthompsa			sc->nrxchains = 2;
1836203134Sthompsa		}
1837203134Sthompsa	} else {
1838259032Skevlo		if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) {
1839257955Skevlo			sc->rf_rev = val;
1840257955Skevlo			run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1841257955Skevlo		} else
1842257955Skevlo			sc->rf_rev = (val >> 8) & 0xf;
1843203134Sthompsa		sc->ntxchains = (val >> 4) & 0xf;
1844203134Sthompsa		sc->nrxchains = val & 0xf;
1845203134Sthompsa	}
1846257955Skevlo	DPRINTF("EEPROM RF rev=0x%04x chains=%dT%dR\n",
1847203134Sthompsa	    sc->rf_rev, sc->ntxchains, sc->nrxchains);
1848203134Sthompsa
1849208019Sthompsa	/* check if RF supports automatic Tx access gain control */
1850203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_CONFIG, &val);
1851203134Sthompsa	DPRINTF("EEPROM CFG 0x%04x\n", val);
1852205042Sthompsa	/* check if driver should patch the DAC issue */
1853205042Sthompsa	if ((val >> 8) != 0xff)
1854205042Sthompsa		sc->patch_dac = (val >> 15) & 1;
1855203134Sthompsa	if ((val & 0xff) != 0xff) {
1856203134Sthompsa		sc->ext_5ghz_lna = (val >> 3) & 1;
1857203134Sthompsa		sc->ext_2ghz_lna = (val >> 2) & 1;
1858205042Sthompsa		/* check if RF supports automatic Tx access gain control */
1859203134Sthompsa		sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1;
1860205042Sthompsa		/* check if we have a hardware radio switch */
1861205042Sthompsa		sc->rfswitch = val & 1;
1862203134Sthompsa	}
1863203134Sthompsa
1864260219Skevlo	/* Read Tx power settings. */
1865260219Skevlo	if (sc->mac_ver == 0x3593)
1866260219Skevlo		run_rt3593_get_txpower(sc);
1867260219Skevlo	else
1868260219Skevlo		run_get_txpower(sc);
1869203134Sthompsa
1870203134Sthompsa	/* read Tx power compensation for each Tx rate */
1871203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val);
1872203134Sthompsa	delta_2ghz = delta_5ghz = 0;
1873203134Sthompsa	if ((val & 0xff) != 0xff && (val & 0x80)) {
1874203134Sthompsa		delta_2ghz = val & 0xf;
1875203134Sthompsa		if (!(val & 0x40))	/* negative number */
1876203134Sthompsa			delta_2ghz = -delta_2ghz;
1877203134Sthompsa	}
1878203134Sthompsa	val >>= 8;
1879203134Sthompsa	if ((val & 0xff) != 0xff && (val & 0x80)) {
1880203134Sthompsa		delta_5ghz = val & 0xf;
1881203134Sthompsa		if (!(val & 0x40))	/* negative number */
1882203134Sthompsa			delta_5ghz = -delta_5ghz;
1883203134Sthompsa	}
1884203134Sthompsa	DPRINTF("power compensation=%d (2GHz), %d (5GHz)\n",
1885203134Sthompsa	    delta_2ghz, delta_5ghz);
1886203134Sthompsa
1887203134Sthompsa	for (ridx = 0; ridx < 5; ridx++) {
1888203134Sthompsa		uint32_t reg;
1889203134Sthompsa
1890208019Sthompsa		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val);
1891208019Sthompsa		reg = val;
1892208019Sthompsa		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val);
1893208019Sthompsa		reg |= (uint32_t)val << 16;
1894203134Sthompsa
1895203134Sthompsa		sc->txpow20mhz[ridx] = reg;
1896203134Sthompsa		sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz);
1897203134Sthompsa		sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz);
1898203134Sthompsa
1899203134Sthompsa		DPRINTF("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, "
1900203134Sthompsa		    "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx],
1901203134Sthompsa		    sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]);
1902203134Sthompsa	}
1903203134Sthompsa
1904260219Skevlo	/* Read RSSI offsets and LNA gains from EEPROM. */
1905260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_2GHZ :
1906260219Skevlo	    RT3593_EEPROM_RSSI1_2GHZ, &val);
1907203134Sthompsa	sc->rssi_2ghz[0] = val & 0xff;	/* Ant A */
1908203134Sthompsa	sc->rssi_2ghz[1] = val >> 8;	/* Ant B */
1909260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_2GHZ :
1910260219Skevlo	    RT3593_EEPROM_RSSI2_2GHZ, &val);
1911205042Sthompsa	if (sc->mac_ver >= 0x3070) {
1912260219Skevlo		if (sc->mac_ver == 0x3593) {
1913260219Skevlo			sc->txmixgain_2ghz = 0;
1914260219Skevlo			sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1915260219Skevlo		} else {
1916260219Skevlo			/*
1917260219Skevlo			 * On RT3070 chips (limited to 2 Rx chains), this ROM
1918260219Skevlo			 * field contains the Tx mixer gain for the 2GHz band.
1919260219Skevlo			 */
1920260219Skevlo			if ((val & 0xff) != 0xff)
1921260219Skevlo				sc->txmixgain_2ghz = val & 0x7;
1922260219Skevlo		}
1923205042Sthompsa		DPRINTF("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz);
1924205042Sthompsa	} else
1925205042Sthompsa		sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1926260219Skevlo	if (sc->mac_ver == 0x3593)
1927260219Skevlo		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
1928203134Sthompsa	sc->lna[2] = val >> 8;		/* channel group 2 */
1929203134Sthompsa
1930260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_5GHZ :
1931260219Skevlo	    RT3593_EEPROM_RSSI1_5GHZ, &val);
1932203134Sthompsa	sc->rssi_5ghz[0] = val & 0xff;	/* Ant A */
1933203134Sthompsa	sc->rssi_5ghz[1] = val >> 8;	/* Ant B */
1934260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_5GHZ :
1935260219Skevlo	    RT3593_EEPROM_RSSI2_5GHZ, &val);
1936205042Sthompsa	if (sc->mac_ver == 0x3572) {
1937205042Sthompsa		/*
1938205042Sthompsa		 * On RT3572 chips (limited to 2 Rx chains), this ROM
1939205042Sthompsa		 * field contains the Tx mixer gain for the 5GHz band.
1940205042Sthompsa		 */
1941205042Sthompsa		if ((val & 0xff) != 0xff)
1942205042Sthompsa			sc->txmixgain_5ghz = val & 0x7;
1943205042Sthompsa		DPRINTF("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz);
1944205042Sthompsa	} else
1945205042Sthompsa		sc->rssi_5ghz[2] = val & 0xff;	/* Ant C */
1946260219Skevlo	if (sc->mac_ver == 0x3593) {
1947260219Skevlo		sc->txmixgain_5ghz = 0;
1948260219Skevlo		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
1949260219Skevlo	}
1950203134Sthompsa	sc->lna[3] = val >> 8;		/* channel group 3 */
1951203134Sthompsa
1952260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LNA :
1953260219Skevlo	    RT3593_EEPROM_LNA, &val);
1954203134Sthompsa	sc->lna[0] = val & 0xff;	/* channel group 0 */
1955203134Sthompsa	sc->lna[1] = val >> 8;		/* channel group 1 */
1956203134Sthompsa
1957203134Sthompsa	/* fix broken 5GHz LNA entries */
1958203134Sthompsa	if (sc->lna[2] == 0 || sc->lna[2] == 0xff) {
1959203134Sthompsa		DPRINTF("invalid LNA for channel group %d\n", 2);
1960203134Sthompsa		sc->lna[2] = sc->lna[1];
1961203134Sthompsa	}
1962203134Sthompsa	if (sc->lna[3] == 0 || sc->lna[3] == 0xff) {
1963203134Sthompsa		DPRINTF("invalid LNA for channel group %d\n", 3);
1964203134Sthompsa		sc->lna[3] = sc->lna[1];
1965203134Sthompsa	}
1966203134Sthompsa
1967203134Sthompsa	/* fix broken RSSI offset entries */
1968203134Sthompsa	for (ant = 0; ant < 3; ant++) {
1969203134Sthompsa		if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) {
1970203134Sthompsa			DPRINTF("invalid RSSI%d offset: %d (2GHz)\n",
1971203134Sthompsa			    ant + 1, sc->rssi_2ghz[ant]);
1972203134Sthompsa			sc->rssi_2ghz[ant] = 0;
1973203134Sthompsa		}
1974203134Sthompsa		if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) {
1975203134Sthompsa			DPRINTF("invalid RSSI%d offset: %d (5GHz)\n",
1976203134Sthompsa			    ant + 1, sc->rssi_5ghz[ant]);
1977203134Sthompsa			sc->rssi_5ghz[ant] = 0;
1978203134Sthompsa		}
1979203134Sthompsa	}
1980209917Sthompsa	return (0);
1981203134Sthompsa}
1982203134Sthompsa
1983218676Shselaskystatic struct ieee80211_node *
1984203134Sthompsarun_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
1985203134Sthompsa{
1986343821Savos	return malloc(sizeof (struct run_node), M_80211_NODE,
1987343821Savos	    M_NOWAIT | M_ZERO);
1988203134Sthompsa}
1989203134Sthompsa
1990203134Sthompsastatic int
1991203134Sthompsarun_media_change(struct ifnet *ifp)
1992203134Sthompsa{
1993208019Sthompsa	struct ieee80211vap *vap = ifp->if_softc;
1994208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
1995203134Sthompsa	const struct ieee80211_txparam *tp;
1996286950Sadrian	struct run_softc *sc = ic->ic_softc;
1997203134Sthompsa	uint8_t rate, ridx;
1998203134Sthompsa	int error;
1999203134Sthompsa
2000203134Sthompsa	RUN_LOCK(sc);
2001203134Sthompsa
2002203134Sthompsa	error = ieee80211_media_change(ifp);
2003209917Sthompsa	if (error != ENETRESET) {
2004203134Sthompsa		RUN_UNLOCK(sc);
2005209917Sthompsa		return (error);
2006208019Sthompsa	}
2007203134Sthompsa
2008203134Sthompsa	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
2009203134Sthompsa	if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
2010212127Sthompsa		struct ieee80211_node *ni;
2011212127Sthompsa		struct run_node	*rn;
2012212127Sthompsa
2013203134Sthompsa		rate = ic->ic_sup_rates[ic->ic_curmode].
2014203134Sthompsa		    rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL;
2015203134Sthompsa		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2016203134Sthompsa			if (rt2860_rates[ridx].rate == rate)
2017203134Sthompsa				break;
2018212127Sthompsa		ni = ieee80211_ref_node(vap->iv_bss);
2019287552Skevlo		rn = RUN_NODE(ni);
2020208019Sthompsa		rn->fix_ridx = ridx;
2021208019Sthompsa		DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx);
2022212127Sthompsa		ieee80211_free_node(ni);
2023203134Sthompsa	}
2024203134Sthompsa
2025208019Sthompsa#if 0
2026203134Sthompsa	if ((ifp->if_flags & IFF_UP) &&
2027287197Sglebius	    (ifp->if_drv_flags &  RUN_RUNNING)){
2028203134Sthompsa		run_init_locked(sc);
2029203134Sthompsa	}
2030208019Sthompsa#endif
2031203134Sthompsa
2032203134Sthompsa	RUN_UNLOCK(sc);
2033203134Sthompsa
2034209917Sthompsa	return (0);
2035203134Sthompsa}
2036203134Sthompsa
2037203134Sthompsastatic int
2038203134Sthompsarun_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
2039203134Sthompsa{
2040203134Sthompsa	const struct ieee80211_txparam *tp;
2041203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2042286950Sadrian	struct run_softc *sc = ic->ic_softc;
2043203134Sthompsa	struct run_vap *rvp = RUN_VAP(vap);
2044203134Sthompsa	enum ieee80211_state ostate;
2045208019Sthompsa	uint32_t sta[3];
2046208019Sthompsa	uint8_t ratectl;
2047208019Sthompsa	uint8_t restart_ratectl = 0;
2048208019Sthompsa	uint8_t bid = 1 << rvp->rvp_id;
2049203134Sthompsa
2050203134Sthompsa	ostate = vap->iv_state;
2051203134Sthompsa	DPRINTF("%s -> %s\n",
2052203134Sthompsa		ieee80211_state_name[ostate],
2053203134Sthompsa		ieee80211_state_name[nstate]);
2054203134Sthompsa
2055203134Sthompsa	IEEE80211_UNLOCK(ic);
2056203134Sthompsa	RUN_LOCK(sc);
2057203134Sthompsa
2058208019Sthompsa	ratectl = sc->ratectl_run; /* remember current state */
2059208019Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
2060208019Sthompsa	usb_callout_stop(&sc->ratectl_ch);
2061203134Sthompsa
2062203134Sthompsa	if (ostate == IEEE80211_S_RUN) {
2063203134Sthompsa		/* turn link LED off */
2064203134Sthompsa		run_set_leds(sc, RT2860_LED_RADIO);
2065203134Sthompsa	}
2066203134Sthompsa
2067203134Sthompsa	switch (nstate) {
2068203134Sthompsa	case IEEE80211_S_INIT:
2069208019Sthompsa		restart_ratectl = 1;
2070208019Sthompsa
2071208019Sthompsa		if (ostate != IEEE80211_S_RUN)
2072208019Sthompsa			break;
2073208019Sthompsa
2074208019Sthompsa		ratectl &= ~bid;
2075208019Sthompsa		sc->runbmap &= ~bid;
2076208019Sthompsa
2077208019Sthompsa		/* abort TSF synchronization if there is no vap running */
2078345752Savos		if (--sc->running == 0)
2079345752Savos			run_disable_tsf(sc);
2080203134Sthompsa		break;
2081203134Sthompsa
2082203134Sthompsa	case IEEE80211_S_RUN:
2083209917Sthompsa		if (!(sc->runbmap & bid)) {
2084208019Sthompsa			if(sc->running++)
2085208019Sthompsa				restart_ratectl = 1;
2086208019Sthompsa			sc->runbmap |= bid;
2087208019Sthompsa		}
2088203134Sthompsa
2089218492Sbschmidt		m_freem(rvp->beacon_mbuf);
2090218492Sbschmidt		rvp->beacon_mbuf = NULL;
2091218492Sbschmidt
2092209917Sthompsa		switch (vap->iv_opmode) {
2093208019Sthompsa		case IEEE80211_M_HOSTAP:
2094208019Sthompsa		case IEEE80211_M_MBSS:
2095208019Sthompsa			sc->ap_running |= bid;
2096208019Sthompsa			ic->ic_opmode = vap->iv_opmode;
2097208019Sthompsa			run_update_beacon_cb(vap);
2098208019Sthompsa			break;
2099208019Sthompsa		case IEEE80211_M_IBSS:
2100208019Sthompsa			sc->adhoc_running |= bid;
2101209917Sthompsa			if (!sc->ap_running)
2102208019Sthompsa				ic->ic_opmode = vap->iv_opmode;
2103208019Sthompsa			run_update_beacon_cb(vap);
2104208019Sthompsa			break;
2105208019Sthompsa		case IEEE80211_M_STA:
2106208019Sthompsa			sc->sta_running |= bid;
2107209917Sthompsa			if (!sc->ap_running && !sc->adhoc_running)
2108208019Sthompsa				ic->ic_opmode = vap->iv_opmode;
2109208019Sthompsa
2110208019Sthompsa			/* read statistic counters (clear on read) */
2111208019Sthompsa			run_read_region_1(sc, RT2860_TX_STA_CNT0,
2112208019Sthompsa			    (uint8_t *)sta, sizeof sta);
2113208019Sthompsa
2114208019Sthompsa			break;
2115208019Sthompsa		default:
2116208019Sthompsa			ic->ic_opmode = vap->iv_opmode;
2117208019Sthompsa			break;
2118208019Sthompsa		}
2119208019Sthompsa
2120203134Sthompsa		if (vap->iv_opmode != IEEE80211_M_MONITOR) {
2121212127Sthompsa			struct ieee80211_node *ni;
2122212127Sthompsa
2123236439Shselasky			if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) {
2124236439Shselasky				RUN_UNLOCK(sc);
2125236439Shselasky				IEEE80211_LOCK(ic);
2126236439Shselasky				return (-1);
2127236439Shselasky			}
2128283540Sglebius			run_updateslot(ic);
2129203134Sthompsa			run_enable_mrr(sc);
2130203134Sthompsa			run_set_txpreamble(sc);
2131203134Sthompsa			run_set_basicrates(sc);
2132212127Sthompsa			ni = ieee80211_ref_node(vap->iv_bss);
2133296356Savos			IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid);
2134296356Savos			run_set_bssid(sc, sc->sc_bssid);
2135212127Sthompsa			ieee80211_free_node(ni);
2136208019Sthompsa			run_enable_tsf_sync(sc);
2137203134Sthompsa
2138208019Sthompsa			/* enable automatic rate adaptation */
2139208019Sthompsa			tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
2140208019Sthompsa			if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
2141208019Sthompsa				ratectl |= bid;
2142287555Skevlo		} else
2143287555Skevlo			run_enable_tsf(sc);
2144203134Sthompsa
2145203134Sthompsa		/* turn link LED on */
2146203134Sthompsa		run_set_leds(sc, RT2860_LED_RADIO |
2147208019Sthompsa		    (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ?
2148203134Sthompsa		     RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ));
2149203134Sthompsa
2150203134Sthompsa		break;
2151203134Sthompsa	default:
2152203134Sthompsa		DPRINTFN(6, "undefined case\n");
2153203134Sthompsa		break;
2154203134Sthompsa	}
2155203134Sthompsa
2156208019Sthompsa	/* restart amrr for running VAPs */
2157209917Sthompsa	if ((sc->ratectl_run = ratectl) && restart_ratectl)
2158208019Sthompsa		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2159208019Sthompsa
2160203134Sthompsa	RUN_UNLOCK(sc);
2161203134Sthompsa	IEEE80211_LOCK(ic);
2162203134Sthompsa
2163203134Sthompsa	return(rvp->newstate(vap, nstate, arg));
2164203134Sthompsa}
2165203134Sthompsa
2166290407Savosstatic int
2167290407Savosrun_wme_update(struct ieee80211com *ic)
2168203134Sthompsa{
2169286950Sadrian	struct run_softc *sc = ic->ic_softc;
2170288646Sadrian	const struct wmeParams *ac =
2171288646Sadrian	    ic->ic_wme.wme_chanParams.cap_wmeParams;
2172203134Sthompsa	int aci, error = 0;
2173203134Sthompsa
2174203134Sthompsa	/* update MAC TX configuration registers */
2175290407Savos	RUN_LOCK(sc);
2176203134Sthompsa	for (aci = 0; aci < WME_NUM_AC; aci++) {
2177203134Sthompsa		error = run_write(sc, RT2860_EDCA_AC_CFG(aci),
2178288646Sadrian		    ac[aci].wmep_logcwmax << 16 |
2179288646Sadrian		    ac[aci].wmep_logcwmin << 12 |
2180288646Sadrian		    ac[aci].wmep_aifsn    <<  8 |
2181288646Sadrian		    ac[aci].wmep_txopLimit);
2182209917Sthompsa		if (error) goto err;
2183203134Sthompsa	}
2184203134Sthompsa
2185203134Sthompsa	/* update SCH/DMA registers too */
2186203134Sthompsa	error = run_write(sc, RT2860_WMM_AIFSN_CFG,
2187288646Sadrian	    ac[WME_AC_VO].wmep_aifsn  << 12 |
2188288646Sadrian	    ac[WME_AC_VI].wmep_aifsn  <<  8 |
2189288646Sadrian	    ac[WME_AC_BK].wmep_aifsn  <<  4 |
2190288646Sadrian	    ac[WME_AC_BE].wmep_aifsn);
2191209917Sthompsa	if (error) goto err;
2192203134Sthompsa	error = run_write(sc, RT2860_WMM_CWMIN_CFG,
2193288646Sadrian	    ac[WME_AC_VO].wmep_logcwmin << 12 |
2194288646Sadrian	    ac[WME_AC_VI].wmep_logcwmin <<  8 |
2195288646Sadrian	    ac[WME_AC_BK].wmep_logcwmin <<  4 |
2196288646Sadrian	    ac[WME_AC_BE].wmep_logcwmin);
2197209917Sthompsa	if (error) goto err;
2198203134Sthompsa	error = run_write(sc, RT2860_WMM_CWMAX_CFG,
2199288646Sadrian	    ac[WME_AC_VO].wmep_logcwmax << 12 |
2200288646Sadrian	    ac[WME_AC_VI].wmep_logcwmax <<  8 |
2201288646Sadrian	    ac[WME_AC_BK].wmep_logcwmax <<  4 |
2202288646Sadrian	    ac[WME_AC_BE].wmep_logcwmax);
2203209917Sthompsa	if (error) goto err;
2204203134Sthompsa	error = run_write(sc, RT2860_WMM_TXOP0_CFG,
2205288646Sadrian	    ac[WME_AC_BK].wmep_txopLimit << 16 |
2206288646Sadrian	    ac[WME_AC_BE].wmep_txopLimit);
2207209917Sthompsa	if (error) goto err;
2208203134Sthompsa	error = run_write(sc, RT2860_WMM_TXOP1_CFG,
2209288646Sadrian	    ac[WME_AC_VO].wmep_txopLimit << 16 |
2210288646Sadrian	    ac[WME_AC_VI].wmep_txopLimit);
2211203134Sthompsa
2212203134Sthompsaerr:
2213290407Savos	RUN_UNLOCK(sc);
2214209917Sthompsa	if (error)
2215203134Sthompsa		DPRINTF("WME update failed\n");
2216203134Sthompsa
2217290407Savos	return (error);
2218203134Sthompsa}
2219203134Sthompsa
2220203134Sthompsastatic void
2221208019Sthompsarun_key_set_cb(void *arg)
2222203134Sthompsa{
2223208019Sthompsa	struct run_cmdq *cmdq = arg;
2224208019Sthompsa	struct ieee80211vap *vap = cmdq->arg1;
2225208019Sthompsa	struct ieee80211_key *k = cmdq->k;
2226203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2227286950Sadrian	struct run_softc *sc = ic->ic_softc;
2228203134Sthompsa	struct ieee80211_node *ni;
2229287553Skevlo	u_int cipher = k->wk_cipher->ic_cipher;
2230203134Sthompsa	uint32_t attr;
2231203134Sthompsa	uint16_t base, associd;
2232209144Sthompsa	uint8_t mode, wcid, iv[8];
2233203134Sthompsa
2234208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2235203134Sthompsa
2236209917Sthompsa	if (vap->iv_opmode == IEEE80211_M_HOSTAP)
2237208019Sthompsa		ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac);
2238209144Sthompsa	else
2239203134Sthompsa		ni = vap->iv_bss;
2240208019Sthompsa	associd = (ni != NULL) ? ni->ni_associd : 0;
2241203134Sthompsa
2242203134Sthompsa	/* map net80211 cipher to RT2860 security mode */
2243287553Skevlo	switch (cipher) {
2244203134Sthompsa	case IEEE80211_CIPHER_WEP:
2245203134Sthompsa		if(k->wk_keylen < 8)
2246203134Sthompsa			mode = RT2860_MODE_WEP40;
2247203134Sthompsa		else
2248203134Sthompsa			mode = RT2860_MODE_WEP104;
2249203134Sthompsa		break;
2250203134Sthompsa	case IEEE80211_CIPHER_TKIP:
2251203134Sthompsa		mode = RT2860_MODE_TKIP;
2252203134Sthompsa		break;
2253203134Sthompsa	case IEEE80211_CIPHER_AES_CCM:
2254203134Sthompsa		mode = RT2860_MODE_AES_CCMP;
2255203134Sthompsa		break;
2256203134Sthompsa	default:
2257203134Sthompsa		DPRINTF("undefined case\n");
2258208019Sthompsa		return;
2259203134Sthompsa	}
2260203134Sthompsa
2261208019Sthompsa	DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n",
2262203134Sthompsa	    associd, k->wk_keyix, mode,
2263208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise",
2264208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off",
2265208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off");
2266203134Sthompsa
2267203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2268203134Sthompsa		wcid = 0;	/* NB: update WCID0 for group keys */
2269208019Sthompsa		base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix);
2270203134Sthompsa	} else {
2271245047Shselasky		wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2272245047Shselasky		    1 : RUN_AID2WCID(associd);
2273203134Sthompsa		base = RT2860_PKEY(wcid);
2274203134Sthompsa	}
2275203134Sthompsa
2276287553Skevlo	if (cipher == IEEE80211_CIPHER_TKIP) {
2277203134Sthompsa		if(run_write_region_1(sc, base, k->wk_key, 16))
2278208019Sthompsa			return;
2279209144Sthompsa		if(run_write_region_1(sc, base + 16, &k->wk_key[16], 8))	/* wk_txmic */
2280208019Sthompsa			return;
2281209144Sthompsa		if(run_write_region_1(sc, base + 24, &k->wk_key[24], 8))	/* wk_rxmic */
2282208019Sthompsa			return;
2283203134Sthompsa	} else {
2284203134Sthompsa		/* roundup len to 16-bit: XXX fix write_region_1() instead */
2285203134Sthompsa		if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1))
2286208019Sthompsa			return;
2287203134Sthompsa	}
2288203134Sthompsa
2289203134Sthompsa	if (!(k->wk_flags & IEEE80211_KEY_GROUP) ||
2290203134Sthompsa	    (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) {
2291203134Sthompsa		/* set initial packet number in IV+EIV */
2292287553Skevlo		if (cipher == IEEE80211_CIPHER_WEP) {
2293203134Sthompsa			memset(iv, 0, sizeof iv);
2294208019Sthompsa			iv[3] = vap->iv_def_txkey << 6;
2295203134Sthompsa		} else {
2296287553Skevlo			if (cipher == IEEE80211_CIPHER_TKIP) {
2297203134Sthompsa				iv[0] = k->wk_keytsc >> 8;
2298203134Sthompsa				iv[1] = (iv[0] | 0x20) & 0x7f;
2299203134Sthompsa				iv[2] = k->wk_keytsc;
2300203134Sthompsa			} else /* CCMP */ {
2301203134Sthompsa				iv[0] = k->wk_keytsc;
2302203134Sthompsa				iv[1] = k->wk_keytsc >> 8;
2303203134Sthompsa				iv[2] = 0;
2304203134Sthompsa			}
2305203134Sthompsa			iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV;
2306203134Sthompsa			iv[4] = k->wk_keytsc >> 16;
2307203134Sthompsa			iv[5] = k->wk_keytsc >> 24;
2308203134Sthompsa			iv[6] = k->wk_keytsc >> 32;
2309203134Sthompsa			iv[7] = k->wk_keytsc >> 40;
2310203134Sthompsa		}
2311209917Sthompsa		if (run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8))
2312208019Sthompsa			return;
2313203134Sthompsa	}
2314203134Sthompsa
2315203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2316203134Sthompsa		/* install group key */
2317209917Sthompsa		if (run_read(sc, RT2860_SKEY_MODE_0_7, &attr))
2318208019Sthompsa			return;
2319203134Sthompsa		attr &= ~(0xf << (k->wk_keyix * 4));
2320203134Sthompsa		attr |= mode << (k->wk_keyix * 4);
2321209917Sthompsa		if (run_write(sc, RT2860_SKEY_MODE_0_7, attr))
2322208019Sthompsa			return;
2323203134Sthompsa	} else {
2324203134Sthompsa		/* install pairwise key */
2325209917Sthompsa		if (run_read(sc, RT2860_WCID_ATTR(wcid), &attr))
2326208019Sthompsa			return;
2327203134Sthompsa		attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN;
2328209917Sthompsa		if (run_write(sc, RT2860_WCID_ATTR(wcid), attr))
2329208019Sthompsa			return;
2330203134Sthompsa	}
2331203134Sthompsa
2332203134Sthompsa	/* TODO create a pass-thru key entry? */
2333203134Sthompsa
2334208019Sthompsa	/* need wcid to delete the right key later */
2335208019Sthompsa	k->wk_pad = wcid;
2336203134Sthompsa}
2337203134Sthompsa
2338203134Sthompsa/*
2339208019Sthompsa * Don't have to be deferred, but in order to keep order of
2340208019Sthompsa * execution, i.e. with run_key_delete(), defer this and let
2341208019Sthompsa * run_cmdq_cb() maintain the order.
2342208019Sthompsa *
2343203134Sthompsa * return 0 on error
2344203134Sthompsa */
2345203134Sthompsastatic int
2346288635Sadrianrun_key_set(struct ieee80211vap *vap, struct ieee80211_key *k)
2347203134Sthompsa{
2348203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2349286950Sadrian	struct run_softc *sc = ic->ic_softc;
2350208019Sthompsa	uint32_t i;
2351208019Sthompsa
2352208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
2353208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
2354208019Sthompsa	sc->cmdq[i].func = run_key_set_cb;
2355208019Sthompsa	sc->cmdq[i].arg0 = NULL;
2356208019Sthompsa	sc->cmdq[i].arg1 = vap;
2357208019Sthompsa	sc->cmdq[i].k = k;
2358288635Sadrian	IEEE80211_ADDR_COPY(sc->cmdq[i].mac, k->wk_macaddr);
2359208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
2360208019Sthompsa
2361209144Sthompsa	/*
2362209144Sthompsa	 * To make sure key will be set when hostapd
2363209144Sthompsa	 * calls iv_key_set() before if_init().
2364209144Sthompsa	 */
2365209917Sthompsa	if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
2366209144Sthompsa		RUN_LOCK(sc);
2367209144Sthompsa		sc->cmdq_key_set = RUN_CMDQ_GO;
2368209144Sthompsa		RUN_UNLOCK(sc);
2369209144Sthompsa	}
2370209144Sthompsa
2371209917Sthompsa	return (1);
2372208019Sthompsa}
2373208019Sthompsa
2374208019Sthompsa/*
2375208019Sthompsa * If wlan is destroyed without being brought down i.e. without
2376208019Sthompsa * wlan down or wpa_cli terminate, this function is called after
2377208019Sthompsa * vap is gone. Don't refer it.
2378208019Sthompsa */
2379208019Sthompsastatic void
2380208019Sthompsarun_key_delete_cb(void *arg)
2381208019Sthompsa{
2382208019Sthompsa	struct run_cmdq *cmdq = arg;
2383208019Sthompsa	struct run_softc *sc = cmdq->arg1;
2384208019Sthompsa	struct ieee80211_key *k = &cmdq->key;
2385203134Sthompsa	uint32_t attr;
2386203134Sthompsa	uint8_t wcid;
2387203134Sthompsa
2388208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2389203134Sthompsa
2390203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2391203134Sthompsa		/* remove group key */
2392208019Sthompsa		DPRINTF("removing group key\n");
2393208019Sthompsa		run_read(sc, RT2860_SKEY_MODE_0_7, &attr);
2394203134Sthompsa		attr &= ~(0xf << (k->wk_keyix * 4));
2395208019Sthompsa		run_write(sc, RT2860_SKEY_MODE_0_7, attr);
2396203134Sthompsa	} else {
2397203134Sthompsa		/* remove pairwise key */
2398208019Sthompsa		DPRINTF("removing key for wcid %x\n", k->wk_pad);
2399208019Sthompsa		/* matching wcid was written to wk_pad in run_key_set() */
2400208019Sthompsa		wcid = k->wk_pad;
2401208019Sthompsa		run_read(sc, RT2860_WCID_ATTR(wcid), &attr);
2402203134Sthompsa		attr &= ~0xf;
2403208019Sthompsa		run_write(sc, RT2860_WCID_ATTR(wcid), attr);
2404208019Sthompsa		run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8);
2405203134Sthompsa	}
2406203134Sthompsa
2407208019Sthompsa	k->wk_pad = 0;
2408203134Sthompsa}
2409203134Sthompsa
2410208019Sthompsa/*
2411208019Sthompsa * return 0 on error
2412208019Sthompsa */
2413208019Sthompsastatic int
2414208019Sthompsarun_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k)
2415203134Sthompsa{
2416208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2417286950Sadrian	struct run_softc *sc = ic->ic_softc;
2418208019Sthompsa	struct ieee80211_key *k0;
2419208019Sthompsa	uint32_t i;
2420203134Sthompsa
2421208019Sthompsa	/*
2422208019Sthompsa	 * When called back, key might be gone. So, make a copy
2423208019Sthompsa	 * of some values need to delete keys before deferring.
2424208019Sthompsa	 * But, because of LOR with node lock, cannot use lock here.
2425208019Sthompsa	 * So, use atomic instead.
2426208019Sthompsa	 */
2427208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
2428208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
2429208019Sthompsa	sc->cmdq[i].func = run_key_delete_cb;
2430208019Sthompsa	sc->cmdq[i].arg0 = NULL;
2431208019Sthompsa	sc->cmdq[i].arg1 = sc;
2432208019Sthompsa	k0 = &sc->cmdq[i].key;
2433208019Sthompsa	k0->wk_flags = k->wk_flags;
2434208019Sthompsa	k0->wk_keyix = k->wk_keyix;
2435208019Sthompsa	/* matching wcid was written to wk_pad in run_key_set() */
2436208019Sthompsa	k0->wk_pad = k->wk_pad;
2437208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
2438208019Sthompsa	return (1);	/* return fake success */
2439203134Sthompsa
2440203134Sthompsa}
2441203134Sthompsa
2442203134Sthompsastatic void
2443206358Srpaulorun_ratectl_to(void *arg)
2444203134Sthompsa{
2445208019Sthompsa	struct run_softc *sc = arg;
2446203134Sthompsa
2447203134Sthompsa	/* do it in a process context, so it can go sleep */
2448287197Sglebius	ieee80211_runtask(&sc->sc_ic, &sc->ratectl_task);
2449203134Sthompsa	/* next timeout will be rescheduled in the callback task */
2450203134Sthompsa}
2451203134Sthompsa
2452203134Sthompsa/* ARGSUSED */
2453203134Sthompsastatic void
2454206358Srpaulorun_ratectl_cb(void *arg, int pending)
2455203134Sthompsa{
2456208019Sthompsa	struct run_softc *sc = arg;
2457287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
2458208019Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
2459203134Sthompsa
2460209917Sthompsa	if (vap == NULL)
2461208019Sthompsa		return;
2462208019Sthompsa
2463262795Shselasky	if (sc->rvp_cnt > 1 || vap->iv_opmode != IEEE80211_M_STA) {
2464203134Sthompsa		/*
2465203134Sthompsa		 * run_reset_livelock() doesn't do anything with AMRR,
2466203134Sthompsa		 * but Ralink wants us to call it every 1 sec. So, we
2467203134Sthompsa		 * piggyback here rather than creating another callout.
2468203134Sthompsa		 * Livelock may occur only in HOSTAP or IBSS mode
2469203134Sthompsa		 * (when h/w is sending beacons).
2470203134Sthompsa		 */
2471203134Sthompsa		RUN_LOCK(sc);
2472203134Sthompsa		run_reset_livelock(sc);
2473208019Sthompsa		/* just in case, there are some stats to drain */
2474208019Sthompsa		run_drain_fifo(sc);
2475203134Sthompsa		RUN_UNLOCK(sc);
2476203134Sthompsa	}
2477203134Sthompsa
2478262795Shselasky	ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc);
2479262795Shselasky
2480257712Shselasky	RUN_LOCK(sc);
2481208019Sthompsa	if(sc->ratectl_run != RUN_RATECTL_OFF)
2482208019Sthompsa		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2483257712Shselasky	RUN_UNLOCK(sc);
2484203134Sthompsa}
2485203134Sthompsa
2486203134Sthompsastatic void
2487208019Sthompsarun_drain_fifo(void *arg)
2488203134Sthompsa{
2489208019Sthompsa	struct run_softc *sc = arg;
2490208019Sthompsa	uint32_t stat;
2491218676Shselasky	uint16_t (*wstat)[3];
2492203134Sthompsa	uint8_t wcid, mcs, pid;
2493218676Shselasky	int8_t retry;
2494203134Sthompsa
2495208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2496203134Sthompsa
2497208019Sthompsa	for (;;) {
2498203134Sthompsa		/* drain Tx status FIFO (maxsize = 16) */
2499203134Sthompsa		run_read(sc, RT2860_TX_STAT_FIFO, &stat);
2500208019Sthompsa		DPRINTFN(4, "tx stat 0x%08x\n", stat);
2501209917Sthompsa		if (!(stat & RT2860_TXQ_VLD))
2502208019Sthompsa			break;
2503203134Sthompsa
2504208019Sthompsa		wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff;
2505203134Sthompsa
2506208019Sthompsa		/* if no ACK was requested, no feedback is available */
2507208019Sthompsa		if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX ||
2508208019Sthompsa		    wcid == 0)
2509208019Sthompsa			continue;
2510203134Sthompsa
2511218676Shselasky		/*
2512218676Shselasky		 * Even though each stat is Tx-complete-status like format,
2513218676Shselasky		 * the device can poll stats. Because there is no guarantee
2514218676Shselasky		 * that the referring node is still around when read the stats.
2515218676Shselasky		 * So that, if we use ieee80211_ratectl_tx_update(), we will
2516218676Shselasky		 * have hard time not to refer already freed node.
2517218676Shselasky		 *
2518218676Shselasky		 * To eliminate such page faults, we poll stats in softc.
2519218676Shselasky		 * Then, update the rates later with ieee80211_ratectl_tx_update().
2520218676Shselasky		 */
2521218676Shselasky		wstat = &(sc->wcid_stats[wcid]);
2522218676Shselasky		(*wstat)[RUN_TXCNT]++;
2523218676Shselasky		if (stat & RT2860_TXQ_OK)
2524218676Shselasky			(*wstat)[RUN_SUCCESS]++;
2525218676Shselasky		else
2526287197Sglebius			counter_u64_add(sc->sc_ic.ic_oerrors, 1);
2527218676Shselasky		/*
2528218676Shselasky		 * Check if there were retries, ie if the Tx success rate is
2529218676Shselasky		 * different from the requested rate. Note that it works only
2530218676Shselasky		 * because we do not allow rate fallback from OFDM to CCK.
2531218676Shselasky		 */
2532218676Shselasky		mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f;
2533218676Shselasky		pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf;
2534218676Shselasky		if ((retry = pid -1 - mcs) > 0) {
2535218676Shselasky			(*wstat)[RUN_TXCNT] += retry;
2536218676Shselasky			(*wstat)[RUN_RETRY] += retry;
2537203134Sthompsa		}
2538208019Sthompsa	}
2539208019Sthompsa	DPRINTFN(3, "count=%d\n", sc->fifo_cnt);
2540208019Sthompsa
2541208019Sthompsa	sc->fifo_cnt = 0;
2542208019Sthompsa}
2543208019Sthompsa
2544208019Sthompsastatic void
2545208019Sthompsarun_iter_func(void *arg, struct ieee80211_node *ni)
2546208019Sthompsa{
2547208019Sthompsa	struct run_softc *sc = arg;
2548208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
2549287552Skevlo	struct run_node *rn = RUN_NODE(ni);
2550218676Shselasky	union run_stats sta[2];
2551218676Shselasky	uint16_t (*wstat)[3];
2552218676Shselasky	int txcnt, success, retrycnt, error;
2553208019Sthompsa
2554218676Shselasky	RUN_LOCK(sc);
2555218676Shselasky
2556262795Shselasky	/* Check for special case */
2557262795Shselasky	if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA &&
2558262795Shselasky	    ni != vap->iv_bss)
2559262795Shselasky		goto fail;
2560262795Shselasky
2561209917Sthompsa	if (sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS ||
2562209917Sthompsa	    vap->iv_opmode == IEEE80211_M_STA)) {
2563203134Sthompsa		/* read statistic counters (clear on read) and update AMRR state */
2564203134Sthompsa		error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta,
2565203134Sthompsa		    sizeof sta);
2566203134Sthompsa		if (error != 0)
2567218676Shselasky			goto fail;
2568203134Sthompsa
2569203134Sthompsa		/* count failed TX as errors */
2570287197Sglebius		if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS,
2571287197Sglebius		    le16toh(sta[0].error.fail));
2572203134Sthompsa
2573218676Shselasky		retrycnt = le16toh(sta[1].tx.retry);
2574218676Shselasky		success = le16toh(sta[1].tx.success);
2575218676Shselasky		txcnt = retrycnt + success + le16toh(sta[0].error.fail);
2576203134Sthompsa
2577218676Shselasky		DPRINTFN(3, "retrycnt=%d success=%d failcnt=%d\n",
2578218676Shselasky			retrycnt, success, le16toh(sta[0].error.fail));
2579218676Shselasky	} else {
2580218676Shselasky		wstat = &(sc->wcid_stats[RUN_AID2WCID(ni->ni_associd)]);
2581203134Sthompsa
2582218676Shselasky		if (wstat == &(sc->wcid_stats[0]) ||
2583218676Shselasky		    wstat > &(sc->wcid_stats[RT2870_WCID_MAX]))
2584218676Shselasky			goto fail;
2585208019Sthompsa
2586218676Shselasky		txcnt = (*wstat)[RUN_TXCNT];
2587218676Shselasky		success = (*wstat)[RUN_SUCCESS];
2588218676Shselasky		retrycnt = (*wstat)[RUN_RETRY];
2589218676Shselasky		DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n",
2590218676Shselasky		    retrycnt, txcnt, success);
2591208019Sthompsa
2592218676Shselasky		memset(wstat, 0, sizeof(*wstat));
2593203134Sthompsa	}
2594203134Sthompsa
2595218676Shselasky	ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt);
2596208019Sthompsa	rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0);
2597218676Shselasky
2598218676Shselaskyfail:
2599218676Shselasky	RUN_UNLOCK(sc);
2600218676Shselasky
2601208019Sthompsa	DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx);
2602208019Sthompsa}
2603203134Sthompsa
2604208019Sthompsastatic void
2605208019Sthompsarun_newassoc_cb(void *arg)
2606208019Sthompsa{
2607208019Sthompsa	struct run_cmdq *cmdq = arg;
2608208019Sthompsa	struct ieee80211_node *ni = cmdq->arg1;
2609286950Sadrian	struct run_softc *sc = ni->ni_vap->iv_ic->ic_softc;
2610208019Sthompsa	uint8_t wcid = cmdq->wcid;
2611203134Sthompsa
2612208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2613208019Sthompsa
2614208019Sthompsa	run_write_region_1(sc, RT2860_WCID_ENTRY(wcid),
2615208019Sthompsa	    ni->ni_macaddr, IEEE80211_ADDR_LEN);
2616218676Shselasky
2617218676Shselasky	memset(&(sc->wcid_stats[wcid]), 0, sizeof(sc->wcid_stats[wcid]));
2618203134Sthompsa}
2619203134Sthompsa
2620203134Sthompsastatic void
2621203134Sthompsarun_newassoc(struct ieee80211_node *ni, int isnew)
2622203134Sthompsa{
2623287552Skevlo	struct run_node *rn = RUN_NODE(ni);
2624203134Sthompsa	struct ieee80211_rateset *rs = &ni->ni_rates;
2625208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
2626208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2627286950Sadrian	struct run_softc *sc = ic->ic_softc;
2628203134Sthompsa	uint8_t rate;
2629208019Sthompsa	uint8_t ridx;
2630245047Shselasky	uint8_t wcid;
2631208019Sthompsa	int i, j;
2632203134Sthompsa
2633245047Shselasky	wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2634245047Shselasky	    1 : RUN_AID2WCID(ni->ni_associd);
2635245047Shselasky
2636209917Sthompsa	if (wcid > RT2870_WCID_MAX) {
2637208019Sthompsa		device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid);
2638208019Sthompsa		return;
2639208019Sthompsa	}
2640203134Sthompsa
2641208019Sthompsa	/* only interested in true associations */
2642209917Sthompsa	if (isnew && ni->ni_associd != 0) {
2643208019Sthompsa
2644208019Sthompsa		/*
2645208019Sthompsa		 * This function could is called though timeout function.
2646208019Sthompsa		 * Need to defer.
2647208019Sthompsa		 */
2648208019Sthompsa		uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store);
2649208019Sthompsa		DPRINTF("cmdq_store=%d\n", cnt);
2650208019Sthompsa		sc->cmdq[cnt].func = run_newassoc_cb;
2651208019Sthompsa		sc->cmdq[cnt].arg0 = NULL;
2652208019Sthompsa		sc->cmdq[cnt].arg1 = ni;
2653208019Sthompsa		sc->cmdq[cnt].wcid = wcid;
2654208019Sthompsa		ieee80211_runtask(ic, &sc->cmdq_task);
2655208019Sthompsa	}
2656208019Sthompsa
2657208019Sthompsa	DPRINTF("new assoc isnew=%d associd=%x addr=%s\n",
2658208019Sthompsa	    isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr));
2659208019Sthompsa
2660203134Sthompsa	for (i = 0; i < rs->rs_nrates; i++) {
2661203134Sthompsa		rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
2662203134Sthompsa		/* convert 802.11 rate to hardware rate index */
2663203134Sthompsa		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2664203134Sthompsa			if (rt2860_rates[ridx].rate == rate)
2665203134Sthompsa				break;
2666203134Sthompsa		rn->ridx[i] = ridx;
2667203134Sthompsa		/* determine rate of control response frames */
2668203134Sthompsa		for (j = i; j >= 0; j--) {
2669203134Sthompsa			if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) &&
2670203134Sthompsa			    rt2860_rates[rn->ridx[i]].phy ==
2671203134Sthompsa			    rt2860_rates[rn->ridx[j]].phy)
2672203134Sthompsa				break;
2673203134Sthompsa		}
2674203134Sthompsa		if (j >= 0) {
2675203134Sthompsa			rn->ctl_ridx[i] = rn->ridx[j];
2676203134Sthompsa		} else {
2677203134Sthompsa			/* no basic rate found, use mandatory one */
2678203134Sthompsa			rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx;
2679203134Sthompsa		}
2680203134Sthompsa		DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n",
2681203134Sthompsa		    rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]);
2682203134Sthompsa	}
2683208019Sthompsa	rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate;
2684208019Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2685208019Sthompsa		if (rt2860_rates[ridx].rate == rate)
2686208019Sthompsa			break;
2687208019Sthompsa	rn->mgt_ridx = ridx;
2688208019Sthompsa	DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx);
2689208019Sthompsa
2690262795Shselasky	RUN_LOCK(sc);
2691262795Shselasky	if(sc->ratectl_run != RUN_RATECTL_OFF)
2692262795Shselasky		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2693262795Shselasky	RUN_UNLOCK(sc);
2694203134Sthompsa}
2695203134Sthompsa
2696203134Sthompsa/*
2697203134Sthompsa * Return the Rx chain with the highest RSSI for a given frame.
2698203134Sthompsa */
2699203134Sthompsastatic __inline uint8_t
2700203134Sthompsarun_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi)
2701203134Sthompsa{
2702203134Sthompsa	uint8_t rxchain = 0;
2703203134Sthompsa
2704203134Sthompsa	if (sc->nrxchains > 1) {
2705203134Sthompsa		if (rxwi->rssi[1] > rxwi->rssi[rxchain])
2706203134Sthompsa			rxchain = 1;
2707203134Sthompsa		if (sc->nrxchains > 2)
2708203134Sthompsa			if (rxwi->rssi[2] > rxwi->rssi[rxchain])
2709203134Sthompsa				rxchain = 2;
2710203134Sthompsa	}
2711209917Sthompsa	return (rxchain);
2712203134Sthompsa}
2713203134Sthompsa
2714203134Sthompsastatic void
2715288603Sadrianrun_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype,
2716288603Sadrian    const struct ieee80211_rx_stats *rxs, int rssi, int nf)
2717288603Sadrian{
2718288603Sadrian	struct ieee80211vap *vap = ni->ni_vap;
2719288603Sadrian	struct run_softc *sc = vap->iv_ic->ic_softc;
2720288603Sadrian	struct run_vap *rvp = RUN_VAP(vap);
2721288603Sadrian	uint64_t ni_tstamp, rx_tstamp;
2722288603Sadrian
2723288603Sadrian	rvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf);
2724288603Sadrian
2725288603Sadrian	if (vap->iv_state == IEEE80211_S_RUN &&
2726288603Sadrian	    (subtype == IEEE80211_FC0_SUBTYPE_BEACON ||
2727288603Sadrian	    subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) {
2728288603Sadrian		ni_tstamp = le64toh(ni->ni_tstamp.tsf);
2729288603Sadrian		RUN_LOCK(sc);
2730288603Sadrian		run_get_tsf(sc, &rx_tstamp);
2731288603Sadrian		RUN_UNLOCK(sc);
2732288603Sadrian		rx_tstamp = le64toh(rx_tstamp);
2733288603Sadrian
2734288603Sadrian		if (ni_tstamp >= rx_tstamp) {
2735288603Sadrian			DPRINTF("ibss merge, tsf %ju tstamp %ju\n",
2736288603Sadrian			    (uintmax_t)rx_tstamp, (uintmax_t)ni_tstamp);
2737288603Sadrian			(void) ieee80211_ibss_merge(ni);
2738288603Sadrian		}
2739288603Sadrian	}
2740288603Sadrian}
2741288603Sadrian
2742288603Sadrianstatic void
2743203134Sthompsarun_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen)
2744203134Sthompsa{
2745287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
2746203134Sthompsa	struct ieee80211_frame *wh;
2747203134Sthompsa	struct ieee80211_node *ni;
2748203134Sthompsa	struct rt2870_rxd *rxd;
2749203134Sthompsa	struct rt2860_rxwi *rxwi;
2750203134Sthompsa	uint32_t flags;
2751259032Skevlo	uint16_t len, rxwisize;
2752203134Sthompsa	uint8_t ant, rssi;
2753203134Sthompsa	int8_t nf;
2754203134Sthompsa
2755260219Skevlo	rxwisize = sizeof(struct rt2860_rxwi);
2756260219Skevlo	if (sc->mac_ver == 0x5592)
2757260219Skevlo		rxwisize += sizeof(uint64_t);
2758260219Skevlo	else if (sc->mac_ver == 0x3593)
2759260219Skevlo		rxwisize += sizeof(uint32_t);
2760343513Savos
2761343513Savos	if (__predict_false(dmalen <
2762343513Savos	    rxwisize + sizeof(struct ieee80211_frame_ack))) {
2763343513Savos		DPRINTF("payload is too short: dma length %u < %zu\n",
2764343513Savos		    dmalen, rxwisize + sizeof(struct ieee80211_frame_ack));
2765343513Savos		goto fail;
2766343513Savos	}
2767343513Savos
2768343513Savos	rxwi = mtod(m, struct rt2860_rxwi *);
2769343513Savos	len = le16toh(rxwi->len) & 0xfff;
2770343513Savos
2771343513Savos	if (__predict_false(len > dmalen - rxwisize)) {
2772203134Sthompsa		DPRINTF("bad RXWI length %u > %u\n", len, dmalen);
2773343513Savos		goto fail;
2774203134Sthompsa	}
2775343513Savos
2776203134Sthompsa	/* Rx descriptor is located at the end */
2777203134Sthompsa	rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen);
2778203134Sthompsa	flags = le32toh(rxd->flags);
2779203134Sthompsa
2780203134Sthompsa	if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) {
2781203134Sthompsa		DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV");
2782343513Savos		goto fail;
2783203134Sthompsa	}
2784203134Sthompsa
2785343513Savos	if (flags & RT2860_RX_L2PAD) {
2786343513Savos		DPRINTFN(8, "received RT2860_RX_L2PAD frame\n");
2787343513Savos		len += 2;
2788343513Savos	}
2789343513Savos
2790259032Skevlo	m->m_data += rxwisize;
2791343513Savos	m->m_pkthdr.len = m->m_len = len;
2792203134Sthompsa
2793203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
2794203134Sthompsa
2795346004Savos	if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) != 0 &&
2796346004Savos	    (flags & RT2860_RX_DEC) != 0) {
2797260444Skevlo		wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
2798203134Sthompsa		m->m_flags |= M_WEP;
2799203134Sthompsa	}
2800203134Sthompsa
2801343513Savos	if (len >= sizeof(struct ieee80211_frame_min)) {
2802343513Savos		ni = ieee80211_find_rxnode(ic,
2803343513Savos		    mtod(m, struct ieee80211_frame_min *));
2804343513Savos	} else
2805343513Savos		ni = NULL;
2806203134Sthompsa
2807203134Sthompsa	if (__predict_false(flags & RT2860_RX_MICERR)) {
2808203134Sthompsa		/* report MIC failures to net80211 for TKIP */
2809209917Sthompsa		if (ni != NULL)
2810259032Skevlo			ieee80211_notify_michael_failure(ni->ni_vap, wh,
2811259032Skevlo			    rxwi->keyidx);
2812203134Sthompsa		DPRINTF("MIC error. Someone is lying.\n");
2813343513Savos		goto fail;
2814203134Sthompsa	}
2815203134Sthompsa
2816203134Sthompsa	ant = run_maxrssi_chain(sc, rxwi);
2817203134Sthompsa	rssi = rxwi->rssi[ant];
2818203134Sthompsa	nf = run_rssi2dbm(sc, rssi, ant);
2819203134Sthompsa
2820209917Sthompsa	if (__predict_false(ieee80211_radiotap_active(ic))) {
2821203134Sthompsa		struct run_rx_radiotap_header *tap = &sc->sc_rxtap;
2822258643Shselasky		uint16_t phy;
2823203134Sthompsa
2824203134Sthompsa		tap->wr_flags = 0;
2825346006Savos		if (flags & RT2860_RX_L2PAD)
2826346006Savos			tap->wr_flags |= IEEE80211_RADIOTAP_F_DATAPAD;
2827203134Sthompsa		tap->wr_antsignal = rssi;
2828203134Sthompsa		tap->wr_antenna = ant;
2829203134Sthompsa		tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant);
2830203134Sthompsa		tap->wr_rate = 2;	/* in case it can't be found below */
2831301302Sadrian		RUN_LOCK(sc);
2832287554Skevlo		run_get_tsf(sc, &tap->wr_tsf);
2833301302Sadrian		RUN_UNLOCK(sc);
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	}
2860289753Savos
2861289753Savos	if (ni != NULL) {
2862289753Savos		(void)ieee80211_input(ni, m, rssi, nf);
2863289753Savos		ieee80211_free_node(ni);
2864289753Savos	} else {
2865289753Savos		(void)ieee80211_input_all(ic, m, rssi, nf);
2866289753Savos	}
2867343513Savos
2868343513Savos	return;
2869343513Savos
2870343513Savosfail:
2871343513Savos	m_freem(m);
2872343513Savos	counter_u64_add(ic->ic_ierrors, 1);
2873203134Sthompsa}
2874203134Sthompsa
2875203134Sthompsastatic void
2876203134Sthompsarun_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
2877203134Sthompsa{
2878203134Sthompsa	struct run_softc *sc = usbd_xfer_softc(xfer);
2879287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
2880203134Sthompsa	struct mbuf *m = NULL;
2881203134Sthompsa	struct mbuf *m0;
2882343513Savos	uint32_t dmalen, mbuf_len;
2883259032Skevlo	uint16_t rxwisize;
2884203134Sthompsa	int xferlen;
2885203134Sthompsa
2886260219Skevlo	rxwisize = sizeof(struct rt2860_rxwi);
2887260219Skevlo	if (sc->mac_ver == 0x5592)
2888260219Skevlo		rxwisize += sizeof(uint64_t);
2889260219Skevlo	else if (sc->mac_ver == 0x3593)
2890260219Skevlo		rxwisize += sizeof(uint32_t);
2891259032Skevlo
2892203134Sthompsa	usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL);
2893203134Sthompsa
2894203134Sthompsa	switch (USB_GET_STATE(xfer)) {
2895203134Sthompsa	case USB_ST_TRANSFERRED:
2896203134Sthompsa
2897203134Sthompsa		DPRINTFN(15, "rx done, actlen=%d\n", xferlen);
2898203134Sthompsa
2899259032Skevlo		if (xferlen < (int)(sizeof(uint32_t) + rxwisize +
2900259032Skevlo		    sizeof(struct rt2870_rxd))) {
2901203134Sthompsa			DPRINTF("xfer too short %d\n", xferlen);
2902203134Sthompsa			goto tr_setup;
2903203134Sthompsa		}
2904203134Sthompsa
2905203134Sthompsa		m = sc->rx_m;
2906203134Sthompsa		sc->rx_m = NULL;
2907203134Sthompsa
2908203134Sthompsa		/* FALLTHROUGH */
2909203134Sthompsa	case USB_ST_SETUP:
2910203134Sthompsatr_setup:
2911203134Sthompsa		if (sc->rx_m == NULL) {
2912243857Sglebius			sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
2913203134Sthompsa			    MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */);
2914203134Sthompsa		}
2915203134Sthompsa		if (sc->rx_m == NULL) {
2916203134Sthompsa			DPRINTF("could not allocate mbuf - idle with stall\n");
2917287197Sglebius			counter_u64_add(ic->ic_ierrors, 1);
2918203134Sthompsa			usbd_xfer_set_stall(xfer);
2919203134Sthompsa			usbd_xfer_set_frames(xfer, 0);
2920203134Sthompsa		} else {
2921203134Sthompsa			/*
2922203134Sthompsa			 * Directly loading a mbuf cluster into DMA to
2923203134Sthompsa			 * save some data copying. This works because
2924203134Sthompsa			 * there is only one cluster.
2925203134Sthompsa			 */
2926203134Sthompsa			usbd_xfer_set_frame_data(xfer, 0,
2927203134Sthompsa			    mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ);
2928203134Sthompsa			usbd_xfer_set_frames(xfer, 1);
2929203134Sthompsa		}
2930203134Sthompsa		usbd_transfer_submit(xfer);
2931203134Sthompsa		break;
2932203134Sthompsa
2933203134Sthompsa	default:	/* Error */
2934203134Sthompsa		if (error != USB_ERR_CANCELLED) {
2935203134Sthompsa			/* try to clear stall first */
2936203134Sthompsa			usbd_xfer_set_stall(xfer);
2937203134Sthompsa			if (error == USB_ERR_TIMEOUT)
2938203134Sthompsa				device_printf(sc->sc_dev, "device timeout\n");
2939287197Sglebius			counter_u64_add(ic->ic_ierrors, 1);
2940203134Sthompsa			goto tr_setup;
2941203134Sthompsa		}
2942209917Sthompsa		if (sc->rx_m != NULL) {
2943203134Sthompsa			m_freem(sc->rx_m);
2944203134Sthompsa			sc->rx_m = NULL;
2945203134Sthompsa		}
2946203134Sthompsa		break;
2947203134Sthompsa	}
2948203134Sthompsa
2949203134Sthompsa	if (m == NULL)
2950203134Sthompsa		return;
2951203134Sthompsa
2952203134Sthompsa	/* inputting all the frames must be last */
2953203134Sthompsa
2954203134Sthompsa	RUN_UNLOCK(sc);
2955203134Sthompsa
2956203134Sthompsa	m->m_pkthdr.len = m->m_len = xferlen;
2957203134Sthompsa
2958203134Sthompsa	/* HW can aggregate multiple 802.11 frames in a single USB xfer */
2959203134Sthompsa	for(;;) {
2960203134Sthompsa		dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff;
2961203134Sthompsa
2962233774Shselasky		if ((dmalen >= (uint32_t)-8) || (dmalen == 0) ||
2963233774Shselasky		    ((dmalen & 3) != 0)) {
2964203134Sthompsa			DPRINTF("bad DMA length %u\n", dmalen);
2965203134Sthompsa			break;
2966203134Sthompsa		}
2967233774Shselasky		if ((dmalen + 8) > (uint32_t)xferlen) {
2968203134Sthompsa			DPRINTF("bad DMA length %u > %d\n",
2969203134Sthompsa			dmalen + 8, xferlen);
2970203134Sthompsa			break;
2971203134Sthompsa		}
2972203134Sthompsa
2973203134Sthompsa		/* If it is the last one or a single frame, we won't copy. */
2974209917Sthompsa		if ((xferlen -= dmalen + 8) <= 8) {
2975203134Sthompsa			/* trim 32-bit DMA-len header */
2976203134Sthompsa			m->m_data += 4;
2977203134Sthompsa			m->m_pkthdr.len = m->m_len -= 4;
2978203134Sthompsa			run_rx_frame(sc, m, dmalen);
2979257435Shselasky			m = NULL;	/* don't free source buffer */
2980203134Sthompsa			break;
2981203134Sthompsa		}
2982203134Sthompsa
2983343513Savos		mbuf_len = dmalen + sizeof(struct rt2870_rxd);
2984343513Savos		if (__predict_false(mbuf_len > MCLBYTES)) {
2985343513Savos			DPRINTF("payload is too big: mbuf_len %u\n", mbuf_len);
2986343513Savos			counter_u64_add(ic->ic_ierrors, 1);
2987343513Savos			break;
2988343513Savos		}
2989343513Savos
2990203134Sthompsa		/* copy aggregated frames to another mbuf */
2991243857Sglebius		m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
2992203134Sthompsa		if (__predict_false(m0 == NULL)) {
2993203134Sthompsa			DPRINTF("could not allocate mbuf\n");
2994287197Sglebius			counter_u64_add(ic->ic_ierrors, 1);
2995203134Sthompsa			break;
2996203134Sthompsa		}
2997203134Sthompsa		m_copydata(m, 4 /* skip 32-bit DMA-len header */,
2998343513Savos		    mbuf_len, mtod(m0, caddr_t));
2999343513Savos		m0->m_pkthdr.len = m0->m_len = mbuf_len;
3000203134Sthompsa		run_rx_frame(sc, m0, dmalen);
3001203134Sthompsa
3002203134Sthompsa		/* update data ptr */
3003343513Savos		m->m_data += mbuf_len + 4;
3004343513Savos		m->m_pkthdr.len = m->m_len -= mbuf_len + 4;
3005203134Sthompsa	}
3006203134Sthompsa
3007257435Shselasky	/* make sure we free the source buffer, if any */
3008257435Shselasky	m_freem(m);
3009257435Shselasky
3010203134Sthompsa	RUN_LOCK(sc);
3011203134Sthompsa}
3012203134Sthompsa
3013203134Sthompsastatic void
3014203134Sthompsarun_tx_free(struct run_endpoint_queue *pq,
3015203134Sthompsa    struct run_tx_data *data, int txerr)
3016203134Sthompsa{
3017203134Sthompsa
3018289841Savos	ieee80211_tx_complete(data->ni, data->m, txerr);
3019203134Sthompsa
3020289841Savos	data->m = NULL;
3021289841Savos	data->ni = NULL;
3022289841Savos
3023203134Sthompsa	STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
3024203134Sthompsa	pq->tx_nfree++;
3025203134Sthompsa}
3026203134Sthompsa
3027203134Sthompsastatic void
3028257429Shselaskyrun_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index)
3029203134Sthompsa{
3030203134Sthompsa	struct run_softc *sc = usbd_xfer_softc(xfer);
3031287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3032203134Sthompsa	struct run_tx_data *data;
3033203134Sthompsa	struct ieee80211vap *vap = NULL;
3034203134Sthompsa	struct usb_page_cache *pc;
3035203134Sthompsa	struct run_endpoint_queue *pq = &sc->sc_epq[index];
3036203134Sthompsa	struct mbuf *m;
3037203134Sthompsa	usb_frlength_t size;
3038203134Sthompsa	int actlen;
3039203134Sthompsa	int sumlen;
3040203134Sthompsa
3041203134Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
3042203134Sthompsa
3043209917Sthompsa	switch (USB_GET_STATE(xfer)) {
3044203134Sthompsa	case USB_ST_TRANSFERRED:
3045203134Sthompsa		DPRINTFN(11, "transfer complete: %d "
3046203134Sthompsa		    "bytes @ index %d\n", actlen, index);
3047203134Sthompsa
3048203134Sthompsa		data = usbd_xfer_get_priv(xfer);
3049203134Sthompsa		run_tx_free(pq, data, 0);
3050203134Sthompsa		usbd_xfer_set_priv(xfer, NULL);
3051203134Sthompsa
3052203134Sthompsa		/* FALLTHROUGH */
3053203134Sthompsa	case USB_ST_SETUP:
3054203134Sthompsatr_setup:
3055203134Sthompsa		data = STAILQ_FIRST(&pq->tx_qh);
3056209917Sthompsa		if (data == NULL)
3057203134Sthompsa			break;
3058203134Sthompsa
3059203134Sthompsa		STAILQ_REMOVE_HEAD(&pq->tx_qh, next);
3060203134Sthompsa
3061203134Sthompsa		m = data->m;
3062261330Shselasky		size = (sc->mac_ver == 0x5592) ?
3063261330Shselasky		    sizeof(data->desc) + sizeof(uint32_t) : sizeof(data->desc);
3064261076Shselasky		if ((m->m_pkthdr.len +
3065261330Shselasky		    size + 3 + 8) > RUN_MAX_TXSZ) {
3066203134Sthompsa			DPRINTF("data overflow, %u bytes\n",
3067203134Sthompsa			    m->m_pkthdr.len);
3068203134Sthompsa			run_tx_free(pq, data, 1);
3069203134Sthompsa			goto tr_setup;
3070203134Sthompsa		}
3071203134Sthompsa
3072203134Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
3073203134Sthompsa		usbd_copy_in(pc, 0, &data->desc, size);
3074203134Sthompsa		usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len);
3075228508Shselasky		size += m->m_pkthdr.len;
3076228508Shselasky		/*
3077228508Shselasky		 * Align end on a 4-byte boundary, pad 8 bytes (CRC +
3078228508Shselasky		 * 4-byte padding), and be sure to zero those trailing
3079228508Shselasky		 * bytes:
3080228508Shselasky		 */
3081228508Shselasky		usbd_frame_zero(pc, size, ((-size) & 3) + 8);
3082228508Shselasky		size += ((-size) & 3) + 8;
3083203134Sthompsa
3084203134Sthompsa		vap = data->ni->ni_vap;
3085203134Sthompsa		if (ieee80211_radiotap_active_vap(vap)) {
3086346006Savos			const struct ieee80211_frame *wh;
3087203134Sthompsa			struct run_tx_radiotap_header *tap = &sc->sc_txtap;
3088259032Skevlo			struct rt2860_txwi *txwi =
3089208019Sthompsa			    (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd));
3090346006Savos			int has_l2pad;
3091346006Savos
3092346006Savos			wh = mtod(m, struct ieee80211_frame *);
3093346006Savos			has_l2pad = IEEE80211_HAS_ADDR4(wh) !=
3094346006Savos			    IEEE80211_QOS_HAS_SEQ(wh);
3095346006Savos
3096203134Sthompsa			tap->wt_flags = 0;
3097203134Sthompsa			tap->wt_rate = rt2860_rates[data->ridx].rate;
3098203134Sthompsa			tap->wt_hwqueue = index;
3099208019Sthompsa			if (le16toh(txwi->phy) & RT2860_PHY_SHPRE)
3100203134Sthompsa				tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
3101346006Savos			if (has_l2pad)
3102346006Savos				tap->wt_flags |= IEEE80211_RADIOTAP_F_DATAPAD;
3103203134Sthompsa
3104203134Sthompsa			ieee80211_radiotap_tx(vap, m);
3105203134Sthompsa		}
3106203134Sthompsa
3107228508Shselasky		DPRINTFN(11, "sending frame len=%u/%u  @ index %d\n",
3108228508Shselasky		    m->m_pkthdr.len, size, index);
3109203134Sthompsa
3110228508Shselasky		usbd_xfer_set_frame_len(xfer, 0, size);
3111203134Sthompsa		usbd_xfer_set_priv(xfer, data);
3112203134Sthompsa		usbd_transfer_submit(xfer);
3113287197Sglebius		run_start(sc);
3114203134Sthompsa
3115203134Sthompsa		break;
3116203134Sthompsa
3117203134Sthompsa	default:
3118203134Sthompsa		DPRINTF("USB transfer error, %s\n",
3119203134Sthompsa		    usbd_errstr(error));
3120203134Sthompsa
3121203134Sthompsa		data = usbd_xfer_get_priv(xfer);
3122203134Sthompsa
3123203134Sthompsa		if (data != NULL) {
3124208019Sthompsa			if(data->ni != NULL)
3125208019Sthompsa				vap = data->ni->ni_vap;
3126203134Sthompsa			run_tx_free(pq, data, error);
3127203134Sthompsa			usbd_xfer_set_priv(xfer, NULL);
3128203134Sthompsa		}
3129287197Sglebius
3130209917Sthompsa		if (vap == NULL)
3131208019Sthompsa			vap = TAILQ_FIRST(&ic->ic_vaps);
3132203134Sthompsa
3133203134Sthompsa		if (error != USB_ERR_CANCELLED) {
3134203134Sthompsa			if (error == USB_ERR_TIMEOUT) {
3135203134Sthompsa				device_printf(sc->sc_dev, "device timeout\n");
3136208019Sthompsa				uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3137208019Sthompsa				DPRINTF("cmdq_store=%d\n", i);
3138208019Sthompsa				sc->cmdq[i].func = run_usb_timeout_cb;
3139208019Sthompsa				sc->cmdq[i].arg0 = vap;
3140208019Sthompsa				ieee80211_runtask(ic, &sc->cmdq_task);
3141203134Sthompsa			}
3142203134Sthompsa
3143203134Sthompsa			/*
3144203134Sthompsa			 * Try to clear stall first, also if other
3145203134Sthompsa			 * errors occur, hence clearing stall
3146203134Sthompsa			 * introduces a 50 ms delay:
3147203134Sthompsa			 */
3148203134Sthompsa			usbd_xfer_set_stall(xfer);
3149203134Sthompsa			goto tr_setup;
3150203134Sthompsa		}
3151203134Sthompsa		break;
3152203134Sthompsa	}
3153203134Sthompsa}
3154203134Sthompsa
3155203134Sthompsastatic void
3156203134Sthompsarun_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error)
3157203134Sthompsa{
3158203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 0);
3159203134Sthompsa}
3160203134Sthompsa
3161203134Sthompsastatic void
3162203134Sthompsarun_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error)
3163203134Sthompsa{
3164203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 1);
3165203134Sthompsa}
3166203134Sthompsa
3167203134Sthompsastatic void
3168203134Sthompsarun_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error)
3169203134Sthompsa{
3170203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 2);
3171203134Sthompsa}
3172203134Sthompsa
3173203134Sthompsastatic void
3174203134Sthompsarun_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error)
3175203134Sthompsa{
3176203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 3);
3177203134Sthompsa}
3178203134Sthompsa
3179203134Sthompsastatic void
3180203134Sthompsarun_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error)
3181203134Sthompsa{
3182203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 4);
3183203134Sthompsa}
3184203134Sthompsa
3185203134Sthompsastatic void
3186203134Sthompsarun_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error)
3187203134Sthompsa{
3188203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 5);
3189203134Sthompsa}
3190203134Sthompsa
3191203134Sthompsastatic void
3192208019Sthompsarun_set_tx_desc(struct run_softc *sc, struct run_tx_data *data)
3193203134Sthompsa{
3194203134Sthompsa	struct mbuf *m = data->m;
3195287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3196208019Sthompsa	struct ieee80211vap *vap = data->ni->ni_vap;
3197203134Sthompsa	struct ieee80211_frame *wh;
3198203134Sthompsa	struct rt2870_txd *txd;
3199203134Sthompsa	struct rt2860_txwi *txwi;
3200259032Skevlo	uint16_t xferlen, txwisize;
3201208019Sthompsa	uint16_t mcs;
3202203134Sthompsa	uint8_t ridx = data->ridx;
3203208019Sthompsa	uint8_t pad;
3204203134Sthompsa
3205203134Sthompsa	/* get MCS code from rate index */
3206208019Sthompsa	mcs = rt2860_rates[ridx].mcs;
3207203134Sthompsa
3208259032Skevlo	txwisize = (sc->mac_ver == 0x5592) ?
3209259032Skevlo	    sizeof(*txwi) + sizeof(uint32_t) : sizeof(*txwi);
3210259032Skevlo	xferlen = txwisize + m->m_pkthdr.len;
3211203134Sthompsa
3212203134Sthompsa	/* roundup to 32-bit alignment */
3213203134Sthompsa	xferlen = (xferlen + 3) & ~3;
3214203134Sthompsa
3215203134Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3216203134Sthompsa	txd->len = htole16(xferlen);
3217203134Sthompsa
3218208019Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3219208019Sthompsa
3220208019Sthompsa	/*
3221208019Sthompsa	 * Ether both are true or both are false, the header
3222208019Sthompsa	 * are nicely aligned to 32-bit. So, no L2 padding.
3223208019Sthompsa	 */
3224208019Sthompsa	if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh))
3225208019Sthompsa		pad = 0;
3226208019Sthompsa	else
3227208019Sthompsa		pad = 2;
3228208019Sthompsa
3229203134Sthompsa	/* setup TX Wireless Information */
3230203134Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3231203134Sthompsa	txwi->len = htole16(m->m_pkthdr.len - pad);
3232203134Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_DS) {
3233270192Skevlo		mcs |= RT2860_PHY_CCK;
3234203134Sthompsa		if (ridx != RT2860_RIDX_CCK1 &&
3235203134Sthompsa		    (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
3236203134Sthompsa			mcs |= RT2860_PHY_SHPRE;
3237203134Sthompsa	} else
3238270192Skevlo		mcs |= RT2860_PHY_OFDM;
3239270192Skevlo	txwi->phy = htole16(mcs);
3240203134Sthompsa
3241203134Sthompsa	/* check if RTS/CTS or CTS-to-self protection is required */
3242203134Sthompsa	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3243203134Sthompsa	    (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold ||
3244203134Sthompsa	     ((ic->ic_flags & IEEE80211_F_USEPROT) &&
3245203134Sthompsa	      rt2860_rates[ridx].phy == IEEE80211_T_OFDM)))
3246208019Sthompsa		txwi->txop |= RT2860_TX_TXOP_HT;
3247203134Sthompsa	else
3248208019Sthompsa		txwi->txop |= RT2860_TX_TXOP_BACKOFF;
3249209144Sthompsa
3250209917Sthompsa	if (vap->iv_opmode != IEEE80211_M_STA && !IEEE80211_QOS_HAS_SEQ(wh))
3251209144Sthompsa		txwi->xflags |= RT2860_TX_NSEQ;
3252203134Sthompsa}
3253203134Sthompsa
3254203134Sthompsa/* This function must be called locked */
3255203134Sthompsastatic int
3256203134Sthompsarun_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3257203134Sthompsa{
3258287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3259208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
3260203134Sthompsa	struct ieee80211_frame *wh;
3261208019Sthompsa	struct ieee80211_channel *chan;
3262203134Sthompsa	const struct ieee80211_txparam *tp;
3263287552Skevlo	struct run_node *rn = RUN_NODE(ni);
3264203134Sthompsa	struct run_tx_data *data;
3265208019Sthompsa	struct rt2870_txd *txd;
3266208019Sthompsa	struct rt2860_txwi *txwi;
3267203134Sthompsa	uint16_t qos;
3268203134Sthompsa	uint16_t dur;
3269208019Sthompsa	uint16_t qid;
3270203134Sthompsa	uint8_t type;
3271203134Sthompsa	uint8_t tid;
3272208019Sthompsa	uint8_t ridx;
3273208019Sthompsa	uint8_t ctl_ridx;
3274203134Sthompsa	uint8_t qflags;
3275203134Sthompsa	uint8_t xflags = 0;
3276203134Sthompsa	int hasqos;
3277203134Sthompsa
3278203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3279203134Sthompsa
3280203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3281203134Sthompsa
3282203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3283203134Sthompsa
3284203134Sthompsa	/*
3285203134Sthompsa	 * There are 7 bulk endpoints: 1 for RX
3286203134Sthompsa	 * and 6 for TX (4 EDCAs + HCCA + Prio).
3287203134Sthompsa	 * Update 03-14-2009:  some devices like the Planex GW-US300MiniS
3288203134Sthompsa	 * seem to have only 4 TX bulk endpoints (Fukaumi Naoki).
3289203134Sthompsa	 */
3290203134Sthompsa	if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) {
3291203134Sthompsa		uint8_t *frm;
3292203134Sthompsa
3293344969Savos		frm = ieee80211_getqos(wh);
3294203134Sthompsa		qos = le16toh(*(const uint16_t *)frm);
3295203134Sthompsa		tid = qos & IEEE80211_QOS_TID;
3296203134Sthompsa		qid = TID_TO_WME_AC(tid);
3297203134Sthompsa	} else {
3298203134Sthompsa		qos = 0;
3299203134Sthompsa		tid = 0;
3300203134Sthompsa		qid = WME_AC_BE;
3301203134Sthompsa	}
3302203134Sthompsa	qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA;
3303203134Sthompsa
3304203134Sthompsa	DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n",
3305203134Sthompsa	    qos, qid, tid, qflags);
3306203134Sthompsa
3307208019Sthompsa	chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan;
3308208019Sthompsa	tp = &vap->iv_txparms[ieee80211_chan2mode(chan)];
3309203134Sthompsa
3310203134Sthompsa	/* pickup a rate index */
3311203134Sthompsa	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
3312270192Skevlo	    type != IEEE80211_FC0_TYPE_DATA || m->m_flags & M_EAPOL) {
3313203134Sthompsa		ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
3314203134Sthompsa		    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
3315203134Sthompsa		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3316203134Sthompsa	} else {
3317208019Sthompsa		if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
3318208019Sthompsa			ridx = rn->fix_ridx;
3319208019Sthompsa		else
3320208019Sthompsa			ridx = rn->amrr_ridx;
3321203134Sthompsa		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3322203134Sthompsa	}
3323203134Sthompsa
3324203134Sthompsa	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3325203134Sthompsa	    (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) !=
3326203134Sthompsa	     IEEE80211_QOS_ACKPOLICY_NOACK)) {
3327209144Sthompsa		xflags |= RT2860_TX_ACK;
3328203134Sthompsa		if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
3329208019Sthompsa			dur = rt2860_rates[ctl_ridx].sp_ack_dur;
3330203134Sthompsa		else
3331208019Sthompsa			dur = rt2860_rates[ctl_ridx].lp_ack_dur;
3332258919Shselasky		USETW(wh->i_dur, dur);
3333203134Sthompsa	}
3334203134Sthompsa
3335203134Sthompsa	/* reserve slots for mgmt packets, just in case */
3336203134Sthompsa	if (sc->sc_epq[qid].tx_nfree < 3) {
3337203134Sthompsa		DPRINTFN(10, "tx ring %d is full\n", qid);
3338203134Sthompsa		return (-1);
3339203134Sthompsa	}
3340203134Sthompsa
3341203134Sthompsa	data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh);
3342203134Sthompsa	STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next);
3343203134Sthompsa	sc->sc_epq[qid].tx_nfree--;
3344203134Sthompsa
3345208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3346208019Sthompsa	txd->flags = qflags;
3347208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3348208019Sthompsa	txwi->xflags = xflags;
3349259032Skevlo	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
3350245047Shselasky		txwi->wcid = 0;
3351259032Skevlo	else
3352245047Shselasky		txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
3353245047Shselasky		    1 : RUN_AID2WCID(ni->ni_associd);
3354259032Skevlo
3355208019Sthompsa	/* clear leftover garbage bits */
3356208019Sthompsa	txwi->flags = 0;
3357208019Sthompsa	txwi->txop = 0;
3358208019Sthompsa
3359203134Sthompsa	data->m = m;
3360203134Sthompsa	data->ni = ni;
3361203134Sthompsa	data->ridx = ridx;
3362203134Sthompsa
3363208019Sthompsa	run_set_tx_desc(sc, data);
3364203134Sthompsa
3365208019Sthompsa	/*
3366208019Sthompsa	 * The chip keeps track of 2 kind of Tx stats,
3367208019Sthompsa	 *  * TX_STAT_FIFO, for per WCID stats, and
3368208019Sthompsa	 *  * TX_STA_CNT0 for all-TX-in-one stats.
3369208019Sthompsa	 *
3370208019Sthompsa	 * To use FIFO stats, we need to store MCS into the driver-private
3371208019Sthompsa 	 * PacketID field. So that, we can tell whose stats when we read them.
3372208019Sthompsa 	 * We add 1 to the MCS because setting the PacketID field to 0 means
3373208019Sthompsa 	 * that we don't want feedback in TX_STAT_FIFO.
3374208019Sthompsa 	 * And, that's what we want for STA mode, since TX_STA_CNT0 does the job.
3375208019Sthompsa 	 *
3376208019Sthompsa 	 * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx().
3377208019Sthompsa 	 */
3378209917Sthompsa	if (sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP ||
3379209917Sthompsa	    vap->iv_opmode == IEEE80211_M_MBSS) {
3380208019Sthompsa		uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf;
3381208019Sthompsa		txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT);
3382208019Sthompsa
3383208019Sthompsa		/*
3384208019Sthompsa		 * Unlike PCI based devices, we don't get any interrupt from
3385208019Sthompsa		 * USB devices, so we simulate FIFO-is-full interrupt here.
3386298932Spfg		 * Ralink recommends to drain FIFO stats every 100 ms, but 16 slots
3387208019Sthompsa		 * quickly get fulled. To prevent overflow, increment a counter on
3388208019Sthompsa		 * every FIFO stat request, so we know how many slots are left.
3389208019Sthompsa		 * We do this only in HOSTAP or multiple vap mode since FIFO stats
3390208019Sthompsa		 * are used only in those modes.
3391208019Sthompsa		 * We just drain stats. AMRR gets updated every 1 sec by
3392208019Sthompsa		 * run_ratectl_cb() via callout.
3393208019Sthompsa		 * Call it early. Otherwise overflow.
3394208019Sthompsa		 */
3395209917Sthompsa		if (sc->fifo_cnt++ == 10) {
3396208019Sthompsa			/*
3397208019Sthompsa			 * With multiple vaps or if_bridge, if_start() is called
3398208019Sthompsa			 * with a non-sleepable lock, tcpinp. So, need to defer.
3399208019Sthompsa			 */
3400208019Sthompsa			uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3401208019Sthompsa			DPRINTFN(6, "cmdq_store=%d\n", i);
3402208019Sthompsa			sc->cmdq[i].func = run_drain_fifo;
3403208019Sthompsa			sc->cmdq[i].arg0 = sc;
3404208019Sthompsa			ieee80211_runtask(ic, &sc->cmdq_task);
3405208019Sthompsa		}
3406208019Sthompsa	}
3407208019Sthompsa
3408203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next);
3409203134Sthompsa
3410203134Sthompsa	usbd_transfer_start(sc->sc_xfer[qid]);
3411203134Sthompsa
3412258840Skevlo	DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n",
3413259032Skevlo	    m->m_pkthdr.len + (int)(sizeof(struct rt2870_txd) +
3414259046Shselasky	    sizeof(struct rt2860_txwi)), rt2860_rates[ridx].rate, qid);
3415203134Sthompsa
3416203134Sthompsa	return (0);
3417203134Sthompsa}
3418203134Sthompsa
3419203134Sthompsastatic int
3420203134Sthompsarun_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3421203134Sthompsa{
3422287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3423287552Skevlo	struct run_node *rn = RUN_NODE(ni);
3424203134Sthompsa	struct run_tx_data *data;
3425203134Sthompsa	struct ieee80211_frame *wh;
3426208019Sthompsa	struct rt2870_txd *txd;
3427208019Sthompsa	struct rt2860_txwi *txwi;
3428203134Sthompsa	uint16_t dur;
3429208019Sthompsa	uint8_t ridx = rn->mgt_ridx;
3430203134Sthompsa	uint8_t type;
3431203134Sthompsa	uint8_t xflags = 0;
3432208019Sthompsa	uint8_t wflags = 0;
3433203134Sthompsa
3434203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3435203134Sthompsa
3436203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3437203134Sthompsa
3438203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3439203134Sthompsa
3440208019Sthompsa	/* tell hardware to add timestamp for probe responses */
3441208019Sthompsa	if ((wh->i_fc[0] &
3442208019Sthompsa	    (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
3443208019Sthompsa	    (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
3444208019Sthompsa		wflags |= RT2860_TX_TS;
3445208019Sthompsa	else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3446203134Sthompsa		xflags |= RT2860_TX_ACK;
3447203134Sthompsa
3448208019Sthompsa		dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate,
3449203134Sthompsa		    ic->ic_flags & IEEE80211_F_SHPREAMBLE);
3450258919Shselasky		USETW(wh->i_dur, dur);
3451203134Sthompsa	}
3452203134Sthompsa
3453287197Sglebius	if (sc->sc_epq[0].tx_nfree == 0)
3454203134Sthompsa		/* let caller free mbuf */
3455203134Sthompsa		return (EIO);
3456203134Sthompsa	data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3457203134Sthompsa	STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3458203134Sthompsa	sc->sc_epq[0].tx_nfree--;
3459203134Sthompsa
3460208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3461208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3462208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3463208019Sthompsa	txwi->wcid = 0xff;
3464208019Sthompsa	txwi->flags = wflags;
3465208019Sthompsa	txwi->xflags = xflags;
3466208019Sthompsa	txwi->txop = 0;	/* clear leftover garbage bits */
3467208019Sthompsa
3468203134Sthompsa	data->m = m;
3469203134Sthompsa	data->ni = ni;
3470203134Sthompsa	data->ridx = ridx;
3471203134Sthompsa
3472208019Sthompsa	run_set_tx_desc(sc, data);
3473203134Sthompsa
3474203134Sthompsa	DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len +
3475258840Skevlo	    (int)(sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi)),
3476208019Sthompsa	    rt2860_rates[ridx].rate);
3477203134Sthompsa
3478203134Sthompsa	STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3479203134Sthompsa
3480203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3481203134Sthompsa
3482203134Sthompsa	return (0);
3483203134Sthompsa}
3484203134Sthompsa
3485203134Sthompsastatic int
3486203134Sthompsarun_sendprot(struct run_softc *sc,
3487203134Sthompsa    const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate)
3488203134Sthompsa{
3489203134Sthompsa	struct ieee80211com *ic = ni->ni_ic;
3490203134Sthompsa	struct ieee80211_frame *wh;
3491203134Sthompsa	struct run_tx_data *data;
3492208019Sthompsa	struct rt2870_txd *txd;
3493208019Sthompsa	struct rt2860_txwi *txwi;
3494203134Sthompsa	struct mbuf *mprot;
3495203134Sthompsa	int ridx;
3496203134Sthompsa	int protrate;
3497203134Sthompsa	int ackrate;
3498203134Sthompsa	int pktlen;
3499203134Sthompsa	int isshort;
3500203134Sthompsa	uint16_t dur;
3501203134Sthompsa	uint8_t type;
3502208019Sthompsa	uint8_t wflags = 0;
3503208019Sthompsa	uint8_t xflags = 0;
3504203134Sthompsa
3505203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3506203134Sthompsa
3507203134Sthompsa	KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY,
3508203134Sthompsa	    ("protection %d", prot));
3509203134Sthompsa
3510203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3511203134Sthompsa	pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
3512203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3513203134Sthompsa
3514203134Sthompsa	protrate = ieee80211_ctl_rate(ic->ic_rt, rate);
3515203134Sthompsa	ackrate = ieee80211_ack_rate(ic->ic_rt, rate);
3516203134Sthompsa
3517203134Sthompsa	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
3518209189Sjkim	dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort)
3519203134Sthompsa	    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3520203134Sthompsa	wflags = RT2860_TX_FRAG;
3521203134Sthompsa
3522203134Sthompsa	/* check that there are free slots before allocating the mbuf */
3523287197Sglebius	if (sc->sc_epq[0].tx_nfree == 0)
3524203134Sthompsa		/* let caller free mbuf */
3525203134Sthompsa		return (ENOBUFS);
3526203134Sthompsa
3527203134Sthompsa	if (prot == IEEE80211_PROT_RTSCTS) {
3528203134Sthompsa		/* NB: CTS is the same size as an ACK */
3529203134Sthompsa		dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3530208019Sthompsa		xflags |= RT2860_TX_ACK;
3531203134Sthompsa		mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur);
3532203134Sthompsa	} else {
3533203134Sthompsa		mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur);
3534203134Sthompsa	}
3535203134Sthompsa	if (mprot == NULL) {
3536287197Sglebius		if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1);
3537203134Sthompsa		DPRINTF("could not allocate mbuf\n");
3538203134Sthompsa		return (ENOBUFS);
3539203134Sthompsa	}
3540203134Sthompsa
3541203134Sthompsa        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3542203134Sthompsa        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3543203134Sthompsa        sc->sc_epq[0].tx_nfree--;
3544203134Sthompsa
3545208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3546208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3547208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3548208019Sthompsa	txwi->wcid = 0xff;
3549208019Sthompsa	txwi->flags = wflags;
3550208019Sthompsa	txwi->xflags = xflags;
3551208019Sthompsa	txwi->txop = 0;	/* clear leftover garbage bits */
3552208019Sthompsa
3553203134Sthompsa	data->m = mprot;
3554203134Sthompsa	data->ni = ieee80211_ref_node(ni);
3555203134Sthompsa
3556203134Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3557203134Sthompsa		if (rt2860_rates[ridx].rate == protrate)
3558203134Sthompsa			break;
3559203134Sthompsa	data->ridx = ridx;
3560203134Sthompsa
3561208019Sthompsa	run_set_tx_desc(sc, data);
3562203134Sthompsa
3563203134Sthompsa        DPRINTFN(1, "sending prot len=%u rate=%u\n",
3564203134Sthompsa            m->m_pkthdr.len, rate);
3565203134Sthompsa
3566203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3567203134Sthompsa
3568203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3569203134Sthompsa
3570203134Sthompsa	return (0);
3571203134Sthompsa}
3572203134Sthompsa
3573203134Sthompsastatic int
3574203134Sthompsarun_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
3575203134Sthompsa    const struct ieee80211_bpf_params *params)
3576203134Sthompsa{
3577203134Sthompsa	struct ieee80211com *ic = ni->ni_ic;
3578203134Sthompsa	struct ieee80211_frame *wh;
3579203134Sthompsa	struct run_tx_data *data;
3580208019Sthompsa	struct rt2870_txd *txd;
3581208019Sthompsa	struct rt2860_txwi *txwi;
3582203134Sthompsa	uint8_t type;
3583208019Sthompsa	uint8_t ridx;
3584208019Sthompsa	uint8_t rate;
3585208019Sthompsa	uint8_t opflags = 0;
3586208019Sthompsa	uint8_t xflags = 0;
3587203134Sthompsa	int error;
3588203134Sthompsa
3589203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3590203134Sthompsa
3591203134Sthompsa	KASSERT(params != NULL, ("no raw xmit params"));
3592203134Sthompsa
3593203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3594203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3595203134Sthompsa
3596203134Sthompsa	rate = params->ibp_rate0;
3597203134Sthompsa	if (!ieee80211_isratevalid(ic->ic_rt, rate)) {
3598203134Sthompsa		/* let caller free mbuf */
3599203134Sthompsa		return (EINVAL);
3600203134Sthompsa	}
3601203134Sthompsa
3602203134Sthompsa	if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0)
3603208019Sthompsa		xflags |= RT2860_TX_ACK;
3604203134Sthompsa	if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) {
3605203134Sthompsa		error = run_sendprot(sc, m, ni,
3606203134Sthompsa		    params->ibp_flags & IEEE80211_BPF_RTS ?
3607203134Sthompsa			IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY,
3608203134Sthompsa		    rate);
3609203134Sthompsa		if (error) {
3610203134Sthompsa			/* let caller free mbuf */
3611209917Sthompsa			return error;
3612203134Sthompsa		}
3613203134Sthompsa		opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS;
3614203134Sthompsa	}
3615203134Sthompsa
3616203134Sthompsa	if (sc->sc_epq[0].tx_nfree == 0) {
3617203134Sthompsa		/* let caller free mbuf */
3618203134Sthompsa		DPRINTF("sending raw frame, but tx ring is full\n");
3619203134Sthompsa		return (EIO);
3620203134Sthompsa	}
3621203134Sthompsa        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3622203134Sthompsa        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3623203134Sthompsa        sc->sc_epq[0].tx_nfree--;
3624203134Sthompsa
3625208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3626208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3627208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3628208019Sthompsa	txwi->wcid = 0xff;
3629208019Sthompsa	txwi->xflags = xflags;
3630208019Sthompsa	txwi->txop = opflags;
3631208019Sthompsa	txwi->flags = 0;	/* clear leftover garbage bits */
3632208019Sthompsa
3633203134Sthompsa        data->m = m;
3634203134Sthompsa        data->ni = ni;
3635203134Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3636203134Sthompsa		if (rt2860_rates[ridx].rate == rate)
3637203134Sthompsa			break;
3638203134Sthompsa	data->ridx = ridx;
3639203134Sthompsa
3640208019Sthompsa        run_set_tx_desc(sc, data);
3641203134Sthompsa
3642203134Sthompsa        DPRINTFN(10, "sending raw frame len=%u rate=%u\n",
3643203134Sthompsa            m->m_pkthdr.len, rate);
3644203134Sthompsa
3645203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3646203134Sthompsa
3647203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3648203134Sthompsa
3649209917Sthompsa        return (0);
3650203134Sthompsa}
3651203134Sthompsa
3652203134Sthompsastatic int
3653203134Sthompsarun_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
3654203134Sthompsa    const struct ieee80211_bpf_params *params)
3655203134Sthompsa{
3656286950Sadrian	struct run_softc *sc = ni->ni_ic->ic_softc;
3657208019Sthompsa	int error = 0;
3658208019Sthompsa
3659203134Sthompsa	RUN_LOCK(sc);
3660203134Sthompsa
3661203134Sthompsa	/* prevent management frames from being sent if we're not ready */
3662287197Sglebius	if (!(sc->sc_flags & RUN_RUNNING)) {
3663287197Sglebius		error = ENETDOWN;
3664208019Sthompsa		goto done;
3665203134Sthompsa	}
3666203134Sthompsa
3667203134Sthompsa	if (params == NULL) {
3668203134Sthompsa		/* tx mgt packet */
3669209917Sthompsa		if ((error = run_tx_mgt(sc, m, ni)) != 0) {
3670203134Sthompsa			DPRINTF("mgt tx failed\n");
3671208019Sthompsa			goto done;
3672203134Sthompsa		}
3673203134Sthompsa	} else {
3674203134Sthompsa		/* tx raw packet with param */
3675209917Sthompsa		if ((error = run_tx_param(sc, m, ni, params)) != 0) {
3676203134Sthompsa			DPRINTF("tx with param failed\n");
3677208019Sthompsa			goto done;
3678203134Sthompsa		}
3679203134Sthompsa	}
3680203134Sthompsa
3681208019Sthompsadone:
3682203134Sthompsa	RUN_UNLOCK(sc);
3683203134Sthompsa
3684209917Sthompsa	if (error != 0) {
3685208019Sthompsa		if(m != NULL)
3686208019Sthompsa			m_freem(m);
3687208019Sthompsa	}
3688203134Sthompsa
3689203134Sthompsa	return (error);
3690203134Sthompsa}
3691203134Sthompsa
3692287197Sglebiusstatic int
3693287197Sglebiusrun_transmit(struct ieee80211com *ic, struct mbuf *m)
3694287197Sglebius{
3695287197Sglebius	struct run_softc *sc = ic->ic_softc;
3696287197Sglebius	int error;
3697287197Sglebius
3698287197Sglebius	RUN_LOCK(sc);
3699287197Sglebius	if ((sc->sc_flags & RUN_RUNNING) == 0) {
3700287197Sglebius		RUN_UNLOCK(sc);
3701287197Sglebius		return (ENXIO);
3702287197Sglebius	}
3703287197Sglebius	error = mbufq_enqueue(&sc->sc_snd, m);
3704287197Sglebius	if (error) {
3705287197Sglebius		RUN_UNLOCK(sc);
3706287197Sglebius		return (error);
3707287197Sglebius	}
3708287197Sglebius	run_start(sc);
3709287197Sglebius	RUN_UNLOCK(sc);
3710287197Sglebius
3711287197Sglebius	return (0);
3712287197Sglebius}
3713287197Sglebius
3714203134Sthompsastatic void
3715287197Sglebiusrun_start(struct run_softc *sc)
3716203134Sthompsa{
3717203134Sthompsa	struct ieee80211_node *ni;
3718203134Sthompsa	struct mbuf *m;
3719203134Sthompsa
3720287197Sglebius	RUN_LOCK_ASSERT(sc, MA_OWNED);
3721203134Sthompsa
3722287197Sglebius	if ((sc->sc_flags & RUN_RUNNING) == 0)
3723203134Sthompsa		return;
3724203134Sthompsa
3725287197Sglebius	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
3726203134Sthompsa		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
3727203134Sthompsa		if (run_tx(sc, m, ni) != 0) {
3728287197Sglebius			mbufq_prepend(&sc->sc_snd, m);
3729203134Sthompsa			break;
3730203134Sthompsa		}
3731203134Sthompsa	}
3732203134Sthompsa}
3733203134Sthompsa
3734287197Sglebiusstatic void
3735287197Sglebiusrun_parent(struct ieee80211com *ic)
3736203134Sthompsa{
3737286950Sadrian	struct run_softc *sc = ic->ic_softc;
3738208019Sthompsa	int startall = 0;
3739203134Sthompsa
3740246614Shselasky	RUN_LOCK(sc);
3741287197Sglebius	if (sc->sc_detached) {
3742203134Sthompsa		RUN_UNLOCK(sc);
3743287197Sglebius		return;
3744203134Sthompsa	}
3745203134Sthompsa
3746287197Sglebius	if (ic->ic_nrunning > 0) {
3747287197Sglebius		if (!(sc->sc_flags & RUN_RUNNING)) {
3748287197Sglebius			startall = 1;
3749287197Sglebius			run_init_locked(sc);
3750287197Sglebius		} else
3751287197Sglebius			run_update_promisc_locked(sc);
3752287197Sglebius	} else if ((sc->sc_flags & RUN_RUNNING) && sc->rvp_cnt <= 1)
3753287197Sglebius		run_stop(sc);
3754287197Sglebius	RUN_UNLOCK(sc);
3755287197Sglebius	if (startall)
3756287197Sglebius		ieee80211_start_all(ic);
3757203134Sthompsa}
3758203134Sthompsa
3759203134Sthompsastatic void
3760259544Skevlorun_iq_calib(struct run_softc *sc, u_int chan)
3761259544Skevlo{
3762259544Skevlo	uint16_t val;
3763259544Skevlo
3764259544Skevlo	/* Tx0 IQ gain. */
3765259544Skevlo	run_bbp_write(sc, 158, 0x2c);
3766259544Skevlo	if (chan <= 14)
3767259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX0_2GHZ, &val, 1);
3768259544Skevlo	else if (chan <= 64) {
3769259544Skevlo		run_efuse_read(sc,
3770259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5GHZ,
3771259544Skevlo		    &val, 1);
3772259544Skevlo	} else if (chan <= 138) {
3773259544Skevlo		run_efuse_read(sc,
3774259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5GHZ,
3775259544Skevlo		    &val, 1);
3776259544Skevlo	} else if (chan <= 165) {
3777259544Skevlo		run_efuse_read(sc,
3778259544Skevlo	    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5GHZ,
3779259544Skevlo		    &val, 1);
3780259544Skevlo	} else
3781259544Skevlo		val = 0;
3782259547Skevlo	run_bbp_write(sc, 159, val);
3783259544Skevlo
3784259544Skevlo	/* Tx0 IQ phase. */
3785259544Skevlo	run_bbp_write(sc, 158, 0x2d);
3786259544Skevlo	if (chan <= 14) {
3787259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX0_2GHZ,
3788259544Skevlo		    &val, 1);
3789259544Skevlo	} else if (chan <= 64) {
3790259544Skevlo		run_efuse_read(sc,
3791259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5GHZ,
3792259544Skevlo		    &val, 1);
3793259544Skevlo	} else if (chan <= 138) {
3794259544Skevlo		run_efuse_read(sc,
3795259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5GHZ,
3796259544Skevlo		    &val, 1);
3797259544Skevlo	} else if (chan <= 165) {
3798259544Skevlo		run_efuse_read(sc,
3799259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5GHZ,
3800259544Skevlo		    &val, 1);
3801259544Skevlo	} else
3802259544Skevlo		val = 0;
3803259547Skevlo	run_bbp_write(sc, 159, val);
3804259544Skevlo
3805259544Skevlo	/* Tx1 IQ gain. */
3806259544Skevlo	run_bbp_write(sc, 158, 0x4a);
3807259544Skevlo	if (chan <= 14) {
3808259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX1_2GHZ,
3809259544Skevlo		    &val, 1);
3810259544Skevlo	} else if (chan <= 64) {
3811259544Skevlo		run_efuse_read(sc,
3812259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5GHZ,
3813259544Skevlo		    &val, 1);
3814259544Skevlo	} else if (chan <= 138) {
3815259544Skevlo		run_efuse_read(sc,
3816259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5GHZ,
3817259544Skevlo		    &val, 1);
3818259544Skevlo	} else if (chan <= 165) {
3819259544Skevlo		run_efuse_read(sc,
3820259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5GHZ,
3821259544Skevlo		    &val, 1);
3822259544Skevlo	} else
3823259544Skevlo		val = 0;
3824259547Skevlo	run_bbp_write(sc, 159, val);
3825259544Skevlo
3826259544Skevlo	/* Tx1 IQ phase. */
3827259544Skevlo	run_bbp_write(sc, 158, 0x4b);
3828259544Skevlo	if (chan <= 14) {
3829259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX1_2GHZ,
3830259544Skevlo		    &val, 1);
3831259544Skevlo	} else if (chan <= 64) {
3832259544Skevlo		run_efuse_read(sc,
3833259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5GHZ,
3834259544Skevlo		    &val, 1);
3835259544Skevlo	} else if (chan <= 138) {
3836259544Skevlo		run_efuse_read(sc,
3837259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5GHZ,
3838259544Skevlo		    &val, 1);
3839259544Skevlo	} else if (chan <= 165) {
3840259544Skevlo		run_efuse_read(sc,
3841259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5GHZ,
3842259544Skevlo		    &val, 1);
3843259544Skevlo	} else
3844259544Skevlo		val = 0;
3845259547Skevlo	run_bbp_write(sc, 159, val);
3846259544Skevlo
3847259544Skevlo	/* RF IQ compensation control. */
3848259544Skevlo	run_bbp_write(sc, 158, 0x04);
3849259544Skevlo	run_efuse_read(sc, RT5390_EEPROM_RF_IQ_COMPENSATION_CTL,
3850259544Skevlo	    &val, 1);
3851259547Skevlo	run_bbp_write(sc, 159, val);
3852259544Skevlo
3853259544Skevlo	/* RF IQ imbalance compensation control. */
3854259544Skevlo	run_bbp_write(sc, 158, 0x03);
3855259544Skevlo	run_efuse_read(sc,
3856259544Skevlo	    RT5390_EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CTL, &val, 1);
3857259547Skevlo	run_bbp_write(sc, 159, val);
3858259544Skevlo}
3859259544Skevlo
3860259544Skevlostatic void
3861205042Sthompsarun_set_agc(struct run_softc *sc, uint8_t agc)
3862205042Sthompsa{
3863205042Sthompsa	uint8_t bbp;
3864205042Sthompsa
3865205042Sthompsa	if (sc->mac_ver == 0x3572) {
3866205042Sthompsa		run_bbp_read(sc, 27, &bbp);
3867205042Sthompsa		bbp &= ~(0x3 << 5);
3868205042Sthompsa		run_bbp_write(sc, 27, bbp | 0 << 5);	/* select Rx0 */
3869205042Sthompsa		run_bbp_write(sc, 66, agc);
3870205042Sthompsa		run_bbp_write(sc, 27, bbp | 1 << 5);	/* select Rx1 */
3871205042Sthompsa		run_bbp_write(sc, 66, agc);
3872205042Sthompsa	} else
3873205042Sthompsa		run_bbp_write(sc, 66, agc);
3874205042Sthompsa}
3875205042Sthompsa
3876205042Sthompsastatic void
3877203134Sthompsarun_select_chan_group(struct run_softc *sc, int group)
3878203134Sthompsa{
3879203134Sthompsa	uint32_t tmp;
3880205042Sthompsa	uint8_t agc;
3881203134Sthompsa
3882203134Sthompsa	run_bbp_write(sc, 62, 0x37 - sc->lna[group]);
3883203134Sthompsa	run_bbp_write(sc, 63, 0x37 - sc->lna[group]);
3884203134Sthompsa	run_bbp_write(sc, 64, 0x37 - sc->lna[group]);
3885258082Skevlo	if (sc->mac_ver < 0x3572)
3886257955Skevlo		run_bbp_write(sc, 86, 0x00);
3887203134Sthompsa
3888260219Skevlo	if (sc->mac_ver == 0x3593) {
3889260219Skevlo		run_bbp_write(sc, 77, 0x98);
3890260219Skevlo		run_bbp_write(sc, 83, (group == 0) ? 0x8a : 0x9a);
3891260219Skevlo	}
3892260219Skevlo
3893203134Sthompsa	if (group == 0) {
3894203134Sthompsa		if (sc->ext_2ghz_lna) {
3895257955Skevlo			if (sc->mac_ver >= 0x5390)
3896257955Skevlo				run_bbp_write(sc, 75, 0x52);
3897257955Skevlo			else {
3898257955Skevlo				run_bbp_write(sc, 82, 0x62);
3899257955Skevlo				run_bbp_write(sc, 75, 0x46);
3900257955Skevlo			}
3901203134Sthompsa		} else {
3902259032Skevlo			if (sc->mac_ver == 0x5592) {
3903259032Skevlo				run_bbp_write(sc, 79, 0x1c);
3904259032Skevlo				run_bbp_write(sc, 80, 0x0e);
3905259032Skevlo				run_bbp_write(sc, 81, 0x3a);
3906259032Skevlo				run_bbp_write(sc, 82, 0x62);
3907259032Skevlo
3908259032Skevlo				run_bbp_write(sc, 195, 0x80);
3909259032Skevlo				run_bbp_write(sc, 196, 0xe0);
3910259032Skevlo				run_bbp_write(sc, 195, 0x81);
3911259032Skevlo				run_bbp_write(sc, 196, 0x1f);
3912259032Skevlo				run_bbp_write(sc, 195, 0x82);
3913259032Skevlo				run_bbp_write(sc, 196, 0x38);
3914259032Skevlo				run_bbp_write(sc, 195, 0x83);
3915259032Skevlo				run_bbp_write(sc, 196, 0x32);
3916259032Skevlo				run_bbp_write(sc, 195, 0x85);
3917259032Skevlo				run_bbp_write(sc, 196, 0x28);
3918259032Skevlo				run_bbp_write(sc, 195, 0x86);
3919259032Skevlo				run_bbp_write(sc, 196, 0x19);
3920259032Skevlo			} else if (sc->mac_ver >= 0x5390)
3921257955Skevlo				run_bbp_write(sc, 75, 0x50);
3922257955Skevlo			else {
3923260219Skevlo				run_bbp_write(sc, 82,
3924260219Skevlo				    (sc->mac_ver == 0x3593) ? 0x62 : 0x84);
3925257955Skevlo				run_bbp_write(sc, 75, 0x50);
3926257955Skevlo			}
3927203134Sthompsa		}
3928203134Sthompsa	} else {
3929259032Skevlo		if (sc->mac_ver == 0x5592) {
3930259032Skevlo			run_bbp_write(sc, 79, 0x18);
3931259032Skevlo			run_bbp_write(sc, 80, 0x08);
3932259032Skevlo			run_bbp_write(sc, 81, 0x38);
3933259032Skevlo			run_bbp_write(sc, 82, 0x92);
3934259032Skevlo
3935259032Skevlo			run_bbp_write(sc, 195, 0x80);
3936259032Skevlo			run_bbp_write(sc, 196, 0xf0);
3937259032Skevlo			run_bbp_write(sc, 195, 0x81);
3938259032Skevlo			run_bbp_write(sc, 196, 0x1e);
3939259032Skevlo			run_bbp_write(sc, 195, 0x82);
3940259032Skevlo			run_bbp_write(sc, 196, 0x28);
3941259032Skevlo			run_bbp_write(sc, 195, 0x83);
3942259032Skevlo			run_bbp_write(sc, 196, 0x20);
3943259032Skevlo			run_bbp_write(sc, 195, 0x85);
3944259032Skevlo			run_bbp_write(sc, 196, 0x7f);
3945259032Skevlo			run_bbp_write(sc, 195, 0x86);
3946259032Skevlo			run_bbp_write(sc, 196, 0x7f);
3947259032Skevlo		} else if (sc->mac_ver == 0x3572)
3948205042Sthompsa			run_bbp_write(sc, 82, 0x94);
3949205042Sthompsa		else
3950260219Skevlo			run_bbp_write(sc, 82,
3951260219Skevlo			    (sc->mac_ver == 0x3593) ? 0x82 : 0xf2);
3952205042Sthompsa		if (sc->ext_5ghz_lna)
3953203134Sthompsa			run_bbp_write(sc, 75, 0x46);
3954205042Sthompsa		else
3955203134Sthompsa			run_bbp_write(sc, 75, 0x50);
3956203134Sthompsa	}
3957203134Sthompsa
3958203134Sthompsa	run_read(sc, RT2860_TX_BAND_CFG, &tmp);
3959203134Sthompsa	tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P);
3960203134Sthompsa	tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P;
3961203134Sthompsa	run_write(sc, RT2860_TX_BAND_CFG, tmp);
3962203134Sthompsa
3963203134Sthompsa	/* enable appropriate Power Amplifiers and Low Noise Amplifiers */
3964208019Sthompsa	tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN;
3965260219Skevlo	if (sc->mac_ver == 0x3593)
3966260219Skevlo		tmp |= 1 << 29 | 1 << 28;
3967208019Sthompsa	if (sc->nrxchains > 1)
3968208019Sthompsa		tmp |= RT2860_LNA_PE1_EN;
3969203134Sthompsa	if (group == 0) {	/* 2GHz */
3970208019Sthompsa		tmp |= RT2860_PA_PE_G0_EN;
3971203134Sthompsa		if (sc->ntxchains > 1)
3972203134Sthompsa			tmp |= RT2860_PA_PE_G1_EN;
3973260219Skevlo		if (sc->mac_ver == 0x3593) {
3974260219Skevlo			if (sc->ntxchains > 2)
3975260219Skevlo				tmp |= 1 << 25;
3976260219Skevlo		}
3977203134Sthompsa	} else {		/* 5GHz */
3978208019Sthompsa		tmp |= RT2860_PA_PE_A0_EN;
3979203134Sthompsa		if (sc->ntxchains > 1)
3980203134Sthompsa			tmp |= RT2860_PA_PE_A1_EN;
3981203134Sthompsa	}
3982205042Sthompsa	if (sc->mac_ver == 0x3572) {
3983205042Sthompsa		run_rt3070_rf_write(sc, 8, 0x00);
3984205042Sthompsa		run_write(sc, RT2860_TX_PIN_CFG, tmp);
3985205042Sthompsa		run_rt3070_rf_write(sc, 8, 0x80);
3986205042Sthompsa	} else
3987205042Sthompsa		run_write(sc, RT2860_TX_PIN_CFG, tmp);
3988203134Sthompsa
3989259032Skevlo	if (sc->mac_ver == 0x5592) {
3990259032Skevlo		run_bbp_write(sc, 195, 0x8d);
3991259032Skevlo		run_bbp_write(sc, 196, 0x1a);
3992259032Skevlo	}
3993259032Skevlo
3994260219Skevlo	if (sc->mac_ver == 0x3593) {
3995260219Skevlo		run_read(sc, RT2860_GPIO_CTRL, &tmp);
3996260219Skevlo		tmp &= ~0x01010000;
3997260219Skevlo		if (group == 0)
3998260219Skevlo			tmp |= 0x00010000;
3999260219Skevlo		tmp = (tmp & ~0x00009090) | 0x00000090;
4000260219Skevlo		run_write(sc, RT2860_GPIO_CTRL, tmp);
4001260219Skevlo	}
4002260219Skevlo
4003203134Sthompsa	/* set initial AGC value */
4004205042Sthompsa	if (group == 0) {	/* 2GHz band */
4005205042Sthompsa		if (sc->mac_ver >= 0x3070)
4006205042Sthompsa			agc = 0x1c + sc->lna[0] * 2;
4007205042Sthompsa		else
4008205042Sthompsa			agc = 0x2e + sc->lna[0];
4009205042Sthompsa	} else {		/* 5GHz band */
4010259032Skevlo		if (sc->mac_ver == 0x5592)
4011259032Skevlo			agc = 0x24 + sc->lna[group] * 2;
4012260219Skevlo		else if (sc->mac_ver == 0x3572 || sc->mac_ver == 0x3593)
4013205042Sthompsa			agc = 0x22 + (sc->lna[group] * 5) / 3;
4014205042Sthompsa		else
4015205042Sthompsa			agc = 0x32 + (sc->lna[group] * 5) / 3;
4016205042Sthompsa	}
4017205042Sthompsa	run_set_agc(sc, agc);
4018203134Sthompsa}
4019203134Sthompsa
4020203134Sthompsastatic void
4021257429Shselaskyrun_rt2870_set_chan(struct run_softc *sc, u_int chan)
4022203134Sthompsa{
4023203134Sthompsa	const struct rfprog *rfprog = rt2860_rf2850;
4024203134Sthompsa	uint32_t r2, r3, r4;
4025203134Sthompsa	int8_t txpow1, txpow2;
4026203134Sthompsa	int i;
4027203134Sthompsa
4028203134Sthompsa	/* find the settings for this channel (we know it exists) */
4029203134Sthompsa	for (i = 0; rfprog[i].chan != chan; i++);
4030203134Sthompsa
4031203134Sthompsa	r2 = rfprog[i].r2;
4032203134Sthompsa	if (sc->ntxchains == 1)
4033258732Skevlo		r2 |= 1 << 14;		/* 1T: disable Tx chain 2 */
4034203134Sthompsa	if (sc->nrxchains == 1)
4035258732Skevlo		r2 |= 1 << 17 | 1 << 6;	/* 1R: disable Rx chains 2 & 3 */
4036203134Sthompsa	else if (sc->nrxchains == 2)
4037258732Skevlo		r2 |= 1 << 6;		/* 2R: disable Rx chain 3 */
4038203134Sthompsa
4039203134Sthompsa	/* use Tx power values from EEPROM */
4040203134Sthompsa	txpow1 = sc->txpow1[i];
4041203134Sthompsa	txpow2 = sc->txpow2[i];
4042258732Skevlo
4043258732Skevlo	/* Initialize RF R3 and R4. */
4044258732Skevlo	r3 = rfprog[i].r3 & 0xffffc1ff;
4045258732Skevlo	r4 = (rfprog[i].r4 & ~(0x001f87c0)) | (sc->freq << 15);
4046203134Sthompsa	if (chan > 14) {
4047258732Skevlo		if (txpow1 >= 0) {
4048258732Skevlo			txpow1 = (txpow1 > 0xf) ? (0xf) : (txpow1);
4049258732Skevlo			r3 |= (txpow1 << 10) | (1 << 9);
4050258732Skevlo		} else {
4051258732Skevlo			txpow1 += 7;
4052258732Skevlo
4053258732Skevlo			/* txpow1 is not possible larger than 15. */
4054258732Skevlo			r3 |= (txpow1 << 10);
4055258732Skevlo		}
4056258732Skevlo		if (txpow2 >= 0) {
4057258732Skevlo			txpow2 = (txpow2 > 0xf) ? (0xf) : (txpow2);
4058258921Shselasky			r4 |= (txpow2 << 7) | (1 << 6);
4059258732Skevlo		} else {
4060258732Skevlo			txpow2 += 7;
4061258732Skevlo			r4 |= (txpow2 << 7);
4062258732Skevlo		}
4063258732Skevlo	} else {
4064258732Skevlo		/* Set Tx0 power. */
4065258732Skevlo		r3 |= (txpow1 << 9);
4066258732Skevlo
4067258732Skevlo		/* Set frequency offset and Tx1 power. */
4068258732Skevlo		r4 |= (txpow2 << 6);
4069203134Sthompsa	}
4070203134Sthompsa
4071258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4072258733Skevlo	run_rt2870_rf_write(sc, r2);
4073258733Skevlo	run_rt2870_rf_write(sc, r3 & ~(1 << 2));
4074258733Skevlo	run_rt2870_rf_write(sc, r4);
4075203134Sthompsa
4076203134Sthompsa	run_delay(sc, 10);
4077203134Sthompsa
4078258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4079258733Skevlo	run_rt2870_rf_write(sc, r2);
4080258733Skevlo	run_rt2870_rf_write(sc, r3 | (1 << 2));
4081258733Skevlo	run_rt2870_rf_write(sc, r4);
4082203134Sthompsa
4083203134Sthompsa	run_delay(sc, 10);
4084203134Sthompsa
4085258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4086258733Skevlo	run_rt2870_rf_write(sc, r2);
4087258733Skevlo	run_rt2870_rf_write(sc, r3 & ~(1 << 2));
4088258733Skevlo	run_rt2870_rf_write(sc, r4);
4089203134Sthompsa}
4090203134Sthompsa
4091203134Sthompsastatic void
4092257429Shselaskyrun_rt3070_set_chan(struct run_softc *sc, u_int chan)
4093203134Sthompsa{
4094203134Sthompsa	int8_t txpow1, txpow2;
4095203134Sthompsa	uint8_t rf;
4096205042Sthompsa	int i;
4097203134Sthompsa
4098205042Sthompsa	/* find the settings for this channel (we know it exists) */
4099205042Sthompsa	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4100205042Sthompsa
4101203134Sthompsa	/* use Tx power values from EEPROM */
4102205042Sthompsa	txpow1 = sc->txpow1[i];
4103205042Sthompsa	txpow2 = sc->txpow2[i];
4104203134Sthompsa
4105205042Sthompsa	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
4106256720Skevlo
4107256720Skevlo	/* RT3370/RT3390: RF R3 [7:4] is not reserved bits. */
4108256720Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4109256720Skevlo	rf = (rf & ~0x0f) | rt3070_freqs[i].k;
4110256720Skevlo	run_rt3070_rf_write(sc, 3, rf);
4111256720Skevlo
4112203134Sthompsa	run_rt3070_rf_read(sc, 6, &rf);
4113205042Sthompsa	rf = (rf & ~0x03) | rt3070_freqs[i].r;
4114203134Sthompsa	run_rt3070_rf_write(sc, 6, rf);
4115203134Sthompsa
4116203134Sthompsa	/* set Tx0 power */
4117203134Sthompsa	run_rt3070_rf_read(sc, 12, &rf);
4118203134Sthompsa	rf = (rf & ~0x1f) | txpow1;
4119203134Sthompsa	run_rt3070_rf_write(sc, 12, rf);
4120203134Sthompsa
4121203134Sthompsa	/* set Tx1 power */
4122203134Sthompsa	run_rt3070_rf_read(sc, 13, &rf);
4123203134Sthompsa	rf = (rf & ~0x1f) | txpow2;
4124203134Sthompsa	run_rt3070_rf_write(sc, 13, rf);
4125203134Sthompsa
4126203134Sthompsa	run_rt3070_rf_read(sc, 1, &rf);
4127203134Sthompsa	rf &= ~0xfc;
4128203134Sthompsa	if (sc->ntxchains == 1)
4129203134Sthompsa		rf |= 1 << 7 | 1 << 5;	/* 1T: disable Tx chains 2 & 3 */
4130203134Sthompsa	else if (sc->ntxchains == 2)
4131203134Sthompsa		rf |= 1 << 7;		/* 2T: disable Tx chain 3 */
4132203134Sthompsa	if (sc->nrxchains == 1)
4133203134Sthompsa		rf |= 1 << 6 | 1 << 4;	/* 1R: disable Rx chains 2 & 3 */
4134203134Sthompsa	else if (sc->nrxchains == 2)
4135203134Sthompsa		rf |= 1 << 6;		/* 2R: disable Rx chain 3 */
4136203134Sthompsa	run_rt3070_rf_write(sc, 1, rf);
4137203134Sthompsa
4138203134Sthompsa	/* set RF offset */
4139203134Sthompsa	run_rt3070_rf_read(sc, 23, &rf);
4140203134Sthompsa	rf = (rf & ~0x7f) | sc->freq;
4141203134Sthompsa	run_rt3070_rf_write(sc, 23, rf);
4142203134Sthompsa
4143203134Sthompsa	/* program RF filter */
4144205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf);	/* Tx */
4145205042Sthompsa	rf = (rf & ~0x3f) | sc->rf24_20mhz;
4146205042Sthompsa	run_rt3070_rf_write(sc, 24, rf);
4147205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);	/* Rx */
4148205042Sthompsa	rf = (rf & ~0x3f) | sc->rf24_20mhz;
4149205042Sthompsa	run_rt3070_rf_write(sc, 31, rf);
4150203134Sthompsa
4151203134Sthompsa	/* enable RF tuning */
4152203134Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4153203134Sthompsa	run_rt3070_rf_write(sc, 7, rf | 0x01);
4154203134Sthompsa}
4155203134Sthompsa
4156203134Sthompsastatic void
4157205042Sthompsarun_rt3572_set_chan(struct run_softc *sc, u_int chan)
4158205042Sthompsa{
4159205042Sthompsa	int8_t txpow1, txpow2;
4160205042Sthompsa	uint32_t tmp;
4161205042Sthompsa	uint8_t rf;
4162205042Sthompsa	int i;
4163205042Sthompsa
4164205042Sthompsa	/* find the settings for this channel (we know it exists) */
4165205042Sthompsa	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4166205042Sthompsa
4167205042Sthompsa	/* use Tx power values from EEPROM */
4168205042Sthompsa	txpow1 = sc->txpow1[i];
4169205042Sthompsa	txpow2 = sc->txpow2[i];
4170205042Sthompsa
4171205042Sthompsa	if (chan <= 14) {
4172205042Sthompsa		run_bbp_write(sc, 25, sc->bbp25);
4173205042Sthompsa		run_bbp_write(sc, 26, sc->bbp26);
4174205042Sthompsa	} else {
4175205042Sthompsa		/* enable IQ phase correction */
4176205042Sthompsa		run_bbp_write(sc, 25, 0x09);
4177205042Sthompsa		run_bbp_write(sc, 26, 0xff);
4178205042Sthompsa	}
4179205042Sthompsa
4180205042Sthompsa	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
4181205042Sthompsa	run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k);
4182205042Sthompsa	run_rt3070_rf_read(sc, 6, &rf);
4183205042Sthompsa	rf  = (rf & ~0x0f) | rt3070_freqs[i].r;
4184205042Sthompsa	rf |= (chan <= 14) ? 0x08 : 0x04;
4185205042Sthompsa	run_rt3070_rf_write(sc, 6, rf);
4186205042Sthompsa
4187205042Sthompsa	/* set PLL mode */
4188205042Sthompsa	run_rt3070_rf_read(sc, 5, &rf);
4189205042Sthompsa	rf &= ~(0x08 | 0x04);
4190205042Sthompsa	rf |= (chan <= 14) ? 0x04 : 0x08;
4191205042Sthompsa	run_rt3070_rf_write(sc, 5, rf);
4192205042Sthompsa
4193205042Sthompsa	/* set Tx power for chain 0 */
4194205042Sthompsa	if (chan <= 14)
4195205042Sthompsa		rf = 0x60 | txpow1;
4196205042Sthompsa	else
4197205042Sthompsa		rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3);
4198205042Sthompsa	run_rt3070_rf_write(sc, 12, rf);
4199205042Sthompsa
4200205042Sthompsa	/* set Tx power for chain 1 */
4201205042Sthompsa	if (chan <= 14)
4202205042Sthompsa		rf = 0x60 | txpow2;
4203205042Sthompsa	else
4204205042Sthompsa		rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3);
4205205042Sthompsa	run_rt3070_rf_write(sc, 13, rf);
4206205042Sthompsa
4207205042Sthompsa	/* set Tx/Rx streams */
4208205042Sthompsa	run_rt3070_rf_read(sc, 1, &rf);
4209205042Sthompsa	rf &= ~0xfc;
4210205042Sthompsa	if (sc->ntxchains == 1)
4211205042Sthompsa		rf |= 1 << 7 | 1 << 5;  /* 1T: disable Tx chains 2 & 3 */
4212205042Sthompsa	else if (sc->ntxchains == 2)
4213205042Sthompsa		rf |= 1 << 7;           /* 2T: disable Tx chain 3 */
4214205042Sthompsa	if (sc->nrxchains == 1)
4215205042Sthompsa		rf |= 1 << 6 | 1 << 4;  /* 1R: disable Rx chains 2 & 3 */
4216205042Sthompsa	else if (sc->nrxchains == 2)
4217205042Sthompsa		rf |= 1 << 6;           /* 2R: disable Rx chain 3 */
4218205042Sthompsa	run_rt3070_rf_write(sc, 1, rf);
4219205042Sthompsa
4220205042Sthompsa	/* set RF offset */
4221205042Sthompsa	run_rt3070_rf_read(sc, 23, &rf);
4222205042Sthompsa	rf = (rf & ~0x7f) | sc->freq;
4223205042Sthompsa	run_rt3070_rf_write(sc, 23, rf);
4224205042Sthompsa
4225205042Sthompsa	/* program RF filter */
4226205042Sthompsa	rf = sc->rf24_20mhz;
4227205042Sthompsa	run_rt3070_rf_write(sc, 24, rf);	/* Tx */
4228205042Sthompsa	run_rt3070_rf_write(sc, 31, rf);	/* Rx */
4229205042Sthompsa
4230205042Sthompsa	/* enable RF tuning */
4231205042Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4232205042Sthompsa	rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14);
4233205042Sthompsa	run_rt3070_rf_write(sc, 7, rf);
4234205042Sthompsa
4235205042Sthompsa	/* TSSI */
4236205042Sthompsa	rf = (chan <= 14) ? 0xc3 : 0xc0;
4237205042Sthompsa	run_rt3070_rf_write(sc, 9, rf);
4238205042Sthompsa
4239205042Sthompsa	/* set loop filter 1 */
4240205042Sthompsa	run_rt3070_rf_write(sc, 10, 0xf1);
4241205042Sthompsa	/* set loop filter 2 */
4242205042Sthompsa	run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00);
4243205042Sthompsa
4244205042Sthompsa	/* set tx_mx2_ic */
4245205042Sthompsa	run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43);
4246205042Sthompsa	/* set tx_mx1_ic */
4247205042Sthompsa	if (chan <= 14)
4248205042Sthompsa		rf = 0x48 | sc->txmixgain_2ghz;
4249205042Sthompsa	else
4250205042Sthompsa		rf = 0x78 | sc->txmixgain_5ghz;
4251205042Sthompsa	run_rt3070_rf_write(sc, 16, rf);
4252205042Sthompsa
4253205042Sthompsa	/* set tx_lo1 */
4254205042Sthompsa	run_rt3070_rf_write(sc, 17, 0x23);
4255205042Sthompsa	/* set tx_lo2 */
4256205042Sthompsa	if (chan <= 14)
4257205042Sthompsa		rf = 0x93;
4258205042Sthompsa	else if (chan <= 64)
4259205042Sthompsa		rf = 0xb7;
4260205042Sthompsa	else if (chan <= 128)
4261205042Sthompsa		rf = 0x74;
4262205042Sthompsa	else
4263205042Sthompsa		rf = 0x72;
4264205042Sthompsa	run_rt3070_rf_write(sc, 19, rf);
4265205042Sthompsa
4266205042Sthompsa	/* set rx_lo1 */
4267205042Sthompsa	if (chan <= 14)
4268205042Sthompsa		rf = 0xb3;
4269205042Sthompsa	else if (chan <= 64)
4270205042Sthompsa		rf = 0xf6;
4271205042Sthompsa	else if (chan <= 128)
4272205042Sthompsa		rf = 0xf4;
4273205042Sthompsa	else
4274205042Sthompsa		rf = 0xf3;
4275205042Sthompsa	run_rt3070_rf_write(sc, 20, rf);
4276205042Sthompsa
4277205042Sthompsa	/* set pfd_delay */
4278205042Sthompsa	if (chan <= 14)
4279205042Sthompsa		rf = 0x15;
4280205042Sthompsa	else if (chan <= 64)
4281205042Sthompsa		rf = 0x3d;
4282205042Sthompsa	else
4283205042Sthompsa		rf = 0x01;
4284205042Sthompsa	run_rt3070_rf_write(sc, 25, rf);
4285205042Sthompsa
4286205042Sthompsa	/* set rx_lo2 */
4287205042Sthompsa	run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87);
4288205042Sthompsa	/* set ldo_rf_vc */
4289205042Sthompsa	run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01);
4290205042Sthompsa	/* set drv_cc */
4291205042Sthompsa	run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f);
4292205042Sthompsa
4293205042Sthompsa	run_read(sc, RT2860_GPIO_CTRL, &tmp);
4294205042Sthompsa	tmp &= ~0x8080;
4295205042Sthompsa	if (chan <= 14)
4296205042Sthompsa		tmp |= 0x80;
4297205042Sthompsa	run_write(sc, RT2860_GPIO_CTRL, tmp);
4298205042Sthompsa
4299205042Sthompsa	/* enable RF tuning */
4300205042Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4301205042Sthompsa	run_rt3070_rf_write(sc, 7, rf | 0x01);
4302205042Sthompsa
4303205042Sthompsa	run_delay(sc, 2);
4304205042Sthompsa}
4305205042Sthompsa
4306205042Sthompsastatic void
4307260219Skevlorun_rt3593_set_chan(struct run_softc *sc, u_int chan)
4308260219Skevlo{
4309260219Skevlo	int8_t txpow1, txpow2, txpow3;
4310260219Skevlo	uint8_t h20mhz, rf;
4311260219Skevlo	int i;
4312260219Skevlo
4313260219Skevlo	/* find the settings for this channel (we know it exists) */
4314260219Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4315260219Skevlo
4316260219Skevlo	/* use Tx power values from EEPROM */
4317260219Skevlo	txpow1 = sc->txpow1[i];
4318260219Skevlo	txpow2 = sc->txpow2[i];
4319260219Skevlo	txpow3 = (sc->ntxchains == 3) ? sc->txpow3[i] : 0;
4320260219Skevlo
4321260219Skevlo	if (chan <= 14) {
4322260219Skevlo		run_bbp_write(sc, 25, sc->bbp25);
4323260219Skevlo		run_bbp_write(sc, 26, sc->bbp26);
4324260219Skevlo	} else {
4325260219Skevlo		/* Enable IQ phase correction. */
4326260219Skevlo		run_bbp_write(sc, 25, 0x09);
4327260219Skevlo		run_bbp_write(sc, 26, 0xff);
4328260219Skevlo	}
4329260219Skevlo
4330260219Skevlo	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
4331260219Skevlo	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
4332260219Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4333260219Skevlo	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
4334260219Skevlo	run_rt3070_rf_write(sc, 11, rf);
4335260219Skevlo
4336260219Skevlo	/* Set pll_idoh. */
4337260219Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4338260219Skevlo	rf &= ~0x4c;
4339260219Skevlo	rf |= (chan <= 14) ? 0x44 : 0x48;
4340260219Skevlo	run_rt3070_rf_write(sc, 11, rf);
4341260219Skevlo
4342260219Skevlo	if (chan <= 14)
4343260219Skevlo		rf = txpow1 & 0x1f;
4344260219Skevlo	else
4345260219Skevlo		rf = 0x40 | ((txpow1 & 0x18) << 1) | (txpow1 & 0x07);
4346260219Skevlo	run_rt3070_rf_write(sc, 53, rf);
4347260219Skevlo
4348260219Skevlo	if (chan <= 14)
4349260219Skevlo		rf = txpow2 & 0x1f;
4350260219Skevlo	else
4351260219Skevlo		rf = 0x40 | ((txpow2 & 0x18) << 1) | (txpow2 & 0x07);
4352260219Skevlo	run_rt3070_rf_write(sc, 55, rf);
4353260219Skevlo
4354260219Skevlo	if (chan <= 14)
4355260219Skevlo		rf = txpow3 & 0x1f;
4356260219Skevlo	else
4357260219Skevlo		rf = 0x40 | ((txpow3 & 0x18) << 1) | (txpow3 & 0x07);
4358260219Skevlo	run_rt3070_rf_write(sc, 54, rf);
4359260219Skevlo
4360260219Skevlo	rf = RT3070_RF_BLOCK | RT3070_PLL_PD;
4361260219Skevlo	if (sc->ntxchains == 3)
4362260219Skevlo		rf |= RT3070_TX0_PD | RT3070_TX1_PD | RT3070_TX2_PD;
4363260219Skevlo	else
4364260219Skevlo		rf |= RT3070_TX0_PD | RT3070_TX1_PD;
4365260219Skevlo	rf |= RT3070_RX0_PD | RT3070_RX1_PD | RT3070_RX2_PD;
4366260219Skevlo	run_rt3070_rf_write(sc, 1, rf);
4367260219Skevlo
4368260219Skevlo	run_adjust_freq_offset(sc);
4369260219Skevlo
4370260219Skevlo	run_rt3070_rf_write(sc, 31, (chan <= 14) ? 0xa0 : 0x80);
4371260219Skevlo
4372260219Skevlo	h20mhz = (sc->rf24_20mhz & 0x20) >> 5;
4373260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
4374260219Skevlo	rf = (rf & ~0x06) | (h20mhz << 1) | (h20mhz << 2);
4375260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
4376260219Skevlo
4377260219Skevlo	run_rt3070_rf_read(sc, 36, &rf);
4378260219Skevlo	if (chan <= 14)
4379260219Skevlo		rf |= 0x80;
4380260219Skevlo	else
4381260219Skevlo		rf &= ~0x80;
4382260219Skevlo	run_rt3070_rf_write(sc, 36, rf);
4383260219Skevlo
4384260219Skevlo	/* Set vcolo_bs. */
4385260219Skevlo	run_rt3070_rf_write(sc, 34, (chan <= 14) ? 0x3c : 0x20);
4386260219Skevlo	/* Set pfd_delay. */
4387260219Skevlo	run_rt3070_rf_write(sc, 12, (chan <= 14) ? 0x1a : 0x12);
4388260219Skevlo
4389260219Skevlo	/* Set vco bias current control. */
4390260219Skevlo	run_rt3070_rf_read(sc, 6, &rf);
4391260219Skevlo	rf &= ~0xc0;
4392260219Skevlo	if (chan <= 14)
4393260219Skevlo		rf |= 0x40;
4394260219Skevlo	else if (chan <= 128)
4395260219Skevlo		rf |= 0x80;
4396260219Skevlo	else
4397260219Skevlo		rf |= 0x40;
4398260219Skevlo	run_rt3070_rf_write(sc, 6, rf);
4399260219Skevlo
4400260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
4401260219Skevlo	rf = (rf & ~0x18) | 0x10;
4402260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
4403260219Skevlo
4404260219Skevlo	run_rt3070_rf_write(sc, 10, (chan <= 14) ? 0xd3 : 0xd8);
4405260219Skevlo	run_rt3070_rf_write(sc, 13, (chan <= 14) ? 0x12 : 0x23);
4406260219Skevlo
4407260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4408260219Skevlo	rf = (rf & ~0x03) | 0x01;
4409260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4410260219Skevlo	/* Set tx_mx1_cc. */
4411260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4412260219Skevlo	rf &= ~0x1c;
4413260219Skevlo	rf |= (chan <= 14) ? 0x14 : 0x10;
4414260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4415260219Skevlo	/* Set tx_mx1_ic. */
4416260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4417260219Skevlo	rf &= ~0xe0;
4418260219Skevlo	rf |= (chan <= 14) ? 0x60 : 0x40;
4419260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4420260219Skevlo	/* Set tx_lo1_ic. */
4421260219Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4422260219Skevlo	rf &= ~0x1c;
4423260219Skevlo	rf |= (chan <= 14) ? 0x0c : 0x08;
4424260219Skevlo	run_rt3070_rf_write(sc, 49, rf);
4425260219Skevlo	/* Set tx_lo1_en. */
4426260219Skevlo	run_rt3070_rf_read(sc, 50, &rf);
4427260219Skevlo	run_rt3070_rf_write(sc, 50, rf & ~0x20);
4428260219Skevlo	/* Set drv_cc. */
4429260219Skevlo	run_rt3070_rf_read(sc, 57, &rf);
4430260219Skevlo	rf &= ~0xfc;
4431260219Skevlo	rf |= (chan <= 14) ?  0x6c : 0x3c;
4432260219Skevlo	run_rt3070_rf_write(sc, 57, rf);
4433260219Skevlo	/* Set rx_mix1_ic, rxa_lnactr, lna_vc, lna_inbias_en and lna_en. */
4434260219Skevlo	run_rt3070_rf_write(sc, 44, (chan <= 14) ? 0x93 : 0x9b);
4435260219Skevlo	/* Set drv_gnd_a, tx_vga_cc_a and tx_mx2_gain. */
4436260219Skevlo	run_rt3070_rf_write(sc, 52, (chan <= 14) ? 0x45 : 0x05);
4437260219Skevlo	/* Enable VCO calibration. */
4438260219Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4439260219Skevlo	rf &= ~RT5390_VCOCAL;
4440260219Skevlo	rf |= (chan <= 14) ? RT5390_VCOCAL : 0xbe;
4441260219Skevlo	run_rt3070_rf_write(sc, 3, rf);
4442260219Skevlo
4443260219Skevlo	if (chan <= 14)
4444260219Skevlo		rf = 0x23;
4445260219Skevlo	else if (chan <= 64)
4446260219Skevlo		rf = 0x36;
4447260219Skevlo	else if (chan <= 128)
4448260219Skevlo		rf = 0x32;
4449260219Skevlo	else
4450260219Skevlo		rf = 0x30;
4451260219Skevlo	run_rt3070_rf_write(sc, 39, rf);
4452260219Skevlo	if (chan <= 14)
4453260219Skevlo		rf = 0xbb;
4454260219Skevlo	else if (chan <= 64)
4455260219Skevlo		rf = 0xeb;
4456260219Skevlo	else if (chan <= 128)
4457260219Skevlo		rf = 0xb3;
4458260219Skevlo	else
4459260219Skevlo		rf = 0x9b;
4460260219Skevlo	run_rt3070_rf_write(sc, 45, rf);
4461260219Skevlo
4462260219Skevlo	/* Set FEQ/AEQ control. */
4463260219Skevlo	run_bbp_write(sc, 105, 0x34);
4464260219Skevlo}
4465260219Skevlo
4466260219Skevlostatic void
4467257955Skevlorun_rt5390_set_chan(struct run_softc *sc, u_int chan)
4468257955Skevlo{
4469257955Skevlo	int8_t txpow1, txpow2;
4470257955Skevlo	uint8_t rf;
4471257955Skevlo	int i;
4472257955Skevlo
4473257955Skevlo	/* find the settings for this channel (we know it exists) */
4474257955Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4475257955Skevlo
4476257955Skevlo	/* use Tx power values from EEPROM */
4477257955Skevlo	txpow1 = sc->txpow1[i];
4478257955Skevlo	txpow2 = sc->txpow2[i];
4479257955Skevlo
4480257955Skevlo	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
4481257955Skevlo	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
4482257955Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4483257955Skevlo	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
4484257955Skevlo	run_rt3070_rf_write(sc, 11, rf);
4485257955Skevlo
4486257955Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4487257955Skevlo	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
4488257955Skevlo	/* The valid range of the RF R49 is 0x00 to 0x27. */
4489257955Skevlo	if ((rf & 0x3f) > 0x27)
4490257955Skevlo		rf = (rf & ~0x3f) | 0x27;
4491257955Skevlo	run_rt3070_rf_write(sc, 49, rf);
4492257955Skevlo
4493257955Skevlo	if (sc->mac_ver == 0x5392) {
4494257955Skevlo		run_rt3070_rf_read(sc, 50, &rf);
4495257955Skevlo		rf = (rf & ~0x3f) | (txpow2 & 0x3f);
4496257955Skevlo		/* The valid range of the RF R50 is 0x00 to 0x27. */
4497257955Skevlo		if ((rf & 0x3f) > 0x27)
4498257955Skevlo			rf = (rf & ~0x3f) | 0x27;
4499257955Skevlo		run_rt3070_rf_write(sc, 50, rf);
4500257955Skevlo	}
4501257955Skevlo
4502257955Skevlo	run_rt3070_rf_read(sc, 1, &rf);
4503257955Skevlo	rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD;
4504257955Skevlo	if (sc->mac_ver == 0x5392)
4505257955Skevlo		rf |= RT3070_RX1_PD | RT3070_TX1_PD;
4506257955Skevlo	run_rt3070_rf_write(sc, 1, rf);
4507257955Skevlo
4508257955Skevlo	if (sc->mac_ver != 0x5392) {
4509257955Skevlo		run_rt3070_rf_read(sc, 2, &rf);
4510257955Skevlo		rf |= 0x80;
4511257955Skevlo		run_rt3070_rf_write(sc, 2, rf);
4512257955Skevlo		run_delay(sc, 10);
4513257955Skevlo		rf &= 0x7f;
4514257955Skevlo		run_rt3070_rf_write(sc, 2, rf);
4515257955Skevlo	}
4516257955Skevlo
4517257955Skevlo	run_adjust_freq_offset(sc);
4518257955Skevlo
4519257955Skevlo	if (sc->mac_ver == 0x5392) {
4520257955Skevlo		/* Fix for RT5392C. */
4521257955Skevlo		if (sc->mac_rev >= 0x0223) {
4522259030Skevlo			if (chan <= 4)
4523257955Skevlo				rf = 0x0f;
4524259030Skevlo			else if (chan >= 5 && chan <= 7)
4525257955Skevlo				rf = 0x0e;
4526259030Skevlo			else
4527257955Skevlo				rf = 0x0d;
4528257955Skevlo			run_rt3070_rf_write(sc, 23, rf);
4529257955Skevlo
4530259030Skevlo			if (chan <= 4)
4531257955Skevlo				rf = 0x0c;
4532257955Skevlo			else if (chan == 5)
4533257955Skevlo				rf = 0x0b;
4534259030Skevlo			else if (chan >= 6 && chan <= 7)
4535257955Skevlo				rf = 0x0a;
4536259030Skevlo			else if (chan >= 8 && chan <= 10)
4537257955Skevlo				rf = 0x09;
4538259030Skevlo			else
4539257955Skevlo				rf = 0x08;
4540257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4541257955Skevlo		} else {
4542259030Skevlo			if (chan <= 11)
4543257955Skevlo				rf = 0x0f;
4544259030Skevlo			else
4545257955Skevlo				rf = 0x0b;
4546257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4547257955Skevlo		}
4548257955Skevlo	} else {
4549257955Skevlo		/* Fix for RT5390F. */
4550257955Skevlo		if (sc->mac_rev >= 0x0502) {
4551259030Skevlo			if (chan <= 11)
4552257955Skevlo				rf = 0x43;
4553259030Skevlo			else
4554257955Skevlo				rf = 0x23;
4555257955Skevlo			run_rt3070_rf_write(sc, 55, rf);
4556257955Skevlo
4557259030Skevlo			if (chan <= 11)
4558257955Skevlo				rf = 0x0f;
4559257955Skevlo			else if (chan == 12)
4560257955Skevlo				rf = 0x0d;
4561259030Skevlo			else
4562257955Skevlo				rf = 0x0b;
4563257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4564257955Skevlo		} else {
4565257955Skevlo			run_rt3070_rf_write(sc, 55, 0x44);
4566257955Skevlo			run_rt3070_rf_write(sc, 59, 0x8f);
4567257955Skevlo		}
4568257955Skevlo	}
4569257955Skevlo
4570257955Skevlo	/* Enable VCO calibration. */
4571257955Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4572257955Skevlo	rf |= RT5390_VCOCAL;
4573257955Skevlo	run_rt3070_rf_write(sc, 3, rf);
4574257955Skevlo}
4575257955Skevlo
4576257955Skevlostatic void
4577259032Skevlorun_rt5592_set_chan(struct run_softc *sc, u_int chan)
4578259032Skevlo{
4579259032Skevlo	const struct rt5592_freqs *freqs;
4580259032Skevlo	uint32_t tmp;
4581259032Skevlo	uint8_t reg, rf, txpow_bound;
4582259032Skevlo	int8_t txpow1, txpow2;
4583259032Skevlo	int i;
4584259032Skevlo
4585259032Skevlo	run_read(sc, RT5592_DEBUG_INDEX, &tmp);
4586259032Skevlo	freqs = (tmp & RT5592_SEL_XTAL) ?
4587259032Skevlo	    rt5592_freqs_40mhz : rt5592_freqs_20mhz;
4588259032Skevlo
4589259032Skevlo	/* find the settings for this channel (we know it exists) */
4590259032Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++, freqs++);
4591259032Skevlo
4592259032Skevlo	/* use Tx power values from EEPROM */
4593259032Skevlo	txpow1 = sc->txpow1[i];
4594259032Skevlo	txpow2 = sc->txpow2[i];
4595259032Skevlo
4596259032Skevlo	run_read(sc, RT3070_LDO_CFG0, &tmp);
4597259032Skevlo	tmp &= ~0x1c000000;
4598259032Skevlo	if (chan > 14)
4599259032Skevlo		tmp |= 0x14000000;
4600259032Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
4601259032Skevlo
4602259032Skevlo	/* N setting. */
4603259032Skevlo	run_rt3070_rf_write(sc, 8, freqs->n & 0xff);
4604259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4605259032Skevlo	rf &= ~(1 << 4);
4606259032Skevlo	rf |= ((freqs->n & 0x0100) >> 8) << 4;
4607259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4608259032Skevlo
4609259032Skevlo	/* K setting. */
4610259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4611259032Skevlo	rf &= ~0x0f;
4612259032Skevlo	rf |= (freqs->k & 0x0f);
4613259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4614259032Skevlo
4615259032Skevlo	/* Mode setting. */
4616259032Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4617259032Skevlo	rf &= ~0x0c;
4618259032Skevlo	rf |= ((freqs->m - 0x8) & 0x3) << 2;
4619259032Skevlo	run_rt3070_rf_write(sc, 11, rf);
4620259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4621259032Skevlo	rf &= ~(1 << 7);
4622259032Skevlo	rf |= (((freqs->m - 0x8) & 0x4) >> 2) << 7;
4623259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4624259032Skevlo
4625259032Skevlo	/* R setting. */
4626259032Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4627259032Skevlo	rf &= ~0x03;
4628259032Skevlo	rf |= (freqs->r - 0x1);
4629259032Skevlo	run_rt3070_rf_write(sc, 11, rf);
4630259032Skevlo
4631259032Skevlo	if (chan <= 14) {
4632259032Skevlo		/* Initialize RF registers for 2GHZ. */
4633259032Skevlo		for (i = 0; i < nitems(rt5592_2ghz_def_rf); i++) {
4634259032Skevlo			run_rt3070_rf_write(sc, rt5592_2ghz_def_rf[i].reg,
4635259032Skevlo			    rt5592_2ghz_def_rf[i].val);
4636259032Skevlo		}
4637259032Skevlo
4638259032Skevlo		rf = (chan <= 10) ? 0x07 : 0x06;
4639259032Skevlo		run_rt3070_rf_write(sc, 23, rf);
4640259032Skevlo		run_rt3070_rf_write(sc, 59, rf);
4641259032Skevlo
4642259032Skevlo		run_rt3070_rf_write(sc, 55, 0x43);
4643259032Skevlo
4644259032Skevlo		/*
4645259032Skevlo		 * RF R49/R50 Tx power ALC code.
4646259032Skevlo		 * G-band bit<7:6>=1:0, bit<5:0> range from 0x0 ~ 0x27.
4647259032Skevlo		 */
4648259032Skevlo		reg = 2;
4649259032Skevlo		txpow_bound = 0x27;
4650259032Skevlo	} else {
4651259032Skevlo		/* Initialize RF registers for 5GHZ. */
4652259032Skevlo		for (i = 0; i < nitems(rt5592_5ghz_def_rf); i++) {
4653259032Skevlo			run_rt3070_rf_write(sc, rt5592_5ghz_def_rf[i].reg,
4654259032Skevlo			    rt5592_5ghz_def_rf[i].val);
4655259032Skevlo		}
4656259032Skevlo		for (i = 0; i < nitems(rt5592_chan_5ghz); i++) {
4657259032Skevlo			if (chan >= rt5592_chan_5ghz[i].firstchan &&
4658259032Skevlo			    chan <= rt5592_chan_5ghz[i].lastchan) {
4659259032Skevlo				run_rt3070_rf_write(sc, rt5592_chan_5ghz[i].reg,
4660259032Skevlo				    rt5592_chan_5ghz[i].val);
4661259032Skevlo			}
4662259032Skevlo		}
4663259032Skevlo
4664259032Skevlo		/*
4665259032Skevlo		 * RF R49/R50 Tx power ALC code.
4666259032Skevlo		 * A-band bit<7:6>=1:1, bit<5:0> range from 0x0 ~ 0x2b.
4667259032Skevlo		 */
4668259032Skevlo		reg = 3;
4669259032Skevlo		txpow_bound = 0x2b;
4670259032Skevlo	}
4671259032Skevlo
4672259032Skevlo	/* RF R49 ch0 Tx power ALC code. */
4673259032Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4674259032Skevlo	rf &= ~0xc0;
4675259032Skevlo	rf |= (reg << 6);
4676259032Skevlo	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
4677259032Skevlo	if ((rf & 0x3f) > txpow_bound)
4678259032Skevlo		rf = (rf & ~0x3f) | txpow_bound;
4679259032Skevlo	run_rt3070_rf_write(sc, 49, rf);
4680259032Skevlo
4681259032Skevlo	/* RF R50 ch1 Tx power ALC code. */
4682259032Skevlo	run_rt3070_rf_read(sc, 50, &rf);
4683259032Skevlo	rf &= ~(1 << 7 | 1 << 6);
4684259032Skevlo	rf |= (reg << 6);
4685259032Skevlo	rf = (rf & ~0x3f) | (txpow2 & 0x3f);
4686259032Skevlo	if ((rf & 0x3f) > txpow_bound)
4687259032Skevlo		rf = (rf & ~0x3f) | txpow_bound;
4688259032Skevlo	run_rt3070_rf_write(sc, 50, rf);
4689259032Skevlo
4690259032Skevlo	/* Enable RF_BLOCK, PLL_PD, RX0_PD, and TX0_PD. */
4691259032Skevlo	run_rt3070_rf_read(sc, 1, &rf);
4692259032Skevlo	rf |= (RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD);
4693259032Skevlo	if (sc->ntxchains > 1)
4694259032Skevlo		rf |= RT3070_TX1_PD;
4695259032Skevlo	if (sc->nrxchains > 1)
4696259032Skevlo		rf |= RT3070_RX1_PD;
4697259032Skevlo	run_rt3070_rf_write(sc, 1, rf);
4698259032Skevlo
4699259032Skevlo	run_rt3070_rf_write(sc, 6, 0xe4);
4700259032Skevlo
4701259032Skevlo	run_rt3070_rf_write(sc, 30, 0x10);
4702259032Skevlo	run_rt3070_rf_write(sc, 31, 0x80);
4703259032Skevlo	run_rt3070_rf_write(sc, 32, 0x80);
4704259032Skevlo
4705259032Skevlo	run_adjust_freq_offset(sc);
4706259032Skevlo
4707259032Skevlo	/* Enable VCO calibration. */
4708259032Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4709259032Skevlo	rf |= RT5390_VCOCAL;
4710259032Skevlo	run_rt3070_rf_write(sc, 3, rf);
4711259032Skevlo}
4712259032Skevlo
4713259032Skevlostatic void
4714203134Sthompsarun_set_rx_antenna(struct run_softc *sc, int aux)
4715203134Sthompsa{
4716203134Sthompsa	uint32_t tmp;
4717257955Skevlo	uint8_t bbp152;
4718203134Sthompsa
4719203134Sthompsa	if (aux) {
4720257955Skevlo		if (sc->rf_rev == RT5390_RF_5370) {
4721257955Skevlo			run_bbp_read(sc, 152, &bbp152);
4722257955Skevlo			run_bbp_write(sc, 152, bbp152 & ~0x80);
4723259030Skevlo		} else {
4724257955Skevlo			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0);
4725257955Skevlo			run_read(sc, RT2860_GPIO_CTRL, &tmp);
4726257955Skevlo			run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08);
4727257955Skevlo		}
4728203134Sthompsa	} else {
4729257955Skevlo		if (sc->rf_rev == RT5390_RF_5370) {
4730257955Skevlo			run_bbp_read(sc, 152, &bbp152);
4731257955Skevlo			run_bbp_write(sc, 152, bbp152 | 0x80);
4732259030Skevlo		} else {
4733257955Skevlo			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1);
4734257955Skevlo			run_read(sc, RT2860_GPIO_CTRL, &tmp);
4735257955Skevlo			run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808);
4736257955Skevlo		}
4737203134Sthompsa	}
4738203134Sthompsa}
4739203134Sthompsa
4740203134Sthompsastatic int
4741203134Sthompsarun_set_chan(struct run_softc *sc, struct ieee80211_channel *c)
4742203134Sthompsa{
4743287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4744257429Shselasky	u_int chan, group;
4745203134Sthompsa
4746203134Sthompsa	chan = ieee80211_chan2ieee(ic, c);
4747203134Sthompsa	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
4748209917Sthompsa		return (EINVAL);
4749203134Sthompsa
4750259032Skevlo	if (sc->mac_ver == 0x5592)
4751259032Skevlo		run_rt5592_set_chan(sc, chan);
4752259032Skevlo	else if (sc->mac_ver >= 0x5390)
4753257955Skevlo		run_rt5390_set_chan(sc, chan);
4754260219Skevlo	else if (sc->mac_ver == 0x3593)
4755260219Skevlo		run_rt3593_set_chan(sc, chan);
4756257955Skevlo	else if (sc->mac_ver == 0x3572)
4757205042Sthompsa		run_rt3572_set_chan(sc, chan);
4758205042Sthompsa	else if (sc->mac_ver >= 0x3070)
4759203134Sthompsa		run_rt3070_set_chan(sc, chan);
4760203134Sthompsa	else
4761203134Sthompsa		run_rt2870_set_chan(sc, chan);
4762203134Sthompsa
4763203134Sthompsa	/* determine channel group */
4764203134Sthompsa	if (chan <= 14)
4765203134Sthompsa		group = 0;
4766203134Sthompsa	else if (chan <= 64)
4767203134Sthompsa		group = 1;
4768203134Sthompsa	else if (chan <= 128)
4769203134Sthompsa		group = 2;
4770203134Sthompsa	else
4771203134Sthompsa		group = 3;
4772203134Sthompsa
4773203134Sthompsa	/* XXX necessary only when group has changed! */
4774203134Sthompsa	run_select_chan_group(sc, group);
4775203134Sthompsa
4776203134Sthompsa	run_delay(sc, 10);
4777203134Sthompsa
4778259545Skevlo	/* Perform IQ calibration. */
4779259544Skevlo	if (sc->mac_ver >= 0x5392)
4780259544Skevlo		run_iq_calib(sc, chan);
4781259544Skevlo
4782209917Sthompsa	return (0);
4783203134Sthompsa}
4784203134Sthompsa
4785203134Sthompsastatic void
4786203134Sthompsarun_set_channel(struct ieee80211com *ic)
4787203134Sthompsa{
4788286950Sadrian	struct run_softc *sc = ic->ic_softc;
4789203134Sthompsa
4790203134Sthompsa	RUN_LOCK(sc);
4791203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
4792203134Sthompsa	RUN_UNLOCK(sc);
4793203134Sthompsa
4794203134Sthompsa	return;
4795203134Sthompsa}
4796203134Sthompsa
4797203134Sthompsastatic void
4798300748Savosrun_getradiocaps(struct ieee80211com *ic,
4799300748Savos    int maxchans, int *nchans, struct ieee80211_channel chans[])
4800300748Savos{
4801300748Savos	struct run_softc *sc = ic->ic_softc;
4802300748Savos	uint8_t bands[IEEE80211_MODE_BYTES];
4803300748Savos
4804300748Savos	memset(bands, 0, sizeof(bands));
4805300748Savos	setbit(bands, IEEE80211_MODE_11B);
4806300748Savos	setbit(bands, IEEE80211_MODE_11G);
4807343976Savos	ieee80211_add_channels_default_2ghz(chans, maxchans, nchans, bands, 0);
4808300748Savos
4809300748Savos	if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850 ||
4810300748Savos	    sc->rf_rev == RT3070_RF_3052 || sc->rf_rev == RT3593_RF_3053 ||
4811300748Savos	    sc->rf_rev == RT5592_RF_5592) {
4812300748Savos		setbit(bands, IEEE80211_MODE_11A);
4813300748Savos		ieee80211_add_channel_list_5ghz(chans, maxchans, nchans,
4814300748Savos		    run_chan_5ghz, nitems(run_chan_5ghz), bands, 0);
4815300748Savos	}
4816300748Savos}
4817300748Savos
4818300748Savosstatic void
4819203134Sthompsarun_scan_start(struct ieee80211com *ic)
4820203134Sthompsa{
4821286950Sadrian	struct run_softc *sc = ic->ic_softc;
4822203134Sthompsa
4823203134Sthompsa	RUN_LOCK(sc);
4824203134Sthompsa
4825203134Sthompsa	/* abort TSF synchronization */
4826345752Savos	run_disable_tsf(sc);
4827287197Sglebius	run_set_bssid(sc, ieee80211broadcastaddr);
4828203134Sthompsa
4829203134Sthompsa	RUN_UNLOCK(sc);
4830203134Sthompsa
4831203134Sthompsa	return;
4832203134Sthompsa}
4833203134Sthompsa
4834203134Sthompsastatic void
4835203134Sthompsarun_scan_end(struct ieee80211com *ic)
4836203134Sthompsa{
4837286950Sadrian	struct run_softc *sc = ic->ic_softc;
4838203134Sthompsa
4839203134Sthompsa	RUN_LOCK(sc);
4840203134Sthompsa
4841203134Sthompsa	run_enable_tsf_sync(sc);
4842296356Savos	run_set_bssid(sc, sc->sc_bssid);
4843203134Sthompsa
4844203134Sthompsa	RUN_UNLOCK(sc);
4845203134Sthompsa
4846203134Sthompsa	return;
4847203134Sthompsa}
4848203134Sthompsa
4849208019Sthompsa/*
4850208019Sthompsa * Could be called from ieee80211_node_timeout()
4851208019Sthompsa * (non-sleepable thread)
4852208019Sthompsa */
4853208019Sthompsastatic void
4854208019Sthompsarun_update_beacon(struct ieee80211vap *vap, int item)
4855203134Sthompsa{
4856208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4857288095Sadrian	struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off;
4858288095Sadrian	struct ieee80211_node *ni = vap->iv_bss;
4859286950Sadrian	struct run_softc *sc = ic->ic_softc;
4860218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4861218492Sbschmidt	int mcast = 0;
4862208019Sthompsa	uint32_t i;
4863208019Sthompsa
4864218492Sbschmidt	switch (item) {
4865218492Sbschmidt	case IEEE80211_BEACON_ERP:
4866283540Sglebius		run_updateslot(ic);
4867218492Sbschmidt		break;
4868218492Sbschmidt	case IEEE80211_BEACON_HTINFO:
4869218492Sbschmidt		run_updateprot(ic);
4870218492Sbschmidt		break;
4871218492Sbschmidt	case IEEE80211_BEACON_TIM:
4872218492Sbschmidt		mcast = 1;	/*TODO*/
4873218492Sbschmidt		break;
4874218492Sbschmidt	default:
4875218492Sbschmidt		break;
4876218492Sbschmidt	}
4877218492Sbschmidt
4878288095Sadrian	setbit(bo->bo_flags, item);
4879273448Skevlo	if (rvp->beacon_mbuf == NULL) {
4880288636Sadrian		rvp->beacon_mbuf = ieee80211_beacon_alloc(ni);
4881273448Skevlo		if (rvp->beacon_mbuf == NULL)
4882273448Skevlo			return;
4883273448Skevlo	}
4884288636Sadrian	ieee80211_beacon_update(ni, rvp->beacon_mbuf, mcast);
4885218492Sbschmidt
4886208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
4887208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
4888208019Sthompsa	sc->cmdq[i].func = run_update_beacon_cb;
4889208019Sthompsa	sc->cmdq[i].arg0 = vap;
4890208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
4891208019Sthompsa
4892208019Sthompsa	return;
4893203134Sthompsa}
4894203134Sthompsa
4895203134Sthompsastatic void
4896208019Sthompsarun_update_beacon_cb(void *arg)
4897203134Sthompsa{
4898208019Sthompsa	struct ieee80211vap *vap = arg;
4899288095Sadrian	struct ieee80211_node *ni = vap->iv_bss;
4900218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4901203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4902286950Sadrian	struct run_softc *sc = ic->ic_softc;
4903203134Sthompsa	struct rt2860_txwi txwi;
4904203134Sthompsa	struct mbuf *m;
4905259032Skevlo	uint16_t txwisize;
4906208019Sthompsa	uint8_t ridx;
4907203134Sthompsa
4908288095Sadrian	if (ni->ni_chan == IEEE80211_CHAN_ANYC)
4909208019Sthompsa		return;
4910236439Shselasky	if (ic->ic_bsschan == IEEE80211_CHAN_ANYC)
4911236439Shselasky		return;
4912208019Sthompsa
4913218492Sbschmidt	/*
4914218492Sbschmidt	 * No need to call ieee80211_beacon_update(), run_update_beacon()
4915298932Spfg	 * is taking care of appropriate calls.
4916218492Sbschmidt	 */
4917218492Sbschmidt	if (rvp->beacon_mbuf == NULL) {
4918288636Sadrian		rvp->beacon_mbuf = ieee80211_beacon_alloc(ni);
4919218492Sbschmidt		if (rvp->beacon_mbuf == NULL)
4920218492Sbschmidt			return;
4921218492Sbschmidt	}
4922218492Sbschmidt	m = rvp->beacon_mbuf;
4923203134Sthompsa
4924259032Skevlo	memset(&txwi, 0, sizeof(txwi));
4925203134Sthompsa	txwi.wcid = 0xff;
4926203134Sthompsa	txwi.len = htole16(m->m_pkthdr.len);
4927259032Skevlo
4928203134Sthompsa	/* send beacons at the lowest available rate */
4929208019Sthompsa	ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
4930208019Sthompsa	    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
4931208019Sthompsa	txwi.phy = htole16(rt2860_rates[ridx].mcs);
4932208019Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM)
4933259032Skevlo		txwi.phy |= htole16(RT2860_PHY_OFDM);
4934203134Sthompsa	txwi.txop = RT2860_TX_TXOP_HT;
4935203134Sthompsa	txwi.flags = RT2860_TX_TS;
4936209144Sthompsa	txwi.xflags = RT2860_TX_NSEQ;
4937203134Sthompsa
4938259032Skevlo	txwisize = (sc->mac_ver == 0x5592) ?
4939259032Skevlo	    sizeof(txwi) + sizeof(uint32_t) : sizeof(txwi);
4940259032Skevlo	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id), (uint8_t *)&txwi,
4941259032Skevlo	    txwisize);
4942259032Skevlo	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id) + txwisize,
4943259032Skevlo	    mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1);
4944203134Sthompsa}
4945203134Sthompsa
4946203134Sthompsastatic void
4947203134Sthompsarun_updateprot(struct ieee80211com *ic)
4948203134Sthompsa{
4949286950Sadrian	struct run_softc *sc = ic->ic_softc;
4950218492Sbschmidt	uint32_t i;
4951218492Sbschmidt
4952218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
4953218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
4954218492Sbschmidt	sc->cmdq[i].func = run_updateprot_cb;
4955218492Sbschmidt	sc->cmdq[i].arg0 = ic;
4956218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
4957218492Sbschmidt}
4958218492Sbschmidt
4959218492Sbschmidtstatic void
4960218492Sbschmidtrun_updateprot_cb(void *arg)
4961218492Sbschmidt{
4962218492Sbschmidt	struct ieee80211com *ic = arg;
4963286950Sadrian	struct run_softc *sc = ic->ic_softc;
4964203134Sthompsa	uint32_t tmp;
4965203134Sthompsa
4966203134Sthompsa	tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL;
4967203134Sthompsa	/* setup protection frame rate (MCS code) */
4968203134Sthompsa	tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ?
4969270192Skevlo	    rt2860_rates[RT2860_RIDX_OFDM6].mcs | RT2860_PHY_OFDM :
4970203134Sthompsa	    rt2860_rates[RT2860_RIDX_CCK11].mcs;
4971203134Sthompsa
4972203134Sthompsa	/* CCK frames don't require protection */
4973203134Sthompsa	run_write(sc, RT2860_CCK_PROT_CFG, tmp);
4974203134Sthompsa	if (ic->ic_flags & IEEE80211_F_USEPROT) {
4975203134Sthompsa		if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
4976203134Sthompsa			tmp |= RT2860_PROT_CTRL_RTS_CTS;
4977203134Sthompsa		else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
4978203134Sthompsa			tmp |= RT2860_PROT_CTRL_CTS;
4979203134Sthompsa	}
4980203134Sthompsa	run_write(sc, RT2860_OFDM_PROT_CFG, tmp);
4981203134Sthompsa}
4982203134Sthompsa
4983203134Sthompsastatic void
4984208019Sthompsarun_usb_timeout_cb(void *arg)
4985203134Sthompsa{
4986208019Sthompsa	struct ieee80211vap *vap = arg;
4987286950Sadrian	struct run_softc *sc = vap->iv_ic->ic_softc;
4988203134Sthompsa
4989208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
4990203134Sthompsa
4991203134Sthompsa	if(vap->iv_state == IEEE80211_S_RUN &&
4992203134Sthompsa	    vap->iv_opmode != IEEE80211_M_STA)
4993203134Sthompsa		run_reset_livelock(sc);
4994209917Sthompsa	else if (vap->iv_state == IEEE80211_S_SCAN) {
4995203134Sthompsa		DPRINTF("timeout caused by scan\n");
4996203134Sthompsa		/* cancel bgscan */
4997203134Sthompsa		ieee80211_cancel_scan(vap);
4998203134Sthompsa	} else
4999203134Sthompsa		DPRINTF("timeout by unknown cause\n");
5000203134Sthompsa}
5001203134Sthompsa
5002203134Sthompsastatic void
5003203134Sthompsarun_reset_livelock(struct run_softc *sc)
5004203134Sthompsa{
5005203134Sthompsa	uint32_t tmp;
5006203134Sthompsa
5007208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
5008208019Sthompsa
5009203134Sthompsa	/*
5010203134Sthompsa	 * In IBSS or HostAP modes (when the hardware sends beacons), the MAC
5011203134Sthompsa	 * can run into a livelock and start sending CTS-to-self frames like
5012203134Sthompsa	 * crazy if protection is enabled.  Reset MAC/BBP for a while
5013203134Sthompsa	 */
5014203134Sthompsa	run_read(sc, RT2860_DEBUG, &tmp);
5015208019Sthompsa	DPRINTFN(3, "debug reg %08x\n", tmp);
5016209917Sthompsa	if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) {
5017203134Sthompsa		DPRINTF("CTS-to-self livelock detected\n");
5018203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST);
5019203134Sthompsa		run_delay(sc, 1);
5020203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL,
5021203134Sthompsa		    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
5022203134Sthompsa	}
5023203134Sthompsa}
5024203134Sthompsa
5025203134Sthompsastatic void
5026283540Sglebiusrun_update_promisc_locked(struct run_softc *sc)
5027203134Sthompsa{
5028203134Sthompsa        uint32_t tmp;
5029203134Sthompsa
5030203134Sthompsa	run_read(sc, RT2860_RX_FILTR_CFG, &tmp);
5031203134Sthompsa
5032203134Sthompsa	tmp |= RT2860_DROP_UC_NOME;
5033287197Sglebius        if (sc->sc_ic.ic_promisc > 0)
5034203134Sthompsa		tmp &= ~RT2860_DROP_UC_NOME;
5035203134Sthompsa
5036203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5037203134Sthompsa
5038287197Sglebius        DPRINTF("%s promiscuous mode\n", (sc->sc_ic.ic_promisc > 0) ?
5039203134Sthompsa            "entering" : "leaving");
5040203134Sthompsa}
5041203134Sthompsa
5042203134Sthompsastatic void
5043283540Sglebiusrun_update_promisc(struct ieee80211com *ic)
5044203134Sthompsa{
5045283540Sglebius	struct run_softc *sc = ic->ic_softc;
5046203134Sthompsa
5047287197Sglebius	if ((sc->sc_flags & RUN_RUNNING) == 0)
5048203134Sthompsa		return;
5049203134Sthompsa
5050203134Sthompsa	RUN_LOCK(sc);
5051283540Sglebius	run_update_promisc_locked(sc);
5052203134Sthompsa	RUN_UNLOCK(sc);
5053203134Sthompsa}
5054203134Sthompsa
5055203134Sthompsastatic void
5056203134Sthompsarun_enable_tsf_sync(struct run_softc *sc)
5057203134Sthompsa{
5058287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5059203134Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
5060203134Sthompsa	uint32_t tmp;
5061203134Sthompsa
5062257955Skevlo	DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id,
5063257955Skevlo	    ic->ic_opmode);
5064208019Sthompsa
5065203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
5066203134Sthompsa	tmp &= ~0x1fffff;
5067203134Sthompsa	tmp |= vap->iv_bss->ni_intval * 16;
5068203134Sthompsa	tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN;
5069203134Sthompsa
5070208019Sthompsa	if (ic->ic_opmode == IEEE80211_M_STA) {
5071203134Sthompsa		/*
5072203134Sthompsa		 * Local TSF is always updated with remote TSF on beacon
5073203134Sthompsa		 * reception.
5074203134Sthompsa		 */
5075203134Sthompsa		tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT;
5076208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_IBSS) {
5077203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5078203134Sthompsa	        /*
5079203134Sthompsa	         * Local TSF is updated with remote TSF on beacon reception
5080203134Sthompsa	         * only if the remote TSF is greater than local TSF.
5081203134Sthompsa	         */
5082203134Sthompsa	        tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT;
5083208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
5084208019Sthompsa		    ic->ic_opmode == IEEE80211_M_MBSS) {
5085203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5086203134Sthompsa	        /* SYNC with nobody */
5087203134Sthompsa	        tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT;
5088208019Sthompsa	} else {
5089203134Sthompsa		DPRINTF("Enabling TSF failed. undefined opmode\n");
5090208019Sthompsa		return;
5091208019Sthompsa	}
5092203134Sthompsa
5093203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
5094203134Sthompsa}
5095203134Sthompsa
5096203134Sthompsastatic void
5097287555Skevlorun_enable_tsf(struct run_softc *sc)
5098287555Skevlo{
5099287555Skevlo	uint32_t tmp;
5100287555Skevlo
5101287555Skevlo	if (run_read(sc, RT2860_BCN_TIME_CFG, &tmp) == 0) {
5102287555Skevlo		tmp &= ~(RT2860_BCN_TX_EN | RT2860_TBTT_TIMER_EN);
5103287555Skevlo		tmp |= RT2860_TSF_TIMER_EN;
5104287555Skevlo		run_write(sc, RT2860_BCN_TIME_CFG, tmp);
5105287555Skevlo	}
5106287555Skevlo}
5107287555Skevlo
5108287555Skevlostatic void
5109345752Savosrun_disable_tsf(struct run_softc *sc)
5110345752Savos{
5111345752Savos	uint32_t tmp;
5112345752Savos
5113345752Savos	if (run_read(sc, RT2860_BCN_TIME_CFG, &tmp) == 0) {
5114345752Savos		tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
5115345752Savos		    RT2860_TBTT_TIMER_EN);
5116345752Savos		run_write(sc, RT2860_BCN_TIME_CFG, tmp);
5117345752Savos	}
5118345752Savos}
5119345752Savos
5120345752Savosstatic void
5121287554Skevlorun_get_tsf(struct run_softc *sc, uint64_t *buf)
5122287554Skevlo{
5123287554Skevlo	run_read_region_1(sc, RT2860_TSF_TIMER_DW0, (uint8_t *)buf,
5124287554Skevlo	    sizeof(*buf));
5125287554Skevlo}
5126287554Skevlo
5127287554Skevlostatic void
5128203134Sthompsarun_enable_mrr(struct run_softc *sc)
5129203134Sthompsa{
5130259546Skevlo#define	CCK(mcs)	(mcs)
5131259546Skevlo#define	OFDM(mcs)	(1 << 3 | (mcs))
5132203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG0,
5133203134Sthompsa	    OFDM(6) << 28 |	/* 54->48 */
5134203134Sthompsa	    OFDM(5) << 24 |	/* 48->36 */
5135203134Sthompsa	    OFDM(4) << 20 |	/* 36->24 */
5136203134Sthompsa	    OFDM(3) << 16 |	/* 24->18 */
5137203134Sthompsa	    OFDM(2) << 12 |	/* 18->12 */
5138203134Sthompsa	    OFDM(1) <<  8 |	/* 12-> 9 */
5139203134Sthompsa	    OFDM(0) <<  4 |	/*  9-> 6 */
5140203134Sthompsa	    OFDM(0));		/*  6-> 6 */
5141203134Sthompsa
5142203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG1,
5143203134Sthompsa	    CCK(2) << 12 |	/* 11->5.5 */
5144203134Sthompsa	    CCK(1) <<  8 |	/* 5.5-> 2 */
5145203134Sthompsa	    CCK(0) <<  4 |	/*   2-> 1 */
5146203134Sthompsa	    CCK(0));		/*   1-> 1 */
5147203134Sthompsa#undef OFDM
5148203134Sthompsa#undef CCK
5149203134Sthompsa}
5150203134Sthompsa
5151203134Sthompsastatic void
5152203134Sthompsarun_set_txpreamble(struct run_softc *sc)
5153203134Sthompsa{
5154287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5155203134Sthompsa	uint32_t tmp;
5156203134Sthompsa
5157203134Sthompsa	run_read(sc, RT2860_AUTO_RSP_CFG, &tmp);
5158203134Sthompsa	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
5159203134Sthompsa		tmp |= RT2860_CCK_SHORT_EN;
5160203134Sthompsa	else
5161203134Sthompsa		tmp &= ~RT2860_CCK_SHORT_EN;
5162203134Sthompsa	run_write(sc, RT2860_AUTO_RSP_CFG, tmp);
5163203134Sthompsa}
5164203134Sthompsa
5165203134Sthompsastatic void
5166203134Sthompsarun_set_basicrates(struct run_softc *sc)
5167203134Sthompsa{
5168287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5169203134Sthompsa
5170203134Sthompsa	/* set basic rates mask */
5171203134Sthompsa	if (ic->ic_curmode == IEEE80211_MODE_11B)
5172203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003);
5173203134Sthompsa	else if (ic->ic_curmode == IEEE80211_MODE_11A)
5174203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150);
5175203134Sthompsa	else	/* 11g */
5176203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f);
5177203134Sthompsa}
5178203134Sthompsa
5179203134Sthompsastatic void
5180203134Sthompsarun_set_leds(struct run_softc *sc, uint16_t which)
5181203134Sthompsa{
5182203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS,
5183203134Sthompsa	    which | (sc->leds & 0x7f));
5184203134Sthompsa}
5185203134Sthompsa
5186203134Sthompsastatic void
5187203134Sthompsarun_set_bssid(struct run_softc *sc, const uint8_t *bssid)
5188203134Sthompsa{
5189203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW0,
5190203134Sthompsa	    bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24);
5191203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW1,
5192203134Sthompsa	    bssid[4] | bssid[5] << 8);
5193203134Sthompsa}
5194203134Sthompsa
5195203134Sthompsastatic void
5196203134Sthompsarun_set_macaddr(struct run_softc *sc, const uint8_t *addr)
5197203134Sthompsa{
5198203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW0,
5199203134Sthompsa	    addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24);
5200203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW1,
5201203134Sthompsa	    addr[4] | addr[5] << 8 | 0xff << 16);
5202203134Sthompsa}
5203203134Sthompsa
5204203134Sthompsastatic void
5205283540Sglebiusrun_updateslot(struct ieee80211com *ic)
5206203134Sthompsa{
5207283540Sglebius	struct run_softc *sc = ic->ic_softc;
5208218492Sbschmidt	uint32_t i;
5209218492Sbschmidt
5210218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
5211218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
5212218492Sbschmidt	sc->cmdq[i].func = run_updateslot_cb;
5213287197Sglebius	sc->cmdq[i].arg0 = ic;
5214218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
5215218492Sbschmidt
5216218492Sbschmidt	return;
5217218492Sbschmidt}
5218218492Sbschmidt
5219218492Sbschmidt/* ARGSUSED */
5220218492Sbschmidtstatic void
5221218492Sbschmidtrun_updateslot_cb(void *arg)
5222218492Sbschmidt{
5223287197Sglebius	struct ieee80211com *ic = arg;
5224286950Sadrian	struct run_softc *sc = ic->ic_softc;
5225203134Sthompsa	uint32_t tmp;
5226203134Sthompsa
5227203134Sthompsa	run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp);
5228203134Sthompsa	tmp &= ~0xff;
5229292165Savos	tmp |= IEEE80211_GET_SLOTTIME(ic);
5230203134Sthompsa	run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp);
5231203134Sthompsa}
5232203134Sthompsa
5233208019Sthompsastatic void
5234283540Sglebiusrun_update_mcast(struct ieee80211com *ic)
5235208019Sthompsa{
5236208019Sthompsa}
5237208019Sthompsa
5238203134Sthompsastatic int8_t
5239203134Sthompsarun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain)
5240203134Sthompsa{
5241287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5242203134Sthompsa	struct ieee80211_channel *c = ic->ic_curchan;
5243203134Sthompsa	int delta;
5244203134Sthompsa
5245203134Sthompsa	if (IEEE80211_IS_CHAN_5GHZ(c)) {
5246257429Shselasky		u_int chan = ieee80211_chan2ieee(ic, c);
5247203134Sthompsa		delta = sc->rssi_5ghz[rxchain];
5248203134Sthompsa
5249203134Sthompsa		/* determine channel group */
5250203134Sthompsa		if (chan <= 64)
5251203134Sthompsa			delta -= sc->lna[1];
5252203134Sthompsa		else if (chan <= 128)
5253203134Sthompsa			delta -= sc->lna[2];
5254203134Sthompsa		else
5255203134Sthompsa			delta -= sc->lna[3];
5256203134Sthompsa	} else
5257203134Sthompsa		delta = sc->rssi_2ghz[rxchain] - sc->lna[0];
5258203134Sthompsa
5259209917Sthompsa	return (-12 - delta - rssi);
5260203134Sthompsa}
5261203134Sthompsa
5262257955Skevlostatic void
5263257955Skevlorun_rt5390_bbp_init(struct run_softc *sc)
5264257955Skevlo{
5265299176Spfg	u_int i;
5266259032Skevlo	uint8_t bbp;
5267257955Skevlo
5268259032Skevlo	/* Apply maximum likelihood detection for 2 stream case. */
5269259032Skevlo	run_bbp_read(sc, 105, &bbp);
5270259032Skevlo	if (sc->nrxchains > 1)
5271259032Skevlo		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5272259032Skevlo
5273257955Skevlo	/* Avoid data lost and CRC error. */
5274259032Skevlo	run_bbp_read(sc, 4, &bbp);
5275259031Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5276257955Skevlo
5277259032Skevlo	if (sc->mac_ver == 0x5592) {
5278259032Skevlo		for (i = 0; i < nitems(rt5592_def_bbp); i++) {
5279259032Skevlo			run_bbp_write(sc, rt5592_def_bbp[i].reg,
5280259032Skevlo			    rt5592_def_bbp[i].val);
5281259032Skevlo		}
5282259032Skevlo		for (i = 0; i < nitems(rt5592_bbp_r196); i++) {
5283259032Skevlo			run_bbp_write(sc, 195, i + 0x80);
5284259032Skevlo			run_bbp_write(sc, 196, rt5592_bbp_r196[i]);
5285259032Skevlo		}
5286259032Skevlo	} else {
5287259032Skevlo		for (i = 0; i < nitems(rt5390_def_bbp); i++) {
5288259032Skevlo			run_bbp_write(sc, rt5390_def_bbp[i].reg,
5289259032Skevlo			    rt5390_def_bbp[i].val);
5290259032Skevlo		}
5291257955Skevlo	}
5292257955Skevlo	if (sc->mac_ver == 0x5392) {
5293257955Skevlo		run_bbp_write(sc, 88, 0x90);
5294257955Skevlo		run_bbp_write(sc, 95, 0x9a);
5295257955Skevlo		run_bbp_write(sc, 98, 0x12);
5296257955Skevlo		run_bbp_write(sc, 106, 0x12);
5297257955Skevlo		run_bbp_write(sc, 134, 0xd0);
5298257955Skevlo		run_bbp_write(sc, 135, 0xf6);
5299257955Skevlo		run_bbp_write(sc, 148, 0x84);
5300257955Skevlo	}
5301257955Skevlo
5302259032Skevlo	run_bbp_read(sc, 152, &bbp);
5303259032Skevlo	run_bbp_write(sc, 152, bbp | 0x80);
5304259032Skevlo
5305259032Skevlo	/* Fix BBP254 for RT5592C. */
5306259032Skevlo	if (sc->mac_ver == 0x5592 && sc->mac_rev >= 0x0221) {
5307259032Skevlo		run_bbp_read(sc, 254, &bbp);
5308259032Skevlo		run_bbp_write(sc, 254, bbp | 0x80);
5309259032Skevlo	}
5310259032Skevlo
5311257955Skevlo	/* Disable hardware antenna diversity. */
5312257955Skevlo	if (sc->mac_ver == 0x5390)
5313257955Skevlo		run_bbp_write(sc, 154, 0);
5314259032Skevlo
5315259032Skevlo	/* Initialize Rx CCK/OFDM frequency offset report. */
5316259032Skevlo	run_bbp_write(sc, 142, 1);
5317259032Skevlo	run_bbp_write(sc, 143, 57);
5318257955Skevlo}
5319257955Skevlo
5320203134Sthompsastatic int
5321203134Sthompsarun_bbp_init(struct run_softc *sc)
5322203134Sthompsa{
5323203134Sthompsa	int i, error, ntries;
5324203134Sthompsa	uint8_t bbp0;
5325203134Sthompsa
5326203134Sthompsa	/* wait for BBP to wake up */
5327203134Sthompsa	for (ntries = 0; ntries < 20; ntries++) {
5328203134Sthompsa		if ((error = run_bbp_read(sc, 0, &bbp0)) != 0)
5329203134Sthompsa			return error;
5330203134Sthompsa		if (bbp0 != 0 && bbp0 != 0xff)
5331203134Sthompsa			break;
5332203134Sthompsa	}
5333203134Sthompsa	if (ntries == 20)
5334209917Sthompsa		return (ETIMEDOUT);
5335203134Sthompsa
5336203134Sthompsa	/* initialize BBP registers to default values */
5337257955Skevlo	if (sc->mac_ver >= 0x5390)
5338257955Skevlo		run_rt5390_bbp_init(sc);
5339257955Skevlo	else {
5340257955Skevlo		for (i = 0; i < nitems(rt2860_def_bbp); i++) {
5341257955Skevlo			run_bbp_write(sc, rt2860_def_bbp[i].reg,
5342257955Skevlo			    rt2860_def_bbp[i].val);
5343257955Skevlo		}
5344203134Sthompsa	}
5345203134Sthompsa
5346260219Skevlo	if (sc->mac_ver == 0x3593) {
5347260219Skevlo		run_bbp_write(sc, 79, 0x13);
5348260219Skevlo		run_bbp_write(sc, 80, 0x05);
5349260219Skevlo		run_bbp_write(sc, 81, 0x33);
5350260219Skevlo		run_bbp_write(sc, 86, 0x46);
5351260219Skevlo		run_bbp_write(sc, 137, 0x0f);
5352260219Skevlo	}
5353260219Skevlo
5354203134Sthompsa	/* fix BBP84 for RT2860E */
5355205042Sthompsa	if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101)
5356205042Sthompsa		run_bbp_write(sc, 84, 0x19);
5357203134Sthompsa
5358260219Skevlo	if (sc->mac_ver >= 0x3070 && (sc->mac_ver != 0x3593 &&
5359260219Skevlo	    sc->mac_ver != 0x5592)) {
5360203134Sthompsa		run_bbp_write(sc, 79, 0x13);
5361203134Sthompsa		run_bbp_write(sc, 80, 0x05);
5362203134Sthompsa		run_bbp_write(sc, 81, 0x33);
5363205042Sthompsa	} else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) {
5364203134Sthompsa		run_bbp_write(sc, 69, 0x16);
5365203134Sthompsa		run_bbp_write(sc, 73, 0x12);
5366203134Sthompsa	}
5367209917Sthompsa	return (0);
5368203134Sthompsa}
5369203134Sthompsa
5370203134Sthompsastatic int
5371203134Sthompsarun_rt3070_rf_init(struct run_softc *sc)
5372203134Sthompsa{
5373203134Sthompsa	uint32_t tmp;
5374256722Skevlo	uint8_t bbp4, mingain, rf, target;
5375299176Spfg	u_int i;
5376203134Sthompsa
5377203134Sthompsa	run_rt3070_rf_read(sc, 30, &rf);
5378203134Sthompsa	/* toggle RF R30 bit 7 */
5379203134Sthompsa	run_rt3070_rf_write(sc, 30, rf | 0x80);
5380203134Sthompsa	run_delay(sc, 10);
5381203134Sthompsa	run_rt3070_rf_write(sc, 30, rf & ~0x80);
5382203134Sthompsa
5383203134Sthompsa	/* initialize RF registers to default value */
5384205042Sthompsa	if (sc->mac_ver == 0x3572) {
5385257955Skevlo		for (i = 0; i < nitems(rt3572_def_rf); i++) {
5386205042Sthompsa			run_rt3070_rf_write(sc, rt3572_def_rf[i].reg,
5387205042Sthompsa			    rt3572_def_rf[i].val);
5388205042Sthompsa		}
5389205042Sthompsa	} else {
5390257955Skevlo		for (i = 0; i < nitems(rt3070_def_rf); i++) {
5391205042Sthompsa			run_rt3070_rf_write(sc, rt3070_def_rf[i].reg,
5392205042Sthompsa			    rt3070_def_rf[i].val);
5393205042Sthompsa		}
5394203134Sthompsa	}
5395205042Sthompsa
5396256721Skevlo	if (sc->mac_ver == 0x3070 && sc->mac_rev < 0x0201) {
5397256721Skevlo		/*
5398256721Skevlo		 * Change voltage from 1.2V to 1.35V for RT3070.
5399256721Skevlo		 * The DAC issue (RT3070_LDO_CFG0) has been fixed
5400256721Skevlo		 * in RT3070(F).
5401256721Skevlo		 */
5402203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5403203134Sthompsa		tmp = (tmp & ~0x0f000000) | 0x0d000000;
5404203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5405203134Sthompsa
5406205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5407203134Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5408203134Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5409203134Sthompsa		run_rt3070_rf_write(sc, 31, 0x14);
5410203134Sthompsa
5411203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5412203134Sthompsa		tmp &= ~0x1f000000;
5413205042Sthompsa		if (sc->mac_rev < 0x0211)
5414205042Sthompsa			tmp |= 0x0d000000;	/* 1.3V */
5415203134Sthompsa		else
5416205042Sthompsa			tmp |= 0x01000000;	/* 1.2V */
5417203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5418203134Sthompsa
5419203134Sthompsa		/* patch LNA_PE_G1 */
5420203134Sthompsa		run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5421203134Sthompsa		run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20);
5422208019Sthompsa
5423209917Sthompsa	} else if (sc->mac_ver == 0x3572) {
5424205042Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5425205042Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5426205042Sthompsa
5427208019Sthompsa		/* increase voltage from 1.2V to 1.35V */
5428208019Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5429208019Sthompsa		tmp = (tmp & ~0x1f000000) | 0x0d000000;
5430208019Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5431203134Sthompsa
5432209917Sthompsa		if (sc->mac_rev < 0x0211 || !sc->patch_dac) {
5433203134Sthompsa			run_delay(sc, 1);	/* wait for 1msec */
5434205042Sthompsa			/* decrease voltage back to 1.2V */
5435203134Sthompsa			tmp = (tmp & ~0x1f000000) | 0x01000000;
5436203134Sthompsa			run_write(sc, RT3070_LDO_CFG0, tmp);
5437203134Sthompsa		}
5438203134Sthompsa	}
5439203134Sthompsa
5440203134Sthompsa	/* select 20MHz bandwidth */
5441203134Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5442203134Sthompsa	run_rt3070_rf_write(sc, 31, rf & ~0x20);
5443203134Sthompsa
5444203134Sthompsa	/* calibrate filter for 20MHz bandwidth */
5445203134Sthompsa	sc->rf24_20mhz = 0x1f;	/* default value */
5446205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13;
5447205042Sthompsa	run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz);
5448203134Sthompsa
5449203134Sthompsa	/* select 40MHz bandwidth */
5450203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5451256721Skevlo	run_bbp_write(sc, 4, (bbp4 & ~0x18) | 0x10);
5452205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5453205042Sthompsa	run_rt3070_rf_write(sc, 31, rf | 0x20);
5454203134Sthompsa
5455203134Sthompsa	/* calibrate filter for 40MHz bandwidth */
5456203134Sthompsa	sc->rf24_40mhz = 0x2f;	/* default value */
5457205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15;
5458205042Sthompsa	run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz);
5459203134Sthompsa
5460203134Sthompsa	/* go back to 20MHz bandwidth */
5461203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5462203134Sthompsa	run_bbp_write(sc, 4, bbp4 & ~0x18);
5463203134Sthompsa
5464205042Sthompsa	if (sc->mac_ver == 0x3572) {
5465205042Sthompsa		/* save default BBP registers 25 and 26 values */
5466205042Sthompsa		run_bbp_read(sc, 25, &sc->bbp25);
5467205042Sthompsa		run_bbp_read(sc, 26, &sc->bbp26);
5468256721Skevlo	} else if (sc->mac_rev < 0x0201 || sc->mac_rev < 0x0211)
5469203134Sthompsa		run_rt3070_rf_write(sc, 27, 0x03);
5470203134Sthompsa
5471203134Sthompsa	run_read(sc, RT3070_OPT_14, &tmp);
5472203134Sthompsa	run_write(sc, RT3070_OPT_14, tmp | 1);
5473203134Sthompsa
5474205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5475205042Sthompsa		run_rt3070_rf_read(sc, 17, &rf);
5476205042Sthompsa		rf &= ~RT3070_TX_LO1;
5477205042Sthompsa		if ((sc->mac_ver == 0x3070 ||
5478205042Sthompsa		     (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) &&
5479205042Sthompsa		    !sc->ext_2ghz_lna)
5480205042Sthompsa			rf |= 0x20;	/* fix for long range Rx issue */
5481256722Skevlo		mingain = (sc->mac_ver == 0x3070) ? 1 : 2;
5482256722Skevlo		if (sc->txmixgain_2ghz >= mingain)
5483205042Sthompsa			rf = (rf & ~0x7) | sc->txmixgain_2ghz;
5484205042Sthompsa		run_rt3070_rf_write(sc, 17, rf);
5485205042Sthompsa	}
5486205042Sthompsa
5487270643Skevlo	if (sc->mac_ver == 0x3071) {
5488203134Sthompsa		run_rt3070_rf_read(sc, 1, &rf);
5489203134Sthompsa		rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD);
5490203134Sthompsa		rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD;
5491203134Sthompsa		run_rt3070_rf_write(sc, 1, rf);
5492203134Sthompsa
5493203134Sthompsa		run_rt3070_rf_read(sc, 15, &rf);
5494203134Sthompsa		run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2);
5495203134Sthompsa
5496203134Sthompsa		run_rt3070_rf_read(sc, 20, &rf);
5497203134Sthompsa		run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1);
5498203134Sthompsa
5499203134Sthompsa		run_rt3070_rf_read(sc, 21, &rf);
5500203134Sthompsa		run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2);
5501205042Sthompsa	}
5502203134Sthompsa
5503205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5504205042Sthompsa		/* fix Tx to Rx IQ glitch by raising RF voltage */
5505203134Sthompsa		run_rt3070_rf_read(sc, 27, &rf);
5506203134Sthompsa		rf &= ~0x77;
5507205042Sthompsa		if (sc->mac_rev < 0x0211)
5508203134Sthompsa			rf |= 0x03;
5509203134Sthompsa		run_rt3070_rf_write(sc, 27, rf);
5510203134Sthompsa	}
5511209917Sthompsa	return (0);
5512203134Sthompsa}
5513203134Sthompsa
5514257955Skevlostatic void
5515260219Skevlorun_rt3593_rf_init(struct run_softc *sc)
5516260219Skevlo{
5517260219Skevlo	uint32_t tmp;
5518260219Skevlo	uint8_t rf;
5519299176Spfg	u_int i;
5520260219Skevlo
5521260219Skevlo	/* Disable the GPIO bits 4 and 7 for LNA PE control. */
5522260219Skevlo	run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5523260219Skevlo	tmp &= ~(1 << 4 | 1 << 7);
5524260219Skevlo	run_write(sc, RT3070_GPIO_SWITCH, tmp);
5525260219Skevlo
5526260219Skevlo	/* Initialize RF registers to default value. */
5527260219Skevlo	for (i = 0; i < nitems(rt3593_def_rf); i++) {
5528260219Skevlo		run_rt3070_rf_write(sc, rt3593_def_rf[i].reg,
5529260219Skevlo		    rt3593_def_rf[i].val);
5530260219Skevlo	}
5531260219Skevlo
5532260219Skevlo	/* Toggle RF R2 to initiate calibration. */
5533260219Skevlo	run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5534260219Skevlo
5535260219Skevlo	/* Initialize RF frequency offset. */
5536260219Skevlo	run_adjust_freq_offset(sc);
5537260219Skevlo
5538260219Skevlo	run_rt3070_rf_read(sc, 18, &rf);
5539260219Skevlo	run_rt3070_rf_write(sc, 18, rf | RT3593_AUTOTUNE_BYPASS);
5540260219Skevlo
5541260219Skevlo	/*
5542260219Skevlo	 * Increase voltage from 1.2V to 1.35V, wait for 1 msec to
5543260219Skevlo	 * decrease voltage back to 1.2V.
5544260219Skevlo	 */
5545260219Skevlo	run_read(sc, RT3070_LDO_CFG0, &tmp);
5546260219Skevlo	tmp = (tmp & ~0x1f000000) | 0x0d000000;
5547260219Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5548260219Skevlo	run_delay(sc, 1);
5549260219Skevlo	tmp = (tmp & ~0x1f000000) | 0x01000000;
5550260219Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5551260219Skevlo
5552260219Skevlo	sc->rf24_20mhz = 0x1f;
5553260219Skevlo	sc->rf24_40mhz = 0x2f;
5554260219Skevlo
5555260219Skevlo	/* Save default BBP registers 25 and 26 values. */
5556260219Skevlo	run_bbp_read(sc, 25, &sc->bbp25);
5557260219Skevlo	run_bbp_read(sc, 26, &sc->bbp26);
5558260219Skevlo
5559260219Skevlo	run_read(sc, RT3070_OPT_14, &tmp);
5560260219Skevlo	run_write(sc, RT3070_OPT_14, tmp | 1);
5561260219Skevlo}
5562260219Skevlo
5563260219Skevlostatic void
5564257955Skevlorun_rt5390_rf_init(struct run_softc *sc)
5565257955Skevlo{
5566257955Skevlo	uint32_t tmp;
5567257955Skevlo	uint8_t rf;
5568299176Spfg	u_int i;
5569257955Skevlo
5570259030Skevlo	/* Toggle RF R2 to initiate calibration. */
5571259030Skevlo	if (sc->mac_ver == 0x5390) {
5572257955Skevlo		run_rt3070_rf_read(sc, 2, &rf);
5573259031Skevlo		run_rt3070_rf_write(sc, 2, rf | RT5390_RESCAL);
5574257955Skevlo		run_delay(sc, 10);
5575259031Skevlo		run_rt3070_rf_write(sc, 2, rf & ~RT5390_RESCAL);
5576259030Skevlo	} else {
5577259031Skevlo		run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5578259030Skevlo		run_delay(sc, 10);
5579257955Skevlo	}
5580257955Skevlo
5581257955Skevlo	/* Initialize RF registers to default value. */
5582259032Skevlo	if (sc->mac_ver == 0x5592) {
5583259032Skevlo		for (i = 0; i < nitems(rt5592_def_rf); i++) {
5584259032Skevlo			run_rt3070_rf_write(sc, rt5592_def_rf[i].reg,
5585259032Skevlo			    rt5592_def_rf[i].val);
5586259032Skevlo		}
5587259032Skevlo		/* Initialize RF frequency offset. */
5588259032Skevlo		run_adjust_freq_offset(sc);
5589259032Skevlo	} else if (sc->mac_ver == 0x5392) {
5590257955Skevlo		for (i = 0; i < nitems(rt5392_def_rf); i++) {
5591257955Skevlo			run_rt3070_rf_write(sc, rt5392_def_rf[i].reg,
5592257955Skevlo			    rt5392_def_rf[i].val);
5593257955Skevlo		}
5594257955Skevlo		if (sc->mac_rev >= 0x0223) {
5595257955Skevlo			run_rt3070_rf_write(sc, 23, 0x0f);
5596257955Skevlo			run_rt3070_rf_write(sc, 24, 0x3e);
5597257955Skevlo			run_rt3070_rf_write(sc, 51, 0x32);
5598257955Skevlo			run_rt3070_rf_write(sc, 53, 0x22);
5599257955Skevlo			run_rt3070_rf_write(sc, 56, 0xc1);
5600257955Skevlo			run_rt3070_rf_write(sc, 59, 0x0f);
5601257955Skevlo		}
5602257955Skevlo	} else {
5603257955Skevlo		for (i = 0; i < nitems(rt5390_def_rf); i++) {
5604257955Skevlo			run_rt3070_rf_write(sc, rt5390_def_rf[i].reg,
5605257955Skevlo			    rt5390_def_rf[i].val);
5606257955Skevlo		}
5607257955Skevlo		if (sc->mac_rev >= 0x0502) {
5608257955Skevlo			run_rt3070_rf_write(sc, 6, 0xe0);
5609257955Skevlo			run_rt3070_rf_write(sc, 25, 0x80);
5610257955Skevlo			run_rt3070_rf_write(sc, 46, 0x73);
5611257955Skevlo			run_rt3070_rf_write(sc, 53, 0x00);
5612257955Skevlo			run_rt3070_rf_write(sc, 56, 0x42);
5613257955Skevlo			run_rt3070_rf_write(sc, 61, 0xd1);
5614257955Skevlo		}
5615257955Skevlo	}
5616257955Skevlo
5617257955Skevlo	sc->rf24_20mhz = 0x1f;	/* default value */
5618259032Skevlo	sc->rf24_40mhz = (sc->mac_ver == 0x5592) ? 0 : 0x2f;
5619257955Skevlo
5620257955Skevlo	if (sc->mac_rev < 0x0211)
5621257955Skevlo		run_rt3070_rf_write(sc, 27, 0x3);
5622257955Skevlo
5623257955Skevlo	run_read(sc, RT3070_OPT_14, &tmp);
5624257955Skevlo	run_write(sc, RT3070_OPT_14, tmp | 1);
5625257955Skevlo}
5626257955Skevlo
5627203134Sthompsastatic int
5628203134Sthompsarun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target,
5629203134Sthompsa    uint8_t *val)
5630203134Sthompsa{
5631203134Sthompsa	uint8_t rf22, rf24;
5632203134Sthompsa	uint8_t bbp55_pb, bbp55_sb, delta;
5633203134Sthompsa	int ntries;
5634203134Sthompsa
5635203134Sthompsa	/* program filter */
5636205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf24);
5637205042Sthompsa	rf24 = (rf24 & 0xc0) | init;	/* initial filter value */
5638203134Sthompsa	run_rt3070_rf_write(sc, 24, rf24);
5639203134Sthompsa
5640203134Sthompsa	/* enable baseband loopback mode */
5641203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5642203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 | 0x01);
5643203134Sthompsa
5644203134Sthompsa	/* set power and frequency of passband test tone */
5645203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5646203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5647203134Sthompsa		/* transmit test tone */
5648203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5649203134Sthompsa		run_delay(sc, 10);
5650203134Sthompsa		/* read received power */
5651203134Sthompsa		run_bbp_read(sc, 55, &bbp55_pb);
5652203134Sthompsa		if (bbp55_pb != 0)
5653203134Sthompsa			break;
5654203134Sthompsa	}
5655203134Sthompsa	if (ntries == 100)
5656257955Skevlo		return (ETIMEDOUT);
5657203134Sthompsa
5658203134Sthompsa	/* set power and frequency of stopband test tone */
5659203134Sthompsa	run_bbp_write(sc, 24, 0x06);
5660203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5661203134Sthompsa		/* transmit test tone */
5662203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5663203134Sthompsa		run_delay(sc, 10);
5664203134Sthompsa		/* read received power */
5665203134Sthompsa		run_bbp_read(sc, 55, &bbp55_sb);
5666203134Sthompsa
5667203134Sthompsa		delta = bbp55_pb - bbp55_sb;
5668203134Sthompsa		if (delta > target)
5669203134Sthompsa			break;
5670203134Sthompsa
5671203134Sthompsa		/* reprogram filter */
5672203134Sthompsa		rf24++;
5673203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5674203134Sthompsa	}
5675203134Sthompsa	if (ntries < 100) {
5676203134Sthompsa		if (rf24 != init)
5677203134Sthompsa			rf24--;	/* backtrack */
5678203134Sthompsa		*val = rf24;
5679203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5680203134Sthompsa	}
5681203134Sthompsa
5682203134Sthompsa	/* restore initial state */
5683203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5684203134Sthompsa
5685203134Sthompsa	/* disable baseband loopback mode */
5686203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5687203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 & ~0x01);
5688203134Sthompsa
5689209917Sthompsa	return (0);
5690203134Sthompsa}
5691203134Sthompsa
5692205042Sthompsastatic void
5693205042Sthompsarun_rt3070_rf_setup(struct run_softc *sc)
5694205042Sthompsa{
5695205042Sthompsa	uint8_t bbp, rf;
5696205042Sthompsa	int i;
5697205042Sthompsa
5698260219Skevlo	if (sc->mac_ver == 0x3572) {
5699205042Sthompsa		/* enable DC filter */
5700205042Sthompsa		if (sc->mac_rev >= 0x0201)
5701205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5702205042Sthompsa
5703205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5704205042Sthompsa		if (sc->ntxchains == 1)
5705205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5706205042Sthompsa		if (sc->nrxchains == 1)
5707205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5708205042Sthompsa		run_bbp_write(sc, 138, bbp);
5709205042Sthompsa
5710205042Sthompsa		if (sc->mac_rev >= 0x0211) {
5711205042Sthompsa			/* improve power consumption */
5712205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5713205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5714205042Sthompsa		}
5715205042Sthompsa
5716205042Sthompsa		run_rt3070_rf_read(sc, 16, &rf);
5717205042Sthompsa		rf = (rf & ~0x07) | sc->txmixgain_2ghz;
5718205042Sthompsa		run_rt3070_rf_write(sc, 16, rf);
5719205042Sthompsa
5720205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5721257409Skevlo		if (sc->mac_rev >= 0x0211) {
5722257409Skevlo			/* enable DC filter */
5723205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5724205042Sthompsa
5725257409Skevlo			/* improve power consumption */
5726257409Skevlo			run_bbp_read(sc, 31, &bbp);
5727257409Skevlo			run_bbp_write(sc, 31, bbp & ~0x03);
5728257409Skevlo		}
5729257409Skevlo
5730205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5731205042Sthompsa		if (sc->ntxchains == 1)
5732205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5733205042Sthompsa		if (sc->nrxchains == 1)
5734205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5735205042Sthompsa		run_bbp_write(sc, 138, bbp);
5736205042Sthompsa
5737205042Sthompsa		run_write(sc, RT2860_TX_SW_CFG1, 0);
5738205042Sthompsa		if (sc->mac_rev < 0x0211) {
5739205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2,
5740205042Sthompsa			    sc->patch_dac ? 0x2c : 0x0f);
5741205042Sthompsa		} else
5742205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5743205042Sthompsa
5744205042Sthompsa	} else if (sc->mac_ver == 0x3070) {
5745205042Sthompsa		if (sc->mac_rev >= 0x0201) {
5746205042Sthompsa			/* enable DC filter */
5747205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5748205042Sthompsa
5749205042Sthompsa			/* improve power consumption */
5750205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5751205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5752205042Sthompsa		}
5753205042Sthompsa
5754256955Skevlo		if (sc->mac_rev < 0x0201) {
5755205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG1, 0);
5756205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0x2c);
5757205042Sthompsa		} else
5758205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5759205042Sthompsa	}
5760205042Sthompsa
5761205042Sthompsa	/* initialize RF registers from ROM for >=RT3071*/
5762260219Skevlo	if (sc->mac_ver >= 0x3071) {
5763205042Sthompsa		for (i = 0; i < 10; i++) {
5764205042Sthompsa			if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff)
5765205042Sthompsa				continue;
5766205042Sthompsa			run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val);
5767205042Sthompsa		}
5768205042Sthompsa	}
5769205042Sthompsa}
5770205042Sthompsa
5771260219Skevlostatic void
5772260219Skevlorun_rt3593_rf_setup(struct run_softc *sc)
5773260219Skevlo{
5774260219Skevlo	uint8_t bbp, rf;
5775260219Skevlo
5776260219Skevlo	if (sc->mac_rev >= 0x0211) {
5777260219Skevlo		/* Enable DC filter. */
5778260219Skevlo		run_bbp_write(sc, 103, 0xc0);
5779260219Skevlo	}
5780260219Skevlo	run_write(sc, RT2860_TX_SW_CFG1, 0);
5781260219Skevlo	if (sc->mac_rev < 0x0211) {
5782260219Skevlo		run_write(sc, RT2860_TX_SW_CFG2,
5783260219Skevlo		    sc->patch_dac ? 0x2c : 0x0f);
5784260219Skevlo	} else
5785260219Skevlo		run_write(sc, RT2860_TX_SW_CFG2, 0);
5786260219Skevlo
5787260219Skevlo	run_rt3070_rf_read(sc, 50, &rf);
5788260219Skevlo	run_rt3070_rf_write(sc, 50, rf & ~RT3593_TX_LO2);
5789260219Skevlo
5790260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
5791260219Skevlo	rf = (rf & ~(RT3593_TX_LO1 | 0x0c)) |
5792260219Skevlo	    ((sc->txmixgain_2ghz & 0x07) << 2);
5793260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
5794260219Skevlo
5795260219Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5796260219Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5797260219Skevlo
5798260219Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5799260219Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5800260219Skevlo
5801260219Skevlo	run_rt3070_rf_read(sc, 1, &rf);
5802260219Skevlo	run_rt3070_rf_write(sc, 1, rf & ~(RT3070_RF_BLOCK | RT3070_PLL_PD));
5803260219Skevlo
5804260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5805260219Skevlo	rf = (rf & ~0x18) | 0x10;
5806260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
5807260219Skevlo
5808260219Skevlo	/* Apply maximum likelihood detection for 2 stream case. */
5809260219Skevlo	run_bbp_read(sc, 105, &bbp);
5810260219Skevlo	if (sc->nrxchains > 1)
5811260219Skevlo		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5812260219Skevlo
5813260219Skevlo	/* Avoid data lost and CRC error. */
5814260219Skevlo	run_bbp_read(sc, 4, &bbp);
5815260219Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5816260219Skevlo
5817260219Skevlo	run_bbp_write(sc, 92, 0x02);
5818260219Skevlo	run_bbp_write(sc, 82, 0x82);
5819260219Skevlo	run_bbp_write(sc, 106, 0x05);
5820260219Skevlo	run_bbp_write(sc, 104, 0x92);
5821260219Skevlo	run_bbp_write(sc, 88, 0x90);
5822260219Skevlo	run_bbp_write(sc, 148, 0xc8);
5823260219Skevlo	run_bbp_write(sc, 47, 0x48);
5824260219Skevlo	run_bbp_write(sc, 120, 0x50);
5825260219Skevlo
5826260219Skevlo	run_bbp_write(sc, 163, 0x9d);
5827260219Skevlo
5828260219Skevlo	/* SNR mapping. */
5829260219Skevlo	run_bbp_write(sc, 142, 0x06);
5830260219Skevlo	run_bbp_write(sc, 143, 0xa0);
5831260219Skevlo	run_bbp_write(sc, 142, 0x07);
5832260219Skevlo	run_bbp_write(sc, 143, 0xa1);
5833260219Skevlo	run_bbp_write(sc, 142, 0x08);
5834260219Skevlo	run_bbp_write(sc, 143, 0xa2);
5835260219Skevlo
5836260219Skevlo	run_bbp_write(sc, 31, 0x08);
5837260219Skevlo	run_bbp_write(sc, 68, 0x0b);
5838260219Skevlo	run_bbp_write(sc, 105, 0x04);
5839260219Skevlo}
5840260219Skevlo
5841260219Skevlostatic void
5842260219Skevlorun_rt5390_rf_setup(struct run_softc *sc)
5843260219Skevlo{
5844260219Skevlo	uint8_t bbp, rf;
5845260219Skevlo
5846260219Skevlo	if (sc->mac_rev >= 0x0211) {
5847260219Skevlo		/* Enable DC filter. */
5848260219Skevlo		run_bbp_write(sc, 103, 0xc0);
5849260219Skevlo
5850260219Skevlo		if (sc->mac_ver != 0x5592) {
5851260219Skevlo			/* Improve power consumption. */
5852260219Skevlo			run_bbp_read(sc, 31, &bbp);
5853260219Skevlo			run_bbp_write(sc, 31, bbp & ~0x03);
5854260219Skevlo		}
5855260219Skevlo	}
5856260219Skevlo
5857260219Skevlo	run_bbp_read(sc, 138, &bbp);
5858260219Skevlo	if (sc->ntxchains == 1)
5859260219Skevlo		bbp |= 0x20;	/* turn off DAC1 */
5860260219Skevlo	if (sc->nrxchains == 1)
5861260219Skevlo		bbp &= ~0x02;	/* turn off ADC1 */
5862260219Skevlo	run_bbp_write(sc, 138, bbp);
5863260219Skevlo
5864260219Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5865260219Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5866260219Skevlo
5867260219Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5868260219Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5869260219Skevlo
5870260219Skevlo	/* Avoid data lost and CRC error. */
5871260219Skevlo	run_bbp_read(sc, 4, &bbp);
5872260219Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5873260219Skevlo
5874260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5875260219Skevlo	rf = (rf & ~0x18) | 0x10;
5876260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
5877260219Skevlo
5878260219Skevlo	if (sc->mac_ver != 0x5592) {
5879260219Skevlo		run_write(sc, RT2860_TX_SW_CFG1, 0);
5880260219Skevlo		if (sc->mac_rev < 0x0211) {
5881260219Skevlo			run_write(sc, RT2860_TX_SW_CFG2,
5882260219Skevlo			    sc->patch_dac ? 0x2c : 0x0f);
5883260219Skevlo		} else
5884260219Skevlo			run_write(sc, RT2860_TX_SW_CFG2, 0);
5885260219Skevlo	}
5886260219Skevlo}
5887260219Skevlo
5888203134Sthompsastatic int
5889203134Sthompsarun_txrx_enable(struct run_softc *sc)
5890203134Sthompsa{
5891287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5892203134Sthompsa	uint32_t tmp;
5893203134Sthompsa	int error, ntries;
5894203134Sthompsa
5895203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN);
5896203134Sthompsa	for (ntries = 0; ntries < 200; ntries++) {
5897203134Sthompsa		if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0)
5898257955Skevlo			return (error);
5899203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5900203134Sthompsa			break;
5901203134Sthompsa		run_delay(sc, 50);
5902203134Sthompsa	}
5903203134Sthompsa	if (ntries == 200)
5904257955Skevlo		return (ETIMEDOUT);
5905203134Sthompsa
5906203134Sthompsa	run_delay(sc, 50);
5907203134Sthompsa
5908203134Sthompsa	tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE;
5909203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
5910203134Sthompsa
5911203134Sthompsa	/* enable Rx bulk aggregation (set timeout and limit) */
5912203134Sthompsa	tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN |
5913203134Sthompsa	    RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2);
5914203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, tmp);
5915203134Sthompsa
5916203134Sthompsa	/* set Rx filter */
5917203134Sthompsa	tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR;
5918203134Sthompsa	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
5919203134Sthompsa		tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL |
5920203134Sthompsa		    RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK |
5921203134Sthompsa		    RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV |
5922203134Sthompsa		    RT2860_DROP_CFACK | RT2860_DROP_CFEND;
5923203134Sthompsa		if (ic->ic_opmode == IEEE80211_M_STA)
5924203134Sthompsa			tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL;
5925203134Sthompsa	}
5926203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5927203134Sthompsa
5928203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
5929203134Sthompsa	    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
5930203134Sthompsa
5931209917Sthompsa	return (0);
5932203134Sthompsa}
5933203134Sthompsa
5934203134Sthompsastatic void
5935259030Skevlorun_adjust_freq_offset(struct run_softc *sc)
5936257955Skevlo{
5937257955Skevlo	uint8_t rf, tmp;
5938257955Skevlo
5939257955Skevlo	run_rt3070_rf_read(sc, 17, &rf);
5940257955Skevlo	tmp = rf;
5941257955Skevlo	rf = (rf & ~0x7f) | (sc->freq & 0x7f);
5942257955Skevlo	rf = MIN(rf, 0x5f);
5943257955Skevlo
5944257955Skevlo	if (tmp != rf)
5945257955Skevlo		run_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf);
5946257955Skevlo}
5947257955Skevlo
5948257955Skevlostatic void
5949203134Sthompsarun_init_locked(struct run_softc *sc)
5950203134Sthompsa{
5951287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5952287197Sglebius	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
5953203134Sthompsa	uint32_t tmp;
5954203134Sthompsa	uint8_t bbp1, bbp3;
5955203134Sthompsa	int i;
5956203134Sthompsa	int ridx;
5957203134Sthompsa	int ntries;
5958203134Sthompsa
5959209917Sthompsa	if (ic->ic_nrunning > 1)
5960208019Sthompsa		return;
5961208019Sthompsa
5962203134Sthompsa	run_stop(sc);
5963203134Sthompsa
5964233283Sbschmidt	if (run_load_microcode(sc) != 0) {
5965233283Sbschmidt		device_printf(sc->sc_dev, "could not load 8051 microcode\n");
5966233283Sbschmidt		goto fail;
5967233283Sbschmidt	}
5968233283Sbschmidt
5969203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5970203134Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0)
5971203134Sthompsa			goto fail;
5972203134Sthompsa		if (tmp != 0 && tmp != 0xffffffff)
5973203134Sthompsa			break;
5974203134Sthompsa		run_delay(sc, 10);
5975203134Sthompsa	}
5976203134Sthompsa	if (ntries == 100)
5977203134Sthompsa		goto fail;
5978203134Sthompsa
5979203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
5980203134Sthompsa		run_setup_tx_list(sc, &sc->sc_epq[i]);
5981203134Sthompsa
5982287197Sglebius	run_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr);
5983203134Sthompsa
5984203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5985203134Sthompsa		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
5986203134Sthompsa			goto fail;
5987203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5988203134Sthompsa			break;
5989203134Sthompsa		run_delay(sc, 10);
5990203134Sthompsa	}
5991203134Sthompsa	if (ntries == 100) {
5992203138Sthompsa		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
5993203134Sthompsa		goto fail;
5994203134Sthompsa	}
5995203134Sthompsa	tmp &= 0xff0;
5996203134Sthompsa	tmp |= RT2860_TX_WB_DDONE;
5997203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
5998203134Sthompsa
5999203134Sthompsa	/* turn off PME_OEN to solve high-current issue */
6000203134Sthompsa	run_read(sc, RT2860_SYS_CTRL, &tmp);
6001203134Sthompsa	run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN);
6002203134Sthompsa
6003203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
6004203134Sthompsa	    RT2860_BBP_HRST | RT2860_MAC_SRST);
6005203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
6006203134Sthompsa
6007203134Sthompsa	if (run_reset(sc) != 0) {
6008203138Sthompsa		device_printf(sc->sc_dev, "could not reset chipset\n");
6009203134Sthompsa		goto fail;
6010203134Sthompsa	}
6011203134Sthompsa
6012203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
6013203134Sthompsa
6014203134Sthompsa	/* init Tx power for all Tx rates (from EEPROM) */
6015203134Sthompsa	for (ridx = 0; ridx < 5; ridx++) {
6016203134Sthompsa		if (sc->txpow20mhz[ridx] == 0xffffffff)
6017203134Sthompsa			continue;
6018203134Sthompsa		run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]);
6019203134Sthompsa	}
6020203134Sthompsa
6021257955Skevlo	for (i = 0; i < nitems(rt2870_def_mac); i++)
6022203134Sthompsa		run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val);
6023203134Sthompsa	run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273);
6024203134Sthompsa	run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344);
6025203134Sthompsa	run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa);
6026203134Sthompsa
6027259030Skevlo	if (sc->mac_ver >= 0x5390) {
6028259030Skevlo		run_write(sc, RT2860_TX_SW_CFG0,
6029259030Skevlo		    4 << RT2860_DLY_PAPE_EN_SHIFT | 4);
6030259030Skevlo		if (sc->mac_ver >= 0x5392) {
6031259030Skevlo			run_write(sc, RT2860_MAX_LEN_CFG, 0x00002fff);
6032259032Skevlo			if (sc->mac_ver == 0x5592) {
6033259032Skevlo				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcba980);
6034259032Skevlo				run_write(sc, RT2860_TXOP_HLDR_ET, 0x00000082);
6035259032Skevlo			} else {
6036259032Skevlo				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcb4980);
6037259032Skevlo				run_write(sc, RT2860_LG_FBK_CFG0, 0xedcba322);
6038259032Skevlo			}
6039259030Skevlo		}
6040260219Skevlo	} else if (sc->mac_ver == 0x3593) {
6041260219Skevlo		run_write(sc, RT2860_TX_SW_CFG0,
6042260219Skevlo		    4 << RT2860_DLY_PAPE_EN_SHIFT | 2);
6043257955Skevlo	} else if (sc->mac_ver >= 0x3070) {
6044203134Sthompsa		/* set delay of PA_PE assertion to 1us (unit of 0.25us) */
6045203134Sthompsa		run_write(sc, RT2860_TX_SW_CFG0,
6046203134Sthompsa		    4 << RT2860_DLY_PAPE_EN_SHIFT);
6047203134Sthompsa	}
6048203134Sthompsa
6049203134Sthompsa	/* wait while MAC is busy */
6050203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
6051203134Sthompsa		if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0)
6052203134Sthompsa			goto fail;
6053203134Sthompsa		if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY)))
6054203134Sthompsa			break;
6055203134Sthompsa		run_delay(sc, 10);
6056203134Sthompsa	}
6057203134Sthompsa	if (ntries == 100)
6058203134Sthompsa		goto fail;
6059203134Sthompsa
6060203134Sthompsa	/* clear Host to MCU mailbox */
6061203134Sthompsa	run_write(sc, RT2860_H2M_BBPAGENT, 0);
6062203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
6063203134Sthompsa	run_delay(sc, 10);
6064203134Sthompsa
6065203134Sthompsa	if (run_bbp_init(sc) != 0) {
6066203138Sthompsa		device_printf(sc->sc_dev, "could not initialize BBP\n");
6067203134Sthompsa		goto fail;
6068203134Sthompsa	}
6069203134Sthompsa
6070203134Sthompsa	/* abort TSF synchronization */
6071345752Savos	run_disable_tsf(sc);
6072203134Sthompsa
6073203134Sthompsa	/* clear RX WCID search table */
6074203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512);
6075203134Sthompsa	/* clear WCID attribute table */
6076203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32);
6077203134Sthompsa
6078209144Sthompsa	/* hostapd sets a key before init. So, don't clear it. */
6079209917Sthompsa	if (sc->cmdq_key_set != RUN_CMDQ_GO) {
6080209144Sthompsa		/* clear shared key table */
6081209144Sthompsa		run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32);
6082209144Sthompsa		/* clear shared key mode */
6083209144Sthompsa		run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4);
6084209144Sthompsa	}
6085209144Sthompsa
6086203134Sthompsa	run_read(sc, RT2860_US_CYC_CNT, &tmp);
6087203134Sthompsa	tmp = (tmp & ~0xff) | 0x1e;
6088203134Sthompsa	run_write(sc, RT2860_US_CYC_CNT, tmp);
6089203134Sthompsa
6090205042Sthompsa	if (sc->mac_rev != 0x0101)
6091203134Sthompsa		run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f);
6092203134Sthompsa
6093203134Sthompsa	run_write(sc, RT2860_WMM_TXOP0_CFG, 0);
6094203134Sthompsa	run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96);
6095203134Sthompsa
6096203134Sthompsa	/* write vendor-specific BBP values (from EEPROM) */
6097260219Skevlo	if (sc->mac_ver < 0x3593) {
6098257955Skevlo		for (i = 0; i < 10; i++) {
6099257955Skevlo			if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff)
6100257955Skevlo				continue;
6101257955Skevlo			run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val);
6102257955Skevlo		}
6103203134Sthompsa	}
6104203134Sthompsa
6105203134Sthompsa	/* select Main antenna for 1T1R devices */
6106257955Skevlo	if (sc->rf_rev == RT3070_RF_3020 || sc->rf_rev == RT5390_RF_5370)
6107203134Sthompsa		run_set_rx_antenna(sc, 0);
6108203134Sthompsa
6109203134Sthompsa	/* send LEDs operating mode to microcontroller */
6110203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]);
6111203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]);
6112203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]);
6113203134Sthompsa
6114257955Skevlo	if (sc->mac_ver >= 0x5390)
6115257955Skevlo		run_rt5390_rf_init(sc);
6116260219Skevlo	else if (sc->mac_ver == 0x3593)
6117260219Skevlo		run_rt3593_rf_init(sc);
6118257955Skevlo	else if (sc->mac_ver >= 0x3070)
6119205042Sthompsa		run_rt3070_rf_init(sc);
6120205042Sthompsa
6121203134Sthompsa	/* disable non-existing Rx chains */
6122203134Sthompsa	run_bbp_read(sc, 3, &bbp3);
6123203134Sthompsa	bbp3 &= ~(1 << 3 | 1 << 4);
6124203134Sthompsa	if (sc->nrxchains == 2)
6125203134Sthompsa		bbp3 |= 1 << 3;
6126203134Sthompsa	else if (sc->nrxchains == 3)
6127203134Sthompsa		bbp3 |= 1 << 4;
6128203134Sthompsa	run_bbp_write(sc, 3, bbp3);
6129203134Sthompsa
6130203134Sthompsa	/* disable non-existing Tx chains */
6131203134Sthompsa	run_bbp_read(sc, 1, &bbp1);
6132203134Sthompsa	if (sc->ntxchains == 1)
6133203134Sthompsa		bbp1 &= ~(1 << 3 | 1 << 4);
6134203134Sthompsa	run_bbp_write(sc, 1, bbp1);
6135203134Sthompsa
6136260219Skevlo	if (sc->mac_ver >= 0x5390)
6137260219Skevlo		run_rt5390_rf_setup(sc);
6138260219Skevlo	else if (sc->mac_ver == 0x3593)
6139260219Skevlo		run_rt3593_rf_setup(sc);
6140260219Skevlo	else if (sc->mac_ver >= 0x3070)
6141205042Sthompsa		run_rt3070_rf_setup(sc);
6142203134Sthompsa
6143203134Sthompsa	/* select default channel */
6144203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
6145203134Sthompsa
6146203134Sthompsa	/* setup initial protection mode */
6147218492Sbschmidt	run_updateprot_cb(ic);
6148203134Sthompsa
6149203134Sthompsa	/* turn radio LED on */
6150203134Sthompsa	run_set_leds(sc, RT2860_LED_RADIO);
6151203134Sthompsa
6152287197Sglebius	sc->sc_flags |= RUN_RUNNING;
6153208019Sthompsa	sc->cmdq_run = RUN_CMDQ_GO;
6154203134Sthompsa
6155209917Sthompsa	for (i = 0; i != RUN_N_XFER; i++)
6156203134Sthompsa		usbd_xfer_set_stall(sc->sc_xfer[i]);
6157203134Sthompsa
6158203134Sthompsa	usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]);
6159203134Sthompsa
6160203134Sthompsa	if (run_txrx_enable(sc) != 0)
6161203134Sthompsa		goto fail;
6162203134Sthompsa
6163203134Sthompsa	return;
6164203134Sthompsa
6165203134Sthompsafail:
6166203134Sthompsa	run_stop(sc);
6167203134Sthompsa}
6168203134Sthompsa
6169203134Sthompsastatic void
6170203134Sthompsarun_stop(void *arg)
6171203134Sthompsa{
6172203134Sthompsa	struct run_softc *sc = (struct run_softc *)arg;
6173203134Sthompsa	uint32_t tmp;
6174203134Sthompsa	int i;
6175203134Sthompsa	int ntries;
6176203134Sthompsa
6177203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
6178203134Sthompsa
6179287197Sglebius	if (sc->sc_flags & RUN_RUNNING)
6180203134Sthompsa		run_set_leds(sc, 0);	/* turn all LEDs off */
6181203134Sthompsa
6182287197Sglebius	sc->sc_flags &= ~RUN_RUNNING;
6183203134Sthompsa
6184208019Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
6185209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set;
6186208019Sthompsa
6187203134Sthompsa	RUN_UNLOCK(sc);
6188203134Sthompsa
6189203134Sthompsa	for(i = 0; i < RUN_N_XFER; i++)
6190203134Sthompsa		usbd_transfer_drain(sc->sc_xfer[i]);
6191203134Sthompsa
6192203134Sthompsa	RUN_LOCK(sc);
6193203134Sthompsa
6194288649Sadrian	run_drain_mbufq(sc);
6195288649Sadrian
6196209917Sthompsa	if (sc->rx_m != NULL) {
6197203134Sthompsa		m_free(sc->rx_m);
6198203134Sthompsa		sc->rx_m = NULL;
6199203134Sthompsa	}
6200203134Sthompsa
6201257955Skevlo	/* Disable Tx/Rx DMA. */
6202257955Skevlo	if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6203257955Skevlo		return;
6204257955Skevlo	tmp &= ~(RT2860_RX_DMA_EN | RT2860_TX_DMA_EN);
6205257955Skevlo	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
6206257955Skevlo
6207258643Shselasky	for (ntries = 0; ntries < 100; ntries++) {
6208257955Skevlo		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6209257955Skevlo			return;
6210257955Skevlo		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
6211257955Skevlo				break;
6212257955Skevlo		run_delay(sc, 10);
6213257955Skevlo	}
6214257955Skevlo	if (ntries == 100) {
6215257955Skevlo		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
6216257955Skevlo		return;
6217257955Skevlo	}
6218257955Skevlo
6219203134Sthompsa	/* disable Tx/Rx */
6220203134Sthompsa	run_read(sc, RT2860_MAC_SYS_CTRL, &tmp);
6221203134Sthompsa	tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
6222203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, tmp);
6223203134Sthompsa
6224203134Sthompsa	/* wait for pending Tx to complete */
6225203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
6226209917Sthompsa		if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0) {
6227203134Sthompsa			DPRINTF("Cannot read Tx queue count\n");
6228203134Sthompsa			break;
6229203134Sthompsa		}
6230209917Sthompsa		if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0) {
6231203134Sthompsa			DPRINTF("All Tx cleared\n");
6232203134Sthompsa			break;
6233203134Sthompsa		}
6234203134Sthompsa		run_delay(sc, 10);
6235203134Sthompsa	}
6236209917Sthompsa	if (ntries >= 100)
6237203134Sthompsa		DPRINTF("There are still pending Tx\n");
6238203134Sthompsa	run_delay(sc, 10);
6239203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
6240203134Sthompsa
6241203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST);
6242203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
6243203134Sthompsa
6244203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
6245203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
6246203134Sthompsa}
6247203134Sthompsa
6248203134Sthompsastatic void
6249257429Shselaskyrun_delay(struct run_softc *sc, u_int ms)
6250203134Sthompsa{
6251203134Sthompsa	usb_pause_mtx(mtx_owned(&sc->sc_mtx) ?
6252203134Sthompsa	    &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms));
6253203134Sthompsa}
6254203134Sthompsa
6255203134Sthompsastatic device_method_t run_methods[] = {
6256203134Sthompsa	/* Device interface */
6257203134Sthompsa	DEVMETHOD(device_probe,		run_match),
6258203134Sthompsa	DEVMETHOD(device_attach,	run_attach),
6259203134Sthompsa	DEVMETHOD(device_detach,	run_detach),
6260246614Shselasky	DEVMETHOD_END
6261203134Sthompsa};
6262203134Sthompsa
6263203134Sthompsastatic driver_t run_driver = {
6264233774Shselasky	.name = "run",
6265233774Shselasky	.methods = run_methods,
6266233774Shselasky	.size = sizeof(struct run_softc)
6267203134Sthompsa};
6268203134Sthompsa
6269203134Sthompsastatic devclass_t run_devclass;
6270203134Sthompsa
6271259812SkevloDRIVER_MODULE(run, uhub, run_driver, run_devclass, run_driver_loaded, NULL);
6272212122SthompsaMODULE_DEPEND(run, wlan, 1, 1, 1);
6273212122SthompsaMODULE_DEPEND(run, usb, 1, 1, 1);
6274212122SthompsaMODULE_DEPEND(run, firmware, 1, 1, 1);
6275212122SthompsaMODULE_VERSION(run, 1);
6276292080SimpUSB_PNP_HOST_INFO(run_devs);
6277