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