if_run.c revision 273448
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 273448 2014-10-22 03:32:27Z kevlo $"); 22203134Sthompsa 23203134Sthompsa/*- 24257955Skevlo * Ralink Technology RT2700U/RT2800U/RT3000U/RT3900E chipset driver. 25203134Sthompsa * http://www.ralinktech.com/ 26203134Sthompsa */ 27203134Sthompsa 28203134Sthompsa#include <sys/param.h> 29203134Sthompsa#include <sys/sockio.h> 30203134Sthompsa#include <sys/sysctl.h> 31203134Sthompsa#include <sys/lock.h> 32203134Sthompsa#include <sys/mutex.h> 33203134Sthompsa#include <sys/mbuf.h> 34203134Sthompsa#include <sys/kernel.h> 35203134Sthompsa#include <sys/socket.h> 36203134Sthompsa#include <sys/systm.h> 37203134Sthompsa#include <sys/malloc.h> 38203134Sthompsa#include <sys/module.h> 39203134Sthompsa#include <sys/bus.h> 40203134Sthompsa#include <sys/endian.h> 41203134Sthompsa#include <sys/linker.h> 42203134Sthompsa#include <sys/firmware.h> 43203134Sthompsa#include <sys/kdb.h> 44203134Sthompsa 45203134Sthompsa#include <machine/bus.h> 46203134Sthompsa#include <machine/resource.h> 47203134Sthompsa#include <sys/rman.h> 48203134Sthompsa 49203134Sthompsa#include <net/bpf.h> 50203134Sthompsa#include <net/if.h> 51257176Sglebius#include <net/if_var.h> 52203134Sthompsa#include <net/if_arp.h> 53203134Sthompsa#include <net/ethernet.h> 54203134Sthompsa#include <net/if_dl.h> 55203134Sthompsa#include <net/if_media.h> 56203134Sthompsa#include <net/if_types.h> 57203134Sthompsa 58203134Sthompsa#include <netinet/in.h> 59203134Sthompsa#include <netinet/in_systm.h> 60203134Sthompsa#include <netinet/in_var.h> 61203134Sthompsa#include <netinet/if_ether.h> 62203134Sthompsa#include <netinet/ip.h> 63203134Sthompsa 64203134Sthompsa#include <net80211/ieee80211_var.h> 65203134Sthompsa#include <net80211/ieee80211_regdomain.h> 66203134Sthompsa#include <net80211/ieee80211_radiotap.h> 67206358Srpaulo#include <net80211/ieee80211_ratectl.h> 68203134Sthompsa 69203134Sthompsa#include <dev/usb/usb.h> 70203134Sthompsa#include <dev/usb/usbdi.h> 71203134Sthompsa#include "usbdevs.h" 72203134Sthompsa 73259546Skevlo#define USB_DEBUG_VAR run_debug 74203134Sthompsa#include <dev/usb/usb_debug.h> 75259812Skevlo#include <dev/usb/usb_msctest.h> 76203134Sthompsa 77220235Skevlo#include <dev/usb/wlan/if_runreg.h> 78220235Skevlo#include <dev/usb/wlan/if_runvar.h> 79203134Sthompsa 80207077Sthompsa#ifdef USB_DEBUG 81259546Skevlo#define RUN_DEBUG 82203134Sthompsa#endif 83203134Sthompsa 84203134Sthompsa#ifdef RUN_DEBUG 85203134Sthompsaint run_debug = 0; 86227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, run, CTLFLAG_RW, 0, "USB run"); 87203134SthompsaSYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RW, &run_debug, 0, 88203134Sthompsa "run debug level"); 89203134Sthompsa#endif 90203134Sthompsa 91259546Skevlo#define IEEE80211_HAS_ADDR4(wh) \ 92203134Sthompsa (((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) 93203134Sthompsa 94208019Sthompsa/* 95208019Sthompsa * Because of LOR in run_key_delete(), use atomic instead. 96208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[]. 97208019Sthompsa */ 98259546Skevlo#define RUN_CMDQ_GET(c) (atomic_fetchadd_32((c), 1) & RUN_CMDQ_MASQ) 99208019Sthompsa 100223486Shselaskystatic const STRUCT_USB_HOST_ID run_devs[] = { 101259546Skevlo#define RUN_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } 102259812Skevlo#define RUN_DEV_EJECT(v,p) \ 103262465Skevlo { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RUN_EJECT) } 104262465Skevlo#define RUN_EJECT 1 105209918Sthompsa RUN_DEV(ABOCOM, RT2770), 106209918Sthompsa RUN_DEV(ABOCOM, RT2870), 107209918Sthompsa RUN_DEV(ABOCOM, RT3070), 108209918Sthompsa RUN_DEV(ABOCOM, RT3071), 109209918Sthompsa RUN_DEV(ABOCOM, RT3072), 110209918Sthompsa RUN_DEV(ABOCOM2, RT2870_1), 111209918Sthompsa RUN_DEV(ACCTON, RT2770), 112209918Sthompsa RUN_DEV(ACCTON, RT2870_1), 113209918Sthompsa RUN_DEV(ACCTON, RT2870_2), 114209918Sthompsa RUN_DEV(ACCTON, RT2870_3), 115209918Sthompsa RUN_DEV(ACCTON, RT2870_4), 116209918Sthompsa RUN_DEV(ACCTON, RT2870_5), 117209918Sthompsa RUN_DEV(ACCTON, RT3070), 118209918Sthompsa RUN_DEV(ACCTON, RT3070_1), 119209918Sthompsa RUN_DEV(ACCTON, RT3070_2), 120209918Sthompsa RUN_DEV(ACCTON, RT3070_3), 121209918Sthompsa RUN_DEV(ACCTON, RT3070_4), 122209918Sthompsa RUN_DEV(ACCTON, RT3070_5), 123209918Sthompsa RUN_DEV(AIRTIES, RT3070), 124209918Sthompsa RUN_DEV(ALLWIN, RT2070), 125209918Sthompsa RUN_DEV(ALLWIN, RT2770), 126209918Sthompsa RUN_DEV(ALLWIN, RT2870), 127209918Sthompsa RUN_DEV(ALLWIN, RT3070), 128209918Sthompsa RUN_DEV(ALLWIN, RT3071), 129209918Sthompsa RUN_DEV(ALLWIN, RT3072), 130209918Sthompsa RUN_DEV(ALLWIN, RT3572), 131209918Sthompsa RUN_DEV(AMIGO, RT2870_1), 132209918Sthompsa RUN_DEV(AMIGO, RT2870_2), 133209918Sthompsa RUN_DEV(AMIT, CGWLUSB2GNR), 134209918Sthompsa RUN_DEV(AMIT, RT2870_1), 135209918Sthompsa RUN_DEV(AMIT2, RT2870), 136209918Sthompsa RUN_DEV(ASUS, RT2870_1), 137209918Sthompsa RUN_DEV(ASUS, RT2870_2), 138209918Sthompsa RUN_DEV(ASUS, RT2870_3), 139209918Sthompsa RUN_DEV(ASUS, RT2870_4), 140209918Sthompsa RUN_DEV(ASUS, RT2870_5), 141209918Sthompsa RUN_DEV(ASUS, USBN13), 142209918Sthompsa RUN_DEV(ASUS, RT3070_1), 143260219Skevlo RUN_DEV(ASUS, USBN66), 144239358Shselasky RUN_DEV(ASUS, USB_N53), 145209918Sthompsa RUN_DEV(ASUS2, USBN11), 146209918Sthompsa RUN_DEV(AZUREWAVE, RT2870_1), 147209918Sthompsa RUN_DEV(AZUREWAVE, RT2870_2), 148209918Sthompsa RUN_DEV(AZUREWAVE, RT3070_1), 149209918Sthompsa RUN_DEV(AZUREWAVE, RT3070_2), 150209918Sthompsa RUN_DEV(AZUREWAVE, RT3070_3), 151260219Skevlo RUN_DEV(BELKIN, F9L1103), 152209918Sthompsa RUN_DEV(BELKIN, F5D8053V3), 153209918Sthompsa RUN_DEV(BELKIN, F5D8055), 154226534Shselasky RUN_DEV(BELKIN, F5D8055V2), 155209918Sthompsa RUN_DEV(BELKIN, F6D4050V1), 156256500Shselasky RUN_DEV(BELKIN, F6D4050V2), 157209918Sthompsa RUN_DEV(BELKIN, RT2870_1), 158209918Sthompsa RUN_DEV(BELKIN, RT2870_2), 159226534Shselasky RUN_DEV(CISCOLINKSYS, AE1000), 160209918Sthompsa RUN_DEV(CISCOLINKSYS2, RT3070), 161209918Sthompsa RUN_DEV(CISCOLINKSYS3, RT3070), 162209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_1), 163209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_2), 164209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_3), 165209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_4), 166209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_5), 167209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_6), 168209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_7), 169209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_8), 170209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT3070_1), 171209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT3070_2), 172209918Sthompsa RUN_DEV(CONCEPTRONIC2, VIGORN61), 173209918Sthompsa RUN_DEV(COREGA, CGWLUSB300GNM), 174209918Sthompsa RUN_DEV(COREGA, RT2870_1), 175209918Sthompsa RUN_DEV(COREGA, RT2870_2), 176209918Sthompsa RUN_DEV(COREGA, RT2870_3), 177209918Sthompsa RUN_DEV(COREGA, RT3070), 178209918Sthompsa RUN_DEV(CYBERTAN, RT2870), 179209918Sthompsa RUN_DEV(DLINK, RT2870), 180209918Sthompsa RUN_DEV(DLINK, RT3072), 181255238Sbr RUN_DEV(DLINK, DWA127), 182257955Skevlo RUN_DEV(DLINK, DWA140B3), 183259032Skevlo RUN_DEV(DLINK, DWA160B2), 184267089Skevlo RUN_DEV(DLINK, DWA140D1), 185260219Skevlo RUN_DEV(DLINK, DWA162), 186209918Sthompsa RUN_DEV(DLINK2, DWA130), 187209918Sthompsa RUN_DEV(DLINK2, RT2870_1), 188209918Sthompsa RUN_DEV(DLINK2, RT2870_2), 189209918Sthompsa RUN_DEV(DLINK2, RT3070_1), 190209918Sthompsa RUN_DEV(DLINK2, RT3070_2), 191209918Sthompsa RUN_DEV(DLINK2, RT3070_3), 192209918Sthompsa RUN_DEV(DLINK2, RT3070_4), 193209918Sthompsa RUN_DEV(DLINK2, RT3070_5), 194209918Sthompsa RUN_DEV(DLINK2, RT3072), 195209918Sthompsa RUN_DEV(DLINK2, RT3072_1), 196209918Sthompsa RUN_DEV(EDIMAX, EW7717), 197209918Sthompsa RUN_DEV(EDIMAX, EW7718), 198260219Skevlo RUN_DEV(EDIMAX, EW7733UND), 199209918Sthompsa RUN_DEV(EDIMAX, RT2870_1), 200209918Sthompsa RUN_DEV(ENCORE, RT3070_1), 201209918Sthompsa RUN_DEV(ENCORE, RT3070_2), 202209918Sthompsa RUN_DEV(ENCORE, RT3070_3), 203209918Sthompsa RUN_DEV(GIGABYTE, GNWB31N), 204209918Sthompsa RUN_DEV(GIGABYTE, GNWB32L), 205209918Sthompsa RUN_DEV(GIGABYTE, RT2870_1), 206209918Sthompsa RUN_DEV(GIGASET, RT3070_1), 207209918Sthompsa RUN_DEV(GIGASET, RT3070_2), 208209918Sthompsa RUN_DEV(GUILLEMOT, HWNU300), 209209918Sthompsa RUN_DEV(HAWKING, HWUN2), 210209918Sthompsa RUN_DEV(HAWKING, RT2870_1), 211209918Sthompsa RUN_DEV(HAWKING, RT2870_2), 212209918Sthompsa RUN_DEV(HAWKING, RT3070), 213209918Sthompsa RUN_DEV(IODATA, RT3072_1), 214209918Sthompsa RUN_DEV(IODATA, RT3072_2), 215209918Sthompsa RUN_DEV(IODATA, RT3072_3), 216209918Sthompsa RUN_DEV(IODATA, RT3072_4), 217209918Sthompsa RUN_DEV(LINKSYS4, RT3070), 218209918Sthompsa RUN_DEV(LINKSYS4, WUSB100), 219209918Sthompsa RUN_DEV(LINKSYS4, WUSB54GCV3), 220209918Sthompsa RUN_DEV(LINKSYS4, WUSB600N), 221209918Sthompsa RUN_DEV(LINKSYS4, WUSB600NV2), 222209918Sthompsa RUN_DEV(LOGITEC, RT2870_1), 223209918Sthompsa RUN_DEV(LOGITEC, RT2870_2), 224209918Sthompsa RUN_DEV(LOGITEC, RT2870_3), 225230333Shselasky RUN_DEV(LOGITEC, LANW300NU2), 226238274Shrs RUN_DEV(LOGITEC, LANW150NU2), 227248458Shselasky RUN_DEV(LOGITEC, LANW300NU2S), 228209918Sthompsa RUN_DEV(MELCO, RT2870_1), 229209918Sthompsa RUN_DEV(MELCO, RT2870_2), 230209918Sthompsa RUN_DEV(MELCO, WLIUCAG300N), 231209918Sthompsa RUN_DEV(MELCO, WLIUCG300N), 232219257Sdaichi RUN_DEV(MELCO, WLIUCG301N), 233209918Sthompsa RUN_DEV(MELCO, WLIUCGN), 234227781Shselasky RUN_DEV(MELCO, WLIUCGNM), 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 *); 384203134Sthompsastatic void run_key_update_begin(struct ieee80211vap *); 385203134Sthompsastatic void run_key_update_end(struct ieee80211vap *); 386208019Sthompsastatic void run_key_set_cb(void *); 387208019Sthompsastatic int run_key_set(struct ieee80211vap *, struct ieee80211_key *, 388257955Skevlo const uint8_t mac[IEEE80211_ADDR_LEN]); 389208019Sthompsastatic void run_key_delete_cb(void *); 390208019Sthompsastatic int run_key_delete(struct ieee80211vap *, struct ieee80211_key *); 391206358Srpaulostatic void run_ratectl_to(void *); 392206358Srpaulostatic void run_ratectl_cb(void *, int); 393208019Sthompsastatic void run_drain_fifo(void *); 394203134Sthompsastatic void run_iter_func(void *, struct ieee80211_node *); 395208019Sthompsastatic void run_newassoc_cb(void *); 396203134Sthompsastatic void run_newassoc(struct ieee80211_node *, int); 397203134Sthompsastatic void run_rx_frame(struct run_softc *, struct mbuf *, uint32_t); 398203134Sthompsastatic void run_tx_free(struct run_endpoint_queue *pq, 399203134Sthompsa struct run_tx_data *, int); 400208019Sthompsastatic void run_set_tx_desc(struct run_softc *, struct run_tx_data *); 401203134Sthompsastatic int run_tx(struct run_softc *, struct mbuf *, 402203134Sthompsa struct ieee80211_node *); 403203134Sthompsastatic int run_tx_mgt(struct run_softc *, struct mbuf *, 404203134Sthompsa struct ieee80211_node *); 405203134Sthompsastatic int run_sendprot(struct run_softc *, const struct mbuf *, 406203134Sthompsa struct ieee80211_node *, int, int); 407203134Sthompsastatic int run_tx_param(struct run_softc *, struct mbuf *, 408203134Sthompsa struct ieee80211_node *, 409203134Sthompsa const struct ieee80211_bpf_params *); 410203134Sthompsastatic int run_raw_xmit(struct ieee80211_node *, struct mbuf *, 411203134Sthompsa const struct ieee80211_bpf_params *); 412203134Sthompsastatic void run_start(struct ifnet *); 413203134Sthompsastatic int run_ioctl(struct ifnet *, u_long, caddr_t); 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 *); 435203134Sthompsastatic void run_enable_mrr(struct run_softc *); 436203134Sthompsastatic void run_set_txpreamble(struct run_softc *); 437203134Sthompsastatic void run_set_basicrates(struct run_softc *); 438203134Sthompsastatic void run_set_leds(struct run_softc *, uint16_t); 439203134Sthompsastatic void run_set_bssid(struct run_softc *, const uint8_t *); 440203134Sthompsastatic void run_set_macaddr(struct run_softc *, const uint8_t *); 441203134Sthompsastatic void run_updateslot(struct ifnet *); 442218492Sbschmidtstatic void run_updateslot_cb(void *); 443208019Sthompsastatic void run_update_mcast(struct ifnet *); 444203134Sthompsastatic int8_t run_rssi2dbm(struct run_softc *, uint8_t, uint8_t); 445203134Sthompsastatic void run_update_promisc_locked(struct ifnet *); 446203134Sthompsastatic void run_update_promisc(struct ifnet *); 447257955Skevlostatic void run_rt5390_bbp_init(struct run_softc *); 448203134Sthompsastatic int run_bbp_init(struct run_softc *); 449203134Sthompsastatic int run_rt3070_rf_init(struct run_softc *); 450260219Skevlostatic void run_rt3593_rf_init(struct run_softc *); 451257955Skevlostatic void run_rt5390_rf_init(struct run_softc *); 452203134Sthompsastatic int run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t, 453203134Sthompsa uint8_t *); 454205042Sthompsastatic void run_rt3070_rf_setup(struct run_softc *); 455260219Skevlostatic void run_rt3593_rf_setup(struct run_softc *); 456260219Skevlostatic void run_rt5390_rf_setup(struct run_softc *); 457203134Sthompsastatic int run_txrx_enable(struct run_softc *); 458257955Skevlostatic void run_adjust_freq_offset(struct run_softc *); 459203134Sthompsastatic void run_init(void *); 460203134Sthompsastatic void run_init_locked(struct run_softc *); 461203134Sthompsastatic void run_stop(void *); 462257429Shselaskystatic void run_delay(struct run_softc *, u_int); 463203134Sthompsa 464259812Skevlostatic eventhandler_tag run_etag; 465259812Skevlo 466259544Skevlostatic const struct rt2860_rate { 467259544Skevlo uint8_t rate; 468259544Skevlo uint8_t mcs; 469259544Skevlo enum ieee80211_phytype phy; 470259544Skevlo uint8_t ctl_ridx; 471259544Skevlo uint16_t sp_ack_dur; 472259544Skevlo uint16_t lp_ack_dur; 473259544Skevlo} rt2860_rates[] = { 474259544Skevlo { 2, 0, IEEE80211_T_DS, 0, 314, 314 }, 475259544Skevlo { 4, 1, IEEE80211_T_DS, 1, 258, 162 }, 476259544Skevlo { 11, 2, IEEE80211_T_DS, 2, 223, 127 }, 477259544Skevlo { 22, 3, IEEE80211_T_DS, 3, 213, 117 }, 478259544Skevlo { 12, 0, IEEE80211_T_OFDM, 4, 60, 60 }, 479259544Skevlo { 18, 1, IEEE80211_T_OFDM, 4, 52, 52 }, 480259544Skevlo { 24, 2, IEEE80211_T_OFDM, 6, 48, 48 }, 481259544Skevlo { 36, 3, IEEE80211_T_OFDM, 6, 44, 44 }, 482259544Skevlo { 48, 4, IEEE80211_T_OFDM, 8, 44, 44 }, 483259544Skevlo { 72, 5, IEEE80211_T_OFDM, 8, 40, 40 }, 484259544Skevlo { 96, 6, IEEE80211_T_OFDM, 8, 40, 40 }, 485259544Skevlo { 108, 7, IEEE80211_T_OFDM, 8, 40, 40 } 486259544Skevlo}; 487259544Skevlo 488203134Sthompsastatic const struct { 489208019Sthompsa uint16_t reg; 490203134Sthompsa uint32_t val; 491203134Sthompsa} rt2870_def_mac[] = { 492203134Sthompsa RT2870_DEF_MAC 493203134Sthompsa}; 494203134Sthompsa 495203134Sthompsastatic const struct { 496203134Sthompsa uint8_t reg; 497203134Sthompsa uint8_t val; 498203134Sthompsa} rt2860_def_bbp[] = { 499203134Sthompsa RT2860_DEF_BBP 500257955Skevlo},rt5390_def_bbp[] = { 501257955Skevlo RT5390_DEF_BBP 502259032Skevlo},rt5592_def_bbp[] = { 503259032Skevlo RT5592_DEF_BBP 504203134Sthompsa}; 505203134Sthompsa 506259032Skevlo/* 507259032Skevlo * Default values for BBP register R196 for RT5592. 508259032Skevlo */ 509259032Skevlostatic const uint8_t rt5592_bbp_r196[] = { 510259032Skevlo 0xe0, 0x1f, 0x38, 0x32, 0x08, 0x28, 0x19, 0x0a, 0xff, 0x00, 511259032Skevlo 0x16, 0x10, 0x10, 0x0b, 0x36, 0x2c, 0x26, 0x24, 0x42, 0x36, 512259032Skevlo 0x30, 0x2d, 0x4c, 0x46, 0x3d, 0x40, 0x3e, 0x42, 0x3d, 0x40, 513259032Skevlo 0x3c, 0x34, 0x2c, 0x2f, 0x3c, 0x35, 0x2e, 0x2a, 0x49, 0x41, 514259032Skevlo 0x36, 0x31, 0x30, 0x30, 0x0e, 0x0d, 0x28, 0x21, 0x1c, 0x16, 515259032Skevlo 0x50, 0x4a, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 516259032Skevlo 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 517259032Skevlo 0x00, 0x00, 0x7d, 0x14, 0x32, 0x2c, 0x36, 0x4c, 0x43, 0x2c, 518259032Skevlo 0x2e, 0x36, 0x30, 0x6e 519259032Skevlo}; 520259032Skevlo 521203134Sthompsastatic const struct rfprog { 522203134Sthompsa uint8_t chan; 523203134Sthompsa uint32_t r1, r2, r3, r4; 524203134Sthompsa} rt2860_rf2850[] = { 525203134Sthompsa RT2860_RF2850 526203134Sthompsa}; 527203134Sthompsa 528203134Sthompsastruct { 529203134Sthompsa uint8_t n, r, k; 530205042Sthompsa} rt3070_freqs[] = { 531205042Sthompsa RT3070_RF3052 532203134Sthompsa}; 533203134Sthompsa 534259032Skevlostatic const struct rt5592_freqs { 535259032Skevlo uint16_t n; 536259032Skevlo uint8_t k, m, r; 537259032Skevlo} rt5592_freqs_20mhz[] = { 538259032Skevlo RT5592_RF5592_20MHZ 539259032Skevlo},rt5592_freqs_40mhz[] = { 540259032Skevlo RT5592_RF5592_40MHZ 541259032Skevlo}; 542259032Skevlo 543203134Sthompsastatic const struct { 544203134Sthompsa uint8_t reg; 545203134Sthompsa uint8_t val; 546203134Sthompsa} rt3070_def_rf[] = { 547203134Sthompsa RT3070_DEF_RF 548205042Sthompsa},rt3572_def_rf[] = { 549205042Sthompsa RT3572_DEF_RF 550260219Skevlo},rt3593_def_rf[] = { 551260219Skevlo RT3593_DEF_RF 552257955Skevlo},rt5390_def_rf[] = { 553257955Skevlo RT5390_DEF_RF 554257955Skevlo},rt5392_def_rf[] = { 555257955Skevlo RT5392_DEF_RF 556259032Skevlo},rt5592_def_rf[] = { 557259032Skevlo RT5592_DEF_RF 558259032Skevlo},rt5592_2ghz_def_rf[] = { 559259032Skevlo RT5592_2GHZ_DEF_RF 560259032Skevlo},rt5592_5ghz_def_rf[] = { 561259032Skevlo RT5592_5GHZ_DEF_RF 562203134Sthompsa}; 563203134Sthompsa 564259032Skevlostatic const struct { 565259032Skevlo u_int firstchan; 566259032Skevlo u_int lastchan; 567259032Skevlo uint8_t reg; 568259032Skevlo uint8_t val; 569259032Skevlo} rt5592_chan_5ghz[] = { 570259032Skevlo RT5592_CHAN_5GHZ 571259032Skevlo}; 572259032Skevlo 573203134Sthompsastatic const struct usb_config run_config[RUN_N_XFER] = { 574203134Sthompsa [RUN_BULK_TX_BE] = { 575203134Sthompsa .type = UE_BULK, 576203134Sthompsa .endpoint = UE_ADDR_ANY, 577203134Sthompsa .ep_index = 0, 578203134Sthompsa .direction = UE_DIR_OUT, 579203134Sthompsa .bufsize = RUN_MAX_TXSZ, 580203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 581203134Sthompsa .callback = run_bulk_tx_callback0, 582203134Sthompsa .timeout = 5000, /* ms */ 583203134Sthompsa }, 584203134Sthompsa [RUN_BULK_TX_BK] = { 585203134Sthompsa .type = UE_BULK, 586203134Sthompsa .endpoint = UE_ADDR_ANY, 587203134Sthompsa .direction = UE_DIR_OUT, 588203134Sthompsa .ep_index = 1, 589203134Sthompsa .bufsize = RUN_MAX_TXSZ, 590203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 591203134Sthompsa .callback = run_bulk_tx_callback1, 592203134Sthompsa .timeout = 5000, /* ms */ 593203134Sthompsa }, 594203134Sthompsa [RUN_BULK_TX_VI] = { 595203134Sthompsa .type = UE_BULK, 596203134Sthompsa .endpoint = UE_ADDR_ANY, 597203134Sthompsa .direction = UE_DIR_OUT, 598203134Sthompsa .ep_index = 2, 599203134Sthompsa .bufsize = RUN_MAX_TXSZ, 600203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 601203134Sthompsa .callback = run_bulk_tx_callback2, 602203134Sthompsa .timeout = 5000, /* ms */ 603203134Sthompsa }, 604203134Sthompsa [RUN_BULK_TX_VO] = { 605203134Sthompsa .type = UE_BULK, 606203134Sthompsa .endpoint = UE_ADDR_ANY, 607203134Sthompsa .direction = UE_DIR_OUT, 608203134Sthompsa .ep_index = 3, 609203134Sthompsa .bufsize = RUN_MAX_TXSZ, 610203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 611203134Sthompsa .callback = run_bulk_tx_callback3, 612203134Sthompsa .timeout = 5000, /* ms */ 613203134Sthompsa }, 614203134Sthompsa [RUN_BULK_TX_HCCA] = { 615203134Sthompsa .type = UE_BULK, 616203134Sthompsa .endpoint = UE_ADDR_ANY, 617203134Sthompsa .direction = UE_DIR_OUT, 618203134Sthompsa .ep_index = 4, 619203134Sthompsa .bufsize = RUN_MAX_TXSZ, 620203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 621203134Sthompsa .callback = run_bulk_tx_callback4, 622203134Sthompsa .timeout = 5000, /* ms */ 623203134Sthompsa }, 624203134Sthompsa [RUN_BULK_TX_PRIO] = { 625203134Sthompsa .type = UE_BULK, 626203134Sthompsa .endpoint = UE_ADDR_ANY, 627203134Sthompsa .direction = UE_DIR_OUT, 628203134Sthompsa .ep_index = 5, 629203134Sthompsa .bufsize = RUN_MAX_TXSZ, 630203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 631203134Sthompsa .callback = run_bulk_tx_callback5, 632203134Sthompsa .timeout = 5000, /* ms */ 633203134Sthompsa }, 634203134Sthompsa [RUN_BULK_RX] = { 635203134Sthompsa .type = UE_BULK, 636203134Sthompsa .endpoint = UE_ADDR_ANY, 637203134Sthompsa .direction = UE_DIR_IN, 638203134Sthompsa .bufsize = RUN_MAX_RXSZ, 639203134Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 640203134Sthompsa .callback = run_bulk_rx_callback, 641203134Sthompsa } 642203134Sthompsa}; 643203134Sthompsa 644259812Skevlostatic void 645259812Skevlorun_autoinst(void *arg, struct usb_device *udev, 646259812Skevlo struct usb_attach_arg *uaa) 647259812Skevlo{ 648259812Skevlo struct usb_interface *iface; 649259812Skevlo struct usb_interface_descriptor *id; 650259812Skevlo 651259812Skevlo if (uaa->dev_state != UAA_DEV_READY) 652259812Skevlo return; 653259812Skevlo 654259812Skevlo iface = usbd_get_iface(udev, 0); 655259812Skevlo if (iface == NULL) 656259812Skevlo return; 657259812Skevlo id = iface->idesc; 658259812Skevlo if (id == NULL || id->bInterfaceClass != UICLASS_MASS) 659259812Skevlo return; 660259812Skevlo if (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa)) 661259812Skevlo return; 662259812Skevlo 663259812Skevlo if (usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT) == 0) 664259812Skevlo uaa->dev_state = UAA_DEV_EJECTING; 665259812Skevlo} 666259812Skevlo 667220235Skevlostatic int 668259812Skevlorun_driver_loaded(struct module *mod, int what, void *arg) 669259812Skevlo{ 670259812Skevlo switch (what) { 671259812Skevlo case MOD_LOAD: 672259812Skevlo run_etag = EVENTHANDLER_REGISTER(usb_dev_configured, 673259812Skevlo run_autoinst, NULL, EVENTHANDLER_PRI_ANY); 674259812Skevlo break; 675259812Skevlo case MOD_UNLOAD: 676259812Skevlo EVENTHANDLER_DEREGISTER(usb_dev_configured, run_etag); 677259812Skevlo break; 678259812Skevlo default: 679259812Skevlo return (EOPNOTSUPP); 680259812Skevlo } 681259812Skevlo return (0); 682259812Skevlo} 683259812Skevlo 684259812Skevlostatic int 685203134Sthompsarun_match(device_t self) 686203134Sthompsa{ 687203134Sthompsa struct usb_attach_arg *uaa = device_get_ivars(self); 688203134Sthompsa 689203134Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 690203134Sthompsa return (ENXIO); 691203134Sthompsa if (uaa->info.bConfigIndex != 0) 692203134Sthompsa return (ENXIO); 693203134Sthompsa if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX) 694203134Sthompsa return (ENXIO); 695203134Sthompsa 696203134Sthompsa return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa)); 697203134Sthompsa} 698203134Sthompsa 699203134Sthompsastatic int 700203134Sthompsarun_attach(device_t self) 701203134Sthompsa{ 702203134Sthompsa struct run_softc *sc = device_get_softc(self); 703203134Sthompsa struct usb_attach_arg *uaa = device_get_ivars(self); 704203134Sthompsa struct ieee80211com *ic; 705203134Sthompsa struct ifnet *ifp; 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); 718203134Sthompsa 719203134Sthompsa iface_index = RT2860_IFACE_INDEX; 720208019Sthompsa 721203134Sthompsa error = usbd_transfer_setup(uaa->device, &iface_index, 722203134Sthompsa sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx); 723203134Sthompsa if (error) { 724205042Sthompsa device_printf(self, "could not allocate USB transfers, " 725203134Sthompsa "err=%s\n", usbd_errstr(error)); 726203134Sthompsa goto detach; 727203134Sthompsa } 728203134Sthompsa 729203134Sthompsa RUN_LOCK(sc); 730203134Sthompsa 731203134Sthompsa /* wait for the chip to settle */ 732203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 733209917Sthompsa if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0) { 734203134Sthompsa RUN_UNLOCK(sc); 735203134Sthompsa goto detach; 736203134Sthompsa } 737205042Sthompsa if (ver != 0 && ver != 0xffffffff) 738203134Sthompsa break; 739203134Sthompsa run_delay(sc, 10); 740203134Sthompsa } 741203134Sthompsa if (ntries == 100) { 742203138Sthompsa device_printf(sc->sc_dev, 743203138Sthompsa "timeout waiting for NIC to initialize\n"); 744203134Sthompsa RUN_UNLOCK(sc); 745203134Sthompsa goto detach; 746203134Sthompsa } 747205042Sthompsa sc->mac_ver = ver >> 16; 748205042Sthompsa sc->mac_rev = ver & 0xffff; 749203134Sthompsa 750203134Sthompsa /* retrieve RF rev. no and various other things from EEPROM */ 751203134Sthompsa run_read_eeprom(sc); 752203134Sthompsa 753203138Sthompsa device_printf(sc->sc_dev, 754203138Sthompsa "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n", 755205042Sthompsa sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev), 756203138Sthompsa sc->ntxchains, sc->nrxchains, ether_sprintf(sc->sc_bssid)); 757203134Sthompsa 758203134Sthompsa RUN_UNLOCK(sc); 759203134Sthompsa 760203134Sthompsa ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); 761220235Skevlo if (ifp == NULL) { 762203138Sthompsa device_printf(sc->sc_dev, "can not if_alloc()\n"); 763203134Sthompsa goto detach; 764203134Sthompsa } 765203134Sthompsa ic = ifp->if_l2com; 766203134Sthompsa 767203134Sthompsa ifp->if_softc = sc; 768203134Sthompsa if_initname(ifp, "run", device_get_unit(sc->sc_dev)); 769203134Sthompsa ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 770203134Sthompsa ifp->if_init = run_init; 771203134Sthompsa ifp->if_ioctl = run_ioctl; 772203134Sthompsa ifp->if_start = run_start; 773207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 774207554Ssobomax ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 775203134Sthompsa IFQ_SET_READY(&ifp->if_snd); 776203134Sthompsa 777203134Sthompsa ic->ic_ifp = ifp; 778203134Sthompsa ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 779203134Sthompsa ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 780208019Sthompsa 781203134Sthompsa /* set device capabilities */ 782203134Sthompsa ic->ic_caps = 783203134Sthompsa IEEE80211_C_STA | /* station mode supported */ 784203134Sthompsa IEEE80211_C_MONITOR | /* monitor mode supported */ 785203134Sthompsa IEEE80211_C_IBSS | 786203134Sthompsa IEEE80211_C_HOSTAP | 787208019Sthompsa IEEE80211_C_WDS | /* 4-address traffic works */ 788208019Sthompsa IEEE80211_C_MBSS | 789203134Sthompsa IEEE80211_C_SHPREAMBLE | /* short preamble supported */ 790203134Sthompsa IEEE80211_C_SHSLOT | /* short slot time supported */ 791203134Sthompsa IEEE80211_C_WME | /* WME */ 792214894Sbschmidt IEEE80211_C_WPA; /* WPA1|WPA2(RSN) */ 793203134Sthompsa 794203134Sthompsa ic->ic_cryptocaps = 795203134Sthompsa IEEE80211_CRYPTO_WEP | 796203134Sthompsa IEEE80211_CRYPTO_AES_CCM | 797203134Sthompsa IEEE80211_CRYPTO_TKIPMIC | 798203134Sthompsa IEEE80211_CRYPTO_TKIP; 799203134Sthompsa 800203134Sthompsa ic->ic_flags |= IEEE80211_F_DATAPAD; 801203134Sthompsa ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; 802203134Sthompsa 803203134Sthompsa bands = 0; 804203134Sthompsa setbit(&bands, IEEE80211_MODE_11B); 805203134Sthompsa setbit(&bands, IEEE80211_MODE_11G); 806258082Skevlo if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850 || 807260219Skevlo sc->rf_rev == RT3070_RF_3052 || sc->rf_rev == RT3593_RF_3053 || 808260219Skevlo sc->rf_rev == RT5592_RF_5592) 809258082Skevlo setbit(&bands, IEEE80211_MODE_11A); 810203134Sthompsa ieee80211_init_channels(ic, NULL, &bands); 811203134Sthompsa 812203134Sthompsa ieee80211_ifattach(ic, sc->sc_bssid); 813203134Sthompsa 814203134Sthompsa ic->ic_scan_start = run_scan_start; 815203134Sthompsa ic->ic_scan_end = run_scan_end; 816203134Sthompsa ic->ic_set_channel = run_set_channel; 817203134Sthompsa ic->ic_node_alloc = run_node_alloc; 818203134Sthompsa ic->ic_newassoc = run_newassoc; 819218492Sbschmidt ic->ic_updateslot = run_updateslot; 820208019Sthompsa ic->ic_update_mcast = run_update_mcast; 821203134Sthompsa ic->ic_wme.wme_update = run_wme_update; 822203134Sthompsa ic->ic_raw_xmit = run_raw_xmit; 823203134Sthompsa ic->ic_update_promisc = run_update_promisc; 824203134Sthompsa 825203134Sthompsa ic->ic_vap_create = run_vap_create; 826203134Sthompsa ic->ic_vap_delete = run_vap_delete; 827203134Sthompsa 828203134Sthompsa ieee80211_radiotap_attach(ic, 829203134Sthompsa &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), 830203134Sthompsa RUN_TX_RADIOTAP_PRESENT, 831203134Sthompsa &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 832203134Sthompsa RUN_RX_RADIOTAP_PRESENT); 833203134Sthompsa 834208019Sthompsa TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc); 835208019Sthompsa TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc); 836257712Shselasky usb_callout_init_mtx(&sc->ratectl_ch, &sc->sc_mtx, 0); 837208019Sthompsa 838203134Sthompsa if (bootverbose) 839203134Sthompsa ieee80211_announce(ic); 840203134Sthompsa 841209917Sthompsa return (0); 842203134Sthompsa 843203134Sthompsadetach: 844203134Sthompsa run_detach(self); 845209917Sthompsa return (ENXIO); 846203134Sthompsa} 847203134Sthompsa 848203134Sthompsastatic int 849203134Sthompsarun_detach(device_t self) 850203134Sthompsa{ 851203134Sthompsa struct run_softc *sc = device_get_softc(self); 852203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 853203134Sthompsa struct ieee80211com *ic; 854203134Sthompsa int i; 855203134Sthompsa 856246614Shselasky RUN_LOCK(sc); 857246614Shselasky sc->sc_detached = 1; 858246614Shselasky RUN_UNLOCK(sc); 859246614Shselasky 860203134Sthompsa /* stop all USB transfers */ 861203134Sthompsa usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER); 862203134Sthompsa 863203134Sthompsa RUN_LOCK(sc); 864209144Sthompsa sc->ratectl_run = RUN_RATECTL_OFF; 865209144Sthompsa sc->cmdq_run = sc->cmdq_key_set = RUN_CMDQ_ABORT; 866209144Sthompsa 867203134Sthompsa /* free TX list, if any */ 868203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 869203134Sthompsa run_unsetup_tx_list(sc, &sc->sc_epq[i]); 870203134Sthompsa RUN_UNLOCK(sc); 871203134Sthompsa 872203134Sthompsa if (ifp) { 873203134Sthompsa ic = ifp->if_l2com; 874208019Sthompsa /* drain tasks */ 875208019Sthompsa usb_callout_drain(&sc->ratectl_ch); 876208019Sthompsa ieee80211_draintask(ic, &sc->cmdq_task); 877208019Sthompsa ieee80211_draintask(ic, &sc->ratectl_task); 878203134Sthompsa ieee80211_ifdetach(ic); 879203134Sthompsa if_free(ifp); 880203134Sthompsa } 881203134Sthompsa 882203134Sthompsa mtx_destroy(&sc->sc_mtx); 883203134Sthompsa 884203134Sthompsa return (0); 885203134Sthompsa} 886203134Sthompsa 887203134Sthompsastatic struct ieee80211vap * 888228621Sbschmidtrun_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, 889228621Sbschmidt enum ieee80211_opmode opmode, int flags, 890203134Sthompsa const uint8_t bssid[IEEE80211_ADDR_LEN], 891203134Sthompsa const uint8_t mac[IEEE80211_ADDR_LEN]) 892203134Sthompsa{ 893208019Sthompsa struct ifnet *ifp = ic->ic_ifp; 894208019Sthompsa struct run_softc *sc = ifp->if_softc; 895203134Sthompsa struct run_vap *rvp; 896203134Sthompsa struct ieee80211vap *vap; 897208019Sthompsa int i; 898203134Sthompsa 899209917Sthompsa if (sc->rvp_cnt >= RUN_VAP_MAX) { 900208019Sthompsa if_printf(ifp, "number of VAPs maxed out\n"); 901209917Sthompsa return (NULL); 902208019Sthompsa } 903208019Sthompsa 904208019Sthompsa switch (opmode) { 905208019Sthompsa case IEEE80211_M_STA: 906208019Sthompsa /* enable s/w bmiss handling for sta mode */ 907208019Sthompsa flags |= IEEE80211_CLONE_NOBEACONS; 908208019Sthompsa /* fall though */ 909208019Sthompsa case IEEE80211_M_IBSS: 910208019Sthompsa case IEEE80211_M_MONITOR: 911208019Sthompsa case IEEE80211_M_HOSTAP: 912208019Sthompsa case IEEE80211_M_MBSS: 913208019Sthompsa /* other than WDS vaps, only one at a time */ 914208019Sthompsa if (!TAILQ_EMPTY(&ic->ic_vaps)) 915209917Sthompsa return (NULL); 916208019Sthompsa break; 917208019Sthompsa case IEEE80211_M_WDS: 918208019Sthompsa TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next){ 919208019Sthompsa if(vap->iv_opmode != IEEE80211_M_HOSTAP) 920208019Sthompsa continue; 921208019Sthompsa /* WDS vap's always share the local mac address. */ 922208019Sthompsa flags &= ~IEEE80211_CLONE_BSSID; 923208019Sthompsa break; 924208019Sthompsa } 925209917Sthompsa if (vap == NULL) { 926208019Sthompsa if_printf(ifp, "wds only supported in ap mode\n"); 927209917Sthompsa return (NULL); 928208019Sthompsa } 929208019Sthompsa break; 930208019Sthompsa default: 931208019Sthompsa if_printf(ifp, "unknown opmode %d\n", opmode); 932209917Sthompsa return (NULL); 933208019Sthompsa } 934208019Sthompsa 935208019Sthompsa rvp = (struct run_vap *) malloc(sizeof(struct run_vap), 936203134Sthompsa M_80211_VAP, M_NOWAIT | M_ZERO); 937203134Sthompsa if (rvp == NULL) 938209917Sthompsa return (NULL); 939203134Sthompsa vap = &rvp->vap; 940203134Sthompsa 941257743Shselasky if (ieee80211_vap_setup(ic, vap, name, unit, 942257743Shselasky opmode, flags, bssid, mac) != 0) { 943257743Shselasky /* out of memory */ 944257743Shselasky free(rvp, M_80211_VAP); 945257743Shselasky return (NULL); 946257743Shselasky } 947257743Shselasky 948203134Sthompsa vap->iv_key_update_begin = run_key_update_begin; 949203134Sthompsa vap->iv_key_update_end = run_key_update_end; 950203134Sthompsa vap->iv_update_beacon = run_update_beacon; 951208019Sthompsa vap->iv_max_aid = RT2870_WCID_MAX; 952208019Sthompsa /* 953208019Sthompsa * To delete the right key from h/w, we need wcid. 954208019Sthompsa * Luckily, there is unused space in ieee80211_key{}, wk_pad, 955208019Sthompsa * and matching wcid will be written into there. So, cast 956208019Sthompsa * some spells to remove 'const' from ieee80211_key{} 957208019Sthompsa */ 958208019Sthompsa vap->iv_key_delete = (void *)run_key_delete; 959208019Sthompsa vap->iv_key_set = (void *)run_key_set; 960203134Sthompsa 961203134Sthompsa /* override state transition machine */ 962203134Sthompsa rvp->newstate = vap->iv_newstate; 963203134Sthompsa vap->iv_newstate = run_newstate; 964203134Sthompsa 965206358Srpaulo ieee80211_ratectl_init(vap); 966206358Srpaulo ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */); 967203134Sthompsa 968203134Sthompsa /* complete setup */ 969203134Sthompsa ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status); 970208019Sthompsa 971208019Sthompsa /* make sure id is always unique */ 972209917Sthompsa for (i = 0; i < RUN_VAP_MAX; i++) { 973208019Sthompsa if((sc->rvp_bmap & 1 << i) == 0){ 974208019Sthompsa sc->rvp_bmap |= 1 << i; 975208019Sthompsa rvp->rvp_id = i; 976208019Sthompsa break; 977208019Sthompsa } 978208019Sthompsa } 979209917Sthompsa if (sc->rvp_cnt++ == 0) 980208019Sthompsa ic->ic_opmode = opmode; 981208019Sthompsa 982209917Sthompsa if (opmode == IEEE80211_M_HOSTAP) 983209144Sthompsa sc->cmdq_run = RUN_CMDQ_GO; 984209144Sthompsa 985208019Sthompsa DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n", 986208019Sthompsa rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt); 987208019Sthompsa 988209917Sthompsa return (vap); 989203134Sthompsa} 990203134Sthompsa 991203134Sthompsastatic void 992203134Sthompsarun_vap_delete(struct ieee80211vap *vap) 993203134Sthompsa{ 994203134Sthompsa struct run_vap *rvp = RUN_VAP(vap); 995203134Sthompsa struct ifnet *ifp; 996203134Sthompsa struct ieee80211com *ic; 997203134Sthompsa struct run_softc *sc; 998208019Sthompsa uint8_t rvp_id; 999203134Sthompsa 1000209917Sthompsa if (vap == NULL) 1001203134Sthompsa return; 1002203134Sthompsa 1003203134Sthompsa ic = vap->iv_ic; 1004203134Sthompsa ifp = ic->ic_ifp; 1005203134Sthompsa 1006203134Sthompsa sc = ifp->if_softc; 1007203134Sthompsa 1008205042Sthompsa RUN_LOCK(sc); 1009208019Sthompsa 1010218492Sbschmidt m_freem(rvp->beacon_mbuf); 1011218492Sbschmidt rvp->beacon_mbuf = NULL; 1012218492Sbschmidt 1013208019Sthompsa rvp_id = rvp->rvp_id; 1014208019Sthompsa sc->ratectl_run &= ~(1 << rvp_id); 1015208019Sthompsa sc->rvp_bmap &= ~(1 << rvp_id); 1016208019Sthompsa run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128); 1017208019Sthompsa run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512); 1018208019Sthompsa --sc->rvp_cnt; 1019208019Sthompsa 1020208019Sthompsa DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n", 1021208019Sthompsa vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt); 1022208019Sthompsa 1023205042Sthompsa RUN_UNLOCK(sc); 1024203134Sthompsa 1025206358Srpaulo ieee80211_ratectl_deinit(vap); 1026203134Sthompsa ieee80211_vap_detach(vap); 1027203134Sthompsa free(rvp, M_80211_VAP); 1028203134Sthompsa} 1029203134Sthompsa 1030208019Sthompsa/* 1031208019Sthompsa * There are numbers of functions need to be called in context thread. 1032208019Sthompsa * Rather than creating taskqueue event for each of those functions, 1033208019Sthompsa * here is all-for-one taskqueue callback function. This function 1034208019Sthompsa * gurantees deferred functions are executed in the same order they 1035208019Sthompsa * were enqueued. 1036208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[]. 1037208019Sthompsa */ 1038203134Sthompsastatic void 1039208019Sthompsarun_cmdq_cb(void *arg, int pending) 1040208019Sthompsa{ 1041208019Sthompsa struct run_softc *sc = arg; 1042208019Sthompsa uint8_t i; 1043208019Sthompsa 1044208019Sthompsa /* call cmdq[].func locked */ 1045208019Sthompsa RUN_LOCK(sc); 1046209917Sthompsa for (i = sc->cmdq_exec; sc->cmdq[i].func && pending; 1047209917Sthompsa i = sc->cmdq_exec, pending--) { 1048208019Sthompsa DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending); 1049209917Sthompsa if (sc->cmdq_run == RUN_CMDQ_GO) { 1050208019Sthompsa /* 1051208019Sthompsa * If arg0 is NULL, callback func needs more 1052208019Sthompsa * than one arg. So, pass ptr to cmdq struct. 1053208019Sthompsa */ 1054209917Sthompsa if (sc->cmdq[i].arg0) 1055208019Sthompsa sc->cmdq[i].func(sc->cmdq[i].arg0); 1056208019Sthompsa else 1057208019Sthompsa sc->cmdq[i].func(&sc->cmdq[i]); 1058208019Sthompsa } 1059208019Sthompsa sc->cmdq[i].arg0 = NULL; 1060208019Sthompsa sc->cmdq[i].func = NULL; 1061208019Sthompsa sc->cmdq_exec++; 1062208019Sthompsa sc->cmdq_exec &= RUN_CMDQ_MASQ; 1063208019Sthompsa } 1064208019Sthompsa RUN_UNLOCK(sc); 1065208019Sthompsa} 1066208019Sthompsa 1067208019Sthompsastatic void 1068203134Sthompsarun_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq) 1069203134Sthompsa{ 1070203134Sthompsa struct run_tx_data *data; 1071203134Sthompsa 1072203134Sthompsa memset(pq, 0, sizeof(*pq)); 1073203134Sthompsa 1074203134Sthompsa STAILQ_INIT(&pq->tx_qh); 1075203134Sthompsa STAILQ_INIT(&pq->tx_fh); 1076203134Sthompsa 1077203134Sthompsa for (data = &pq->tx_data[0]; 1078203134Sthompsa data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) { 1079203134Sthompsa data->sc = sc; 1080203134Sthompsa STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); 1081203134Sthompsa } 1082203134Sthompsa pq->tx_nfree = RUN_TX_RING_COUNT; 1083203134Sthompsa} 1084203134Sthompsa 1085203134Sthompsastatic void 1086203134Sthompsarun_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq) 1087203134Sthompsa{ 1088203134Sthompsa struct run_tx_data *data; 1089203134Sthompsa 1090203134Sthompsa /* make sure any subsequent use of the queues will fail */ 1091203134Sthompsa pq->tx_nfree = 0; 1092203134Sthompsa STAILQ_INIT(&pq->tx_fh); 1093203134Sthompsa STAILQ_INIT(&pq->tx_qh); 1094203134Sthompsa 1095203134Sthompsa /* free up all node references and mbufs */ 1096203134Sthompsa for (data = &pq->tx_data[0]; 1097209917Sthompsa data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) { 1098203134Sthompsa if (data->m != NULL) { 1099203134Sthompsa m_freem(data->m); 1100203134Sthompsa data->m = NULL; 1101203134Sthompsa } 1102203134Sthompsa if (data->ni != NULL) { 1103203134Sthompsa ieee80211_free_node(data->ni); 1104203134Sthompsa data->ni = NULL; 1105203134Sthompsa } 1106203134Sthompsa } 1107203134Sthompsa} 1108203134Sthompsa 1109220235Skevlostatic int 1110203134Sthompsarun_load_microcode(struct run_softc *sc) 1111203134Sthompsa{ 1112203134Sthompsa usb_device_request_t req; 1113203137Sthompsa const struct firmware *fw; 1114203134Sthompsa const u_char *base; 1115203134Sthompsa uint32_t tmp; 1116203134Sthompsa int ntries, error; 1117203134Sthompsa const uint64_t *temp; 1118203134Sthompsa uint64_t bytes; 1119203134Sthompsa 1120205042Sthompsa RUN_UNLOCK(sc); 1121203137Sthompsa fw = firmware_get("runfw"); 1122205042Sthompsa RUN_LOCK(sc); 1123209917Sthompsa if (fw == NULL) { 1124203138Sthompsa device_printf(sc->sc_dev, 1125203138Sthompsa "failed loadfirmware of file %s\n", "runfw"); 1126203134Sthompsa return ENOENT; 1127203134Sthompsa } 1128203134Sthompsa 1129203137Sthompsa if (fw->datasize != 8192) { 1130203138Sthompsa device_printf(sc->sc_dev, 1131203138Sthompsa "invalid firmware size (should be 8KB)\n"); 1132203137Sthompsa error = EINVAL; 1133203137Sthompsa goto fail; 1134203134Sthompsa } 1135203134Sthompsa 1136203134Sthompsa /* 1137203134Sthompsa * RT3071/RT3072 use a different firmware 1138203134Sthompsa * run-rt2870 (8KB) contains both, 1139203134Sthompsa * first half (4KB) is for rt2870, 1140203134Sthompsa * last half is for rt3071. 1141203134Sthompsa */ 1142203137Sthompsa base = fw->data; 1143205042Sthompsa if ((sc->mac_ver) != 0x2860 && 1144205042Sthompsa (sc->mac_ver) != 0x2872 && 1145209917Sthompsa (sc->mac_ver) != 0x3070) { 1146203134Sthompsa base += 4096; 1147205042Sthompsa } 1148203134Sthompsa 1149203134Sthompsa /* cheap sanity check */ 1150203137Sthompsa temp = fw->data; 1151203134Sthompsa bytes = *temp; 1152257712Shselasky if (bytes != be64toh(0xffffff0210280210ULL)) { 1153203138Sthompsa device_printf(sc->sc_dev, "firmware checksum failed\n"); 1154203137Sthompsa error = EINVAL; 1155203137Sthompsa goto fail; 1156203137Sthompsa } 1157203134Sthompsa 1158203134Sthompsa /* write microcode image */ 1159262465Skevlo if (sc->sc_flags & RUN_FLAG_FWLOAD_NEEDED) { 1160260219Skevlo run_write_region_1(sc, RT2870_FW_BASE, base, 4096); 1161260219Skevlo run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff); 1162260219Skevlo run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff); 1163260219Skevlo } 1164203134Sthompsa 1165203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1166203134Sthompsa req.bRequest = RT2870_RESET; 1167203134Sthompsa USETW(req.wValue, 8); 1168203134Sthompsa USETW(req.wIndex, 0); 1169203134Sthompsa USETW(req.wLength, 0); 1170220235Skevlo if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)) 1171220235Skevlo != 0) { 1172203138Sthompsa device_printf(sc->sc_dev, "firmware reset failed\n"); 1173203137Sthompsa goto fail; 1174203137Sthompsa } 1175203134Sthompsa 1176203134Sthompsa run_delay(sc, 10); 1177203134Sthompsa 1178260219Skevlo run_write(sc, RT2860_H2M_BBPAGENT, 0); 1179203134Sthompsa run_write(sc, RT2860_H2M_MAILBOX, 0); 1180260219Skevlo run_write(sc, RT2860_H2M_INTSRC, 0); 1181205042Sthompsa if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0) 1182203137Sthompsa goto fail; 1183203134Sthompsa 1184203134Sthompsa /* wait until microcontroller is ready */ 1185203134Sthompsa for (ntries = 0; ntries < 1000; ntries++) { 1186260219Skevlo if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0) 1187203137Sthompsa goto fail; 1188203134Sthompsa if (tmp & RT2860_MCU_READY) 1189203134Sthompsa break; 1190203134Sthompsa run_delay(sc, 10); 1191203134Sthompsa } 1192203134Sthompsa if (ntries == 1000) { 1193203138Sthompsa device_printf(sc->sc_dev, 1194203138Sthompsa "timeout waiting for MCU to initialize\n"); 1195203137Sthompsa error = ETIMEDOUT; 1196203137Sthompsa goto fail; 1197203134Sthompsa } 1198233283Sbschmidt device_printf(sc->sc_dev, "firmware %s ver. %u.%u loaded\n", 1199233283Sbschmidt (base == fw->data) ? "RT2870" : "RT3071", 1200233283Sbschmidt *(base + 4092), *(base + 4093)); 1201203134Sthompsa 1202203137Sthompsafail: 1203203137Sthompsa firmware_put(fw, FIRMWARE_UNLOAD); 1204203137Sthompsa return (error); 1205203134Sthompsa} 1206203134Sthompsa 1207258641Shselaskystatic int 1208203134Sthompsarun_reset(struct run_softc *sc) 1209203134Sthompsa{ 1210203134Sthompsa usb_device_request_t req; 1211203134Sthompsa 1212203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1213203134Sthompsa req.bRequest = RT2870_RESET; 1214203134Sthompsa USETW(req.wValue, 1); 1215203134Sthompsa USETW(req.wIndex, 0); 1216203134Sthompsa USETW(req.wLength, 0); 1217209917Sthompsa return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)); 1218203134Sthompsa} 1219203134Sthompsa 1220203134Sthompsastatic usb_error_t 1221203134Sthompsarun_do_request(struct run_softc *sc, 1222203134Sthompsa struct usb_device_request *req, void *data) 1223203134Sthompsa{ 1224203134Sthompsa usb_error_t err; 1225203134Sthompsa int ntries = 10; 1226203134Sthompsa 1227203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 1228203134Sthompsa 1229203134Sthompsa while (ntries--) { 1230203134Sthompsa err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, 1231203134Sthompsa req, data, 0, NULL, 250 /* ms */); 1232203134Sthompsa if (err == 0) 1233203134Sthompsa break; 1234203134Sthompsa DPRINTFN(1, "Control request failed, %s (retrying)\n", 1235203134Sthompsa usbd_errstr(err)); 1236203134Sthompsa run_delay(sc, 10); 1237203134Sthompsa } 1238203134Sthompsa return (err); 1239203134Sthompsa} 1240203134Sthompsa 1241203134Sthompsastatic int 1242203134Sthompsarun_read(struct run_softc *sc, uint16_t reg, uint32_t *val) 1243203134Sthompsa{ 1244203134Sthompsa uint32_t tmp; 1245203134Sthompsa int error; 1246203134Sthompsa 1247203134Sthompsa error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp); 1248203134Sthompsa if (error == 0) 1249203134Sthompsa *val = le32toh(tmp); 1250203134Sthompsa else 1251203134Sthompsa *val = 0xffffffff; 1252209917Sthompsa return (error); 1253203134Sthompsa} 1254203134Sthompsa 1255203134Sthompsastatic int 1256203134Sthompsarun_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len) 1257203134Sthompsa{ 1258203134Sthompsa usb_device_request_t req; 1259203134Sthompsa 1260203134Sthompsa req.bmRequestType = UT_READ_VENDOR_DEVICE; 1261203134Sthompsa req.bRequest = RT2870_READ_REGION_1; 1262203134Sthompsa USETW(req.wValue, 0); 1263203134Sthompsa USETW(req.wIndex, reg); 1264203134Sthompsa USETW(req.wLength, len); 1265203134Sthompsa 1266209917Sthompsa return (run_do_request(sc, &req, buf)); 1267203134Sthompsa} 1268203134Sthompsa 1269203134Sthompsastatic int 1270203134Sthompsarun_write_2(struct run_softc *sc, uint16_t reg, uint16_t val) 1271203134Sthompsa{ 1272203134Sthompsa usb_device_request_t req; 1273203134Sthompsa 1274203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1275203134Sthompsa req.bRequest = RT2870_WRITE_2; 1276203134Sthompsa USETW(req.wValue, val); 1277203134Sthompsa USETW(req.wIndex, reg); 1278203134Sthompsa USETW(req.wLength, 0); 1279203134Sthompsa 1280209917Sthompsa return (run_do_request(sc, &req, NULL)); 1281203134Sthompsa} 1282203134Sthompsa 1283203134Sthompsastatic int 1284203134Sthompsarun_write(struct run_softc *sc, uint16_t reg, uint32_t val) 1285203134Sthompsa{ 1286203134Sthompsa int error; 1287203134Sthompsa 1288203134Sthompsa if ((error = run_write_2(sc, reg, val & 0xffff)) == 0) 1289203134Sthompsa error = run_write_2(sc, reg + 2, val >> 16); 1290209917Sthompsa return (error); 1291203134Sthompsa} 1292203134Sthompsa 1293203134Sthompsastatic int 1294203134Sthompsarun_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf, 1295203134Sthompsa int len) 1296203134Sthompsa{ 1297203134Sthompsa#if 1 1298203134Sthompsa int i, error = 0; 1299203134Sthompsa /* 1300203134Sthompsa * NB: the WRITE_REGION_1 command is not stable on RT2860. 1301203134Sthompsa * We thus issue multiple WRITE_2 commands instead. 1302203134Sthompsa */ 1303203134Sthompsa KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n")); 1304203134Sthompsa for (i = 0; i < len && error == 0; i += 2) 1305203134Sthompsa error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8); 1306209917Sthompsa return (error); 1307203134Sthompsa#else 1308203134Sthompsa usb_device_request_t req; 1309257958Skevlo int error = 0; 1310203134Sthompsa 1311257958Skevlo /* 1312257958Skevlo * NOTE: It appears the WRITE_REGION_1 command cannot be 1313257958Skevlo * passed a huge amount of data, which will crash the 1314257958Skevlo * firmware. Limit amount of data passed to 64-bytes at a 1315257958Skevlo * time. 1316257958Skevlo */ 1317257958Skevlo while (len > 0) { 1318257958Skevlo int delta = 64; 1319257958Skevlo if (delta > len) 1320257958Skevlo delta = len; 1321257958Skevlo 1322257958Skevlo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1323257958Skevlo req.bRequest = RT2870_WRITE_REGION_1; 1324257958Skevlo USETW(req.wValue, 0); 1325257958Skevlo USETW(req.wIndex, reg); 1326257958Skevlo USETW(req.wLength, delta); 1327257958Skevlo error = run_do_request(sc, &req, __DECONST(uint8_t *, buf)); 1328257958Skevlo if (error != 0) 1329257958Skevlo break; 1330257958Skevlo reg += delta; 1331257958Skevlo buf += delta; 1332257958Skevlo len -= delta; 1333257958Skevlo } 1334257958Skevlo return (error); 1335203134Sthompsa#endif 1336203134Sthompsa} 1337203134Sthompsa 1338203134Sthompsastatic int 1339203134Sthompsarun_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len) 1340203134Sthompsa{ 1341203134Sthompsa int i, error = 0; 1342203134Sthompsa 1343203134Sthompsa KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n")); 1344203134Sthompsa for (i = 0; i < len && error == 0; i += 4) 1345203134Sthompsa error = run_write(sc, reg + i, val); 1346209917Sthompsa return (error); 1347203134Sthompsa} 1348203134Sthompsa 1349203134Sthompsastatic int 1350259544Skevlorun_efuse_read(struct run_softc *sc, uint16_t addr, uint16_t *val, int count) 1351203134Sthompsa{ 1352203134Sthompsa uint32_t tmp; 1353203134Sthompsa uint16_t reg; 1354203134Sthompsa int error, ntries; 1355203134Sthompsa 1356203134Sthompsa if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0) 1357209917Sthompsa return (error); 1358203134Sthompsa 1359261076Shselasky if (count == 2) 1360261076Shselasky addr *= 2; 1361203134Sthompsa /*- 1362203134Sthompsa * Read one 16-byte block into registers EFUSE_DATA[0-3]: 1363203134Sthompsa * DATA0: F E D C 1364203134Sthompsa * DATA1: B A 9 8 1365203134Sthompsa * DATA2: 7 6 5 4 1366203134Sthompsa * DATA3: 3 2 1 0 1367203134Sthompsa */ 1368203134Sthompsa tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK); 1369203134Sthompsa tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK; 1370203134Sthompsa run_write(sc, RT3070_EFUSE_CTRL, tmp); 1371203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1372203134Sthompsa if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0) 1373209917Sthompsa return (error); 1374203134Sthompsa if (!(tmp & RT3070_EFSROM_KICK)) 1375203134Sthompsa break; 1376203134Sthompsa run_delay(sc, 2); 1377203134Sthompsa } 1378203134Sthompsa if (ntries == 100) 1379209917Sthompsa return (ETIMEDOUT); 1380203134Sthompsa 1381261076Shselasky if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) { 1382261076Shselasky *val = 0xffff; /* address not found */ 1383209917Sthompsa return (0); 1384261076Shselasky } 1385203134Sthompsa /* determine to which 32-bit register our 16-bit word belongs */ 1386203134Sthompsa reg = RT3070_EFUSE_DATA3 - (addr & 0xc); 1387203134Sthompsa if ((error = run_read(sc, reg, &tmp)) != 0) 1388209917Sthompsa return (error); 1389203134Sthompsa 1390261118Skevlo tmp >>= (8 * (addr & 0x3)); 1391261118Skevlo *val = (addr & 1) ? tmp >> 16 : tmp & 0xffff; 1392261118Skevlo 1393209917Sthompsa return (0); 1394203134Sthompsa} 1395203134Sthompsa 1396261124Skevlo/* Read 16-bit from eFUSE ROM for RT3xxx. */ 1397203134Sthompsastatic int 1398259544Skevlorun_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val) 1399259544Skevlo{ 1400259544Skevlo return (run_efuse_read(sc, addr, val, 2)); 1401259544Skevlo} 1402259544Skevlo 1403259544Skevlostatic int 1404203134Sthompsarun_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val) 1405203134Sthompsa{ 1406203134Sthompsa usb_device_request_t req; 1407203134Sthompsa uint16_t tmp; 1408203134Sthompsa int error; 1409203134Sthompsa 1410203134Sthompsa addr *= 2; 1411203134Sthompsa req.bmRequestType = UT_READ_VENDOR_DEVICE; 1412203134Sthompsa req.bRequest = RT2870_EEPROM_READ; 1413203134Sthompsa USETW(req.wValue, 0); 1414203134Sthompsa USETW(req.wIndex, addr); 1415260219Skevlo USETW(req.wLength, sizeof(tmp)); 1416203134Sthompsa 1417203134Sthompsa error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp); 1418203134Sthompsa if (error == 0) 1419203134Sthompsa *val = le16toh(tmp); 1420203134Sthompsa else 1421203134Sthompsa *val = 0xffff; 1422209917Sthompsa return (error); 1423203134Sthompsa} 1424203134Sthompsa 1425203134Sthompsastatic __inline int 1426203134Sthompsarun_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val) 1427203134Sthompsa{ 1428203134Sthompsa /* either eFUSE ROM or EEPROM */ 1429203134Sthompsa return sc->sc_srom_read(sc, addr, val); 1430203134Sthompsa} 1431203134Sthompsa 1432203134Sthompsastatic int 1433258733Skevlorun_rt2870_rf_write(struct run_softc *sc, uint32_t val) 1434203134Sthompsa{ 1435203134Sthompsa uint32_t tmp; 1436203134Sthompsa int error, ntries; 1437203134Sthompsa 1438203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1439203134Sthompsa if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0) 1440209917Sthompsa return (error); 1441203134Sthompsa if (!(tmp & RT2860_RF_REG_CTRL)) 1442203134Sthompsa break; 1443203134Sthompsa } 1444203134Sthompsa if (ntries == 10) 1445209917Sthompsa return (ETIMEDOUT); 1446203134Sthompsa 1447258732Skevlo return (run_write(sc, RT2860_RF_CSR_CFG0, val)); 1448203134Sthompsa} 1449203134Sthompsa 1450203134Sthompsastatic int 1451203134Sthompsarun_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val) 1452203134Sthompsa{ 1453203134Sthompsa uint32_t tmp; 1454203134Sthompsa int error, ntries; 1455203134Sthompsa 1456203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1457203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1458209917Sthompsa return (error); 1459203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1460203134Sthompsa break; 1461203134Sthompsa } 1462203134Sthompsa if (ntries == 100) 1463209917Sthompsa return (ETIMEDOUT); 1464203134Sthompsa 1465203134Sthompsa tmp = RT3070_RF_KICK | reg << 8; 1466203134Sthompsa if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0) 1467209917Sthompsa return (error); 1468203134Sthompsa 1469203134Sthompsa for (ntries = 0; ntries < 100; 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 == 100) 1476209917Sthompsa return (ETIMEDOUT); 1477203134Sthompsa 1478203134Sthompsa *val = tmp & 0xff; 1479209917Sthompsa return (0); 1480203134Sthompsa} 1481203134Sthompsa 1482203134Sthompsastatic int 1483203134Sthompsarun_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val) 1484203134Sthompsa{ 1485203134Sthompsa uint32_t tmp; 1486203134Sthompsa int error, ntries; 1487203134Sthompsa 1488203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1489203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1490209917Sthompsa return (error); 1491203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1492203134Sthompsa break; 1493203134Sthompsa } 1494203134Sthompsa if (ntries == 10) 1495209917Sthompsa return (ETIMEDOUT); 1496203134Sthompsa 1497203134Sthompsa tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val; 1498209917Sthompsa return (run_write(sc, RT3070_RF_CSR_CFG, tmp)); 1499203134Sthompsa} 1500203134Sthompsa 1501203134Sthompsastatic int 1502203134Sthompsarun_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val) 1503203134Sthompsa{ 1504203134Sthompsa uint32_t tmp; 1505203134Sthompsa int ntries, error; 1506203134Sthompsa 1507203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1508203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1509209917Sthompsa return (error); 1510203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1511203134Sthompsa break; 1512203134Sthompsa } 1513203134Sthompsa if (ntries == 10) 1514209917Sthompsa return (ETIMEDOUT); 1515203134Sthompsa 1516203134Sthompsa tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8; 1517203134Sthompsa if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0) 1518209917Sthompsa return (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 *val = tmp & 0xff; 1530209917Sthompsa return (0); 1531203134Sthompsa} 1532203134Sthompsa 1533203134Sthompsastatic int 1534203134Sthompsarun_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val) 1535203134Sthompsa{ 1536203134Sthompsa uint32_t tmp; 1537203134Sthompsa int ntries, error; 1538203134Sthompsa 1539203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1540203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1541209917Sthompsa return (error); 1542203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1543203134Sthompsa break; 1544203134Sthompsa } 1545203134Sthompsa if (ntries == 10) 1546209917Sthompsa return (ETIMEDOUT); 1547203134Sthompsa 1548203134Sthompsa tmp = RT2860_BBP_CSR_KICK | reg << 8 | val; 1549209917Sthompsa return (run_write(sc, RT2860_BBP_CSR_CFG, tmp)); 1550203134Sthompsa} 1551203134Sthompsa 1552203134Sthompsa/* 1553203134Sthompsa * Send a command to the 8051 microcontroller unit. 1554203134Sthompsa */ 1555203134Sthompsastatic int 1556203134Sthompsarun_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg) 1557203134Sthompsa{ 1558203134Sthompsa uint32_t tmp; 1559203134Sthompsa int error, ntries; 1560203134Sthompsa 1561203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1562203134Sthompsa if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0) 1563203134Sthompsa return error; 1564203134Sthompsa if (!(tmp & RT2860_H2M_BUSY)) 1565203134Sthompsa break; 1566203134Sthompsa } 1567203134Sthompsa if (ntries == 100) 1568203134Sthompsa return ETIMEDOUT; 1569203134Sthompsa 1570203134Sthompsa tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg; 1571203134Sthompsa if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0) 1572203134Sthompsa error = run_write(sc, RT2860_HOST_CMD, cmd); 1573209917Sthompsa return (error); 1574203134Sthompsa} 1575203134Sthompsa 1576203134Sthompsa/* 1577203134Sthompsa * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word. 1578203134Sthompsa * Used to adjust per-rate Tx power registers. 1579203134Sthompsa */ 1580203134Sthompsastatic __inline uint32_t 1581203134Sthompsab4inc(uint32_t b32, int8_t delta) 1582203134Sthompsa{ 1583203134Sthompsa int8_t i, b4; 1584203134Sthompsa 1585203134Sthompsa for (i = 0; i < 8; i++) { 1586203134Sthompsa b4 = b32 & 0xf; 1587203134Sthompsa b4 += delta; 1588203134Sthompsa if (b4 < 0) 1589203134Sthompsa b4 = 0; 1590203134Sthompsa else if (b4 > 0xf) 1591203134Sthompsa b4 = 0xf; 1592203134Sthompsa b32 = b32 >> 4 | b4 << 28; 1593203134Sthompsa } 1594209917Sthompsa return (b32); 1595203134Sthompsa} 1596203134Sthompsa 1597203134Sthompsastatic const char * 1598257955Skevlorun_get_rf(uint16_t rev) 1599203134Sthompsa{ 1600203134Sthompsa switch (rev) { 1601203134Sthompsa case RT2860_RF_2820: return "RT2820"; 1602203134Sthompsa case RT2860_RF_2850: return "RT2850"; 1603203134Sthompsa case RT2860_RF_2720: return "RT2720"; 1604203134Sthompsa case RT2860_RF_2750: return "RT2750"; 1605203134Sthompsa case RT3070_RF_3020: return "RT3020"; 1606203134Sthompsa case RT3070_RF_2020: return "RT2020"; 1607203134Sthompsa case RT3070_RF_3021: return "RT3021"; 1608203134Sthompsa case RT3070_RF_3022: return "RT3022"; 1609203134Sthompsa case RT3070_RF_3052: return "RT3052"; 1610260219Skevlo case RT3593_RF_3053: return "RT3053"; 1611259032Skevlo case RT5592_RF_5592: return "RT5592"; 1612257955Skevlo case RT5390_RF_5370: return "RT5370"; 1613257955Skevlo case RT5390_RF_5372: return "RT5372"; 1614203134Sthompsa } 1615209917Sthompsa return ("unknown"); 1616203134Sthompsa} 1617203134Sthompsa 1618260219Skevlostatic void 1619260219Skevlorun_rt3593_get_txpower(struct run_softc *sc) 1620260219Skevlo{ 1621260219Skevlo uint16_t addr, val; 1622260219Skevlo int i; 1623260219Skevlo 1624260219Skevlo /* Read power settings for 2GHz channels. */ 1625260219Skevlo for (i = 0; i < 14; i += 2) { 1626260219Skevlo addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE1 : 1627260219Skevlo RT2860_EEPROM_PWR2GHZ_BASE1; 1628260219Skevlo run_srom_read(sc, addr + i / 2, &val); 1629260219Skevlo sc->txpow1[i + 0] = (int8_t)(val & 0xff); 1630260219Skevlo sc->txpow1[i + 1] = (int8_t)(val >> 8); 1631260219Skevlo 1632260219Skevlo addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE2 : 1633260219Skevlo RT2860_EEPROM_PWR2GHZ_BASE2; 1634260219Skevlo run_srom_read(sc, addr + i / 2, &val); 1635260219Skevlo sc->txpow2[i + 0] = (int8_t)(val & 0xff); 1636260219Skevlo sc->txpow2[i + 1] = (int8_t)(val >> 8); 1637260219Skevlo 1638260219Skevlo if (sc->ntxchains == 3) { 1639260219Skevlo run_srom_read(sc, RT3593_EEPROM_PWR2GHZ_BASE3 + i / 2, 1640260219Skevlo &val); 1641260219Skevlo sc->txpow3[i + 0] = (int8_t)(val & 0xff); 1642260219Skevlo sc->txpow3[i + 1] = (int8_t)(val >> 8); 1643260219Skevlo } 1644260219Skevlo } 1645260219Skevlo /* Fix broken Tx power entries. */ 1646260219Skevlo for (i = 0; i < 14; i++) { 1647260542Skevlo if (sc->txpow1[i] > 31) 1648260219Skevlo sc->txpow1[i] = 5; 1649260542Skevlo if (sc->txpow2[i] > 31) 1650260219Skevlo sc->txpow2[i] = 5; 1651260219Skevlo if (sc->ntxchains == 3) { 1652260542Skevlo if (sc->txpow3[i] > 31) 1653260219Skevlo sc->txpow3[i] = 5; 1654260219Skevlo } 1655260219Skevlo } 1656260219Skevlo /* Read power settings for 5GHz channels. */ 1657260219Skevlo for (i = 0; i < 40; i += 2) { 1658260219Skevlo run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE1 + i / 2, &val); 1659260219Skevlo sc->txpow1[i + 14] = (int8_t)(val & 0xff); 1660260219Skevlo sc->txpow1[i + 15] = (int8_t)(val >> 8); 1661260219Skevlo 1662260219Skevlo run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE2 + i / 2, &val); 1663260219Skevlo sc->txpow2[i + 14] = (int8_t)(val & 0xff); 1664260219Skevlo sc->txpow2[i + 15] = (int8_t)(val >> 8); 1665260219Skevlo 1666260219Skevlo if (sc->ntxchains == 3) { 1667260219Skevlo run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE3 + i / 2, 1668260219Skevlo &val); 1669260219Skevlo sc->txpow3[i + 14] = (int8_t)(val & 0xff); 1670260219Skevlo sc->txpow3[i + 15] = (int8_t)(val >> 8); 1671260219Skevlo } 1672260219Skevlo } 1673260219Skevlo} 1674260219Skevlo 1675260219Skevlostatic void 1676260219Skevlorun_get_txpower(struct run_softc *sc) 1677260219Skevlo{ 1678260219Skevlo uint16_t val; 1679260219Skevlo int i; 1680260219Skevlo 1681260219Skevlo /* Read power settings for 2GHz channels. */ 1682260219Skevlo for (i = 0; i < 14; i += 2) { 1683260219Skevlo run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val); 1684260219Skevlo sc->txpow1[i + 0] = (int8_t)(val & 0xff); 1685260219Skevlo sc->txpow1[i + 1] = (int8_t)(val >> 8); 1686260219Skevlo 1687260219Skevlo if (sc->mac_ver != 0x5390) { 1688260219Skevlo run_srom_read(sc, 1689260219Skevlo RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val); 1690260219Skevlo sc->txpow2[i + 0] = (int8_t)(val & 0xff); 1691260219Skevlo sc->txpow2[i + 1] = (int8_t)(val >> 8); 1692260219Skevlo } 1693260219Skevlo } 1694260219Skevlo /* Fix broken Tx power entries. */ 1695260219Skevlo for (i = 0; i < 14; i++) { 1696260219Skevlo if (sc->mac_ver >= 0x5390) { 1697260219Skevlo if (sc->txpow1[i] < 0 || sc->txpow1[i] > 27) 1698260219Skevlo sc->txpow1[i] = 5; 1699260219Skevlo } else { 1700260219Skevlo if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31) 1701260219Skevlo sc->txpow1[i] = 5; 1702260219Skevlo } 1703260219Skevlo if (sc->mac_ver > 0x5390) { 1704260219Skevlo if (sc->txpow2[i] < 0 || sc->txpow2[i] > 27) 1705260219Skevlo sc->txpow2[i] = 5; 1706260219Skevlo } else if (sc->mac_ver < 0x5390) { 1707260219Skevlo if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31) 1708260219Skevlo sc->txpow2[i] = 5; 1709260219Skevlo } 1710260219Skevlo DPRINTF("chan %d: power1=%d, power2=%d\n", 1711260219Skevlo rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]); 1712260219Skevlo } 1713260219Skevlo /* Read power settings for 5GHz channels. */ 1714260219Skevlo for (i = 0; i < 40; i += 2) { 1715260219Skevlo run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val); 1716260219Skevlo sc->txpow1[i + 14] = (int8_t)(val & 0xff); 1717260219Skevlo sc->txpow1[i + 15] = (int8_t)(val >> 8); 1718260219Skevlo 1719260219Skevlo run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val); 1720260219Skevlo sc->txpow2[i + 14] = (int8_t)(val & 0xff); 1721260219Skevlo sc->txpow2[i + 15] = (int8_t)(val >> 8); 1722260219Skevlo } 1723260219Skevlo /* Fix broken Tx power entries. */ 1724260219Skevlo for (i = 0; i < 40; i++ ) { 1725260219Skevlo if (sc->mac_ver != 0x5592) { 1726260219Skevlo if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15) 1727260219Skevlo sc->txpow1[14 + i] = 5; 1728260219Skevlo if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15) 1729260219Skevlo sc->txpow2[14 + i] = 5; 1730260219Skevlo } 1731260219Skevlo DPRINTF("chan %d: power1=%d, power2=%d\n", 1732260219Skevlo rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i], 1733260219Skevlo sc->txpow2[14 + i]); 1734260219Skevlo } 1735260219Skevlo} 1736260219Skevlo 1737258641Shselaskystatic int 1738203134Sthompsarun_read_eeprom(struct run_softc *sc) 1739203134Sthompsa{ 1740203134Sthompsa int8_t delta_2ghz, delta_5ghz; 1741203134Sthompsa uint32_t tmp; 1742203134Sthompsa uint16_t val; 1743203134Sthompsa int ridx, ant, i; 1744203134Sthompsa 1745203134Sthompsa /* check whether the ROM is eFUSE ROM or EEPROM */ 1746203134Sthompsa sc->sc_srom_read = run_eeprom_read_2; 1747205042Sthompsa if (sc->mac_ver >= 0x3070) { 1748203134Sthompsa run_read(sc, RT3070_EFUSE_CTRL, &tmp); 1749203134Sthompsa DPRINTF("EFUSE_CTRL=0x%08x\n", tmp); 1750261118Skevlo if ((tmp & RT3070_SEL_EFUSE) || sc->mac_ver == 0x3593) 1751203134Sthompsa sc->sc_srom_read = run_efuse_read_2; 1752203134Sthompsa } 1753203134Sthompsa 1754203134Sthompsa /* read ROM version */ 1755203134Sthompsa run_srom_read(sc, RT2860_EEPROM_VERSION, &val); 1756203134Sthompsa DPRINTF("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8); 1757203134Sthompsa 1758203134Sthompsa /* read MAC address */ 1759203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC01, &val); 1760203134Sthompsa sc->sc_bssid[0] = val & 0xff; 1761203134Sthompsa sc->sc_bssid[1] = val >> 8; 1762203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC23, &val); 1763203134Sthompsa sc->sc_bssid[2] = val & 0xff; 1764203134Sthompsa sc->sc_bssid[3] = val >> 8; 1765203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC45, &val); 1766203134Sthompsa sc->sc_bssid[4] = val & 0xff; 1767203134Sthompsa sc->sc_bssid[5] = val >> 8; 1768203134Sthompsa 1769260219Skevlo if (sc->mac_ver < 0x3593) { 1770257955Skevlo /* read vender BBP settings */ 1771205042Sthompsa for (i = 0; i < 10; i++) { 1772257955Skevlo run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val); 1773257955Skevlo sc->bbp[i].val = val & 0xff; 1774257955Skevlo sc->bbp[i].reg = val >> 8; 1775257955Skevlo DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg, 1776257955Skevlo sc->bbp[i].val); 1777205042Sthompsa } 1778257955Skevlo if (sc->mac_ver >= 0x3071) { 1779257955Skevlo /* read vendor RF settings */ 1780257955Skevlo for (i = 0; i < 10; i++) { 1781257955Skevlo run_srom_read(sc, RT3071_EEPROM_RF_BASE + i, 1782257955Skevlo &val); 1783257955Skevlo sc->rf[i].val = val & 0xff; 1784257955Skevlo sc->rf[i].reg = val >> 8; 1785257955Skevlo DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg, 1786257955Skevlo sc->rf[i].val); 1787257955Skevlo } 1788257955Skevlo } 1789205042Sthompsa } 1790203134Sthompsa 1791203134Sthompsa /* read RF frequency offset from EEPROM */ 1792260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS : 1793260219Skevlo RT3593_EEPROM_FREQ, &val); 1794203134Sthompsa sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0; 1795203134Sthompsa DPRINTF("EEPROM freq offset %d\n", sc->freq & 0xff); 1796203134Sthompsa 1797260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS : 1798260219Skevlo RT3593_EEPROM_FREQ_LEDS, &val); 1799205042Sthompsa if (val >> 8 != 0xff) { 1800203134Sthompsa /* read LEDs operating mode */ 1801205042Sthompsa sc->leds = val >> 8; 1802260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED1 : 1803260219Skevlo RT3593_EEPROM_LED1, &sc->led[0]); 1804260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED2 : 1805260219Skevlo RT3593_EEPROM_LED2, &sc->led[1]); 1806260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED3 : 1807260219Skevlo RT3593_EEPROM_LED3, &sc->led[2]); 1808203134Sthompsa } else { 1809203134Sthompsa /* broken EEPROM, use default settings */ 1810203134Sthompsa sc->leds = 0x01; 1811203134Sthompsa sc->led[0] = 0x5555; 1812203134Sthompsa sc->led[1] = 0x2221; 1813203134Sthompsa sc->led[2] = 0x5627; /* differs from RT2860 */ 1814203134Sthompsa } 1815203134Sthompsa DPRINTF("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n", 1816203134Sthompsa sc->leds, sc->led[0], sc->led[1], sc->led[2]); 1817203134Sthompsa 1818203134Sthompsa /* read RF information */ 1819259032Skevlo if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) 1820257955Skevlo run_srom_read(sc, 0x00, &val); 1821257955Skevlo else 1822257955Skevlo run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val); 1823257955Skevlo 1824203134Sthompsa if (val == 0xffff) { 1825260219Skevlo device_printf(sc->sc_dev, 1826260219Skevlo "invalid EEPROM antenna info, using default\n"); 1827203134Sthompsa DPRINTF("invalid EEPROM antenna info, using default\n"); 1828205042Sthompsa if (sc->mac_ver == 0x3572) { 1829205042Sthompsa /* default to RF3052 2T2R */ 1830205042Sthompsa sc->rf_rev = RT3070_RF_3052; 1831205042Sthompsa sc->ntxchains = 2; 1832205042Sthompsa sc->nrxchains = 2; 1833205042Sthompsa } else if (sc->mac_ver >= 0x3070) { 1834203134Sthompsa /* default to RF3020 1T1R */ 1835203134Sthompsa sc->rf_rev = RT3070_RF_3020; 1836203134Sthompsa sc->ntxchains = 1; 1837203134Sthompsa sc->nrxchains = 1; 1838203134Sthompsa } else { 1839203134Sthompsa /* default to RF2820 1T2R */ 1840203134Sthompsa sc->rf_rev = RT2860_RF_2820; 1841203134Sthompsa sc->ntxchains = 1; 1842203134Sthompsa sc->nrxchains = 2; 1843203134Sthompsa } 1844203134Sthompsa } else { 1845259032Skevlo if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) { 1846257955Skevlo sc->rf_rev = val; 1847257955Skevlo run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val); 1848257955Skevlo } else 1849257955Skevlo sc->rf_rev = (val >> 8) & 0xf; 1850203134Sthompsa sc->ntxchains = (val >> 4) & 0xf; 1851203134Sthompsa sc->nrxchains = val & 0xf; 1852203134Sthompsa } 1853257955Skevlo DPRINTF("EEPROM RF rev=0x%04x chains=%dT%dR\n", 1854203134Sthompsa sc->rf_rev, sc->ntxchains, sc->nrxchains); 1855203134Sthompsa 1856208019Sthompsa /* check if RF supports automatic Tx access gain control */ 1857203134Sthompsa run_srom_read(sc, RT2860_EEPROM_CONFIG, &val); 1858203134Sthompsa DPRINTF("EEPROM CFG 0x%04x\n", val); 1859205042Sthompsa /* check if driver should patch the DAC issue */ 1860205042Sthompsa if ((val >> 8) != 0xff) 1861205042Sthompsa sc->patch_dac = (val >> 15) & 1; 1862203134Sthompsa if ((val & 0xff) != 0xff) { 1863203134Sthompsa sc->ext_5ghz_lna = (val >> 3) & 1; 1864203134Sthompsa sc->ext_2ghz_lna = (val >> 2) & 1; 1865205042Sthompsa /* check if RF supports automatic Tx access gain control */ 1866203134Sthompsa sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1; 1867205042Sthompsa /* check if we have a hardware radio switch */ 1868205042Sthompsa sc->rfswitch = val & 1; 1869203134Sthompsa } 1870203134Sthompsa 1871260219Skevlo /* Read Tx power settings. */ 1872260219Skevlo if (sc->mac_ver == 0x3593) 1873260219Skevlo run_rt3593_get_txpower(sc); 1874260219Skevlo else 1875260219Skevlo run_get_txpower(sc); 1876203134Sthompsa 1877203134Sthompsa /* read Tx power compensation for each Tx rate */ 1878203134Sthompsa run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val); 1879203134Sthompsa delta_2ghz = delta_5ghz = 0; 1880203134Sthompsa if ((val & 0xff) != 0xff && (val & 0x80)) { 1881203134Sthompsa delta_2ghz = val & 0xf; 1882203134Sthompsa if (!(val & 0x40)) /* negative number */ 1883203134Sthompsa delta_2ghz = -delta_2ghz; 1884203134Sthompsa } 1885203134Sthompsa val >>= 8; 1886203134Sthompsa if ((val & 0xff) != 0xff && (val & 0x80)) { 1887203134Sthompsa delta_5ghz = val & 0xf; 1888203134Sthompsa if (!(val & 0x40)) /* negative number */ 1889203134Sthompsa delta_5ghz = -delta_5ghz; 1890203134Sthompsa } 1891203134Sthompsa DPRINTF("power compensation=%d (2GHz), %d (5GHz)\n", 1892203134Sthompsa delta_2ghz, delta_5ghz); 1893203134Sthompsa 1894203134Sthompsa for (ridx = 0; ridx < 5; ridx++) { 1895203134Sthompsa uint32_t reg; 1896203134Sthompsa 1897208019Sthompsa run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val); 1898208019Sthompsa reg = val; 1899208019Sthompsa run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val); 1900208019Sthompsa reg |= (uint32_t)val << 16; 1901203134Sthompsa 1902203134Sthompsa sc->txpow20mhz[ridx] = reg; 1903203134Sthompsa sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz); 1904203134Sthompsa sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz); 1905203134Sthompsa 1906203134Sthompsa DPRINTF("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, " 1907203134Sthompsa "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx], 1908203134Sthompsa sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]); 1909203134Sthompsa } 1910203134Sthompsa 1911260219Skevlo /* Read RSSI offsets and LNA gains from EEPROM. */ 1912260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_2GHZ : 1913260219Skevlo RT3593_EEPROM_RSSI1_2GHZ, &val); 1914203134Sthompsa sc->rssi_2ghz[0] = val & 0xff; /* Ant A */ 1915203134Sthompsa sc->rssi_2ghz[1] = val >> 8; /* Ant B */ 1916260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_2GHZ : 1917260219Skevlo RT3593_EEPROM_RSSI2_2GHZ, &val); 1918205042Sthompsa if (sc->mac_ver >= 0x3070) { 1919260219Skevlo if (sc->mac_ver == 0x3593) { 1920260219Skevlo sc->txmixgain_2ghz = 0; 1921260219Skevlo sc->rssi_2ghz[2] = val & 0xff; /* Ant C */ 1922260219Skevlo } else { 1923260219Skevlo /* 1924260219Skevlo * On RT3070 chips (limited to 2 Rx chains), this ROM 1925260219Skevlo * field contains the Tx mixer gain for the 2GHz band. 1926260219Skevlo */ 1927260219Skevlo if ((val & 0xff) != 0xff) 1928260219Skevlo sc->txmixgain_2ghz = val & 0x7; 1929260219Skevlo } 1930205042Sthompsa DPRINTF("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz); 1931205042Sthompsa } else 1932205042Sthompsa sc->rssi_2ghz[2] = val & 0xff; /* Ant C */ 1933260219Skevlo if (sc->mac_ver == 0x3593) 1934260219Skevlo run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val); 1935203134Sthompsa sc->lna[2] = val >> 8; /* channel group 2 */ 1936203134Sthompsa 1937260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_5GHZ : 1938260219Skevlo RT3593_EEPROM_RSSI1_5GHZ, &val); 1939203134Sthompsa sc->rssi_5ghz[0] = val & 0xff; /* Ant A */ 1940203134Sthompsa sc->rssi_5ghz[1] = val >> 8; /* Ant B */ 1941260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_5GHZ : 1942260219Skevlo RT3593_EEPROM_RSSI2_5GHZ, &val); 1943205042Sthompsa if (sc->mac_ver == 0x3572) { 1944205042Sthompsa /* 1945205042Sthompsa * On RT3572 chips (limited to 2 Rx chains), this ROM 1946205042Sthompsa * field contains the Tx mixer gain for the 5GHz band. 1947205042Sthompsa */ 1948205042Sthompsa if ((val & 0xff) != 0xff) 1949205042Sthompsa sc->txmixgain_5ghz = val & 0x7; 1950205042Sthompsa DPRINTF("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz); 1951205042Sthompsa } else 1952205042Sthompsa sc->rssi_5ghz[2] = val & 0xff; /* Ant C */ 1953260219Skevlo if (sc->mac_ver == 0x3593) { 1954260219Skevlo sc->txmixgain_5ghz = 0; 1955260219Skevlo run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val); 1956260219Skevlo } 1957203134Sthompsa sc->lna[3] = val >> 8; /* channel group 3 */ 1958203134Sthompsa 1959260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LNA : 1960260219Skevlo RT3593_EEPROM_LNA, &val); 1961203134Sthompsa sc->lna[0] = val & 0xff; /* channel group 0 */ 1962203134Sthompsa sc->lna[1] = val >> 8; /* channel group 1 */ 1963203134Sthompsa 1964203134Sthompsa /* fix broken 5GHz LNA entries */ 1965203134Sthompsa if (sc->lna[2] == 0 || sc->lna[2] == 0xff) { 1966203134Sthompsa DPRINTF("invalid LNA for channel group %d\n", 2); 1967203134Sthompsa sc->lna[2] = sc->lna[1]; 1968203134Sthompsa } 1969203134Sthompsa if (sc->lna[3] == 0 || sc->lna[3] == 0xff) { 1970203134Sthompsa DPRINTF("invalid LNA for channel group %d\n", 3); 1971203134Sthompsa sc->lna[3] = sc->lna[1]; 1972203134Sthompsa } 1973203134Sthompsa 1974203134Sthompsa /* fix broken RSSI offset entries */ 1975203134Sthompsa for (ant = 0; ant < 3; ant++) { 1976203134Sthompsa if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) { 1977203134Sthompsa DPRINTF("invalid RSSI%d offset: %d (2GHz)\n", 1978203134Sthompsa ant + 1, sc->rssi_2ghz[ant]); 1979203134Sthompsa sc->rssi_2ghz[ant] = 0; 1980203134Sthompsa } 1981203134Sthompsa if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) { 1982203134Sthompsa DPRINTF("invalid RSSI%d offset: %d (5GHz)\n", 1983203134Sthompsa ant + 1, sc->rssi_5ghz[ant]); 1984203134Sthompsa sc->rssi_5ghz[ant] = 0; 1985203134Sthompsa } 1986203134Sthompsa } 1987209917Sthompsa return (0); 1988203134Sthompsa} 1989203134Sthompsa 1990218676Shselaskystatic struct ieee80211_node * 1991203134Sthompsarun_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) 1992203134Sthompsa{ 1993203134Sthompsa return malloc(sizeof (struct run_node), M_DEVBUF, M_NOWAIT | M_ZERO); 1994203134Sthompsa} 1995203134Sthompsa 1996203134Sthompsastatic int 1997203134Sthompsarun_media_change(struct ifnet *ifp) 1998203134Sthompsa{ 1999208019Sthompsa struct ieee80211vap *vap = ifp->if_softc; 2000208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 2001203134Sthompsa const struct ieee80211_txparam *tp; 2002208019Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2003203134Sthompsa uint8_t rate, ridx; 2004203134Sthompsa int error; 2005203134Sthompsa 2006203134Sthompsa RUN_LOCK(sc); 2007203134Sthompsa 2008203134Sthompsa error = ieee80211_media_change(ifp); 2009209917Sthompsa if (error != ENETRESET) { 2010203134Sthompsa RUN_UNLOCK(sc); 2011209917Sthompsa return (error); 2012208019Sthompsa } 2013203134Sthompsa 2014203134Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 2015203134Sthompsa if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 2016212127Sthompsa struct ieee80211_node *ni; 2017212127Sthompsa struct run_node *rn; 2018212127Sthompsa 2019203134Sthompsa rate = ic->ic_sup_rates[ic->ic_curmode]. 2020203134Sthompsa rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL; 2021203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2022203134Sthompsa if (rt2860_rates[ridx].rate == rate) 2023203134Sthompsa break; 2024212127Sthompsa ni = ieee80211_ref_node(vap->iv_bss); 2025212127Sthompsa rn = (struct run_node *)ni; 2026208019Sthompsa rn->fix_ridx = ridx; 2027208019Sthompsa DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx); 2028212127Sthompsa ieee80211_free_node(ni); 2029203134Sthompsa } 2030203134Sthompsa 2031208019Sthompsa#if 0 2032203134Sthompsa if ((ifp->if_flags & IFF_UP) && 2033203134Sthompsa (ifp->if_drv_flags & IFF_DRV_RUNNING)){ 2034203134Sthompsa run_init_locked(sc); 2035203134Sthompsa } 2036208019Sthompsa#endif 2037203134Sthompsa 2038203134Sthompsa RUN_UNLOCK(sc); 2039203134Sthompsa 2040209917Sthompsa return (0); 2041203134Sthompsa} 2042203134Sthompsa 2043203134Sthompsastatic int 2044203134Sthompsarun_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 2045203134Sthompsa{ 2046203134Sthompsa const struct ieee80211_txparam *tp; 2047203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2048203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2049203134Sthompsa struct run_vap *rvp = RUN_VAP(vap); 2050203134Sthompsa enum ieee80211_state ostate; 2051208019Sthompsa uint32_t sta[3]; 2052203134Sthompsa uint32_t tmp; 2053208019Sthompsa uint8_t ratectl; 2054208019Sthompsa uint8_t restart_ratectl = 0; 2055208019Sthompsa uint8_t bid = 1 << rvp->rvp_id; 2056203134Sthompsa 2057203134Sthompsa ostate = vap->iv_state; 2058203134Sthompsa DPRINTF("%s -> %s\n", 2059203134Sthompsa ieee80211_state_name[ostate], 2060203134Sthompsa ieee80211_state_name[nstate]); 2061203134Sthompsa 2062203134Sthompsa IEEE80211_UNLOCK(ic); 2063203134Sthompsa RUN_LOCK(sc); 2064203134Sthompsa 2065208019Sthompsa ratectl = sc->ratectl_run; /* remember current state */ 2066208019Sthompsa sc->ratectl_run = RUN_RATECTL_OFF; 2067208019Sthompsa usb_callout_stop(&sc->ratectl_ch); 2068203134Sthompsa 2069203134Sthompsa if (ostate == IEEE80211_S_RUN) { 2070203134Sthompsa /* turn link LED off */ 2071203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO); 2072203134Sthompsa } 2073203134Sthompsa 2074203134Sthompsa switch (nstate) { 2075203134Sthompsa case IEEE80211_S_INIT: 2076208019Sthompsa restart_ratectl = 1; 2077208019Sthompsa 2078208019Sthompsa if (ostate != IEEE80211_S_RUN) 2079208019Sthompsa break; 2080208019Sthompsa 2081208019Sthompsa ratectl &= ~bid; 2082208019Sthompsa sc->runbmap &= ~bid; 2083208019Sthompsa 2084208019Sthompsa /* abort TSF synchronization if there is no vap running */ 2085209917Sthompsa if (--sc->running == 0) { 2086203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 2087203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, 2088203134Sthompsa tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 2089203134Sthompsa RT2860_TBTT_TIMER_EN)); 2090203134Sthompsa } 2091203134Sthompsa break; 2092203134Sthompsa 2093203134Sthompsa case IEEE80211_S_RUN: 2094209917Sthompsa if (!(sc->runbmap & bid)) { 2095208019Sthompsa if(sc->running++) 2096208019Sthompsa restart_ratectl = 1; 2097208019Sthompsa sc->runbmap |= bid; 2098208019Sthompsa } 2099203134Sthompsa 2100218492Sbschmidt m_freem(rvp->beacon_mbuf); 2101218492Sbschmidt rvp->beacon_mbuf = NULL; 2102218492Sbschmidt 2103209917Sthompsa switch (vap->iv_opmode) { 2104208019Sthompsa case IEEE80211_M_HOSTAP: 2105208019Sthompsa case IEEE80211_M_MBSS: 2106208019Sthompsa sc->ap_running |= bid; 2107208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2108208019Sthompsa run_update_beacon_cb(vap); 2109208019Sthompsa break; 2110208019Sthompsa case IEEE80211_M_IBSS: 2111208019Sthompsa sc->adhoc_running |= bid; 2112209917Sthompsa if (!sc->ap_running) 2113208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2114208019Sthompsa run_update_beacon_cb(vap); 2115208019Sthompsa break; 2116208019Sthompsa case IEEE80211_M_STA: 2117208019Sthompsa sc->sta_running |= bid; 2118209917Sthompsa if (!sc->ap_running && !sc->adhoc_running) 2119208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2120208019Sthompsa 2121208019Sthompsa /* read statistic counters (clear on read) */ 2122208019Sthompsa run_read_region_1(sc, RT2860_TX_STA_CNT0, 2123208019Sthompsa (uint8_t *)sta, sizeof sta); 2124208019Sthompsa 2125208019Sthompsa break; 2126208019Sthompsa default: 2127208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2128208019Sthompsa break; 2129208019Sthompsa } 2130208019Sthompsa 2131203134Sthompsa if (vap->iv_opmode != IEEE80211_M_MONITOR) { 2132212127Sthompsa struct ieee80211_node *ni; 2133212127Sthompsa 2134236439Shselasky if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) { 2135236439Shselasky RUN_UNLOCK(sc); 2136236439Shselasky IEEE80211_LOCK(ic); 2137236439Shselasky return (-1); 2138236439Shselasky } 2139203134Sthompsa run_updateslot(ic->ic_ifp); 2140203134Sthompsa run_enable_mrr(sc); 2141203134Sthompsa run_set_txpreamble(sc); 2142203134Sthompsa run_set_basicrates(sc); 2143212127Sthompsa ni = ieee80211_ref_node(vap->iv_bss); 2144203134Sthompsa IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); 2145203134Sthompsa run_set_bssid(sc, ni->ni_bssid); 2146212127Sthompsa ieee80211_free_node(ni); 2147208019Sthompsa run_enable_tsf_sync(sc); 2148203134Sthompsa 2149208019Sthompsa /* enable automatic rate adaptation */ 2150208019Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 2151208019Sthompsa if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) 2152208019Sthompsa ratectl |= bid; 2153203134Sthompsa } 2154203134Sthompsa 2155203134Sthompsa /* turn link LED on */ 2156203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO | 2157208019Sthompsa (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 2158203134Sthompsa RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ)); 2159203134Sthompsa 2160203134Sthompsa break; 2161203134Sthompsa default: 2162203134Sthompsa DPRINTFN(6, "undefined case\n"); 2163203134Sthompsa break; 2164203134Sthompsa } 2165203134Sthompsa 2166208019Sthompsa /* restart amrr for running VAPs */ 2167209917Sthompsa if ((sc->ratectl_run = ratectl) && restart_ratectl) 2168208019Sthompsa usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2169208019Sthompsa 2170203134Sthompsa RUN_UNLOCK(sc); 2171203134Sthompsa IEEE80211_LOCK(ic); 2172203134Sthompsa 2173203134Sthompsa return(rvp->newstate(vap, nstate, arg)); 2174203134Sthompsa} 2175203134Sthompsa 2176203134Sthompsa/* ARGSUSED */ 2177203134Sthompsastatic void 2178208019Sthompsarun_wme_update_cb(void *arg) 2179203134Sthompsa{ 2180203134Sthompsa struct ieee80211com *ic = arg; 2181203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2182203134Sthompsa struct ieee80211_wme_state *wmesp = &ic->ic_wme; 2183203134Sthompsa int aci, error = 0; 2184203134Sthompsa 2185208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2186203134Sthompsa 2187203134Sthompsa /* update MAC TX configuration registers */ 2188203134Sthompsa for (aci = 0; aci < WME_NUM_AC; aci++) { 2189203134Sthompsa error = run_write(sc, RT2860_EDCA_AC_CFG(aci), 2190203134Sthompsa wmesp->wme_params[aci].wmep_logcwmax << 16 | 2191203134Sthompsa wmesp->wme_params[aci].wmep_logcwmin << 12 | 2192203134Sthompsa wmesp->wme_params[aci].wmep_aifsn << 8 | 2193203134Sthompsa wmesp->wme_params[aci].wmep_txopLimit); 2194209917Sthompsa if (error) goto err; 2195203134Sthompsa } 2196203134Sthompsa 2197203134Sthompsa /* update SCH/DMA registers too */ 2198203134Sthompsa error = run_write(sc, RT2860_WMM_AIFSN_CFG, 2199203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_aifsn << 12 | 2200203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_aifsn << 8 | 2201203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_aifsn << 4 | 2202203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_aifsn); 2203209917Sthompsa if (error) goto err; 2204203134Sthompsa error = run_write(sc, RT2860_WMM_CWMIN_CFG, 2205203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_logcwmin << 12 | 2206203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_logcwmin << 8 | 2207203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_logcwmin << 4 | 2208203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_logcwmin); 2209209917Sthompsa if (error) goto err; 2210203134Sthompsa error = run_write(sc, RT2860_WMM_CWMAX_CFG, 2211203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_logcwmax << 12 | 2212203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_logcwmax << 8 | 2213203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_logcwmax << 4 | 2214203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_logcwmax); 2215209917Sthompsa if (error) goto err; 2216203134Sthompsa error = run_write(sc, RT2860_WMM_TXOP0_CFG, 2217203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_txopLimit << 16 | 2218203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_txopLimit); 2219209917Sthompsa if (error) goto err; 2220203134Sthompsa error = run_write(sc, RT2860_WMM_TXOP1_CFG, 2221203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_txopLimit << 16 | 2222203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_txopLimit); 2223203134Sthompsa 2224203134Sthompsaerr: 2225209917Sthompsa if (error) 2226203134Sthompsa DPRINTF("WME update failed\n"); 2227203134Sthompsa 2228203134Sthompsa return; 2229203134Sthompsa} 2230203134Sthompsa 2231208019Sthompsastatic int 2232208019Sthompsarun_wme_update(struct ieee80211com *ic) 2233208019Sthompsa{ 2234208019Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2235208019Sthompsa 2236208019Sthompsa /* sometime called wothout lock */ 2237209917Sthompsa if (mtx_owned(&ic->ic_comlock.mtx)) { 2238208019Sthompsa uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 2239208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 2240208019Sthompsa sc->cmdq[i].func = run_wme_update_cb; 2241208019Sthompsa sc->cmdq[i].arg0 = ic; 2242208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2243209918Sthompsa return (0); 2244208019Sthompsa } 2245208019Sthompsa 2246208019Sthompsa RUN_LOCK(sc); 2247208019Sthompsa run_wme_update_cb(ic); 2248208019Sthompsa RUN_UNLOCK(sc); 2249208019Sthompsa 2250208019Sthompsa /* return whatever, upper layer desn't care anyway */ 2251208019Sthompsa return (0); 2252208019Sthompsa} 2253208019Sthompsa 2254203134Sthompsastatic void 2255203134Sthompsarun_key_update_begin(struct ieee80211vap *vap) 2256203134Sthompsa{ 2257203134Sthompsa /* 2258208019Sthompsa * To avoid out-of-order events, both run_key_set() and 2259208019Sthompsa * _delete() are deferred and handled by run_cmdq_cb(). 2260208019Sthompsa * So, there is nothing we need to do here. 2261203134Sthompsa */ 2262203134Sthompsa} 2263203134Sthompsa 2264203134Sthompsastatic void 2265203134Sthompsarun_key_update_end(struct ieee80211vap *vap) 2266203134Sthompsa{ 2267203134Sthompsa /* null */ 2268203134Sthompsa} 2269203134Sthompsa 2270208019Sthompsastatic void 2271208019Sthompsarun_key_set_cb(void *arg) 2272203134Sthompsa{ 2273208019Sthompsa struct run_cmdq *cmdq = arg; 2274208019Sthompsa struct ieee80211vap *vap = cmdq->arg1; 2275208019Sthompsa struct ieee80211_key *k = cmdq->k; 2276203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2277208019Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2278203134Sthompsa struct ieee80211_node *ni; 2279203134Sthompsa uint32_t attr; 2280203134Sthompsa uint16_t base, associd; 2281209144Sthompsa uint8_t mode, wcid, iv[8]; 2282203134Sthompsa 2283208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2284203134Sthompsa 2285209917Sthompsa if (vap->iv_opmode == IEEE80211_M_HOSTAP) 2286208019Sthompsa ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac); 2287209144Sthompsa else 2288203134Sthompsa ni = vap->iv_bss; 2289208019Sthompsa associd = (ni != NULL) ? ni->ni_associd : 0; 2290203134Sthompsa 2291203134Sthompsa /* map net80211 cipher to RT2860 security mode */ 2292203134Sthompsa switch (k->wk_cipher->ic_cipher) { 2293203134Sthompsa case IEEE80211_CIPHER_WEP: 2294203134Sthompsa if(k->wk_keylen < 8) 2295203134Sthompsa mode = RT2860_MODE_WEP40; 2296203134Sthompsa else 2297203134Sthompsa mode = RT2860_MODE_WEP104; 2298203134Sthompsa break; 2299203134Sthompsa case IEEE80211_CIPHER_TKIP: 2300203134Sthompsa mode = RT2860_MODE_TKIP; 2301203134Sthompsa break; 2302203134Sthompsa case IEEE80211_CIPHER_AES_CCM: 2303203134Sthompsa mode = RT2860_MODE_AES_CCMP; 2304203134Sthompsa break; 2305203134Sthompsa default: 2306203134Sthompsa DPRINTF("undefined case\n"); 2307208019Sthompsa return; 2308203134Sthompsa } 2309203134Sthompsa 2310208019Sthompsa DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n", 2311203134Sthompsa associd, k->wk_keyix, mode, 2312208019Sthompsa (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise", 2313208019Sthompsa (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off", 2314208019Sthompsa (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off"); 2315203134Sthompsa 2316203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 2317203134Sthompsa wcid = 0; /* NB: update WCID0 for group keys */ 2318208019Sthompsa base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix); 2319203134Sthompsa } else { 2320245047Shselasky wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 2321245047Shselasky 1 : RUN_AID2WCID(associd); 2322203134Sthompsa base = RT2860_PKEY(wcid); 2323203134Sthompsa } 2324203134Sthompsa 2325203134Sthompsa if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) { 2326203134Sthompsa if(run_write_region_1(sc, base, k->wk_key, 16)) 2327208019Sthompsa return; 2328209144Sthompsa if(run_write_region_1(sc, base + 16, &k->wk_key[16], 8)) /* wk_txmic */ 2329208019Sthompsa return; 2330209144Sthompsa if(run_write_region_1(sc, base + 24, &k->wk_key[24], 8)) /* wk_rxmic */ 2331208019Sthompsa return; 2332203134Sthompsa } else { 2333203134Sthompsa /* roundup len to 16-bit: XXX fix write_region_1() instead */ 2334203134Sthompsa if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1)) 2335208019Sthompsa return; 2336203134Sthompsa } 2337203134Sthompsa 2338203134Sthompsa if (!(k->wk_flags & IEEE80211_KEY_GROUP) || 2339203134Sthompsa (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) { 2340203134Sthompsa /* set initial packet number in IV+EIV */ 2341209917Sthompsa if (k->wk_cipher == IEEE80211_CIPHER_WEP) { 2342203134Sthompsa memset(iv, 0, sizeof iv); 2343208019Sthompsa iv[3] = vap->iv_def_txkey << 6; 2344203134Sthompsa } else { 2345203134Sthompsa if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) { 2346203134Sthompsa iv[0] = k->wk_keytsc >> 8; 2347203134Sthompsa iv[1] = (iv[0] | 0x20) & 0x7f; 2348203134Sthompsa iv[2] = k->wk_keytsc; 2349203134Sthompsa } else /* CCMP */ { 2350203134Sthompsa iv[0] = k->wk_keytsc; 2351203134Sthompsa iv[1] = k->wk_keytsc >> 8; 2352203134Sthompsa iv[2] = 0; 2353203134Sthompsa } 2354203134Sthompsa iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV; 2355203134Sthompsa iv[4] = k->wk_keytsc >> 16; 2356203134Sthompsa iv[5] = k->wk_keytsc >> 24; 2357203134Sthompsa iv[6] = k->wk_keytsc >> 32; 2358203134Sthompsa iv[7] = k->wk_keytsc >> 40; 2359203134Sthompsa } 2360209917Sthompsa if (run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8)) 2361208019Sthompsa return; 2362203134Sthompsa } 2363203134Sthompsa 2364203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 2365203134Sthompsa /* install group key */ 2366209917Sthompsa if (run_read(sc, RT2860_SKEY_MODE_0_7, &attr)) 2367208019Sthompsa return; 2368203134Sthompsa attr &= ~(0xf << (k->wk_keyix * 4)); 2369203134Sthompsa attr |= mode << (k->wk_keyix * 4); 2370209917Sthompsa if (run_write(sc, RT2860_SKEY_MODE_0_7, attr)) 2371208019Sthompsa return; 2372203134Sthompsa } else { 2373203134Sthompsa /* install pairwise key */ 2374209917Sthompsa if (run_read(sc, RT2860_WCID_ATTR(wcid), &attr)) 2375208019Sthompsa return; 2376203134Sthompsa attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN; 2377209917Sthompsa if (run_write(sc, RT2860_WCID_ATTR(wcid), attr)) 2378208019Sthompsa return; 2379203134Sthompsa } 2380203134Sthompsa 2381203134Sthompsa /* TODO create a pass-thru key entry? */ 2382203134Sthompsa 2383208019Sthompsa /* need wcid to delete the right key later */ 2384208019Sthompsa k->wk_pad = wcid; 2385203134Sthompsa} 2386203134Sthompsa 2387203134Sthompsa/* 2388208019Sthompsa * Don't have to be deferred, but in order to keep order of 2389208019Sthompsa * execution, i.e. with run_key_delete(), defer this and let 2390208019Sthompsa * run_cmdq_cb() maintain the order. 2391208019Sthompsa * 2392203134Sthompsa * return 0 on error 2393203134Sthompsa */ 2394203134Sthompsastatic int 2395208019Sthompsarun_key_set(struct ieee80211vap *vap, struct ieee80211_key *k, 2396208019Sthompsa const uint8_t mac[IEEE80211_ADDR_LEN]) 2397203134Sthompsa{ 2398203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2399203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2400208019Sthompsa uint32_t i; 2401208019Sthompsa 2402208019Sthompsa i = RUN_CMDQ_GET(&sc->cmdq_store); 2403208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 2404208019Sthompsa sc->cmdq[i].func = run_key_set_cb; 2405208019Sthompsa sc->cmdq[i].arg0 = NULL; 2406208019Sthompsa sc->cmdq[i].arg1 = vap; 2407208019Sthompsa sc->cmdq[i].k = k; 2408208019Sthompsa IEEE80211_ADDR_COPY(sc->cmdq[i].mac, mac); 2409208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2410208019Sthompsa 2411209144Sthompsa /* 2412209144Sthompsa * To make sure key will be set when hostapd 2413209144Sthompsa * calls iv_key_set() before if_init(). 2414209144Sthompsa */ 2415209917Sthompsa if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 2416209144Sthompsa RUN_LOCK(sc); 2417209144Sthompsa sc->cmdq_key_set = RUN_CMDQ_GO; 2418209144Sthompsa RUN_UNLOCK(sc); 2419209144Sthompsa } 2420209144Sthompsa 2421209917Sthompsa return (1); 2422208019Sthompsa} 2423208019Sthompsa 2424208019Sthompsa/* 2425208019Sthompsa * If wlan is destroyed without being brought down i.e. without 2426208019Sthompsa * wlan down or wpa_cli terminate, this function is called after 2427208019Sthompsa * vap is gone. Don't refer it. 2428208019Sthompsa */ 2429208019Sthompsastatic void 2430208019Sthompsarun_key_delete_cb(void *arg) 2431208019Sthompsa{ 2432208019Sthompsa struct run_cmdq *cmdq = arg; 2433208019Sthompsa struct run_softc *sc = cmdq->arg1; 2434208019Sthompsa struct ieee80211_key *k = &cmdq->key; 2435203134Sthompsa uint32_t attr; 2436203134Sthompsa uint8_t wcid; 2437203134Sthompsa 2438208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2439203134Sthompsa 2440203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 2441203134Sthompsa /* remove group key */ 2442208019Sthompsa DPRINTF("removing group key\n"); 2443208019Sthompsa run_read(sc, RT2860_SKEY_MODE_0_7, &attr); 2444203134Sthompsa attr &= ~(0xf << (k->wk_keyix * 4)); 2445208019Sthompsa run_write(sc, RT2860_SKEY_MODE_0_7, attr); 2446203134Sthompsa } else { 2447203134Sthompsa /* remove pairwise key */ 2448208019Sthompsa DPRINTF("removing key for wcid %x\n", k->wk_pad); 2449208019Sthompsa /* matching wcid was written to wk_pad in run_key_set() */ 2450208019Sthompsa wcid = k->wk_pad; 2451208019Sthompsa run_read(sc, RT2860_WCID_ATTR(wcid), &attr); 2452203134Sthompsa attr &= ~0xf; 2453208019Sthompsa run_write(sc, RT2860_WCID_ATTR(wcid), attr); 2454208019Sthompsa run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8); 2455203134Sthompsa } 2456203134Sthompsa 2457208019Sthompsa k->wk_pad = 0; 2458203134Sthompsa} 2459203134Sthompsa 2460208019Sthompsa/* 2461208019Sthompsa * return 0 on error 2462208019Sthompsa */ 2463208019Sthompsastatic int 2464208019Sthompsarun_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k) 2465203134Sthompsa{ 2466208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 2467208019Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2468208019Sthompsa struct ieee80211_key *k0; 2469208019Sthompsa uint32_t i; 2470203134Sthompsa 2471208019Sthompsa /* 2472208019Sthompsa * When called back, key might be gone. So, make a copy 2473208019Sthompsa * of some values need to delete keys before deferring. 2474208019Sthompsa * But, because of LOR with node lock, cannot use lock here. 2475208019Sthompsa * So, use atomic instead. 2476208019Sthompsa */ 2477208019Sthompsa i = RUN_CMDQ_GET(&sc->cmdq_store); 2478208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 2479208019Sthompsa sc->cmdq[i].func = run_key_delete_cb; 2480208019Sthompsa sc->cmdq[i].arg0 = NULL; 2481208019Sthompsa sc->cmdq[i].arg1 = sc; 2482208019Sthompsa k0 = &sc->cmdq[i].key; 2483208019Sthompsa k0->wk_flags = k->wk_flags; 2484208019Sthompsa k0->wk_keyix = k->wk_keyix; 2485208019Sthompsa /* matching wcid was written to wk_pad in run_key_set() */ 2486208019Sthompsa k0->wk_pad = k->wk_pad; 2487208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2488208019Sthompsa return (1); /* return fake success */ 2489203134Sthompsa 2490203134Sthompsa} 2491203134Sthompsa 2492203134Sthompsastatic void 2493206358Srpaulorun_ratectl_to(void *arg) 2494203134Sthompsa{ 2495208019Sthompsa struct run_softc *sc = arg; 2496203134Sthompsa 2497203134Sthompsa /* do it in a process context, so it can go sleep */ 2498208019Sthompsa ieee80211_runtask(sc->sc_ifp->if_l2com, &sc->ratectl_task); 2499203134Sthompsa /* next timeout will be rescheduled in the callback task */ 2500203134Sthompsa} 2501203134Sthompsa 2502203134Sthompsa/* ARGSUSED */ 2503203134Sthompsastatic void 2504206358Srpaulorun_ratectl_cb(void *arg, int pending) 2505203134Sthompsa{ 2506208019Sthompsa struct run_softc *sc = arg; 2507208019Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 2508208019Sthompsa struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2509203134Sthompsa 2510209917Sthompsa if (vap == NULL) 2511208019Sthompsa return; 2512208019Sthompsa 2513262795Shselasky if (sc->rvp_cnt > 1 || vap->iv_opmode != IEEE80211_M_STA) { 2514203134Sthompsa /* 2515203134Sthompsa * run_reset_livelock() doesn't do anything with AMRR, 2516203134Sthompsa * but Ralink wants us to call it every 1 sec. So, we 2517203134Sthompsa * piggyback here rather than creating another callout. 2518203134Sthompsa * Livelock may occur only in HOSTAP or IBSS mode 2519203134Sthompsa * (when h/w is sending beacons). 2520203134Sthompsa */ 2521203134Sthompsa RUN_LOCK(sc); 2522203134Sthompsa run_reset_livelock(sc); 2523208019Sthompsa /* just in case, there are some stats to drain */ 2524208019Sthompsa run_drain_fifo(sc); 2525203134Sthompsa RUN_UNLOCK(sc); 2526203134Sthompsa } 2527203134Sthompsa 2528262795Shselasky ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc); 2529262795Shselasky 2530257712Shselasky RUN_LOCK(sc); 2531208019Sthompsa if(sc->ratectl_run != RUN_RATECTL_OFF) 2532208019Sthompsa usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2533257712Shselasky RUN_UNLOCK(sc); 2534203134Sthompsa} 2535203134Sthompsa 2536203134Sthompsastatic void 2537208019Sthompsarun_drain_fifo(void *arg) 2538203134Sthompsa{ 2539208019Sthompsa struct run_softc *sc = arg; 2540208019Sthompsa struct ifnet *ifp = sc->sc_ifp; 2541208019Sthompsa uint32_t stat; 2542218676Shselasky uint16_t (*wstat)[3]; 2543203134Sthompsa uint8_t wcid, mcs, pid; 2544218676Shselasky int8_t retry; 2545203134Sthompsa 2546208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2547203134Sthompsa 2548208019Sthompsa for (;;) { 2549203134Sthompsa /* drain Tx status FIFO (maxsize = 16) */ 2550203134Sthompsa run_read(sc, RT2860_TX_STAT_FIFO, &stat); 2551208019Sthompsa DPRINTFN(4, "tx stat 0x%08x\n", stat); 2552209917Sthompsa if (!(stat & RT2860_TXQ_VLD)) 2553208019Sthompsa break; 2554203134Sthompsa 2555208019Sthompsa wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff; 2556203134Sthompsa 2557208019Sthompsa /* if no ACK was requested, no feedback is available */ 2558208019Sthompsa if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX || 2559208019Sthompsa wcid == 0) 2560208019Sthompsa continue; 2561203134Sthompsa 2562218676Shselasky /* 2563218676Shselasky * Even though each stat is Tx-complete-status like format, 2564218676Shselasky * the device can poll stats. Because there is no guarantee 2565218676Shselasky * that the referring node is still around when read the stats. 2566218676Shselasky * So that, if we use ieee80211_ratectl_tx_update(), we will 2567218676Shselasky * have hard time not to refer already freed node. 2568218676Shselasky * 2569218676Shselasky * To eliminate such page faults, we poll stats in softc. 2570218676Shselasky * Then, update the rates later with ieee80211_ratectl_tx_update(). 2571218676Shselasky */ 2572218676Shselasky wstat = &(sc->wcid_stats[wcid]); 2573218676Shselasky (*wstat)[RUN_TXCNT]++; 2574218676Shselasky if (stat & RT2860_TXQ_OK) 2575218676Shselasky (*wstat)[RUN_SUCCESS]++; 2576218676Shselasky else 2577271866Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 2578218676Shselasky /* 2579218676Shselasky * Check if there were retries, ie if the Tx success rate is 2580218676Shselasky * different from the requested rate. Note that it works only 2581218676Shselasky * because we do not allow rate fallback from OFDM to CCK. 2582218676Shselasky */ 2583218676Shselasky mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f; 2584218676Shselasky pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf; 2585218676Shselasky if ((retry = pid -1 - mcs) > 0) { 2586218676Shselasky (*wstat)[RUN_TXCNT] += retry; 2587218676Shselasky (*wstat)[RUN_RETRY] += retry; 2588203134Sthompsa } 2589208019Sthompsa } 2590208019Sthompsa DPRINTFN(3, "count=%d\n", sc->fifo_cnt); 2591208019Sthompsa 2592208019Sthompsa sc->fifo_cnt = 0; 2593208019Sthompsa} 2594208019Sthompsa 2595208019Sthompsastatic void 2596208019Sthompsarun_iter_func(void *arg, struct ieee80211_node *ni) 2597208019Sthompsa{ 2598208019Sthompsa struct run_softc *sc = arg; 2599208019Sthompsa struct ieee80211vap *vap = ni->ni_vap; 2600208019Sthompsa struct ieee80211com *ic = ni->ni_ic; 2601208019Sthompsa struct ifnet *ifp = ic->ic_ifp; 2602208019Sthompsa struct run_node *rn = (void *)ni; 2603218676Shselasky union run_stats sta[2]; 2604218676Shselasky uint16_t (*wstat)[3]; 2605218676Shselasky int txcnt, success, retrycnt, error; 2606208019Sthompsa 2607218676Shselasky RUN_LOCK(sc); 2608218676Shselasky 2609262795Shselasky /* Check for special case */ 2610262795Shselasky if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA && 2611262795Shselasky ni != vap->iv_bss) 2612262795Shselasky goto fail; 2613262795Shselasky 2614209917Sthompsa if (sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS || 2615209917Sthompsa vap->iv_opmode == IEEE80211_M_STA)) { 2616203134Sthompsa /* read statistic counters (clear on read) and update AMRR state */ 2617203134Sthompsa error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta, 2618203134Sthompsa sizeof sta); 2619203134Sthompsa if (error != 0) 2620218676Shselasky goto fail; 2621203134Sthompsa 2622203134Sthompsa /* count failed TX as errors */ 2623271866Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, le16toh(sta[0].error.fail)); 2624203134Sthompsa 2625218676Shselasky retrycnt = le16toh(sta[1].tx.retry); 2626218676Shselasky success = le16toh(sta[1].tx.success); 2627218676Shselasky txcnt = retrycnt + success + le16toh(sta[0].error.fail); 2628203134Sthompsa 2629218676Shselasky DPRINTFN(3, "retrycnt=%d success=%d failcnt=%d\n", 2630218676Shselasky retrycnt, success, le16toh(sta[0].error.fail)); 2631218676Shselasky } else { 2632218676Shselasky wstat = &(sc->wcid_stats[RUN_AID2WCID(ni->ni_associd)]); 2633203134Sthompsa 2634218676Shselasky if (wstat == &(sc->wcid_stats[0]) || 2635218676Shselasky wstat > &(sc->wcid_stats[RT2870_WCID_MAX])) 2636218676Shselasky goto fail; 2637208019Sthompsa 2638218676Shselasky txcnt = (*wstat)[RUN_TXCNT]; 2639218676Shselasky success = (*wstat)[RUN_SUCCESS]; 2640218676Shselasky retrycnt = (*wstat)[RUN_RETRY]; 2641218676Shselasky DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n", 2642218676Shselasky retrycnt, txcnt, success); 2643208019Sthompsa 2644218676Shselasky memset(wstat, 0, sizeof(*wstat)); 2645203134Sthompsa } 2646203134Sthompsa 2647218676Shselasky ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt); 2648208019Sthompsa rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0); 2649218676Shselasky 2650218676Shselaskyfail: 2651218676Shselasky RUN_UNLOCK(sc); 2652218676Shselasky 2653208019Sthompsa DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx); 2654208019Sthompsa} 2655203134Sthompsa 2656208019Sthompsastatic void 2657208019Sthompsarun_newassoc_cb(void *arg) 2658208019Sthompsa{ 2659208019Sthompsa struct run_cmdq *cmdq = arg; 2660208019Sthompsa struct ieee80211_node *ni = cmdq->arg1; 2661208019Sthompsa struct run_softc *sc = ni->ni_vap->iv_ic->ic_ifp->if_softc; 2662208019Sthompsa uint8_t wcid = cmdq->wcid; 2663203134Sthompsa 2664208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2665208019Sthompsa 2666208019Sthompsa run_write_region_1(sc, RT2860_WCID_ENTRY(wcid), 2667208019Sthompsa ni->ni_macaddr, IEEE80211_ADDR_LEN); 2668218676Shselasky 2669218676Shselasky memset(&(sc->wcid_stats[wcid]), 0, sizeof(sc->wcid_stats[wcid])); 2670203134Sthompsa} 2671203134Sthompsa 2672203134Sthompsastatic void 2673203134Sthompsarun_newassoc(struct ieee80211_node *ni, int isnew) 2674203134Sthompsa{ 2675203134Sthompsa struct run_node *rn = (void *)ni; 2676203134Sthompsa struct ieee80211_rateset *rs = &ni->ni_rates; 2677208019Sthompsa struct ieee80211vap *vap = ni->ni_vap; 2678208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 2679208019Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2680203134Sthompsa uint8_t rate; 2681208019Sthompsa uint8_t ridx; 2682245047Shselasky uint8_t wcid; 2683208019Sthompsa int i, j; 2684203134Sthompsa 2685245047Shselasky wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 2686245047Shselasky 1 : RUN_AID2WCID(ni->ni_associd); 2687245047Shselasky 2688209917Sthompsa if (wcid > RT2870_WCID_MAX) { 2689208019Sthompsa device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid); 2690208019Sthompsa return; 2691208019Sthompsa } 2692203134Sthompsa 2693208019Sthompsa /* only interested in true associations */ 2694209917Sthompsa if (isnew && ni->ni_associd != 0) { 2695208019Sthompsa 2696208019Sthompsa /* 2697208019Sthompsa * This function could is called though timeout function. 2698208019Sthompsa * Need to defer. 2699208019Sthompsa */ 2700208019Sthompsa uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store); 2701208019Sthompsa DPRINTF("cmdq_store=%d\n", cnt); 2702208019Sthompsa sc->cmdq[cnt].func = run_newassoc_cb; 2703208019Sthompsa sc->cmdq[cnt].arg0 = NULL; 2704208019Sthompsa sc->cmdq[cnt].arg1 = ni; 2705208019Sthompsa sc->cmdq[cnt].wcid = wcid; 2706208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2707208019Sthompsa } 2708208019Sthompsa 2709208019Sthompsa DPRINTF("new assoc isnew=%d associd=%x addr=%s\n", 2710208019Sthompsa isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr)); 2711208019Sthompsa 2712203134Sthompsa for (i = 0; i < rs->rs_nrates; i++) { 2713203134Sthompsa rate = rs->rs_rates[i] & IEEE80211_RATE_VAL; 2714203134Sthompsa /* convert 802.11 rate to hardware rate index */ 2715203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2716203134Sthompsa if (rt2860_rates[ridx].rate == rate) 2717203134Sthompsa break; 2718203134Sthompsa rn->ridx[i] = ridx; 2719203134Sthompsa /* determine rate of control response frames */ 2720203134Sthompsa for (j = i; j >= 0; j--) { 2721203134Sthompsa if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) && 2722203134Sthompsa rt2860_rates[rn->ridx[i]].phy == 2723203134Sthompsa rt2860_rates[rn->ridx[j]].phy) 2724203134Sthompsa break; 2725203134Sthompsa } 2726203134Sthompsa if (j >= 0) { 2727203134Sthompsa rn->ctl_ridx[i] = rn->ridx[j]; 2728203134Sthompsa } else { 2729203134Sthompsa /* no basic rate found, use mandatory one */ 2730203134Sthompsa rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx; 2731203134Sthompsa } 2732203134Sthompsa DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n", 2733203134Sthompsa rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]); 2734203134Sthompsa } 2735208019Sthompsa rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate; 2736208019Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2737208019Sthompsa if (rt2860_rates[ridx].rate == rate) 2738208019Sthompsa break; 2739208019Sthompsa rn->mgt_ridx = ridx; 2740208019Sthompsa DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx); 2741208019Sthompsa 2742262795Shselasky RUN_LOCK(sc); 2743262795Shselasky if(sc->ratectl_run != RUN_RATECTL_OFF) 2744262795Shselasky usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2745262795Shselasky RUN_UNLOCK(sc); 2746203134Sthompsa} 2747203134Sthompsa 2748203134Sthompsa/* 2749203134Sthompsa * Return the Rx chain with the highest RSSI for a given frame. 2750203134Sthompsa */ 2751203134Sthompsastatic __inline uint8_t 2752203134Sthompsarun_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi) 2753203134Sthompsa{ 2754203134Sthompsa uint8_t rxchain = 0; 2755203134Sthompsa 2756203134Sthompsa if (sc->nrxchains > 1) { 2757203134Sthompsa if (rxwi->rssi[1] > rxwi->rssi[rxchain]) 2758203134Sthompsa rxchain = 1; 2759203134Sthompsa if (sc->nrxchains > 2) 2760203134Sthompsa if (rxwi->rssi[2] > rxwi->rssi[rxchain]) 2761203134Sthompsa rxchain = 2; 2762203134Sthompsa } 2763209917Sthompsa return (rxchain); 2764203134Sthompsa} 2765203134Sthompsa 2766203134Sthompsastatic void 2767203134Sthompsarun_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) 2768203134Sthompsa{ 2769203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 2770203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 2771203134Sthompsa struct ieee80211_frame *wh; 2772203134Sthompsa struct ieee80211_node *ni; 2773203134Sthompsa struct rt2870_rxd *rxd; 2774203134Sthompsa struct rt2860_rxwi *rxwi; 2775203134Sthompsa uint32_t flags; 2776259032Skevlo uint16_t len, rxwisize; 2777203134Sthompsa uint8_t ant, rssi; 2778203134Sthompsa int8_t nf; 2779203134Sthompsa 2780203134Sthompsa rxwi = mtod(m, struct rt2860_rxwi *); 2781203134Sthompsa len = le16toh(rxwi->len) & 0xfff; 2782260219Skevlo rxwisize = sizeof(struct rt2860_rxwi); 2783260219Skevlo if (sc->mac_ver == 0x5592) 2784260219Skevlo rxwisize += sizeof(uint64_t); 2785260219Skevlo else if (sc->mac_ver == 0x3593) 2786260219Skevlo rxwisize += sizeof(uint32_t); 2787203134Sthompsa if (__predict_false(len > dmalen)) { 2788203134Sthompsa m_freem(m); 2789271866Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 2790203134Sthompsa DPRINTF("bad RXWI length %u > %u\n", len, dmalen); 2791203134Sthompsa return; 2792203134Sthompsa } 2793203134Sthompsa /* Rx descriptor is located at the end */ 2794203134Sthompsa rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen); 2795203134Sthompsa flags = le32toh(rxd->flags); 2796203134Sthompsa 2797203134Sthompsa if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) { 2798203134Sthompsa m_freem(m); 2799271866Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 2800203134Sthompsa DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV"); 2801203134Sthompsa return; 2802203134Sthompsa } 2803203134Sthompsa 2804259032Skevlo m->m_data += rxwisize; 2805259032Skevlo m->m_pkthdr.len = m->m_len -= rxwisize; 2806203134Sthompsa 2807203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 2808203134Sthompsa 2809260444Skevlo if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 2810260444Skevlo wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; 2811203134Sthompsa m->m_flags |= M_WEP; 2812203134Sthompsa } 2813203134Sthompsa 2814209917Sthompsa if (flags & RT2860_RX_L2PAD) { 2815203134Sthompsa DPRINTFN(8, "received RT2860_RX_L2PAD frame\n"); 2816203134Sthompsa len += 2; 2817203134Sthompsa } 2818203134Sthompsa 2819208019Sthompsa ni = ieee80211_find_rxnode(ic, 2820208019Sthompsa mtod(m, struct ieee80211_frame_min *)); 2821208019Sthompsa 2822203134Sthompsa if (__predict_false(flags & RT2860_RX_MICERR)) { 2823203134Sthompsa /* report MIC failures to net80211 for TKIP */ 2824209917Sthompsa if (ni != NULL) 2825259032Skevlo ieee80211_notify_michael_failure(ni->ni_vap, wh, 2826259032Skevlo rxwi->keyidx); 2827203134Sthompsa m_freem(m); 2828271866Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 2829203134Sthompsa DPRINTF("MIC error. Someone is lying.\n"); 2830203134Sthompsa return; 2831203134Sthompsa } 2832203134Sthompsa 2833203134Sthompsa ant = run_maxrssi_chain(sc, rxwi); 2834203134Sthompsa rssi = rxwi->rssi[ant]; 2835203134Sthompsa nf = run_rssi2dbm(sc, rssi, ant); 2836203134Sthompsa 2837203134Sthompsa m->m_pkthdr.rcvif = ifp; 2838203134Sthompsa m->m_pkthdr.len = m->m_len = len; 2839203134Sthompsa 2840203134Sthompsa if (ni != NULL) { 2841203134Sthompsa (void)ieee80211_input(ni, m, rssi, nf); 2842203134Sthompsa ieee80211_free_node(ni); 2843203134Sthompsa } else { 2844203134Sthompsa (void)ieee80211_input_all(ic, m, rssi, nf); 2845203134Sthompsa } 2846203134Sthompsa 2847209917Sthompsa if (__predict_false(ieee80211_radiotap_active(ic))) { 2848203134Sthompsa struct run_rx_radiotap_header *tap = &sc->sc_rxtap; 2849258643Shselasky uint16_t phy; 2850203134Sthompsa 2851203134Sthompsa tap->wr_flags = 0; 2852236439Shselasky tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); 2853236439Shselasky tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); 2854203134Sthompsa tap->wr_antsignal = rssi; 2855203134Sthompsa tap->wr_antenna = ant; 2856203134Sthompsa tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant); 2857203134Sthompsa tap->wr_rate = 2; /* in case it can't be found below */ 2858203134Sthompsa phy = le16toh(rxwi->phy); 2859203134Sthompsa switch (phy & RT2860_PHY_MODE) { 2860203134Sthompsa case RT2860_PHY_CCK: 2861203134Sthompsa switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) { 2862203134Sthompsa case 0: tap->wr_rate = 2; break; 2863203134Sthompsa case 1: tap->wr_rate = 4; break; 2864203134Sthompsa case 2: tap->wr_rate = 11; break; 2865203134Sthompsa case 3: tap->wr_rate = 22; break; 2866203134Sthompsa } 2867203134Sthompsa if (phy & RT2860_PHY_SHPRE) 2868203134Sthompsa tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 2869203134Sthompsa break; 2870203134Sthompsa case RT2860_PHY_OFDM: 2871203134Sthompsa switch (phy & RT2860_PHY_MCS) { 2872203134Sthompsa case 0: tap->wr_rate = 12; break; 2873203134Sthompsa case 1: tap->wr_rate = 18; break; 2874203134Sthompsa case 2: tap->wr_rate = 24; break; 2875203134Sthompsa case 3: tap->wr_rate = 36; break; 2876203134Sthompsa case 4: tap->wr_rate = 48; break; 2877203134Sthompsa case 5: tap->wr_rate = 72; break; 2878203134Sthompsa case 6: tap->wr_rate = 96; break; 2879203134Sthompsa case 7: tap->wr_rate = 108; break; 2880203134Sthompsa } 2881203134Sthompsa break; 2882203134Sthompsa } 2883203134Sthompsa } 2884203134Sthompsa} 2885203134Sthompsa 2886203134Sthompsastatic void 2887203134Sthompsarun_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) 2888203134Sthompsa{ 2889203134Sthompsa struct run_softc *sc = usbd_xfer_softc(xfer); 2890203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 2891203134Sthompsa struct mbuf *m = NULL; 2892203134Sthompsa struct mbuf *m0; 2893203134Sthompsa uint32_t dmalen; 2894259032Skevlo uint16_t rxwisize; 2895203134Sthompsa int xferlen; 2896203134Sthompsa 2897260219Skevlo rxwisize = sizeof(struct rt2860_rxwi); 2898260219Skevlo if (sc->mac_ver == 0x5592) 2899260219Skevlo rxwisize += sizeof(uint64_t); 2900260219Skevlo else if (sc->mac_ver == 0x3593) 2901260219Skevlo rxwisize += sizeof(uint32_t); 2902259032Skevlo 2903203134Sthompsa usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL); 2904203134Sthompsa 2905203134Sthompsa switch (USB_GET_STATE(xfer)) { 2906203134Sthompsa case USB_ST_TRANSFERRED: 2907203134Sthompsa 2908203134Sthompsa DPRINTFN(15, "rx done, actlen=%d\n", xferlen); 2909203134Sthompsa 2910259032Skevlo if (xferlen < (int)(sizeof(uint32_t) + rxwisize + 2911259032Skevlo sizeof(struct rt2870_rxd))) { 2912203134Sthompsa DPRINTF("xfer too short %d\n", xferlen); 2913203134Sthompsa goto tr_setup; 2914203134Sthompsa } 2915203134Sthompsa 2916203134Sthompsa m = sc->rx_m; 2917203134Sthompsa sc->rx_m = NULL; 2918203134Sthompsa 2919203134Sthompsa /* FALLTHROUGH */ 2920203134Sthompsa case USB_ST_SETUP: 2921203134Sthompsatr_setup: 2922203134Sthompsa if (sc->rx_m == NULL) { 2923243857Sglebius sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, 2924203134Sthompsa MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */); 2925203134Sthompsa } 2926203134Sthompsa if (sc->rx_m == NULL) { 2927203134Sthompsa DPRINTF("could not allocate mbuf - idle with stall\n"); 2928271866Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 2929203134Sthompsa usbd_xfer_set_stall(xfer); 2930203134Sthompsa usbd_xfer_set_frames(xfer, 0); 2931203134Sthompsa } else { 2932203134Sthompsa /* 2933203134Sthompsa * Directly loading a mbuf cluster into DMA to 2934203134Sthompsa * save some data copying. This works because 2935203134Sthompsa * there is only one cluster. 2936203134Sthompsa */ 2937203134Sthompsa usbd_xfer_set_frame_data(xfer, 0, 2938203134Sthompsa mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ); 2939203134Sthompsa usbd_xfer_set_frames(xfer, 1); 2940203134Sthompsa } 2941203134Sthompsa usbd_transfer_submit(xfer); 2942203134Sthompsa break; 2943203134Sthompsa 2944203134Sthompsa default: /* Error */ 2945203134Sthompsa if (error != USB_ERR_CANCELLED) { 2946203134Sthompsa /* try to clear stall first */ 2947203134Sthompsa usbd_xfer_set_stall(xfer); 2948203134Sthompsa 2949203134Sthompsa if (error == USB_ERR_TIMEOUT) 2950203134Sthompsa device_printf(sc->sc_dev, "device timeout\n"); 2951203134Sthompsa 2952271866Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 2953203134Sthompsa 2954203134Sthompsa goto tr_setup; 2955203134Sthompsa } 2956209917Sthompsa if (sc->rx_m != NULL) { 2957203134Sthompsa m_freem(sc->rx_m); 2958203134Sthompsa sc->rx_m = NULL; 2959203134Sthompsa } 2960203134Sthompsa break; 2961203134Sthompsa } 2962203134Sthompsa 2963203134Sthompsa if (m == NULL) 2964203134Sthompsa return; 2965203134Sthompsa 2966203134Sthompsa /* inputting all the frames must be last */ 2967203134Sthompsa 2968203134Sthompsa RUN_UNLOCK(sc); 2969203134Sthompsa 2970203134Sthompsa m->m_pkthdr.len = m->m_len = xferlen; 2971203134Sthompsa 2972203134Sthompsa /* HW can aggregate multiple 802.11 frames in a single USB xfer */ 2973203134Sthompsa for(;;) { 2974203134Sthompsa dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff; 2975203134Sthompsa 2976233774Shselasky if ((dmalen >= (uint32_t)-8) || (dmalen == 0) || 2977233774Shselasky ((dmalen & 3) != 0)) { 2978203134Sthompsa DPRINTF("bad DMA length %u\n", dmalen); 2979203134Sthompsa break; 2980203134Sthompsa } 2981233774Shselasky if ((dmalen + 8) > (uint32_t)xferlen) { 2982203134Sthompsa DPRINTF("bad DMA length %u > %d\n", 2983203134Sthompsa dmalen + 8, xferlen); 2984203134Sthompsa break; 2985203134Sthompsa } 2986203134Sthompsa 2987203134Sthompsa /* If it is the last one or a single frame, we won't copy. */ 2988209917Sthompsa if ((xferlen -= dmalen + 8) <= 8) { 2989203134Sthompsa /* trim 32-bit DMA-len header */ 2990203134Sthompsa m->m_data += 4; 2991203134Sthompsa m->m_pkthdr.len = m->m_len -= 4; 2992203134Sthompsa run_rx_frame(sc, m, dmalen); 2993257435Shselasky m = NULL; /* don't free source buffer */ 2994203134Sthompsa break; 2995203134Sthompsa } 2996203134Sthompsa 2997203134Sthompsa /* copy aggregated frames to another mbuf */ 2998243857Sglebius m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 2999203134Sthompsa if (__predict_false(m0 == NULL)) { 3000203134Sthompsa DPRINTF("could not allocate mbuf\n"); 3001271866Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 3002203134Sthompsa break; 3003203134Sthompsa } 3004203134Sthompsa m_copydata(m, 4 /* skip 32-bit DMA-len header */, 3005203134Sthompsa dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t)); 3006203134Sthompsa m0->m_pkthdr.len = m0->m_len = 3007203134Sthompsa dmalen + sizeof(struct rt2870_rxd); 3008203134Sthompsa run_rx_frame(sc, m0, dmalen); 3009203134Sthompsa 3010203134Sthompsa /* update data ptr */ 3011203134Sthompsa m->m_data += dmalen + 8; 3012203134Sthompsa m->m_pkthdr.len = m->m_len -= dmalen + 8; 3013203134Sthompsa } 3014203134Sthompsa 3015257435Shselasky /* make sure we free the source buffer, if any */ 3016257435Shselasky m_freem(m); 3017257435Shselasky 3018203134Sthompsa RUN_LOCK(sc); 3019203134Sthompsa} 3020203134Sthompsa 3021203134Sthompsastatic void 3022203134Sthompsarun_tx_free(struct run_endpoint_queue *pq, 3023203134Sthompsa struct run_tx_data *data, int txerr) 3024203134Sthompsa{ 3025203134Sthompsa if (data->m != NULL) { 3026203134Sthompsa if (data->m->m_flags & M_TXCB) 3027203134Sthompsa ieee80211_process_callback(data->ni, data->m, 3028203134Sthompsa txerr ? ETIMEDOUT : 0); 3029203134Sthompsa m_freem(data->m); 3030203134Sthompsa data->m = NULL; 3031203134Sthompsa 3032209917Sthompsa if (data->ni == NULL) { 3033203134Sthompsa DPRINTF("no node\n"); 3034203134Sthompsa } else { 3035203134Sthompsa ieee80211_free_node(data->ni); 3036203134Sthompsa data->ni = NULL; 3037203134Sthompsa } 3038203134Sthompsa } 3039203134Sthompsa 3040203134Sthompsa STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); 3041203134Sthompsa pq->tx_nfree++; 3042203134Sthompsa} 3043203134Sthompsa 3044203134Sthompsastatic void 3045257429Shselaskyrun_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index) 3046203134Sthompsa{ 3047203134Sthompsa struct run_softc *sc = usbd_xfer_softc(xfer); 3048203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 3049208019Sthompsa struct ieee80211com *ic = ifp->if_l2com; 3050203134Sthompsa struct run_tx_data *data; 3051203134Sthompsa struct ieee80211vap *vap = NULL; 3052203134Sthompsa struct usb_page_cache *pc; 3053203134Sthompsa struct run_endpoint_queue *pq = &sc->sc_epq[index]; 3054203134Sthompsa struct mbuf *m; 3055203134Sthompsa usb_frlength_t size; 3056203134Sthompsa int actlen; 3057203134Sthompsa int sumlen; 3058203134Sthompsa 3059203134Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 3060203134Sthompsa 3061209917Sthompsa switch (USB_GET_STATE(xfer)) { 3062203134Sthompsa case USB_ST_TRANSFERRED: 3063203134Sthompsa DPRINTFN(11, "transfer complete: %d " 3064203134Sthompsa "bytes @ index %d\n", actlen, index); 3065203134Sthompsa 3066203134Sthompsa data = usbd_xfer_get_priv(xfer); 3067203134Sthompsa 3068203134Sthompsa run_tx_free(pq, data, 0); 3069203134Sthompsa ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 3070203134Sthompsa 3071203134Sthompsa usbd_xfer_set_priv(xfer, NULL); 3072203134Sthompsa 3073271866Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 3074203134Sthompsa 3075203134Sthompsa /* FALLTHROUGH */ 3076203134Sthompsa case USB_ST_SETUP: 3077203134Sthompsatr_setup: 3078203134Sthompsa data = STAILQ_FIRST(&pq->tx_qh); 3079209917Sthompsa if (data == NULL) 3080203134Sthompsa break; 3081203134Sthompsa 3082203134Sthompsa STAILQ_REMOVE_HEAD(&pq->tx_qh, next); 3083203134Sthompsa 3084203134Sthompsa m = data->m; 3085261330Shselasky size = (sc->mac_ver == 0x5592) ? 3086261330Shselasky sizeof(data->desc) + sizeof(uint32_t) : sizeof(data->desc); 3087261076Shselasky if ((m->m_pkthdr.len + 3088261330Shselasky size + 3 + 8) > RUN_MAX_TXSZ) { 3089203134Sthompsa DPRINTF("data overflow, %u bytes\n", 3090203134Sthompsa m->m_pkthdr.len); 3091203134Sthompsa 3092271866Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 3093203134Sthompsa 3094203134Sthompsa run_tx_free(pq, data, 1); 3095203134Sthompsa 3096203134Sthompsa goto tr_setup; 3097203134Sthompsa } 3098203134Sthompsa 3099203134Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 3100203134Sthompsa usbd_copy_in(pc, 0, &data->desc, size); 3101203134Sthompsa usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len); 3102228508Shselasky size += m->m_pkthdr.len; 3103228508Shselasky /* 3104228508Shselasky * Align end on a 4-byte boundary, pad 8 bytes (CRC + 3105228508Shselasky * 4-byte padding), and be sure to zero those trailing 3106228508Shselasky * bytes: 3107228508Shselasky */ 3108228508Shselasky usbd_frame_zero(pc, size, ((-size) & 3) + 8); 3109228508Shselasky size += ((-size) & 3) + 8; 3110203134Sthompsa 3111203134Sthompsa vap = data->ni->ni_vap; 3112203134Sthompsa if (ieee80211_radiotap_active_vap(vap)) { 3113203134Sthompsa struct run_tx_radiotap_header *tap = &sc->sc_txtap; 3114259032Skevlo struct rt2860_txwi *txwi = 3115208019Sthompsa (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd)); 3116203134Sthompsa tap->wt_flags = 0; 3117203134Sthompsa tap->wt_rate = rt2860_rates[data->ridx].rate; 3118236439Shselasky tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 3119236439Shselasky tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 3120203134Sthompsa tap->wt_hwqueue = index; 3121208019Sthompsa if (le16toh(txwi->phy) & RT2860_PHY_SHPRE) 3122203134Sthompsa tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 3123203134Sthompsa 3124203134Sthompsa ieee80211_radiotap_tx(vap, m); 3125203134Sthompsa } 3126203134Sthompsa 3127228508Shselasky DPRINTFN(11, "sending frame len=%u/%u @ index %d\n", 3128228508Shselasky m->m_pkthdr.len, size, index); 3129203134Sthompsa 3130228508Shselasky usbd_xfer_set_frame_len(xfer, 0, size); 3131203134Sthompsa usbd_xfer_set_priv(xfer, data); 3132203134Sthompsa 3133203134Sthompsa usbd_transfer_submit(xfer); 3134203134Sthompsa 3135203134Sthompsa RUN_UNLOCK(sc); 3136203134Sthompsa run_start(ifp); 3137203134Sthompsa RUN_LOCK(sc); 3138203134Sthompsa 3139203134Sthompsa break; 3140203134Sthompsa 3141203134Sthompsa default: 3142203134Sthompsa DPRINTF("USB transfer error, %s\n", 3143203134Sthompsa usbd_errstr(error)); 3144203134Sthompsa 3145203134Sthompsa data = usbd_xfer_get_priv(xfer); 3146203134Sthompsa 3147271866Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 3148203134Sthompsa 3149203134Sthompsa if (data != NULL) { 3150208019Sthompsa if(data->ni != NULL) 3151208019Sthompsa vap = data->ni->ni_vap; 3152203134Sthompsa run_tx_free(pq, data, error); 3153203134Sthompsa usbd_xfer_set_priv(xfer, NULL); 3154203134Sthompsa } 3155209917Sthompsa if (vap == NULL) 3156208019Sthompsa vap = TAILQ_FIRST(&ic->ic_vaps); 3157203134Sthompsa 3158203134Sthompsa if (error != USB_ERR_CANCELLED) { 3159203134Sthompsa if (error == USB_ERR_TIMEOUT) { 3160203134Sthompsa device_printf(sc->sc_dev, "device timeout\n"); 3161208019Sthompsa uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 3162208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 3163208019Sthompsa sc->cmdq[i].func = run_usb_timeout_cb; 3164208019Sthompsa sc->cmdq[i].arg0 = vap; 3165208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 3166203134Sthompsa } 3167203134Sthompsa 3168203134Sthompsa /* 3169203134Sthompsa * Try to clear stall first, also if other 3170203134Sthompsa * errors occur, hence clearing stall 3171203134Sthompsa * introduces a 50 ms delay: 3172203134Sthompsa */ 3173203134Sthompsa usbd_xfer_set_stall(xfer); 3174203134Sthompsa goto tr_setup; 3175203134Sthompsa } 3176203134Sthompsa break; 3177203134Sthompsa } 3178203134Sthompsa} 3179203134Sthompsa 3180203134Sthompsastatic void 3181203134Sthompsarun_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error) 3182203134Sthompsa{ 3183203134Sthompsa run_bulk_tx_callbackN(xfer, error, 0); 3184203134Sthompsa} 3185203134Sthompsa 3186203134Sthompsastatic void 3187203134Sthompsarun_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error) 3188203134Sthompsa{ 3189203134Sthompsa run_bulk_tx_callbackN(xfer, error, 1); 3190203134Sthompsa} 3191203134Sthompsa 3192203134Sthompsastatic void 3193203134Sthompsarun_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error) 3194203134Sthompsa{ 3195203134Sthompsa run_bulk_tx_callbackN(xfer, error, 2); 3196203134Sthompsa} 3197203134Sthompsa 3198203134Sthompsastatic void 3199203134Sthompsarun_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error) 3200203134Sthompsa{ 3201203134Sthompsa run_bulk_tx_callbackN(xfer, error, 3); 3202203134Sthompsa} 3203203134Sthompsa 3204203134Sthompsastatic void 3205203134Sthompsarun_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error) 3206203134Sthompsa{ 3207203134Sthompsa run_bulk_tx_callbackN(xfer, error, 4); 3208203134Sthompsa} 3209203134Sthompsa 3210203134Sthompsastatic void 3211203134Sthompsarun_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error) 3212203134Sthompsa{ 3213203134Sthompsa run_bulk_tx_callbackN(xfer, error, 5); 3214203134Sthompsa} 3215203134Sthompsa 3216203134Sthompsastatic void 3217208019Sthompsarun_set_tx_desc(struct run_softc *sc, struct run_tx_data *data) 3218203134Sthompsa{ 3219203134Sthompsa struct mbuf *m = data->m; 3220203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 3221208019Sthompsa struct ieee80211vap *vap = data->ni->ni_vap; 3222203134Sthompsa struct ieee80211_frame *wh; 3223203134Sthompsa struct rt2870_txd *txd; 3224203134Sthompsa struct rt2860_txwi *txwi; 3225259032Skevlo uint16_t xferlen, txwisize; 3226208019Sthompsa uint16_t mcs; 3227203134Sthompsa uint8_t ridx = data->ridx; 3228208019Sthompsa uint8_t pad; 3229203134Sthompsa 3230203134Sthompsa /* get MCS code from rate index */ 3231208019Sthompsa mcs = rt2860_rates[ridx].mcs; 3232203134Sthompsa 3233259032Skevlo txwisize = (sc->mac_ver == 0x5592) ? 3234259032Skevlo sizeof(*txwi) + sizeof(uint32_t) : sizeof(*txwi); 3235259032Skevlo xferlen = txwisize + m->m_pkthdr.len; 3236203134Sthompsa 3237203134Sthompsa /* roundup to 32-bit alignment */ 3238203134Sthompsa xferlen = (xferlen + 3) & ~3; 3239203134Sthompsa 3240203134Sthompsa txd = (struct rt2870_txd *)&data->desc; 3241203134Sthompsa txd->len = htole16(xferlen); 3242203134Sthompsa 3243208019Sthompsa wh = mtod(m, struct ieee80211_frame *); 3244208019Sthompsa 3245208019Sthompsa /* 3246208019Sthompsa * Ether both are true or both are false, the header 3247208019Sthompsa * are nicely aligned to 32-bit. So, no L2 padding. 3248208019Sthompsa */ 3249208019Sthompsa if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh)) 3250208019Sthompsa pad = 0; 3251208019Sthompsa else 3252208019Sthompsa pad = 2; 3253208019Sthompsa 3254203134Sthompsa /* setup TX Wireless Information */ 3255203134Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3256203134Sthompsa txwi->len = htole16(m->m_pkthdr.len - pad); 3257203134Sthompsa if (rt2860_rates[ridx].phy == IEEE80211_T_DS) { 3258270192Skevlo mcs |= RT2860_PHY_CCK; 3259203134Sthompsa if (ridx != RT2860_RIDX_CCK1 && 3260203134Sthompsa (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 3261203134Sthompsa mcs |= RT2860_PHY_SHPRE; 3262203134Sthompsa } else 3263270192Skevlo mcs |= RT2860_PHY_OFDM; 3264270192Skevlo txwi->phy = htole16(mcs); 3265203134Sthompsa 3266203134Sthompsa /* check if RTS/CTS or CTS-to-self protection is required */ 3267203134Sthompsa if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 3268203134Sthompsa (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold || 3269203134Sthompsa ((ic->ic_flags & IEEE80211_F_USEPROT) && 3270203134Sthompsa rt2860_rates[ridx].phy == IEEE80211_T_OFDM))) 3271208019Sthompsa txwi->txop |= RT2860_TX_TXOP_HT; 3272203134Sthompsa else 3273208019Sthompsa txwi->txop |= RT2860_TX_TXOP_BACKOFF; 3274209144Sthompsa 3275209917Sthompsa if (vap->iv_opmode != IEEE80211_M_STA && !IEEE80211_QOS_HAS_SEQ(wh)) 3276209144Sthompsa txwi->xflags |= RT2860_TX_NSEQ; 3277203134Sthompsa} 3278203134Sthompsa 3279203134Sthompsa/* This function must be called locked */ 3280203134Sthompsastatic int 3281203134Sthompsarun_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) 3282203134Sthompsa{ 3283203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 3284208019Sthompsa struct ieee80211vap *vap = ni->ni_vap; 3285203134Sthompsa struct ieee80211_frame *wh; 3286208019Sthompsa struct ieee80211_channel *chan; 3287203134Sthompsa const struct ieee80211_txparam *tp; 3288208019Sthompsa struct run_node *rn = (void *)ni; 3289203134Sthompsa struct run_tx_data *data; 3290208019Sthompsa struct rt2870_txd *txd; 3291208019Sthompsa struct rt2860_txwi *txwi; 3292203134Sthompsa uint16_t qos; 3293203134Sthompsa uint16_t dur; 3294208019Sthompsa uint16_t qid; 3295203134Sthompsa uint8_t type; 3296203134Sthompsa uint8_t tid; 3297208019Sthompsa uint8_t ridx; 3298208019Sthompsa uint8_t ctl_ridx; 3299203134Sthompsa uint8_t qflags; 3300203134Sthompsa uint8_t xflags = 0; 3301203134Sthompsa int hasqos; 3302203134Sthompsa 3303203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3304203134Sthompsa 3305203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3306203134Sthompsa 3307203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3308203134Sthompsa 3309203134Sthompsa /* 3310203134Sthompsa * There are 7 bulk endpoints: 1 for RX 3311203134Sthompsa * and 6 for TX (4 EDCAs + HCCA + Prio). 3312203134Sthompsa * Update 03-14-2009: some devices like the Planex GW-US300MiniS 3313203134Sthompsa * seem to have only 4 TX bulk endpoints (Fukaumi Naoki). 3314203134Sthompsa */ 3315203134Sthompsa if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) { 3316203134Sthompsa uint8_t *frm; 3317203134Sthompsa 3318203134Sthompsa if(IEEE80211_HAS_ADDR4(wh)) 3319203134Sthompsa frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos; 3320203134Sthompsa else 3321203134Sthompsa frm =((struct ieee80211_qosframe *)wh)->i_qos; 3322203134Sthompsa 3323203134Sthompsa qos = le16toh(*(const uint16_t *)frm); 3324203134Sthompsa tid = qos & IEEE80211_QOS_TID; 3325203134Sthompsa qid = TID_TO_WME_AC(tid); 3326203134Sthompsa } else { 3327203134Sthompsa qos = 0; 3328203134Sthompsa tid = 0; 3329203134Sthompsa qid = WME_AC_BE; 3330203134Sthompsa } 3331203134Sthompsa qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA; 3332203134Sthompsa 3333203134Sthompsa DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n", 3334203134Sthompsa qos, qid, tid, qflags); 3335203134Sthompsa 3336208019Sthompsa chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan; 3337208019Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(chan)]; 3338203134Sthompsa 3339203134Sthompsa /* pickup a rate index */ 3340203134Sthompsa if (IEEE80211_IS_MULTICAST(wh->i_addr1) || 3341270192Skevlo type != IEEE80211_FC0_TYPE_DATA || m->m_flags & M_EAPOL) { 3342203134Sthompsa ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? 3343203134Sthompsa RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; 3344203134Sthompsa ctl_ridx = rt2860_rates[ridx].ctl_ridx; 3345203134Sthompsa } else { 3346208019Sthompsa if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) 3347208019Sthompsa ridx = rn->fix_ridx; 3348208019Sthompsa else 3349208019Sthompsa ridx = rn->amrr_ridx; 3350203134Sthompsa ctl_ridx = rt2860_rates[ridx].ctl_ridx; 3351203134Sthompsa } 3352203134Sthompsa 3353203134Sthompsa if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 3354203134Sthompsa (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) != 3355203134Sthompsa IEEE80211_QOS_ACKPOLICY_NOACK)) { 3356209144Sthompsa xflags |= RT2860_TX_ACK; 3357203134Sthompsa if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 3358208019Sthompsa dur = rt2860_rates[ctl_ridx].sp_ack_dur; 3359203134Sthompsa else 3360208019Sthompsa dur = rt2860_rates[ctl_ridx].lp_ack_dur; 3361258919Shselasky USETW(wh->i_dur, dur); 3362203134Sthompsa } 3363203134Sthompsa 3364203134Sthompsa /* reserve slots for mgmt packets, just in case */ 3365203134Sthompsa if (sc->sc_epq[qid].tx_nfree < 3) { 3366203134Sthompsa DPRINTFN(10, "tx ring %d is full\n", qid); 3367203134Sthompsa return (-1); 3368203134Sthompsa } 3369203134Sthompsa 3370203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh); 3371203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next); 3372203134Sthompsa sc->sc_epq[qid].tx_nfree--; 3373203134Sthompsa 3374208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3375208019Sthompsa txd->flags = qflags; 3376208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3377208019Sthompsa txwi->xflags = xflags; 3378259032Skevlo if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 3379245047Shselasky txwi->wcid = 0; 3380259032Skevlo else 3381245047Shselasky txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 3382245047Shselasky 1 : RUN_AID2WCID(ni->ni_associd); 3383259032Skevlo 3384208019Sthompsa /* clear leftover garbage bits */ 3385208019Sthompsa txwi->flags = 0; 3386208019Sthompsa txwi->txop = 0; 3387208019Sthompsa 3388203134Sthompsa data->m = m; 3389203134Sthompsa data->ni = ni; 3390203134Sthompsa data->ridx = ridx; 3391203134Sthompsa 3392208019Sthompsa run_set_tx_desc(sc, data); 3393203134Sthompsa 3394208019Sthompsa /* 3395208019Sthompsa * The chip keeps track of 2 kind of Tx stats, 3396208019Sthompsa * * TX_STAT_FIFO, for per WCID stats, and 3397208019Sthompsa * * TX_STA_CNT0 for all-TX-in-one stats. 3398208019Sthompsa * 3399208019Sthompsa * To use FIFO stats, we need to store MCS into the driver-private 3400208019Sthompsa * PacketID field. So that, we can tell whose stats when we read them. 3401208019Sthompsa * We add 1 to the MCS because setting the PacketID field to 0 means 3402208019Sthompsa * that we don't want feedback in TX_STAT_FIFO. 3403208019Sthompsa * And, that's what we want for STA mode, since TX_STA_CNT0 does the job. 3404208019Sthompsa * 3405208019Sthompsa * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx(). 3406208019Sthompsa */ 3407209917Sthompsa if (sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP || 3408209917Sthompsa vap->iv_opmode == IEEE80211_M_MBSS) { 3409208019Sthompsa uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf; 3410208019Sthompsa txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT); 3411208019Sthompsa 3412208019Sthompsa /* 3413208019Sthompsa * Unlike PCI based devices, we don't get any interrupt from 3414208019Sthompsa * USB devices, so we simulate FIFO-is-full interrupt here. 3415208019Sthompsa * Ralink recomends to drain FIFO stats every 100 ms, but 16 slots 3416208019Sthompsa * quickly get fulled. To prevent overflow, increment a counter on 3417208019Sthompsa * every FIFO stat request, so we know how many slots are left. 3418208019Sthompsa * We do this only in HOSTAP or multiple vap mode since FIFO stats 3419208019Sthompsa * are used only in those modes. 3420208019Sthompsa * We just drain stats. AMRR gets updated every 1 sec by 3421208019Sthompsa * run_ratectl_cb() via callout. 3422208019Sthompsa * Call it early. Otherwise overflow. 3423208019Sthompsa */ 3424209917Sthompsa if (sc->fifo_cnt++ == 10) { 3425208019Sthompsa /* 3426208019Sthompsa * With multiple vaps or if_bridge, if_start() is called 3427208019Sthompsa * with a non-sleepable lock, tcpinp. So, need to defer. 3428208019Sthompsa */ 3429208019Sthompsa uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 3430208019Sthompsa DPRINTFN(6, "cmdq_store=%d\n", i); 3431208019Sthompsa sc->cmdq[i].func = run_drain_fifo; 3432208019Sthompsa sc->cmdq[i].arg0 = sc; 3433208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 3434208019Sthompsa } 3435208019Sthompsa } 3436208019Sthompsa 3437203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next); 3438203134Sthompsa 3439203134Sthompsa usbd_transfer_start(sc->sc_xfer[qid]); 3440203134Sthompsa 3441258840Skevlo DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n", 3442259032Skevlo m->m_pkthdr.len + (int)(sizeof(struct rt2870_txd) + 3443259046Shselasky sizeof(struct rt2860_txwi)), rt2860_rates[ridx].rate, qid); 3444203134Sthompsa 3445203134Sthompsa return (0); 3446203134Sthompsa} 3447203134Sthompsa 3448203134Sthompsastatic int 3449203134Sthompsarun_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) 3450203134Sthompsa{ 3451203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 3452203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 3453208019Sthompsa struct run_node *rn = (void *)ni; 3454203134Sthompsa struct run_tx_data *data; 3455203134Sthompsa struct ieee80211_frame *wh; 3456208019Sthompsa struct rt2870_txd *txd; 3457208019Sthompsa struct rt2860_txwi *txwi; 3458203134Sthompsa uint16_t dur; 3459208019Sthompsa uint8_t ridx = rn->mgt_ridx; 3460203134Sthompsa uint8_t type; 3461203134Sthompsa uint8_t xflags = 0; 3462208019Sthompsa uint8_t wflags = 0; 3463203134Sthompsa 3464203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3465203134Sthompsa 3466203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3467203134Sthompsa 3468203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3469203134Sthompsa 3470208019Sthompsa /* tell hardware to add timestamp for probe responses */ 3471208019Sthompsa if ((wh->i_fc[0] & 3472208019Sthompsa (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == 3473208019Sthompsa (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) 3474208019Sthompsa wflags |= RT2860_TX_TS; 3475208019Sthompsa else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 3476203134Sthompsa xflags |= RT2860_TX_ACK; 3477203134Sthompsa 3478208019Sthompsa dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate, 3479203134Sthompsa ic->ic_flags & IEEE80211_F_SHPREAMBLE); 3480258919Shselasky USETW(wh->i_dur, dur); 3481203134Sthompsa } 3482203134Sthompsa 3483203134Sthompsa if (sc->sc_epq[0].tx_nfree == 0) { 3484203134Sthompsa /* let caller free mbuf */ 3485203134Sthompsa ifp->if_drv_flags |= IFF_DRV_OACTIVE; 3486203134Sthompsa return (EIO); 3487203134Sthompsa } 3488203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3489203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3490203134Sthompsa sc->sc_epq[0].tx_nfree--; 3491203134Sthompsa 3492208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3493208019Sthompsa txd->flags = RT2860_TX_QSEL_EDCA; 3494208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3495208019Sthompsa txwi->wcid = 0xff; 3496208019Sthompsa txwi->flags = wflags; 3497208019Sthompsa txwi->xflags = xflags; 3498208019Sthompsa txwi->txop = 0; /* clear leftover garbage bits */ 3499208019Sthompsa 3500203134Sthompsa data->m = m; 3501203134Sthompsa data->ni = ni; 3502203134Sthompsa data->ridx = ridx; 3503203134Sthompsa 3504208019Sthompsa run_set_tx_desc(sc, data); 3505203134Sthompsa 3506203134Sthompsa DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len + 3507258840Skevlo (int)(sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi)), 3508208019Sthompsa rt2860_rates[ridx].rate); 3509203134Sthompsa 3510203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3511203134Sthompsa 3512203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 3513203134Sthompsa 3514203134Sthompsa return (0); 3515203134Sthompsa} 3516203134Sthompsa 3517203134Sthompsastatic int 3518203134Sthompsarun_sendprot(struct run_softc *sc, 3519203134Sthompsa const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) 3520203134Sthompsa{ 3521203134Sthompsa struct ieee80211com *ic = ni->ni_ic; 3522203134Sthompsa struct ieee80211_frame *wh; 3523203134Sthompsa struct run_tx_data *data; 3524208019Sthompsa struct rt2870_txd *txd; 3525208019Sthompsa struct rt2860_txwi *txwi; 3526203134Sthompsa struct mbuf *mprot; 3527203134Sthompsa int ridx; 3528203134Sthompsa int protrate; 3529203134Sthompsa int ackrate; 3530203134Sthompsa int pktlen; 3531203134Sthompsa int isshort; 3532203134Sthompsa uint16_t dur; 3533203134Sthompsa uint8_t type; 3534208019Sthompsa uint8_t wflags = 0; 3535208019Sthompsa uint8_t xflags = 0; 3536203134Sthompsa 3537203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3538203134Sthompsa 3539203134Sthompsa KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, 3540203134Sthompsa ("protection %d", prot)); 3541203134Sthompsa 3542203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3543203134Sthompsa pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; 3544203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3545203134Sthompsa 3546203134Sthompsa protrate = ieee80211_ctl_rate(ic->ic_rt, rate); 3547203134Sthompsa ackrate = ieee80211_ack_rate(ic->ic_rt, rate); 3548203134Sthompsa 3549203134Sthompsa isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; 3550209189Sjkim dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort) 3551203134Sthompsa + ieee80211_ack_duration(ic->ic_rt, rate, isshort); 3552203134Sthompsa wflags = RT2860_TX_FRAG; 3553203134Sthompsa 3554203134Sthompsa /* check that there are free slots before allocating the mbuf */ 3555203134Sthompsa if (sc->sc_epq[0].tx_nfree == 0) { 3556203134Sthompsa /* let caller free mbuf */ 3557203134Sthompsa sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 3558203134Sthompsa return (ENOBUFS); 3559203134Sthompsa } 3560203134Sthompsa 3561203134Sthompsa if (prot == IEEE80211_PROT_RTSCTS) { 3562203134Sthompsa /* NB: CTS is the same size as an ACK */ 3563203134Sthompsa dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); 3564208019Sthompsa xflags |= RT2860_TX_ACK; 3565203134Sthompsa mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); 3566203134Sthompsa } else { 3567203134Sthompsa mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); 3568203134Sthompsa } 3569203134Sthompsa if (mprot == NULL) { 3570271866Sglebius if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1); 3571203134Sthompsa DPRINTF("could not allocate mbuf\n"); 3572203134Sthompsa return (ENOBUFS); 3573203134Sthompsa } 3574203134Sthompsa 3575203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3576203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3577203134Sthompsa sc->sc_epq[0].tx_nfree--; 3578203134Sthompsa 3579208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3580208019Sthompsa txd->flags = RT2860_TX_QSEL_EDCA; 3581208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3582208019Sthompsa txwi->wcid = 0xff; 3583208019Sthompsa txwi->flags = wflags; 3584208019Sthompsa txwi->xflags = xflags; 3585208019Sthompsa txwi->txop = 0; /* clear leftover garbage bits */ 3586208019Sthompsa 3587203134Sthompsa data->m = mprot; 3588203134Sthompsa data->ni = ieee80211_ref_node(ni); 3589203134Sthompsa 3590203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 3591203134Sthompsa if (rt2860_rates[ridx].rate == protrate) 3592203134Sthompsa break; 3593203134Sthompsa data->ridx = ridx; 3594203134Sthompsa 3595208019Sthompsa run_set_tx_desc(sc, data); 3596203134Sthompsa 3597203134Sthompsa DPRINTFN(1, "sending prot len=%u rate=%u\n", 3598203134Sthompsa m->m_pkthdr.len, rate); 3599203134Sthompsa 3600203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3601203134Sthompsa 3602203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 3603203134Sthompsa 3604203134Sthompsa return (0); 3605203134Sthompsa} 3606203134Sthompsa 3607203134Sthompsastatic int 3608203134Sthompsarun_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, 3609203134Sthompsa const struct ieee80211_bpf_params *params) 3610203134Sthompsa{ 3611203134Sthompsa struct ieee80211com *ic = ni->ni_ic; 3612203134Sthompsa struct ieee80211_frame *wh; 3613203134Sthompsa struct run_tx_data *data; 3614208019Sthompsa struct rt2870_txd *txd; 3615208019Sthompsa struct rt2860_txwi *txwi; 3616203134Sthompsa uint8_t type; 3617208019Sthompsa uint8_t ridx; 3618208019Sthompsa uint8_t rate; 3619208019Sthompsa uint8_t opflags = 0; 3620208019Sthompsa uint8_t xflags = 0; 3621203134Sthompsa int error; 3622203134Sthompsa 3623203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3624203134Sthompsa 3625203134Sthompsa KASSERT(params != NULL, ("no raw xmit params")); 3626203134Sthompsa 3627203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3628203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3629203134Sthompsa 3630203134Sthompsa rate = params->ibp_rate0; 3631203134Sthompsa if (!ieee80211_isratevalid(ic->ic_rt, rate)) { 3632203134Sthompsa /* let caller free mbuf */ 3633203134Sthompsa return (EINVAL); 3634203134Sthompsa } 3635203134Sthompsa 3636203134Sthompsa if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) 3637208019Sthompsa xflags |= RT2860_TX_ACK; 3638203134Sthompsa if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { 3639203134Sthompsa error = run_sendprot(sc, m, ni, 3640203134Sthompsa params->ibp_flags & IEEE80211_BPF_RTS ? 3641203134Sthompsa IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, 3642203134Sthompsa rate); 3643203134Sthompsa if (error) { 3644203134Sthompsa /* let caller free mbuf */ 3645209917Sthompsa return error; 3646203134Sthompsa } 3647203134Sthompsa opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS; 3648203134Sthompsa } 3649203134Sthompsa 3650203134Sthompsa if (sc->sc_epq[0].tx_nfree == 0) { 3651203134Sthompsa /* let caller free mbuf */ 3652203134Sthompsa sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 3653203134Sthompsa DPRINTF("sending raw frame, but tx ring is full\n"); 3654203134Sthompsa return (EIO); 3655203134Sthompsa } 3656203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3657203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3658203134Sthompsa sc->sc_epq[0].tx_nfree--; 3659203134Sthompsa 3660208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3661208019Sthompsa txd->flags = RT2860_TX_QSEL_EDCA; 3662208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3663208019Sthompsa txwi->wcid = 0xff; 3664208019Sthompsa txwi->xflags = xflags; 3665208019Sthompsa txwi->txop = opflags; 3666208019Sthompsa txwi->flags = 0; /* clear leftover garbage bits */ 3667208019Sthompsa 3668203134Sthompsa data->m = m; 3669203134Sthompsa data->ni = ni; 3670203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 3671203134Sthompsa if (rt2860_rates[ridx].rate == rate) 3672203134Sthompsa break; 3673203134Sthompsa data->ridx = ridx; 3674203134Sthompsa 3675208019Sthompsa run_set_tx_desc(sc, data); 3676203134Sthompsa 3677203134Sthompsa DPRINTFN(10, "sending raw frame len=%u rate=%u\n", 3678203134Sthompsa m->m_pkthdr.len, rate); 3679203134Sthompsa 3680203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3681203134Sthompsa 3682203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 3683203134Sthompsa 3684209917Sthompsa return (0); 3685203134Sthompsa} 3686203134Sthompsa 3687203134Sthompsastatic int 3688203134Sthompsarun_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 3689203134Sthompsa const struct ieee80211_bpf_params *params) 3690203134Sthompsa{ 3691203134Sthompsa struct ifnet *ifp = ni->ni_ic->ic_ifp; 3692203134Sthompsa struct run_softc *sc = ifp->if_softc; 3693208019Sthompsa int error = 0; 3694208019Sthompsa 3695203134Sthompsa RUN_LOCK(sc); 3696203134Sthompsa 3697203134Sthompsa /* prevent management frames from being sent if we're not ready */ 3698203134Sthompsa if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 3699203134Sthompsa error = ENETDOWN; 3700208019Sthompsa goto done; 3701203134Sthompsa } 3702203134Sthompsa 3703203134Sthompsa if (params == NULL) { 3704203134Sthompsa /* tx mgt packet */ 3705209917Sthompsa if ((error = run_tx_mgt(sc, m, ni)) != 0) { 3706271866Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 3707203134Sthompsa DPRINTF("mgt tx failed\n"); 3708208019Sthompsa goto done; 3709203134Sthompsa } 3710203134Sthompsa } else { 3711203134Sthompsa /* tx raw packet with param */ 3712209917Sthompsa if ((error = run_tx_param(sc, m, ni, params)) != 0) { 3713271866Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 3714203134Sthompsa DPRINTF("tx with param failed\n"); 3715208019Sthompsa goto done; 3716203134Sthompsa } 3717203134Sthompsa } 3718203134Sthompsa 3719271866Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 3720203134Sthompsa 3721208019Sthompsadone: 3722203134Sthompsa RUN_UNLOCK(sc); 3723203134Sthompsa 3724209917Sthompsa if (error != 0) { 3725208019Sthompsa if(m != NULL) 3726208019Sthompsa m_freem(m); 3727208019Sthompsa ieee80211_free_node(ni); 3728208019Sthompsa } 3729203134Sthompsa 3730203134Sthompsa return (error); 3731203134Sthompsa} 3732203134Sthompsa 3733203134Sthompsastatic void 3734203134Sthompsarun_start(struct ifnet *ifp) 3735203134Sthompsa{ 3736203134Sthompsa struct run_softc *sc = ifp->if_softc; 3737203134Sthompsa struct ieee80211_node *ni; 3738203134Sthompsa struct mbuf *m; 3739203134Sthompsa 3740203134Sthompsa RUN_LOCK(sc); 3741203134Sthompsa 3742203134Sthompsa if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 3743203134Sthompsa RUN_UNLOCK(sc); 3744203134Sthompsa return; 3745203134Sthompsa } 3746203134Sthompsa 3747203134Sthompsa for (;;) { 3748203134Sthompsa /* send data frames */ 3749203134Sthompsa IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 3750203134Sthompsa if (m == NULL) 3751203134Sthompsa break; 3752203134Sthompsa 3753203134Sthompsa ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 3754203134Sthompsa if (run_tx(sc, m, ni) != 0) { 3755203134Sthompsa IFQ_DRV_PREPEND(&ifp->if_snd, m); 3756203134Sthompsa ifp->if_drv_flags |= IFF_DRV_OACTIVE; 3757203134Sthompsa break; 3758203134Sthompsa } 3759203134Sthompsa } 3760203134Sthompsa 3761203134Sthompsa RUN_UNLOCK(sc); 3762203134Sthompsa} 3763203134Sthompsa 3764203134Sthompsastatic int 3765203134Sthompsarun_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 3766203134Sthompsa{ 3767203134Sthompsa struct run_softc *sc = ifp->if_softc; 3768203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 3769203134Sthompsa struct ifreq *ifr = (struct ifreq *) data; 3770208019Sthompsa int startall = 0; 3771246614Shselasky int error; 3772203134Sthompsa 3773246614Shselasky RUN_LOCK(sc); 3774246614Shselasky error = sc->sc_detached ? ENXIO : 0; 3775246614Shselasky RUN_UNLOCK(sc); 3776246614Shselasky if (error) 3777246614Shselasky return (error); 3778246614Shselasky 3779203134Sthompsa switch (cmd) { 3780203134Sthompsa case SIOCSIFFLAGS: 3781203134Sthompsa RUN_LOCK(sc); 3782203134Sthompsa if (ifp->if_flags & IFF_UP) { 3783203134Sthompsa if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)){ 3784208019Sthompsa startall = 1; 3785203134Sthompsa run_init_locked(sc); 3786203134Sthompsa } else 3787203134Sthompsa run_update_promisc_locked(ifp); 3788203134Sthompsa } else { 3789209917Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING && 3790209917Sthompsa (ic->ic_nrunning == 0 || sc->rvp_cnt <= 1)) { 3791208019Sthompsa run_stop(sc); 3792208019Sthompsa } 3793203134Sthompsa } 3794203134Sthompsa RUN_UNLOCK(sc); 3795209917Sthompsa if (startall) 3796208019Sthompsa ieee80211_start_all(ic); 3797203134Sthompsa break; 3798203134Sthompsa case SIOCGIFMEDIA: 3799203134Sthompsa error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); 3800203134Sthompsa break; 3801203134Sthompsa case SIOCGIFADDR: 3802203134Sthompsa error = ether_ioctl(ifp, cmd, data); 3803203134Sthompsa break; 3804203134Sthompsa default: 3805203134Sthompsa error = EINVAL; 3806203134Sthompsa break; 3807203134Sthompsa } 3808203134Sthompsa 3809203134Sthompsa return (error); 3810203134Sthompsa} 3811203134Sthompsa 3812203134Sthompsastatic void 3813259544Skevlorun_iq_calib(struct run_softc *sc, u_int chan) 3814259544Skevlo{ 3815259544Skevlo uint16_t val; 3816259544Skevlo 3817259544Skevlo /* Tx0 IQ gain. */ 3818259544Skevlo run_bbp_write(sc, 158, 0x2c); 3819259544Skevlo if (chan <= 14) 3820259544Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX0_2GHZ, &val, 1); 3821259544Skevlo else if (chan <= 64) { 3822259544Skevlo run_efuse_read(sc, 3823259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5GHZ, 3824259544Skevlo &val, 1); 3825259544Skevlo } else if (chan <= 138) { 3826259544Skevlo run_efuse_read(sc, 3827259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5GHZ, 3828259544Skevlo &val, 1); 3829259544Skevlo } else if (chan <= 165) { 3830259544Skevlo run_efuse_read(sc, 3831259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5GHZ, 3832259544Skevlo &val, 1); 3833259544Skevlo } else 3834259544Skevlo val = 0; 3835259547Skevlo run_bbp_write(sc, 159, val); 3836259544Skevlo 3837259544Skevlo /* Tx0 IQ phase. */ 3838259544Skevlo run_bbp_write(sc, 158, 0x2d); 3839259544Skevlo if (chan <= 14) { 3840259544Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX0_2GHZ, 3841259544Skevlo &val, 1); 3842259544Skevlo } else if (chan <= 64) { 3843259544Skevlo run_efuse_read(sc, 3844259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5GHZ, 3845259544Skevlo &val, 1); 3846259544Skevlo } else if (chan <= 138) { 3847259544Skevlo run_efuse_read(sc, 3848259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5GHZ, 3849259544Skevlo &val, 1); 3850259544Skevlo } else if (chan <= 165) { 3851259544Skevlo run_efuse_read(sc, 3852259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5GHZ, 3853259544Skevlo &val, 1); 3854259544Skevlo } else 3855259544Skevlo val = 0; 3856259547Skevlo run_bbp_write(sc, 159, val); 3857259544Skevlo 3858259544Skevlo /* Tx1 IQ gain. */ 3859259544Skevlo run_bbp_write(sc, 158, 0x4a); 3860259544Skevlo if (chan <= 14) { 3861259544Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX1_2GHZ, 3862259544Skevlo &val, 1); 3863259544Skevlo } else if (chan <= 64) { 3864259544Skevlo run_efuse_read(sc, 3865259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5GHZ, 3866259544Skevlo &val, 1); 3867259544Skevlo } else if (chan <= 138) { 3868259544Skevlo run_efuse_read(sc, 3869259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5GHZ, 3870259544Skevlo &val, 1); 3871259544Skevlo } else if (chan <= 165) { 3872259544Skevlo run_efuse_read(sc, 3873259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5GHZ, 3874259544Skevlo &val, 1); 3875259544Skevlo } else 3876259544Skevlo val = 0; 3877259547Skevlo run_bbp_write(sc, 159, val); 3878259544Skevlo 3879259544Skevlo /* Tx1 IQ phase. */ 3880259544Skevlo run_bbp_write(sc, 158, 0x4b); 3881259544Skevlo if (chan <= 14) { 3882259544Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX1_2GHZ, 3883259544Skevlo &val, 1); 3884259544Skevlo } else if (chan <= 64) { 3885259544Skevlo run_efuse_read(sc, 3886259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5GHZ, 3887259544Skevlo &val, 1); 3888259544Skevlo } else if (chan <= 138) { 3889259544Skevlo run_efuse_read(sc, 3890259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5GHZ, 3891259544Skevlo &val, 1); 3892259544Skevlo } else if (chan <= 165) { 3893259544Skevlo run_efuse_read(sc, 3894259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5GHZ, 3895259544Skevlo &val, 1); 3896259544Skevlo } else 3897259544Skevlo val = 0; 3898259547Skevlo run_bbp_write(sc, 159, val); 3899259544Skevlo 3900259544Skevlo /* RF IQ compensation control. */ 3901259544Skevlo run_bbp_write(sc, 158, 0x04); 3902259544Skevlo run_efuse_read(sc, RT5390_EEPROM_RF_IQ_COMPENSATION_CTL, 3903259544Skevlo &val, 1); 3904259547Skevlo run_bbp_write(sc, 159, val); 3905259544Skevlo 3906259544Skevlo /* RF IQ imbalance compensation control. */ 3907259544Skevlo run_bbp_write(sc, 158, 0x03); 3908259544Skevlo run_efuse_read(sc, 3909259544Skevlo RT5390_EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CTL, &val, 1); 3910259547Skevlo run_bbp_write(sc, 159, val); 3911259544Skevlo} 3912259544Skevlo 3913259544Skevlostatic void 3914205042Sthompsarun_set_agc(struct run_softc *sc, uint8_t agc) 3915205042Sthompsa{ 3916205042Sthompsa uint8_t bbp; 3917205042Sthompsa 3918205042Sthompsa if (sc->mac_ver == 0x3572) { 3919205042Sthompsa run_bbp_read(sc, 27, &bbp); 3920205042Sthompsa bbp &= ~(0x3 << 5); 3921205042Sthompsa run_bbp_write(sc, 27, bbp | 0 << 5); /* select Rx0 */ 3922205042Sthompsa run_bbp_write(sc, 66, agc); 3923205042Sthompsa run_bbp_write(sc, 27, bbp | 1 << 5); /* select Rx1 */ 3924205042Sthompsa run_bbp_write(sc, 66, agc); 3925205042Sthompsa } else 3926205042Sthompsa run_bbp_write(sc, 66, agc); 3927205042Sthompsa} 3928205042Sthompsa 3929205042Sthompsastatic void 3930203134Sthompsarun_select_chan_group(struct run_softc *sc, int group) 3931203134Sthompsa{ 3932203134Sthompsa uint32_t tmp; 3933205042Sthompsa uint8_t agc; 3934203134Sthompsa 3935203134Sthompsa run_bbp_write(sc, 62, 0x37 - sc->lna[group]); 3936203134Sthompsa run_bbp_write(sc, 63, 0x37 - sc->lna[group]); 3937203134Sthompsa run_bbp_write(sc, 64, 0x37 - sc->lna[group]); 3938258082Skevlo if (sc->mac_ver < 0x3572) 3939257955Skevlo run_bbp_write(sc, 86, 0x00); 3940203134Sthompsa 3941260219Skevlo if (sc->mac_ver == 0x3593) { 3942260219Skevlo run_bbp_write(sc, 77, 0x98); 3943260219Skevlo run_bbp_write(sc, 83, (group == 0) ? 0x8a : 0x9a); 3944260219Skevlo } 3945260219Skevlo 3946203134Sthompsa if (group == 0) { 3947203134Sthompsa if (sc->ext_2ghz_lna) { 3948257955Skevlo if (sc->mac_ver >= 0x5390) 3949257955Skevlo run_bbp_write(sc, 75, 0x52); 3950257955Skevlo else { 3951257955Skevlo run_bbp_write(sc, 82, 0x62); 3952257955Skevlo run_bbp_write(sc, 75, 0x46); 3953257955Skevlo } 3954203134Sthompsa } else { 3955259032Skevlo if (sc->mac_ver == 0x5592) { 3956259032Skevlo run_bbp_write(sc, 79, 0x1c); 3957259032Skevlo run_bbp_write(sc, 80, 0x0e); 3958259032Skevlo run_bbp_write(sc, 81, 0x3a); 3959259032Skevlo run_bbp_write(sc, 82, 0x62); 3960259032Skevlo 3961259032Skevlo run_bbp_write(sc, 195, 0x80); 3962259032Skevlo run_bbp_write(sc, 196, 0xe0); 3963259032Skevlo run_bbp_write(sc, 195, 0x81); 3964259032Skevlo run_bbp_write(sc, 196, 0x1f); 3965259032Skevlo run_bbp_write(sc, 195, 0x82); 3966259032Skevlo run_bbp_write(sc, 196, 0x38); 3967259032Skevlo run_bbp_write(sc, 195, 0x83); 3968259032Skevlo run_bbp_write(sc, 196, 0x32); 3969259032Skevlo run_bbp_write(sc, 195, 0x85); 3970259032Skevlo run_bbp_write(sc, 196, 0x28); 3971259032Skevlo run_bbp_write(sc, 195, 0x86); 3972259032Skevlo run_bbp_write(sc, 196, 0x19); 3973259032Skevlo } else if (sc->mac_ver >= 0x5390) 3974257955Skevlo run_bbp_write(sc, 75, 0x50); 3975257955Skevlo else { 3976260219Skevlo run_bbp_write(sc, 82, 3977260219Skevlo (sc->mac_ver == 0x3593) ? 0x62 : 0x84); 3978257955Skevlo run_bbp_write(sc, 75, 0x50); 3979257955Skevlo } 3980203134Sthompsa } 3981203134Sthompsa } else { 3982259032Skevlo if (sc->mac_ver == 0x5592) { 3983259032Skevlo run_bbp_write(sc, 79, 0x18); 3984259032Skevlo run_bbp_write(sc, 80, 0x08); 3985259032Skevlo run_bbp_write(sc, 81, 0x38); 3986259032Skevlo run_bbp_write(sc, 82, 0x92); 3987259032Skevlo 3988259032Skevlo run_bbp_write(sc, 195, 0x80); 3989259032Skevlo run_bbp_write(sc, 196, 0xf0); 3990259032Skevlo run_bbp_write(sc, 195, 0x81); 3991259032Skevlo run_bbp_write(sc, 196, 0x1e); 3992259032Skevlo run_bbp_write(sc, 195, 0x82); 3993259032Skevlo run_bbp_write(sc, 196, 0x28); 3994259032Skevlo run_bbp_write(sc, 195, 0x83); 3995259032Skevlo run_bbp_write(sc, 196, 0x20); 3996259032Skevlo run_bbp_write(sc, 195, 0x85); 3997259032Skevlo run_bbp_write(sc, 196, 0x7f); 3998259032Skevlo run_bbp_write(sc, 195, 0x86); 3999259032Skevlo run_bbp_write(sc, 196, 0x7f); 4000259032Skevlo } else if (sc->mac_ver == 0x3572) 4001205042Sthompsa run_bbp_write(sc, 82, 0x94); 4002205042Sthompsa else 4003260219Skevlo run_bbp_write(sc, 82, 4004260219Skevlo (sc->mac_ver == 0x3593) ? 0x82 : 0xf2); 4005205042Sthompsa if (sc->ext_5ghz_lna) 4006203134Sthompsa run_bbp_write(sc, 75, 0x46); 4007205042Sthompsa else 4008203134Sthompsa run_bbp_write(sc, 75, 0x50); 4009203134Sthompsa } 4010203134Sthompsa 4011203134Sthompsa run_read(sc, RT2860_TX_BAND_CFG, &tmp); 4012203134Sthompsa tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P); 4013203134Sthompsa tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P; 4014203134Sthompsa run_write(sc, RT2860_TX_BAND_CFG, tmp); 4015203134Sthompsa 4016203134Sthompsa /* enable appropriate Power Amplifiers and Low Noise Amplifiers */ 4017208019Sthompsa tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN; 4018260219Skevlo if (sc->mac_ver == 0x3593) 4019260219Skevlo tmp |= 1 << 29 | 1 << 28; 4020208019Sthompsa if (sc->nrxchains > 1) 4021208019Sthompsa tmp |= RT2860_LNA_PE1_EN; 4022203134Sthompsa if (group == 0) { /* 2GHz */ 4023208019Sthompsa tmp |= RT2860_PA_PE_G0_EN; 4024203134Sthompsa if (sc->ntxchains > 1) 4025203134Sthompsa tmp |= RT2860_PA_PE_G1_EN; 4026260219Skevlo if (sc->mac_ver == 0x3593) { 4027260219Skevlo if (sc->ntxchains > 2) 4028260219Skevlo tmp |= 1 << 25; 4029260219Skevlo } 4030203134Sthompsa } else { /* 5GHz */ 4031208019Sthompsa tmp |= RT2860_PA_PE_A0_EN; 4032203134Sthompsa if (sc->ntxchains > 1) 4033203134Sthompsa tmp |= RT2860_PA_PE_A1_EN; 4034203134Sthompsa } 4035205042Sthompsa if (sc->mac_ver == 0x3572) { 4036205042Sthompsa run_rt3070_rf_write(sc, 8, 0x00); 4037205042Sthompsa run_write(sc, RT2860_TX_PIN_CFG, tmp); 4038205042Sthompsa run_rt3070_rf_write(sc, 8, 0x80); 4039205042Sthompsa } else 4040205042Sthompsa run_write(sc, RT2860_TX_PIN_CFG, tmp); 4041203134Sthompsa 4042259032Skevlo if (sc->mac_ver == 0x5592) { 4043259032Skevlo run_bbp_write(sc, 195, 0x8d); 4044259032Skevlo run_bbp_write(sc, 196, 0x1a); 4045259032Skevlo } 4046259032Skevlo 4047260219Skevlo if (sc->mac_ver == 0x3593) { 4048260219Skevlo run_read(sc, RT2860_GPIO_CTRL, &tmp); 4049260219Skevlo tmp &= ~0x01010000; 4050260219Skevlo if (group == 0) 4051260219Skevlo tmp |= 0x00010000; 4052260219Skevlo tmp = (tmp & ~0x00009090) | 0x00000090; 4053260219Skevlo run_write(sc, RT2860_GPIO_CTRL, tmp); 4054260219Skevlo } 4055260219Skevlo 4056203134Sthompsa /* set initial AGC value */ 4057205042Sthompsa if (group == 0) { /* 2GHz band */ 4058205042Sthompsa if (sc->mac_ver >= 0x3070) 4059205042Sthompsa agc = 0x1c + sc->lna[0] * 2; 4060205042Sthompsa else 4061205042Sthompsa agc = 0x2e + sc->lna[0]; 4062205042Sthompsa } else { /* 5GHz band */ 4063259032Skevlo if (sc->mac_ver == 0x5592) 4064259032Skevlo agc = 0x24 + sc->lna[group] * 2; 4065260219Skevlo else if (sc->mac_ver == 0x3572 || sc->mac_ver == 0x3593) 4066205042Sthompsa agc = 0x22 + (sc->lna[group] * 5) / 3; 4067205042Sthompsa else 4068205042Sthompsa agc = 0x32 + (sc->lna[group] * 5) / 3; 4069205042Sthompsa } 4070205042Sthompsa run_set_agc(sc, agc); 4071203134Sthompsa} 4072203134Sthompsa 4073203134Sthompsastatic void 4074257429Shselaskyrun_rt2870_set_chan(struct run_softc *sc, u_int chan) 4075203134Sthompsa{ 4076203134Sthompsa const struct rfprog *rfprog = rt2860_rf2850; 4077203134Sthompsa uint32_t r2, r3, r4; 4078203134Sthompsa int8_t txpow1, txpow2; 4079203134Sthompsa int i; 4080203134Sthompsa 4081203134Sthompsa /* find the settings for this channel (we know it exists) */ 4082203134Sthompsa for (i = 0; rfprog[i].chan != chan; i++); 4083203134Sthompsa 4084203134Sthompsa r2 = rfprog[i].r2; 4085203134Sthompsa if (sc->ntxchains == 1) 4086258732Skevlo r2 |= 1 << 14; /* 1T: disable Tx chain 2 */ 4087203134Sthompsa if (sc->nrxchains == 1) 4088258732Skevlo r2 |= 1 << 17 | 1 << 6; /* 1R: disable Rx chains 2 & 3 */ 4089203134Sthompsa else if (sc->nrxchains == 2) 4090258732Skevlo r2 |= 1 << 6; /* 2R: disable Rx chain 3 */ 4091203134Sthompsa 4092203134Sthompsa /* use Tx power values from EEPROM */ 4093203134Sthompsa txpow1 = sc->txpow1[i]; 4094203134Sthompsa txpow2 = sc->txpow2[i]; 4095258732Skevlo 4096258732Skevlo /* Initialize RF R3 and R4. */ 4097258732Skevlo r3 = rfprog[i].r3 & 0xffffc1ff; 4098258732Skevlo r4 = (rfprog[i].r4 & ~(0x001f87c0)) | (sc->freq << 15); 4099203134Sthompsa if (chan > 14) { 4100258732Skevlo if (txpow1 >= 0) { 4101258732Skevlo txpow1 = (txpow1 > 0xf) ? (0xf) : (txpow1); 4102258732Skevlo r3 |= (txpow1 << 10) | (1 << 9); 4103258732Skevlo } else { 4104258732Skevlo txpow1 += 7; 4105258732Skevlo 4106258732Skevlo /* txpow1 is not possible larger than 15. */ 4107258732Skevlo r3 |= (txpow1 << 10); 4108258732Skevlo } 4109258732Skevlo if (txpow2 >= 0) { 4110258732Skevlo txpow2 = (txpow2 > 0xf) ? (0xf) : (txpow2); 4111258921Shselasky r4 |= (txpow2 << 7) | (1 << 6); 4112258732Skevlo } else { 4113258732Skevlo txpow2 += 7; 4114258732Skevlo r4 |= (txpow2 << 7); 4115258732Skevlo } 4116258732Skevlo } else { 4117258732Skevlo /* Set Tx0 power. */ 4118258732Skevlo r3 |= (txpow1 << 9); 4119258732Skevlo 4120258732Skevlo /* Set frequency offset and Tx1 power. */ 4121258732Skevlo r4 |= (txpow2 << 6); 4122203134Sthompsa } 4123203134Sthompsa 4124258733Skevlo run_rt2870_rf_write(sc, rfprog[i].r1); 4125258733Skevlo run_rt2870_rf_write(sc, r2); 4126258733Skevlo run_rt2870_rf_write(sc, r3 & ~(1 << 2)); 4127258733Skevlo run_rt2870_rf_write(sc, r4); 4128203134Sthompsa 4129203134Sthompsa run_delay(sc, 10); 4130203134Sthompsa 4131258733Skevlo run_rt2870_rf_write(sc, rfprog[i].r1); 4132258733Skevlo run_rt2870_rf_write(sc, r2); 4133258733Skevlo run_rt2870_rf_write(sc, r3 | (1 << 2)); 4134258733Skevlo run_rt2870_rf_write(sc, r4); 4135203134Sthompsa 4136203134Sthompsa run_delay(sc, 10); 4137203134Sthompsa 4138258733Skevlo run_rt2870_rf_write(sc, rfprog[i].r1); 4139258733Skevlo run_rt2870_rf_write(sc, r2); 4140258733Skevlo run_rt2870_rf_write(sc, r3 & ~(1 << 2)); 4141258733Skevlo run_rt2870_rf_write(sc, r4); 4142203134Sthompsa} 4143203134Sthompsa 4144203134Sthompsastatic void 4145257429Shselaskyrun_rt3070_set_chan(struct run_softc *sc, u_int chan) 4146203134Sthompsa{ 4147203134Sthompsa int8_t txpow1, txpow2; 4148203134Sthompsa uint8_t rf; 4149205042Sthompsa int i; 4150203134Sthompsa 4151205042Sthompsa /* find the settings for this channel (we know it exists) */ 4152205042Sthompsa for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4153205042Sthompsa 4154203134Sthompsa /* use Tx power values from EEPROM */ 4155205042Sthompsa txpow1 = sc->txpow1[i]; 4156205042Sthompsa txpow2 = sc->txpow2[i]; 4157203134Sthompsa 4158205042Sthompsa run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n); 4159256720Skevlo 4160256720Skevlo /* RT3370/RT3390: RF R3 [7:4] is not reserved bits. */ 4161256720Skevlo run_rt3070_rf_read(sc, 3, &rf); 4162256720Skevlo rf = (rf & ~0x0f) | rt3070_freqs[i].k; 4163256720Skevlo run_rt3070_rf_write(sc, 3, rf); 4164256720Skevlo 4165203134Sthompsa run_rt3070_rf_read(sc, 6, &rf); 4166205042Sthompsa rf = (rf & ~0x03) | rt3070_freqs[i].r; 4167203134Sthompsa run_rt3070_rf_write(sc, 6, rf); 4168203134Sthompsa 4169203134Sthompsa /* set Tx0 power */ 4170203134Sthompsa run_rt3070_rf_read(sc, 12, &rf); 4171203134Sthompsa rf = (rf & ~0x1f) | txpow1; 4172203134Sthompsa run_rt3070_rf_write(sc, 12, rf); 4173203134Sthompsa 4174203134Sthompsa /* set Tx1 power */ 4175203134Sthompsa run_rt3070_rf_read(sc, 13, &rf); 4176203134Sthompsa rf = (rf & ~0x1f) | txpow2; 4177203134Sthompsa run_rt3070_rf_write(sc, 13, rf); 4178203134Sthompsa 4179203134Sthompsa run_rt3070_rf_read(sc, 1, &rf); 4180203134Sthompsa rf &= ~0xfc; 4181203134Sthompsa if (sc->ntxchains == 1) 4182203134Sthompsa rf |= 1 << 7 | 1 << 5; /* 1T: disable Tx chains 2 & 3 */ 4183203134Sthompsa else if (sc->ntxchains == 2) 4184203134Sthompsa rf |= 1 << 7; /* 2T: disable Tx chain 3 */ 4185203134Sthompsa if (sc->nrxchains == 1) 4186203134Sthompsa rf |= 1 << 6 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 4187203134Sthompsa else if (sc->nrxchains == 2) 4188203134Sthompsa rf |= 1 << 6; /* 2R: disable Rx chain 3 */ 4189203134Sthompsa run_rt3070_rf_write(sc, 1, rf); 4190203134Sthompsa 4191203134Sthompsa /* set RF offset */ 4192203134Sthompsa run_rt3070_rf_read(sc, 23, &rf); 4193203134Sthompsa rf = (rf & ~0x7f) | sc->freq; 4194203134Sthompsa run_rt3070_rf_write(sc, 23, rf); 4195203134Sthompsa 4196203134Sthompsa /* program RF filter */ 4197205042Sthompsa run_rt3070_rf_read(sc, 24, &rf); /* Tx */ 4198205042Sthompsa rf = (rf & ~0x3f) | sc->rf24_20mhz; 4199205042Sthompsa run_rt3070_rf_write(sc, 24, rf); 4200205042Sthompsa run_rt3070_rf_read(sc, 31, &rf); /* Rx */ 4201205042Sthompsa rf = (rf & ~0x3f) | sc->rf24_20mhz; 4202205042Sthompsa run_rt3070_rf_write(sc, 31, rf); 4203203134Sthompsa 4204203134Sthompsa /* enable RF tuning */ 4205203134Sthompsa run_rt3070_rf_read(sc, 7, &rf); 4206203134Sthompsa run_rt3070_rf_write(sc, 7, rf | 0x01); 4207203134Sthompsa} 4208203134Sthompsa 4209203134Sthompsastatic void 4210205042Sthompsarun_rt3572_set_chan(struct run_softc *sc, u_int chan) 4211205042Sthompsa{ 4212205042Sthompsa int8_t txpow1, txpow2; 4213205042Sthompsa uint32_t tmp; 4214205042Sthompsa uint8_t rf; 4215205042Sthompsa int i; 4216205042Sthompsa 4217205042Sthompsa /* find the settings for this channel (we know it exists) */ 4218205042Sthompsa for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4219205042Sthompsa 4220205042Sthompsa /* use Tx power values from EEPROM */ 4221205042Sthompsa txpow1 = sc->txpow1[i]; 4222205042Sthompsa txpow2 = sc->txpow2[i]; 4223205042Sthompsa 4224205042Sthompsa if (chan <= 14) { 4225205042Sthompsa run_bbp_write(sc, 25, sc->bbp25); 4226205042Sthompsa run_bbp_write(sc, 26, sc->bbp26); 4227205042Sthompsa } else { 4228205042Sthompsa /* enable IQ phase correction */ 4229205042Sthompsa run_bbp_write(sc, 25, 0x09); 4230205042Sthompsa run_bbp_write(sc, 26, 0xff); 4231205042Sthompsa } 4232205042Sthompsa 4233205042Sthompsa run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n); 4234205042Sthompsa run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k); 4235205042Sthompsa run_rt3070_rf_read(sc, 6, &rf); 4236205042Sthompsa rf = (rf & ~0x0f) | rt3070_freqs[i].r; 4237205042Sthompsa rf |= (chan <= 14) ? 0x08 : 0x04; 4238205042Sthompsa run_rt3070_rf_write(sc, 6, rf); 4239205042Sthompsa 4240205042Sthompsa /* set PLL mode */ 4241205042Sthompsa run_rt3070_rf_read(sc, 5, &rf); 4242205042Sthompsa rf &= ~(0x08 | 0x04); 4243205042Sthompsa rf |= (chan <= 14) ? 0x04 : 0x08; 4244205042Sthompsa run_rt3070_rf_write(sc, 5, rf); 4245205042Sthompsa 4246205042Sthompsa /* set Tx power for chain 0 */ 4247205042Sthompsa if (chan <= 14) 4248205042Sthompsa rf = 0x60 | txpow1; 4249205042Sthompsa else 4250205042Sthompsa rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3); 4251205042Sthompsa run_rt3070_rf_write(sc, 12, rf); 4252205042Sthompsa 4253205042Sthompsa /* set Tx power for chain 1 */ 4254205042Sthompsa if (chan <= 14) 4255205042Sthompsa rf = 0x60 | txpow2; 4256205042Sthompsa else 4257205042Sthompsa rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3); 4258205042Sthompsa run_rt3070_rf_write(sc, 13, rf); 4259205042Sthompsa 4260205042Sthompsa /* set Tx/Rx streams */ 4261205042Sthompsa run_rt3070_rf_read(sc, 1, &rf); 4262205042Sthompsa rf &= ~0xfc; 4263205042Sthompsa if (sc->ntxchains == 1) 4264205042Sthompsa rf |= 1 << 7 | 1 << 5; /* 1T: disable Tx chains 2 & 3 */ 4265205042Sthompsa else if (sc->ntxchains == 2) 4266205042Sthompsa rf |= 1 << 7; /* 2T: disable Tx chain 3 */ 4267205042Sthompsa if (sc->nrxchains == 1) 4268205042Sthompsa rf |= 1 << 6 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 4269205042Sthompsa else if (sc->nrxchains == 2) 4270205042Sthompsa rf |= 1 << 6; /* 2R: disable Rx chain 3 */ 4271205042Sthompsa run_rt3070_rf_write(sc, 1, rf); 4272205042Sthompsa 4273205042Sthompsa /* set RF offset */ 4274205042Sthompsa run_rt3070_rf_read(sc, 23, &rf); 4275205042Sthompsa rf = (rf & ~0x7f) | sc->freq; 4276205042Sthompsa run_rt3070_rf_write(sc, 23, rf); 4277205042Sthompsa 4278205042Sthompsa /* program RF filter */ 4279205042Sthompsa rf = sc->rf24_20mhz; 4280205042Sthompsa run_rt3070_rf_write(sc, 24, rf); /* Tx */ 4281205042Sthompsa run_rt3070_rf_write(sc, 31, rf); /* Rx */ 4282205042Sthompsa 4283205042Sthompsa /* enable RF tuning */ 4284205042Sthompsa run_rt3070_rf_read(sc, 7, &rf); 4285205042Sthompsa rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14); 4286205042Sthompsa run_rt3070_rf_write(sc, 7, rf); 4287205042Sthompsa 4288205042Sthompsa /* TSSI */ 4289205042Sthompsa rf = (chan <= 14) ? 0xc3 : 0xc0; 4290205042Sthompsa run_rt3070_rf_write(sc, 9, rf); 4291205042Sthompsa 4292205042Sthompsa /* set loop filter 1 */ 4293205042Sthompsa run_rt3070_rf_write(sc, 10, 0xf1); 4294205042Sthompsa /* set loop filter 2 */ 4295205042Sthompsa run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00); 4296205042Sthompsa 4297205042Sthompsa /* set tx_mx2_ic */ 4298205042Sthompsa run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43); 4299205042Sthompsa /* set tx_mx1_ic */ 4300205042Sthompsa if (chan <= 14) 4301205042Sthompsa rf = 0x48 | sc->txmixgain_2ghz; 4302205042Sthompsa else 4303205042Sthompsa rf = 0x78 | sc->txmixgain_5ghz; 4304205042Sthompsa run_rt3070_rf_write(sc, 16, rf); 4305205042Sthompsa 4306205042Sthompsa /* set tx_lo1 */ 4307205042Sthompsa run_rt3070_rf_write(sc, 17, 0x23); 4308205042Sthompsa /* set tx_lo2 */ 4309205042Sthompsa if (chan <= 14) 4310205042Sthompsa rf = 0x93; 4311205042Sthompsa else if (chan <= 64) 4312205042Sthompsa rf = 0xb7; 4313205042Sthompsa else if (chan <= 128) 4314205042Sthompsa rf = 0x74; 4315205042Sthompsa else 4316205042Sthompsa rf = 0x72; 4317205042Sthompsa run_rt3070_rf_write(sc, 19, rf); 4318205042Sthompsa 4319205042Sthompsa /* set rx_lo1 */ 4320205042Sthompsa if (chan <= 14) 4321205042Sthompsa rf = 0xb3; 4322205042Sthompsa else if (chan <= 64) 4323205042Sthompsa rf = 0xf6; 4324205042Sthompsa else if (chan <= 128) 4325205042Sthompsa rf = 0xf4; 4326205042Sthompsa else 4327205042Sthompsa rf = 0xf3; 4328205042Sthompsa run_rt3070_rf_write(sc, 20, rf); 4329205042Sthompsa 4330205042Sthompsa /* set pfd_delay */ 4331205042Sthompsa if (chan <= 14) 4332205042Sthompsa rf = 0x15; 4333205042Sthompsa else if (chan <= 64) 4334205042Sthompsa rf = 0x3d; 4335205042Sthompsa else 4336205042Sthompsa rf = 0x01; 4337205042Sthompsa run_rt3070_rf_write(sc, 25, rf); 4338205042Sthompsa 4339205042Sthompsa /* set rx_lo2 */ 4340205042Sthompsa run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87); 4341205042Sthompsa /* set ldo_rf_vc */ 4342205042Sthompsa run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01); 4343205042Sthompsa /* set drv_cc */ 4344205042Sthompsa run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f); 4345205042Sthompsa 4346205042Sthompsa run_read(sc, RT2860_GPIO_CTRL, &tmp); 4347205042Sthompsa tmp &= ~0x8080; 4348205042Sthompsa if (chan <= 14) 4349205042Sthompsa tmp |= 0x80; 4350205042Sthompsa run_write(sc, RT2860_GPIO_CTRL, tmp); 4351205042Sthompsa 4352205042Sthompsa /* enable RF tuning */ 4353205042Sthompsa run_rt3070_rf_read(sc, 7, &rf); 4354205042Sthompsa run_rt3070_rf_write(sc, 7, rf | 0x01); 4355205042Sthompsa 4356205042Sthompsa run_delay(sc, 2); 4357205042Sthompsa} 4358205042Sthompsa 4359205042Sthompsastatic void 4360260219Skevlorun_rt3593_set_chan(struct run_softc *sc, u_int chan) 4361260219Skevlo{ 4362260219Skevlo int8_t txpow1, txpow2, txpow3; 4363260219Skevlo uint8_t h20mhz, rf; 4364260219Skevlo int i; 4365260219Skevlo 4366260219Skevlo /* find the settings for this channel (we know it exists) */ 4367260219Skevlo for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4368260219Skevlo 4369260219Skevlo /* use Tx power values from EEPROM */ 4370260219Skevlo txpow1 = sc->txpow1[i]; 4371260219Skevlo txpow2 = sc->txpow2[i]; 4372260219Skevlo txpow3 = (sc->ntxchains == 3) ? sc->txpow3[i] : 0; 4373260219Skevlo 4374260219Skevlo if (chan <= 14) { 4375260219Skevlo run_bbp_write(sc, 25, sc->bbp25); 4376260219Skevlo run_bbp_write(sc, 26, sc->bbp26); 4377260219Skevlo } else { 4378260219Skevlo /* Enable IQ phase correction. */ 4379260219Skevlo run_bbp_write(sc, 25, 0x09); 4380260219Skevlo run_bbp_write(sc, 26, 0xff); 4381260219Skevlo } 4382260219Skevlo 4383260219Skevlo run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n); 4384260219Skevlo run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f); 4385260219Skevlo run_rt3070_rf_read(sc, 11, &rf); 4386260219Skevlo rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03); 4387260219Skevlo run_rt3070_rf_write(sc, 11, rf); 4388260219Skevlo 4389260219Skevlo /* Set pll_idoh. */ 4390260219Skevlo run_rt3070_rf_read(sc, 11, &rf); 4391260219Skevlo rf &= ~0x4c; 4392260219Skevlo rf |= (chan <= 14) ? 0x44 : 0x48; 4393260219Skevlo run_rt3070_rf_write(sc, 11, rf); 4394260219Skevlo 4395260219Skevlo if (chan <= 14) 4396260219Skevlo rf = txpow1 & 0x1f; 4397260219Skevlo else 4398260219Skevlo rf = 0x40 | ((txpow1 & 0x18) << 1) | (txpow1 & 0x07); 4399260219Skevlo run_rt3070_rf_write(sc, 53, rf); 4400260219Skevlo 4401260219Skevlo if (chan <= 14) 4402260219Skevlo rf = txpow2 & 0x1f; 4403260219Skevlo else 4404260219Skevlo rf = 0x40 | ((txpow2 & 0x18) << 1) | (txpow2 & 0x07); 4405260219Skevlo run_rt3070_rf_write(sc, 55, rf); 4406260219Skevlo 4407260219Skevlo if (chan <= 14) 4408260219Skevlo rf = txpow3 & 0x1f; 4409260219Skevlo else 4410260219Skevlo rf = 0x40 | ((txpow3 & 0x18) << 1) | (txpow3 & 0x07); 4411260219Skevlo run_rt3070_rf_write(sc, 54, rf); 4412260219Skevlo 4413260219Skevlo rf = RT3070_RF_BLOCK | RT3070_PLL_PD; 4414260219Skevlo if (sc->ntxchains == 3) 4415260219Skevlo rf |= RT3070_TX0_PD | RT3070_TX1_PD | RT3070_TX2_PD; 4416260219Skevlo else 4417260219Skevlo rf |= RT3070_TX0_PD | RT3070_TX1_PD; 4418260219Skevlo rf |= RT3070_RX0_PD | RT3070_RX1_PD | RT3070_RX2_PD; 4419260219Skevlo run_rt3070_rf_write(sc, 1, rf); 4420260219Skevlo 4421260219Skevlo run_adjust_freq_offset(sc); 4422260219Skevlo 4423260219Skevlo run_rt3070_rf_write(sc, 31, (chan <= 14) ? 0xa0 : 0x80); 4424260219Skevlo 4425260219Skevlo h20mhz = (sc->rf24_20mhz & 0x20) >> 5; 4426260219Skevlo run_rt3070_rf_read(sc, 30, &rf); 4427260219Skevlo rf = (rf & ~0x06) | (h20mhz << 1) | (h20mhz << 2); 4428260219Skevlo run_rt3070_rf_write(sc, 30, rf); 4429260219Skevlo 4430260219Skevlo run_rt3070_rf_read(sc, 36, &rf); 4431260219Skevlo if (chan <= 14) 4432260219Skevlo rf |= 0x80; 4433260219Skevlo else 4434260219Skevlo rf &= ~0x80; 4435260219Skevlo run_rt3070_rf_write(sc, 36, rf); 4436260219Skevlo 4437260219Skevlo /* Set vcolo_bs. */ 4438260219Skevlo run_rt3070_rf_write(sc, 34, (chan <= 14) ? 0x3c : 0x20); 4439260219Skevlo /* Set pfd_delay. */ 4440260219Skevlo run_rt3070_rf_write(sc, 12, (chan <= 14) ? 0x1a : 0x12); 4441260219Skevlo 4442260219Skevlo /* Set vco bias current control. */ 4443260219Skevlo run_rt3070_rf_read(sc, 6, &rf); 4444260219Skevlo rf &= ~0xc0; 4445260219Skevlo if (chan <= 14) 4446260219Skevlo rf |= 0x40; 4447260219Skevlo else if (chan <= 128) 4448260219Skevlo rf |= 0x80; 4449260219Skevlo else 4450260219Skevlo rf |= 0x40; 4451260219Skevlo run_rt3070_rf_write(sc, 6, rf); 4452260219Skevlo 4453260219Skevlo run_rt3070_rf_read(sc, 30, &rf); 4454260219Skevlo rf = (rf & ~0x18) | 0x10; 4455260219Skevlo run_rt3070_rf_write(sc, 30, rf); 4456260219Skevlo 4457260219Skevlo run_rt3070_rf_write(sc, 10, (chan <= 14) ? 0xd3 : 0xd8); 4458260219Skevlo run_rt3070_rf_write(sc, 13, (chan <= 14) ? 0x12 : 0x23); 4459260219Skevlo 4460260219Skevlo run_rt3070_rf_read(sc, 51, &rf); 4461260219Skevlo rf = (rf & ~0x03) | 0x01; 4462260219Skevlo run_rt3070_rf_write(sc, 51, rf); 4463260219Skevlo /* Set tx_mx1_cc. */ 4464260219Skevlo run_rt3070_rf_read(sc, 51, &rf); 4465260219Skevlo rf &= ~0x1c; 4466260219Skevlo rf |= (chan <= 14) ? 0x14 : 0x10; 4467260219Skevlo run_rt3070_rf_write(sc, 51, rf); 4468260219Skevlo /* Set tx_mx1_ic. */ 4469260219Skevlo run_rt3070_rf_read(sc, 51, &rf); 4470260219Skevlo rf &= ~0xe0; 4471260219Skevlo rf |= (chan <= 14) ? 0x60 : 0x40; 4472260219Skevlo run_rt3070_rf_write(sc, 51, rf); 4473260219Skevlo /* Set tx_lo1_ic. */ 4474260219Skevlo run_rt3070_rf_read(sc, 49, &rf); 4475260219Skevlo rf &= ~0x1c; 4476260219Skevlo rf |= (chan <= 14) ? 0x0c : 0x08; 4477260219Skevlo run_rt3070_rf_write(sc, 49, rf); 4478260219Skevlo /* Set tx_lo1_en. */ 4479260219Skevlo run_rt3070_rf_read(sc, 50, &rf); 4480260219Skevlo run_rt3070_rf_write(sc, 50, rf & ~0x20); 4481260219Skevlo /* Set drv_cc. */ 4482260219Skevlo run_rt3070_rf_read(sc, 57, &rf); 4483260219Skevlo rf &= ~0xfc; 4484260219Skevlo rf |= (chan <= 14) ? 0x6c : 0x3c; 4485260219Skevlo run_rt3070_rf_write(sc, 57, rf); 4486260219Skevlo /* Set rx_mix1_ic, rxa_lnactr, lna_vc, lna_inbias_en and lna_en. */ 4487260219Skevlo run_rt3070_rf_write(sc, 44, (chan <= 14) ? 0x93 : 0x9b); 4488260219Skevlo /* Set drv_gnd_a, tx_vga_cc_a and tx_mx2_gain. */ 4489260219Skevlo run_rt3070_rf_write(sc, 52, (chan <= 14) ? 0x45 : 0x05); 4490260219Skevlo /* Enable VCO calibration. */ 4491260219Skevlo run_rt3070_rf_read(sc, 3, &rf); 4492260219Skevlo rf &= ~RT5390_VCOCAL; 4493260219Skevlo rf |= (chan <= 14) ? RT5390_VCOCAL : 0xbe; 4494260219Skevlo run_rt3070_rf_write(sc, 3, rf); 4495260219Skevlo 4496260219Skevlo if (chan <= 14) 4497260219Skevlo rf = 0x23; 4498260219Skevlo else if (chan <= 64) 4499260219Skevlo rf = 0x36; 4500260219Skevlo else if (chan <= 128) 4501260219Skevlo rf = 0x32; 4502260219Skevlo else 4503260219Skevlo rf = 0x30; 4504260219Skevlo run_rt3070_rf_write(sc, 39, rf); 4505260219Skevlo if (chan <= 14) 4506260219Skevlo rf = 0xbb; 4507260219Skevlo else if (chan <= 64) 4508260219Skevlo rf = 0xeb; 4509260219Skevlo else if (chan <= 128) 4510260219Skevlo rf = 0xb3; 4511260219Skevlo else 4512260219Skevlo rf = 0x9b; 4513260219Skevlo run_rt3070_rf_write(sc, 45, rf); 4514260219Skevlo 4515260219Skevlo /* Set FEQ/AEQ control. */ 4516260219Skevlo run_bbp_write(sc, 105, 0x34); 4517260219Skevlo} 4518260219Skevlo 4519260219Skevlostatic void 4520257955Skevlorun_rt5390_set_chan(struct run_softc *sc, u_int chan) 4521257955Skevlo{ 4522257955Skevlo int8_t txpow1, txpow2; 4523257955Skevlo uint8_t rf; 4524257955Skevlo int i; 4525257955Skevlo 4526257955Skevlo /* find the settings for this channel (we know it exists) */ 4527257955Skevlo for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4528257955Skevlo 4529257955Skevlo /* use Tx power values from EEPROM */ 4530257955Skevlo txpow1 = sc->txpow1[i]; 4531257955Skevlo txpow2 = sc->txpow2[i]; 4532257955Skevlo 4533257955Skevlo run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n); 4534257955Skevlo run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f); 4535257955Skevlo run_rt3070_rf_read(sc, 11, &rf); 4536257955Skevlo rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03); 4537257955Skevlo run_rt3070_rf_write(sc, 11, rf); 4538257955Skevlo 4539257955Skevlo run_rt3070_rf_read(sc, 49, &rf); 4540257955Skevlo rf = (rf & ~0x3f) | (txpow1 & 0x3f); 4541257955Skevlo /* The valid range of the RF R49 is 0x00 to 0x27. */ 4542257955Skevlo if ((rf & 0x3f) > 0x27) 4543257955Skevlo rf = (rf & ~0x3f) | 0x27; 4544257955Skevlo run_rt3070_rf_write(sc, 49, rf); 4545257955Skevlo 4546257955Skevlo if (sc->mac_ver == 0x5392) { 4547257955Skevlo run_rt3070_rf_read(sc, 50, &rf); 4548257955Skevlo rf = (rf & ~0x3f) | (txpow2 & 0x3f); 4549257955Skevlo /* The valid range of the RF R50 is 0x00 to 0x27. */ 4550257955Skevlo if ((rf & 0x3f) > 0x27) 4551257955Skevlo rf = (rf & ~0x3f) | 0x27; 4552257955Skevlo run_rt3070_rf_write(sc, 50, rf); 4553257955Skevlo } 4554257955Skevlo 4555257955Skevlo run_rt3070_rf_read(sc, 1, &rf); 4556257955Skevlo rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD; 4557257955Skevlo if (sc->mac_ver == 0x5392) 4558257955Skevlo rf |= RT3070_RX1_PD | RT3070_TX1_PD; 4559257955Skevlo run_rt3070_rf_write(sc, 1, rf); 4560257955Skevlo 4561257955Skevlo if (sc->mac_ver != 0x5392) { 4562257955Skevlo run_rt3070_rf_read(sc, 2, &rf); 4563257955Skevlo rf |= 0x80; 4564257955Skevlo run_rt3070_rf_write(sc, 2, rf); 4565257955Skevlo run_delay(sc, 10); 4566257955Skevlo rf &= 0x7f; 4567257955Skevlo run_rt3070_rf_write(sc, 2, rf); 4568257955Skevlo } 4569257955Skevlo 4570257955Skevlo run_adjust_freq_offset(sc); 4571257955Skevlo 4572257955Skevlo if (sc->mac_ver == 0x5392) { 4573257955Skevlo /* Fix for RT5392C. */ 4574257955Skevlo if (sc->mac_rev >= 0x0223) { 4575259030Skevlo if (chan <= 4) 4576257955Skevlo rf = 0x0f; 4577259030Skevlo else if (chan >= 5 && chan <= 7) 4578257955Skevlo rf = 0x0e; 4579259030Skevlo else 4580257955Skevlo rf = 0x0d; 4581257955Skevlo run_rt3070_rf_write(sc, 23, rf); 4582257955Skevlo 4583259030Skevlo if (chan <= 4) 4584257955Skevlo rf = 0x0c; 4585257955Skevlo else if (chan == 5) 4586257955Skevlo rf = 0x0b; 4587259030Skevlo else if (chan >= 6 && chan <= 7) 4588257955Skevlo rf = 0x0a; 4589259030Skevlo else if (chan >= 8 && chan <= 10) 4590257955Skevlo rf = 0x09; 4591259030Skevlo else 4592257955Skevlo rf = 0x08; 4593257955Skevlo run_rt3070_rf_write(sc, 59, rf); 4594257955Skevlo } else { 4595259030Skevlo if (chan <= 11) 4596257955Skevlo rf = 0x0f; 4597259030Skevlo else 4598257955Skevlo rf = 0x0b; 4599257955Skevlo run_rt3070_rf_write(sc, 59, rf); 4600257955Skevlo } 4601257955Skevlo } else { 4602257955Skevlo /* Fix for RT5390F. */ 4603257955Skevlo if (sc->mac_rev >= 0x0502) { 4604259030Skevlo if (chan <= 11) 4605257955Skevlo rf = 0x43; 4606259030Skevlo else 4607257955Skevlo rf = 0x23; 4608257955Skevlo run_rt3070_rf_write(sc, 55, rf); 4609257955Skevlo 4610259030Skevlo if (chan <= 11) 4611257955Skevlo rf = 0x0f; 4612257955Skevlo else if (chan == 12) 4613257955Skevlo rf = 0x0d; 4614259030Skevlo else 4615257955Skevlo rf = 0x0b; 4616257955Skevlo run_rt3070_rf_write(sc, 59, rf); 4617257955Skevlo } else { 4618257955Skevlo run_rt3070_rf_write(sc, 55, 0x44); 4619257955Skevlo run_rt3070_rf_write(sc, 59, 0x8f); 4620257955Skevlo } 4621257955Skevlo } 4622257955Skevlo 4623257955Skevlo /* Enable VCO calibration. */ 4624257955Skevlo run_rt3070_rf_read(sc, 3, &rf); 4625257955Skevlo rf |= RT5390_VCOCAL; 4626257955Skevlo run_rt3070_rf_write(sc, 3, rf); 4627257955Skevlo} 4628257955Skevlo 4629257955Skevlostatic void 4630259032Skevlorun_rt5592_set_chan(struct run_softc *sc, u_int chan) 4631259032Skevlo{ 4632259032Skevlo const struct rt5592_freqs *freqs; 4633259032Skevlo uint32_t tmp; 4634259032Skevlo uint8_t reg, rf, txpow_bound; 4635259032Skevlo int8_t txpow1, txpow2; 4636259032Skevlo int i; 4637259032Skevlo 4638259032Skevlo run_read(sc, RT5592_DEBUG_INDEX, &tmp); 4639259032Skevlo freqs = (tmp & RT5592_SEL_XTAL) ? 4640259032Skevlo rt5592_freqs_40mhz : rt5592_freqs_20mhz; 4641259032Skevlo 4642259032Skevlo /* find the settings for this channel (we know it exists) */ 4643259032Skevlo for (i = 0; rt2860_rf2850[i].chan != chan; i++, freqs++); 4644259032Skevlo 4645259032Skevlo /* use Tx power values from EEPROM */ 4646259032Skevlo txpow1 = sc->txpow1[i]; 4647259032Skevlo txpow2 = sc->txpow2[i]; 4648259032Skevlo 4649259032Skevlo run_read(sc, RT3070_LDO_CFG0, &tmp); 4650259032Skevlo tmp &= ~0x1c000000; 4651259032Skevlo if (chan > 14) 4652259032Skevlo tmp |= 0x14000000; 4653259032Skevlo run_write(sc, RT3070_LDO_CFG0, tmp); 4654259032Skevlo 4655259032Skevlo /* N setting. */ 4656259032Skevlo run_rt3070_rf_write(sc, 8, freqs->n & 0xff); 4657259032Skevlo run_rt3070_rf_read(sc, 9, &rf); 4658259032Skevlo rf &= ~(1 << 4); 4659259032Skevlo rf |= ((freqs->n & 0x0100) >> 8) << 4; 4660259032Skevlo run_rt3070_rf_write(sc, 9, rf); 4661259032Skevlo 4662259032Skevlo /* K setting. */ 4663259032Skevlo run_rt3070_rf_read(sc, 9, &rf); 4664259032Skevlo rf &= ~0x0f; 4665259032Skevlo rf |= (freqs->k & 0x0f); 4666259032Skevlo run_rt3070_rf_write(sc, 9, rf); 4667259032Skevlo 4668259032Skevlo /* Mode setting. */ 4669259032Skevlo run_rt3070_rf_read(sc, 11, &rf); 4670259032Skevlo rf &= ~0x0c; 4671259032Skevlo rf |= ((freqs->m - 0x8) & 0x3) << 2; 4672259032Skevlo run_rt3070_rf_write(sc, 11, rf); 4673259032Skevlo run_rt3070_rf_read(sc, 9, &rf); 4674259032Skevlo rf &= ~(1 << 7); 4675259032Skevlo rf |= (((freqs->m - 0x8) & 0x4) >> 2) << 7; 4676259032Skevlo run_rt3070_rf_write(sc, 9, rf); 4677259032Skevlo 4678259032Skevlo /* R setting. */ 4679259032Skevlo run_rt3070_rf_read(sc, 11, &rf); 4680259032Skevlo rf &= ~0x03; 4681259032Skevlo rf |= (freqs->r - 0x1); 4682259032Skevlo run_rt3070_rf_write(sc, 11, rf); 4683259032Skevlo 4684259032Skevlo if (chan <= 14) { 4685259032Skevlo /* Initialize RF registers for 2GHZ. */ 4686259032Skevlo for (i = 0; i < nitems(rt5592_2ghz_def_rf); i++) { 4687259032Skevlo run_rt3070_rf_write(sc, rt5592_2ghz_def_rf[i].reg, 4688259032Skevlo rt5592_2ghz_def_rf[i].val); 4689259032Skevlo } 4690259032Skevlo 4691259032Skevlo rf = (chan <= 10) ? 0x07 : 0x06; 4692259032Skevlo run_rt3070_rf_write(sc, 23, rf); 4693259032Skevlo run_rt3070_rf_write(sc, 59, rf); 4694259032Skevlo 4695259032Skevlo run_rt3070_rf_write(sc, 55, 0x43); 4696259032Skevlo 4697259032Skevlo /* 4698259032Skevlo * RF R49/R50 Tx power ALC code. 4699259032Skevlo * G-band bit<7:6>=1:0, bit<5:0> range from 0x0 ~ 0x27. 4700259032Skevlo */ 4701259032Skevlo reg = 2; 4702259032Skevlo txpow_bound = 0x27; 4703259032Skevlo } else { 4704259032Skevlo /* Initialize RF registers for 5GHZ. */ 4705259032Skevlo for (i = 0; i < nitems(rt5592_5ghz_def_rf); i++) { 4706259032Skevlo run_rt3070_rf_write(sc, rt5592_5ghz_def_rf[i].reg, 4707259032Skevlo rt5592_5ghz_def_rf[i].val); 4708259032Skevlo } 4709259032Skevlo for (i = 0; i < nitems(rt5592_chan_5ghz); i++) { 4710259032Skevlo if (chan >= rt5592_chan_5ghz[i].firstchan && 4711259032Skevlo chan <= rt5592_chan_5ghz[i].lastchan) { 4712259032Skevlo run_rt3070_rf_write(sc, rt5592_chan_5ghz[i].reg, 4713259032Skevlo rt5592_chan_5ghz[i].val); 4714259032Skevlo } 4715259032Skevlo } 4716259032Skevlo 4717259032Skevlo /* 4718259032Skevlo * RF R49/R50 Tx power ALC code. 4719259032Skevlo * A-band bit<7:6>=1:1, bit<5:0> range from 0x0 ~ 0x2b. 4720259032Skevlo */ 4721259032Skevlo reg = 3; 4722259032Skevlo txpow_bound = 0x2b; 4723259032Skevlo } 4724259032Skevlo 4725259032Skevlo /* RF R49 ch0 Tx power ALC code. */ 4726259032Skevlo run_rt3070_rf_read(sc, 49, &rf); 4727259032Skevlo rf &= ~0xc0; 4728259032Skevlo rf |= (reg << 6); 4729259032Skevlo rf = (rf & ~0x3f) | (txpow1 & 0x3f); 4730259032Skevlo if ((rf & 0x3f) > txpow_bound) 4731259032Skevlo rf = (rf & ~0x3f) | txpow_bound; 4732259032Skevlo run_rt3070_rf_write(sc, 49, rf); 4733259032Skevlo 4734259032Skevlo /* RF R50 ch1 Tx power ALC code. */ 4735259032Skevlo run_rt3070_rf_read(sc, 50, &rf); 4736259032Skevlo rf &= ~(1 << 7 | 1 << 6); 4737259032Skevlo rf |= (reg << 6); 4738259032Skevlo rf = (rf & ~0x3f) | (txpow2 & 0x3f); 4739259032Skevlo if ((rf & 0x3f) > txpow_bound) 4740259032Skevlo rf = (rf & ~0x3f) | txpow_bound; 4741259032Skevlo run_rt3070_rf_write(sc, 50, rf); 4742259032Skevlo 4743259032Skevlo /* Enable RF_BLOCK, PLL_PD, RX0_PD, and TX0_PD. */ 4744259032Skevlo run_rt3070_rf_read(sc, 1, &rf); 4745259032Skevlo rf |= (RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD); 4746259032Skevlo if (sc->ntxchains > 1) 4747259032Skevlo rf |= RT3070_TX1_PD; 4748259032Skevlo if (sc->nrxchains > 1) 4749259032Skevlo rf |= RT3070_RX1_PD; 4750259032Skevlo run_rt3070_rf_write(sc, 1, rf); 4751259032Skevlo 4752259032Skevlo run_rt3070_rf_write(sc, 6, 0xe4); 4753259032Skevlo 4754259032Skevlo run_rt3070_rf_write(sc, 30, 0x10); 4755259032Skevlo run_rt3070_rf_write(sc, 31, 0x80); 4756259032Skevlo run_rt3070_rf_write(sc, 32, 0x80); 4757259032Skevlo 4758259032Skevlo run_adjust_freq_offset(sc); 4759259032Skevlo 4760259032Skevlo /* Enable VCO calibration. */ 4761259032Skevlo run_rt3070_rf_read(sc, 3, &rf); 4762259032Skevlo rf |= RT5390_VCOCAL; 4763259032Skevlo run_rt3070_rf_write(sc, 3, rf); 4764259032Skevlo} 4765259032Skevlo 4766259032Skevlostatic void 4767203134Sthompsarun_set_rx_antenna(struct run_softc *sc, int aux) 4768203134Sthompsa{ 4769203134Sthompsa uint32_t tmp; 4770257955Skevlo uint8_t bbp152; 4771203134Sthompsa 4772203134Sthompsa if (aux) { 4773257955Skevlo if (sc->rf_rev == RT5390_RF_5370) { 4774257955Skevlo run_bbp_read(sc, 152, &bbp152); 4775257955Skevlo run_bbp_write(sc, 152, bbp152 & ~0x80); 4776259030Skevlo } else { 4777257955Skevlo run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0); 4778257955Skevlo run_read(sc, RT2860_GPIO_CTRL, &tmp); 4779257955Skevlo run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08); 4780257955Skevlo } 4781203134Sthompsa } else { 4782257955Skevlo if (sc->rf_rev == RT5390_RF_5370) { 4783257955Skevlo run_bbp_read(sc, 152, &bbp152); 4784257955Skevlo run_bbp_write(sc, 152, bbp152 | 0x80); 4785259030Skevlo } else { 4786257955Skevlo run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1); 4787257955Skevlo run_read(sc, RT2860_GPIO_CTRL, &tmp); 4788257955Skevlo run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808); 4789257955Skevlo } 4790203134Sthompsa } 4791203134Sthompsa} 4792203134Sthompsa 4793203134Sthompsastatic int 4794203134Sthompsarun_set_chan(struct run_softc *sc, struct ieee80211_channel *c) 4795203134Sthompsa{ 4796203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 4797257429Shselasky u_int chan, group; 4798203134Sthompsa 4799203134Sthompsa chan = ieee80211_chan2ieee(ic, c); 4800203134Sthompsa if (chan == 0 || chan == IEEE80211_CHAN_ANY) 4801209917Sthompsa return (EINVAL); 4802203134Sthompsa 4803259032Skevlo if (sc->mac_ver == 0x5592) 4804259032Skevlo run_rt5592_set_chan(sc, chan); 4805259032Skevlo else if (sc->mac_ver >= 0x5390) 4806257955Skevlo run_rt5390_set_chan(sc, chan); 4807260219Skevlo else if (sc->mac_ver == 0x3593) 4808260219Skevlo run_rt3593_set_chan(sc, chan); 4809257955Skevlo else if (sc->mac_ver == 0x3572) 4810205042Sthompsa run_rt3572_set_chan(sc, chan); 4811205042Sthompsa else if (sc->mac_ver >= 0x3070) 4812203134Sthompsa run_rt3070_set_chan(sc, chan); 4813203134Sthompsa else 4814203134Sthompsa run_rt2870_set_chan(sc, chan); 4815203134Sthompsa 4816203134Sthompsa /* determine channel group */ 4817203134Sthompsa if (chan <= 14) 4818203134Sthompsa group = 0; 4819203134Sthompsa else if (chan <= 64) 4820203134Sthompsa group = 1; 4821203134Sthompsa else if (chan <= 128) 4822203134Sthompsa group = 2; 4823203134Sthompsa else 4824203134Sthompsa group = 3; 4825203134Sthompsa 4826203134Sthompsa /* XXX necessary only when group has changed! */ 4827203134Sthompsa run_select_chan_group(sc, group); 4828203134Sthompsa 4829203134Sthompsa run_delay(sc, 10); 4830203134Sthompsa 4831259545Skevlo /* Perform IQ calibration. */ 4832259544Skevlo if (sc->mac_ver >= 0x5392) 4833259544Skevlo run_iq_calib(sc, chan); 4834259544Skevlo 4835209917Sthompsa return (0); 4836203134Sthompsa} 4837203134Sthompsa 4838203134Sthompsastatic void 4839203134Sthompsarun_set_channel(struct ieee80211com *ic) 4840203134Sthompsa{ 4841203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 4842203134Sthompsa 4843203134Sthompsa RUN_LOCK(sc); 4844203134Sthompsa run_set_chan(sc, ic->ic_curchan); 4845203134Sthompsa RUN_UNLOCK(sc); 4846203134Sthompsa 4847203134Sthompsa return; 4848203134Sthompsa} 4849203134Sthompsa 4850203134Sthompsastatic void 4851203134Sthompsarun_scan_start(struct ieee80211com *ic) 4852203134Sthompsa{ 4853203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 4854203134Sthompsa uint32_t tmp; 4855203134Sthompsa 4856203134Sthompsa RUN_LOCK(sc); 4857203134Sthompsa 4858203134Sthompsa /* abort TSF synchronization */ 4859203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 4860203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, 4861203134Sthompsa tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 4862203134Sthompsa RT2860_TBTT_TIMER_EN)); 4863203134Sthompsa run_set_bssid(sc, sc->sc_ifp->if_broadcastaddr); 4864203134Sthompsa 4865203134Sthompsa RUN_UNLOCK(sc); 4866203134Sthompsa 4867203134Sthompsa return; 4868203134Sthompsa} 4869203134Sthompsa 4870203134Sthompsastatic void 4871203134Sthompsarun_scan_end(struct ieee80211com *ic) 4872203134Sthompsa{ 4873203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 4874203134Sthompsa 4875203134Sthompsa RUN_LOCK(sc); 4876203134Sthompsa 4877203134Sthompsa run_enable_tsf_sync(sc); 4878203134Sthompsa /* XXX keep local copy */ 4879203134Sthompsa run_set_bssid(sc, sc->sc_bssid); 4880203134Sthompsa 4881203134Sthompsa RUN_UNLOCK(sc); 4882203134Sthompsa 4883203134Sthompsa return; 4884203134Sthompsa} 4885203134Sthompsa 4886208019Sthompsa/* 4887208019Sthompsa * Could be called from ieee80211_node_timeout() 4888208019Sthompsa * (non-sleepable thread) 4889208019Sthompsa */ 4890208019Sthompsastatic void 4891208019Sthompsarun_update_beacon(struct ieee80211vap *vap, int item) 4892203134Sthompsa{ 4893208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 4894208019Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 4895218492Sbschmidt struct run_vap *rvp = RUN_VAP(vap); 4896218492Sbschmidt int mcast = 0; 4897208019Sthompsa uint32_t i; 4898208019Sthompsa 4899218492Sbschmidt KASSERT(vap != NULL, ("no beacon")); 4900218492Sbschmidt 4901218492Sbschmidt switch (item) { 4902218492Sbschmidt case IEEE80211_BEACON_ERP: 4903218492Sbschmidt run_updateslot(ic->ic_ifp); 4904218492Sbschmidt break; 4905218492Sbschmidt case IEEE80211_BEACON_HTINFO: 4906218492Sbschmidt run_updateprot(ic); 4907218492Sbschmidt break; 4908218492Sbschmidt case IEEE80211_BEACON_TIM: 4909218492Sbschmidt mcast = 1; /*TODO*/ 4910218492Sbschmidt break; 4911218492Sbschmidt default: 4912218492Sbschmidt break; 4913218492Sbschmidt } 4914218492Sbschmidt 4915218492Sbschmidt setbit(rvp->bo.bo_flags, item); 4916273448Skevlo if (rvp->beacon_mbuf == NULL) { 4917273448Skevlo rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss, 4918273448Skevlo &rvp->bo); 4919273448Skevlo if (rvp->beacon_mbuf == NULL) 4920273448Skevlo return; 4921273448Skevlo } 4922218492Sbschmidt ieee80211_beacon_update(vap->iv_bss, &rvp->bo, rvp->beacon_mbuf, mcast); 4923218492Sbschmidt 4924208019Sthompsa i = RUN_CMDQ_GET(&sc->cmdq_store); 4925208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 4926208019Sthompsa sc->cmdq[i].func = run_update_beacon_cb; 4927208019Sthompsa sc->cmdq[i].arg0 = vap; 4928208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 4929208019Sthompsa 4930208019Sthompsa return; 4931203134Sthompsa} 4932203134Sthompsa 4933203134Sthompsastatic void 4934208019Sthompsarun_update_beacon_cb(void *arg) 4935203134Sthompsa{ 4936208019Sthompsa struct ieee80211vap *vap = arg; 4937218492Sbschmidt struct run_vap *rvp = RUN_VAP(vap); 4938203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 4939203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 4940203134Sthompsa struct rt2860_txwi txwi; 4941203134Sthompsa struct mbuf *m; 4942259032Skevlo uint16_t txwisize; 4943208019Sthompsa uint8_t ridx; 4944203134Sthompsa 4945209917Sthompsa if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC) 4946208019Sthompsa return; 4947236439Shselasky if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) 4948236439Shselasky return; 4949208019Sthompsa 4950218492Sbschmidt /* 4951218492Sbschmidt * No need to call ieee80211_beacon_update(), run_update_beacon() 4952218492Sbschmidt * is taking care of apropriate calls. 4953218492Sbschmidt */ 4954218492Sbschmidt if (rvp->beacon_mbuf == NULL) { 4955218492Sbschmidt rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss, 4956218492Sbschmidt &rvp->bo); 4957218492Sbschmidt if (rvp->beacon_mbuf == NULL) 4958218492Sbschmidt return; 4959218492Sbschmidt } 4960218492Sbschmidt m = rvp->beacon_mbuf; 4961203134Sthompsa 4962259032Skevlo memset(&txwi, 0, sizeof(txwi)); 4963203134Sthompsa txwi.wcid = 0xff; 4964203134Sthompsa txwi.len = htole16(m->m_pkthdr.len); 4965259032Skevlo 4966203134Sthompsa /* send beacons at the lowest available rate */ 4967208019Sthompsa ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? 4968208019Sthompsa RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; 4969208019Sthompsa txwi.phy = htole16(rt2860_rates[ridx].mcs); 4970208019Sthompsa if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM) 4971259032Skevlo txwi.phy |= htole16(RT2860_PHY_OFDM); 4972203134Sthompsa txwi.txop = RT2860_TX_TXOP_HT; 4973203134Sthompsa txwi.flags = RT2860_TX_TS; 4974209144Sthompsa txwi.xflags = RT2860_TX_NSEQ; 4975203134Sthompsa 4976259032Skevlo txwisize = (sc->mac_ver == 0x5592) ? 4977259032Skevlo sizeof(txwi) + sizeof(uint32_t) : sizeof(txwi); 4978259032Skevlo run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id), (uint8_t *)&txwi, 4979259032Skevlo txwisize); 4980259032Skevlo run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id) + txwisize, 4981259032Skevlo mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1); 4982203134Sthompsa} 4983203134Sthompsa 4984203134Sthompsastatic void 4985203134Sthompsarun_updateprot(struct ieee80211com *ic) 4986203134Sthompsa{ 4987203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 4988218492Sbschmidt uint32_t i; 4989218492Sbschmidt 4990218492Sbschmidt i = RUN_CMDQ_GET(&sc->cmdq_store); 4991218492Sbschmidt DPRINTF("cmdq_store=%d\n", i); 4992218492Sbschmidt sc->cmdq[i].func = run_updateprot_cb; 4993218492Sbschmidt sc->cmdq[i].arg0 = ic; 4994218492Sbschmidt ieee80211_runtask(ic, &sc->cmdq_task); 4995218492Sbschmidt} 4996218492Sbschmidt 4997218492Sbschmidtstatic void 4998218492Sbschmidtrun_updateprot_cb(void *arg) 4999218492Sbschmidt{ 5000218492Sbschmidt struct ieee80211com *ic = arg; 5001218492Sbschmidt struct run_softc *sc = ic->ic_ifp->if_softc; 5002203134Sthompsa uint32_t tmp; 5003203134Sthompsa 5004203134Sthompsa tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL; 5005203134Sthompsa /* setup protection frame rate (MCS code) */ 5006203134Sthompsa tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ? 5007270192Skevlo rt2860_rates[RT2860_RIDX_OFDM6].mcs | RT2860_PHY_OFDM : 5008203134Sthompsa rt2860_rates[RT2860_RIDX_CCK11].mcs; 5009203134Sthompsa 5010203134Sthompsa /* CCK frames don't require protection */ 5011203134Sthompsa run_write(sc, RT2860_CCK_PROT_CFG, tmp); 5012203134Sthompsa if (ic->ic_flags & IEEE80211_F_USEPROT) { 5013203134Sthompsa if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) 5014203134Sthompsa tmp |= RT2860_PROT_CTRL_RTS_CTS; 5015203134Sthompsa else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) 5016203134Sthompsa tmp |= RT2860_PROT_CTRL_CTS; 5017203134Sthompsa } 5018203134Sthompsa run_write(sc, RT2860_OFDM_PROT_CFG, tmp); 5019203134Sthompsa} 5020203134Sthompsa 5021203134Sthompsastatic void 5022208019Sthompsarun_usb_timeout_cb(void *arg) 5023203134Sthompsa{ 5024208019Sthompsa struct ieee80211vap *vap = arg; 5025208019Sthompsa struct run_softc *sc = vap->iv_ic->ic_ifp->if_softc; 5026203134Sthompsa 5027208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 5028203134Sthompsa 5029203134Sthompsa if(vap->iv_state == IEEE80211_S_RUN && 5030203134Sthompsa vap->iv_opmode != IEEE80211_M_STA) 5031203134Sthompsa run_reset_livelock(sc); 5032209917Sthompsa else if (vap->iv_state == IEEE80211_S_SCAN) { 5033203134Sthompsa DPRINTF("timeout caused by scan\n"); 5034203134Sthompsa /* cancel bgscan */ 5035203134Sthompsa ieee80211_cancel_scan(vap); 5036203134Sthompsa } else 5037203134Sthompsa DPRINTF("timeout by unknown cause\n"); 5038203134Sthompsa} 5039203134Sthompsa 5040203134Sthompsastatic void 5041203134Sthompsarun_reset_livelock(struct run_softc *sc) 5042203134Sthompsa{ 5043203134Sthompsa uint32_t tmp; 5044203134Sthompsa 5045208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 5046208019Sthompsa 5047203134Sthompsa /* 5048203134Sthompsa * In IBSS or HostAP modes (when the hardware sends beacons), the MAC 5049203134Sthompsa * can run into a livelock and start sending CTS-to-self frames like 5050203134Sthompsa * crazy if protection is enabled. Reset MAC/BBP for a while 5051203134Sthompsa */ 5052203134Sthompsa run_read(sc, RT2860_DEBUG, &tmp); 5053208019Sthompsa DPRINTFN(3, "debug reg %08x\n", tmp); 5054209917Sthompsa if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) { 5055203134Sthompsa DPRINTF("CTS-to-self livelock detected\n"); 5056203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST); 5057203134Sthompsa run_delay(sc, 1); 5058203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 5059203134Sthompsa RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 5060203134Sthompsa } 5061203134Sthompsa} 5062203134Sthompsa 5063203134Sthompsastatic void 5064203134Sthompsarun_update_promisc_locked(struct ifnet *ifp) 5065203134Sthompsa{ 5066203134Sthompsa struct run_softc *sc = ifp->if_softc; 5067203134Sthompsa uint32_t tmp; 5068203134Sthompsa 5069203134Sthompsa run_read(sc, RT2860_RX_FILTR_CFG, &tmp); 5070203134Sthompsa 5071203134Sthompsa tmp |= RT2860_DROP_UC_NOME; 5072203134Sthompsa if (ifp->if_flags & IFF_PROMISC) 5073203134Sthompsa tmp &= ~RT2860_DROP_UC_NOME; 5074203134Sthompsa 5075203134Sthompsa run_write(sc, RT2860_RX_FILTR_CFG, tmp); 5076203134Sthompsa 5077203134Sthompsa DPRINTF("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ? 5078203134Sthompsa "entering" : "leaving"); 5079203134Sthompsa} 5080203134Sthompsa 5081203134Sthompsastatic void 5082203134Sthompsarun_update_promisc(struct ifnet *ifp) 5083203134Sthompsa{ 5084203134Sthompsa struct run_softc *sc = ifp->if_softc; 5085203134Sthompsa 5086203134Sthompsa if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 5087203134Sthompsa return; 5088203134Sthompsa 5089203134Sthompsa RUN_LOCK(sc); 5090203134Sthompsa run_update_promisc_locked(ifp); 5091203134Sthompsa RUN_UNLOCK(sc); 5092203134Sthompsa} 5093203134Sthompsa 5094203134Sthompsastatic void 5095203134Sthompsarun_enable_tsf_sync(struct run_softc *sc) 5096203134Sthompsa{ 5097208019Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 5098203134Sthompsa struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 5099203134Sthompsa uint32_t tmp; 5100203134Sthompsa 5101257955Skevlo DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id, 5102257955Skevlo ic->ic_opmode); 5103208019Sthompsa 5104203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 5105203134Sthompsa tmp &= ~0x1fffff; 5106203134Sthompsa tmp |= vap->iv_bss->ni_intval * 16; 5107203134Sthompsa tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN; 5108203134Sthompsa 5109208019Sthompsa if (ic->ic_opmode == IEEE80211_M_STA) { 5110203134Sthompsa /* 5111203134Sthompsa * Local TSF is always updated with remote TSF on beacon 5112203134Sthompsa * reception. 5113203134Sthompsa */ 5114203134Sthompsa tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT; 5115208019Sthompsa } else if (ic->ic_opmode == IEEE80211_M_IBSS) { 5116203134Sthompsa tmp |= RT2860_BCN_TX_EN; 5117203134Sthompsa /* 5118203134Sthompsa * Local TSF is updated with remote TSF on beacon reception 5119203134Sthompsa * only if the remote TSF is greater than local TSF. 5120203134Sthompsa */ 5121203134Sthompsa tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT; 5122208019Sthompsa } else if (ic->ic_opmode == IEEE80211_M_HOSTAP || 5123208019Sthompsa ic->ic_opmode == IEEE80211_M_MBSS) { 5124203134Sthompsa tmp |= RT2860_BCN_TX_EN; 5125203134Sthompsa /* SYNC with nobody */ 5126203134Sthompsa tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT; 5127208019Sthompsa } else { 5128203134Sthompsa DPRINTF("Enabling TSF failed. undefined opmode\n"); 5129208019Sthompsa return; 5130208019Sthompsa } 5131203134Sthompsa 5132203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, tmp); 5133203134Sthompsa} 5134203134Sthompsa 5135203134Sthompsastatic void 5136203134Sthompsarun_enable_mrr(struct run_softc *sc) 5137203134Sthompsa{ 5138259546Skevlo#define CCK(mcs) (mcs) 5139259546Skevlo#define OFDM(mcs) (1 << 3 | (mcs)) 5140203134Sthompsa run_write(sc, RT2860_LG_FBK_CFG0, 5141203134Sthompsa OFDM(6) << 28 | /* 54->48 */ 5142203134Sthompsa OFDM(5) << 24 | /* 48->36 */ 5143203134Sthompsa OFDM(4) << 20 | /* 36->24 */ 5144203134Sthompsa OFDM(3) << 16 | /* 24->18 */ 5145203134Sthompsa OFDM(2) << 12 | /* 18->12 */ 5146203134Sthompsa OFDM(1) << 8 | /* 12-> 9 */ 5147203134Sthompsa OFDM(0) << 4 | /* 9-> 6 */ 5148203134Sthompsa OFDM(0)); /* 6-> 6 */ 5149203134Sthompsa 5150203134Sthompsa run_write(sc, RT2860_LG_FBK_CFG1, 5151203134Sthompsa CCK(2) << 12 | /* 11->5.5 */ 5152203134Sthompsa CCK(1) << 8 | /* 5.5-> 2 */ 5153203134Sthompsa CCK(0) << 4 | /* 2-> 1 */ 5154203134Sthompsa CCK(0)); /* 1-> 1 */ 5155203134Sthompsa#undef OFDM 5156203134Sthompsa#undef CCK 5157203134Sthompsa} 5158203134Sthompsa 5159203134Sthompsastatic void 5160203134Sthompsarun_set_txpreamble(struct run_softc *sc) 5161203134Sthompsa{ 5162203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 5163203134Sthompsa uint32_t tmp; 5164203134Sthompsa 5165203134Sthompsa run_read(sc, RT2860_AUTO_RSP_CFG, &tmp); 5166203134Sthompsa if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 5167203134Sthompsa tmp |= RT2860_CCK_SHORT_EN; 5168203134Sthompsa else 5169203134Sthompsa tmp &= ~RT2860_CCK_SHORT_EN; 5170203134Sthompsa run_write(sc, RT2860_AUTO_RSP_CFG, tmp); 5171203134Sthompsa} 5172203134Sthompsa 5173203134Sthompsastatic void 5174203134Sthompsarun_set_basicrates(struct run_softc *sc) 5175203134Sthompsa{ 5176203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 5177203134Sthompsa 5178203134Sthompsa /* set basic rates mask */ 5179203134Sthompsa if (ic->ic_curmode == IEEE80211_MODE_11B) 5180203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003); 5181203134Sthompsa else if (ic->ic_curmode == IEEE80211_MODE_11A) 5182203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150); 5183203134Sthompsa else /* 11g */ 5184203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f); 5185203134Sthompsa} 5186203134Sthompsa 5187203134Sthompsastatic void 5188203134Sthompsarun_set_leds(struct run_softc *sc, uint16_t which) 5189203134Sthompsa{ 5190203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS, 5191203134Sthompsa which | (sc->leds & 0x7f)); 5192203134Sthompsa} 5193203134Sthompsa 5194203134Sthompsastatic void 5195203134Sthompsarun_set_bssid(struct run_softc *sc, const uint8_t *bssid) 5196203134Sthompsa{ 5197203134Sthompsa run_write(sc, RT2860_MAC_BSSID_DW0, 5198203134Sthompsa bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24); 5199203134Sthompsa run_write(sc, RT2860_MAC_BSSID_DW1, 5200203134Sthompsa bssid[4] | bssid[5] << 8); 5201203134Sthompsa} 5202203134Sthompsa 5203203134Sthompsastatic void 5204203134Sthompsarun_set_macaddr(struct run_softc *sc, const uint8_t *addr) 5205203134Sthompsa{ 5206203134Sthompsa run_write(sc, RT2860_MAC_ADDR_DW0, 5207203134Sthompsa addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24); 5208203134Sthompsa run_write(sc, RT2860_MAC_ADDR_DW1, 5209203134Sthompsa addr[4] | addr[5] << 8 | 0xff << 16); 5210203134Sthompsa} 5211203134Sthompsa 5212203134Sthompsastatic void 5213203134Sthompsarun_updateslot(struct ifnet *ifp) 5214203134Sthompsa{ 5215203134Sthompsa struct run_softc *sc = ifp->if_softc; 5216203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 5217218492Sbschmidt uint32_t i; 5218218492Sbschmidt 5219218492Sbschmidt i = RUN_CMDQ_GET(&sc->cmdq_store); 5220218492Sbschmidt DPRINTF("cmdq_store=%d\n", i); 5221218492Sbschmidt sc->cmdq[i].func = run_updateslot_cb; 5222218492Sbschmidt sc->cmdq[i].arg0 = ifp; 5223218492Sbschmidt ieee80211_runtask(ic, &sc->cmdq_task); 5224218492Sbschmidt 5225218492Sbschmidt return; 5226218492Sbschmidt} 5227218492Sbschmidt 5228218492Sbschmidt/* ARGSUSED */ 5229218492Sbschmidtstatic void 5230218492Sbschmidtrun_updateslot_cb(void *arg) 5231218492Sbschmidt{ 5232218492Sbschmidt struct ifnet *ifp = arg; 5233218492Sbschmidt struct run_softc *sc = ifp->if_softc; 5234218492Sbschmidt struct ieee80211com *ic = ifp->if_l2com; 5235203134Sthompsa uint32_t tmp; 5236203134Sthompsa 5237203134Sthompsa run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp); 5238203134Sthompsa tmp &= ~0xff; 5239203134Sthompsa tmp |= (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; 5240203134Sthompsa run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp); 5241203134Sthompsa} 5242203134Sthompsa 5243208019Sthompsastatic void 5244208019Sthompsarun_update_mcast(struct ifnet *ifp) 5245208019Sthompsa{ 5246208019Sthompsa /* h/w filter supports getting everything or nothing */ 5247208019Sthompsa ifp->if_flags |= IFF_ALLMULTI; 5248208019Sthompsa} 5249208019Sthompsa 5250203134Sthompsastatic int8_t 5251203134Sthompsarun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain) 5252203134Sthompsa{ 5253203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 5254203134Sthompsa struct ieee80211_channel *c = ic->ic_curchan; 5255203134Sthompsa int delta; 5256203134Sthompsa 5257203134Sthompsa if (IEEE80211_IS_CHAN_5GHZ(c)) { 5258257429Shselasky u_int chan = ieee80211_chan2ieee(ic, c); 5259203134Sthompsa delta = sc->rssi_5ghz[rxchain]; 5260203134Sthompsa 5261203134Sthompsa /* determine channel group */ 5262203134Sthompsa if (chan <= 64) 5263203134Sthompsa delta -= sc->lna[1]; 5264203134Sthompsa else if (chan <= 128) 5265203134Sthompsa delta -= sc->lna[2]; 5266203134Sthompsa else 5267203134Sthompsa delta -= sc->lna[3]; 5268203134Sthompsa } else 5269203134Sthompsa delta = sc->rssi_2ghz[rxchain] - sc->lna[0]; 5270203134Sthompsa 5271209917Sthompsa return (-12 - delta - rssi); 5272203134Sthompsa} 5273203134Sthompsa 5274257955Skevlostatic void 5275257955Skevlorun_rt5390_bbp_init(struct run_softc *sc) 5276257955Skevlo{ 5277257955Skevlo int i; 5278259032Skevlo uint8_t bbp; 5279257955Skevlo 5280259032Skevlo /* Apply maximum likelihood detection for 2 stream case. */ 5281259032Skevlo run_bbp_read(sc, 105, &bbp); 5282259032Skevlo if (sc->nrxchains > 1) 5283259032Skevlo run_bbp_write(sc, 105, bbp | RT5390_MLD); 5284259032Skevlo 5285257955Skevlo /* Avoid data lost and CRC error. */ 5286259032Skevlo run_bbp_read(sc, 4, &bbp); 5287259031Skevlo run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 5288257955Skevlo 5289259032Skevlo if (sc->mac_ver == 0x5592) { 5290259032Skevlo for (i = 0; i < nitems(rt5592_def_bbp); i++) { 5291259032Skevlo run_bbp_write(sc, rt5592_def_bbp[i].reg, 5292259032Skevlo rt5592_def_bbp[i].val); 5293259032Skevlo } 5294259032Skevlo for (i = 0; i < nitems(rt5592_bbp_r196); i++) { 5295259032Skevlo run_bbp_write(sc, 195, i + 0x80); 5296259032Skevlo run_bbp_write(sc, 196, rt5592_bbp_r196[i]); 5297259032Skevlo } 5298259032Skevlo } else { 5299259032Skevlo for (i = 0; i < nitems(rt5390_def_bbp); i++) { 5300259032Skevlo run_bbp_write(sc, rt5390_def_bbp[i].reg, 5301259032Skevlo rt5390_def_bbp[i].val); 5302259032Skevlo } 5303257955Skevlo } 5304257955Skevlo if (sc->mac_ver == 0x5392) { 5305257955Skevlo run_bbp_write(sc, 88, 0x90); 5306257955Skevlo run_bbp_write(sc, 95, 0x9a); 5307257955Skevlo run_bbp_write(sc, 98, 0x12); 5308257955Skevlo run_bbp_write(sc, 106, 0x12); 5309257955Skevlo run_bbp_write(sc, 134, 0xd0); 5310257955Skevlo run_bbp_write(sc, 135, 0xf6); 5311257955Skevlo run_bbp_write(sc, 148, 0x84); 5312257955Skevlo } 5313257955Skevlo 5314259032Skevlo run_bbp_read(sc, 152, &bbp); 5315259032Skevlo run_bbp_write(sc, 152, bbp | 0x80); 5316259032Skevlo 5317259032Skevlo /* Fix BBP254 for RT5592C. */ 5318259032Skevlo if (sc->mac_ver == 0x5592 && sc->mac_rev >= 0x0221) { 5319259032Skevlo run_bbp_read(sc, 254, &bbp); 5320259032Skevlo run_bbp_write(sc, 254, bbp | 0x80); 5321259032Skevlo } 5322259032Skevlo 5323257955Skevlo /* Disable hardware antenna diversity. */ 5324257955Skevlo if (sc->mac_ver == 0x5390) 5325257955Skevlo run_bbp_write(sc, 154, 0); 5326259032Skevlo 5327259032Skevlo /* Initialize Rx CCK/OFDM frequency offset report. */ 5328259032Skevlo run_bbp_write(sc, 142, 1); 5329259032Skevlo run_bbp_write(sc, 143, 57); 5330257955Skevlo} 5331257955Skevlo 5332203134Sthompsastatic int 5333203134Sthompsarun_bbp_init(struct run_softc *sc) 5334203134Sthompsa{ 5335203134Sthompsa int i, error, ntries; 5336203134Sthompsa uint8_t bbp0; 5337203134Sthompsa 5338203134Sthompsa /* wait for BBP to wake up */ 5339203134Sthompsa for (ntries = 0; ntries < 20; ntries++) { 5340203134Sthompsa if ((error = run_bbp_read(sc, 0, &bbp0)) != 0) 5341203134Sthompsa return error; 5342203134Sthompsa if (bbp0 != 0 && bbp0 != 0xff) 5343203134Sthompsa break; 5344203134Sthompsa } 5345203134Sthompsa if (ntries == 20) 5346209917Sthompsa return (ETIMEDOUT); 5347203134Sthompsa 5348203134Sthompsa /* initialize BBP registers to default values */ 5349257955Skevlo if (sc->mac_ver >= 0x5390) 5350257955Skevlo run_rt5390_bbp_init(sc); 5351257955Skevlo else { 5352257955Skevlo for (i = 0; i < nitems(rt2860_def_bbp); i++) { 5353257955Skevlo run_bbp_write(sc, rt2860_def_bbp[i].reg, 5354257955Skevlo rt2860_def_bbp[i].val); 5355257955Skevlo } 5356203134Sthompsa } 5357203134Sthompsa 5358260219Skevlo if (sc->mac_ver == 0x3593) { 5359260219Skevlo run_bbp_write(sc, 79, 0x13); 5360260219Skevlo run_bbp_write(sc, 80, 0x05); 5361260219Skevlo run_bbp_write(sc, 81, 0x33); 5362260219Skevlo run_bbp_write(sc, 86, 0x46); 5363260219Skevlo run_bbp_write(sc, 137, 0x0f); 5364260219Skevlo } 5365260219Skevlo 5366203134Sthompsa /* fix BBP84 for RT2860E */ 5367205042Sthompsa if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101) 5368205042Sthompsa run_bbp_write(sc, 84, 0x19); 5369203134Sthompsa 5370260219Skevlo if (sc->mac_ver >= 0x3070 && (sc->mac_ver != 0x3593 && 5371260219Skevlo sc->mac_ver != 0x5592)) { 5372203134Sthompsa run_bbp_write(sc, 79, 0x13); 5373203134Sthompsa run_bbp_write(sc, 80, 0x05); 5374203134Sthompsa run_bbp_write(sc, 81, 0x33); 5375205042Sthompsa } else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) { 5376203134Sthompsa run_bbp_write(sc, 69, 0x16); 5377203134Sthompsa run_bbp_write(sc, 73, 0x12); 5378203134Sthompsa } 5379209917Sthompsa return (0); 5380203134Sthompsa} 5381203134Sthompsa 5382203134Sthompsastatic int 5383203134Sthompsarun_rt3070_rf_init(struct run_softc *sc) 5384203134Sthompsa{ 5385203134Sthompsa uint32_t tmp; 5386256722Skevlo uint8_t bbp4, mingain, rf, target; 5387203134Sthompsa int i; 5388203134Sthompsa 5389203134Sthompsa run_rt3070_rf_read(sc, 30, &rf); 5390203134Sthompsa /* toggle RF R30 bit 7 */ 5391203134Sthompsa run_rt3070_rf_write(sc, 30, rf | 0x80); 5392203134Sthompsa run_delay(sc, 10); 5393203134Sthompsa run_rt3070_rf_write(sc, 30, rf & ~0x80); 5394203134Sthompsa 5395203134Sthompsa /* initialize RF registers to default value */ 5396205042Sthompsa if (sc->mac_ver == 0x3572) { 5397257955Skevlo for (i = 0; i < nitems(rt3572_def_rf); i++) { 5398205042Sthompsa run_rt3070_rf_write(sc, rt3572_def_rf[i].reg, 5399205042Sthompsa rt3572_def_rf[i].val); 5400205042Sthompsa } 5401205042Sthompsa } else { 5402257955Skevlo for (i = 0; i < nitems(rt3070_def_rf); i++) { 5403205042Sthompsa run_rt3070_rf_write(sc, rt3070_def_rf[i].reg, 5404205042Sthompsa rt3070_def_rf[i].val); 5405205042Sthompsa } 5406203134Sthompsa } 5407205042Sthompsa 5408256721Skevlo if (sc->mac_ver == 0x3070 && sc->mac_rev < 0x0201) { 5409256721Skevlo /* 5410256721Skevlo * Change voltage from 1.2V to 1.35V for RT3070. 5411256721Skevlo * The DAC issue (RT3070_LDO_CFG0) has been fixed 5412256721Skevlo * in RT3070(F). 5413256721Skevlo */ 5414203134Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 5415203134Sthompsa tmp = (tmp & ~0x0f000000) | 0x0d000000; 5416203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5417203134Sthompsa 5418205042Sthompsa } else if (sc->mac_ver == 0x3071) { 5419203134Sthompsa run_rt3070_rf_read(sc, 6, &rf); 5420203134Sthompsa run_rt3070_rf_write(sc, 6, rf | 0x40); 5421203134Sthompsa run_rt3070_rf_write(sc, 31, 0x14); 5422203134Sthompsa 5423203134Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 5424203134Sthompsa tmp &= ~0x1f000000; 5425205042Sthompsa if (sc->mac_rev < 0x0211) 5426205042Sthompsa tmp |= 0x0d000000; /* 1.3V */ 5427203134Sthompsa else 5428205042Sthompsa tmp |= 0x01000000; /* 1.2V */ 5429203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5430203134Sthompsa 5431203134Sthompsa /* patch LNA_PE_G1 */ 5432203134Sthompsa run_read(sc, RT3070_GPIO_SWITCH, &tmp); 5433203134Sthompsa run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20); 5434208019Sthompsa 5435209917Sthompsa } else if (sc->mac_ver == 0x3572) { 5436205042Sthompsa run_rt3070_rf_read(sc, 6, &rf); 5437205042Sthompsa run_rt3070_rf_write(sc, 6, rf | 0x40); 5438205042Sthompsa 5439208019Sthompsa /* increase voltage from 1.2V to 1.35V */ 5440208019Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 5441208019Sthompsa tmp = (tmp & ~0x1f000000) | 0x0d000000; 5442208019Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5443203134Sthompsa 5444209917Sthompsa if (sc->mac_rev < 0x0211 || !sc->patch_dac) { 5445203134Sthompsa run_delay(sc, 1); /* wait for 1msec */ 5446205042Sthompsa /* decrease voltage back to 1.2V */ 5447203134Sthompsa tmp = (tmp & ~0x1f000000) | 0x01000000; 5448203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5449203134Sthompsa } 5450203134Sthompsa } 5451203134Sthompsa 5452203134Sthompsa /* select 20MHz bandwidth */ 5453203134Sthompsa run_rt3070_rf_read(sc, 31, &rf); 5454203134Sthompsa run_rt3070_rf_write(sc, 31, rf & ~0x20); 5455203134Sthompsa 5456203134Sthompsa /* calibrate filter for 20MHz bandwidth */ 5457203134Sthompsa sc->rf24_20mhz = 0x1f; /* default value */ 5458205042Sthompsa target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13; 5459205042Sthompsa run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz); 5460203134Sthompsa 5461203134Sthompsa /* select 40MHz bandwidth */ 5462203134Sthompsa run_bbp_read(sc, 4, &bbp4); 5463256721Skevlo run_bbp_write(sc, 4, (bbp4 & ~0x18) | 0x10); 5464205042Sthompsa run_rt3070_rf_read(sc, 31, &rf); 5465205042Sthompsa run_rt3070_rf_write(sc, 31, rf | 0x20); 5466203134Sthompsa 5467203134Sthompsa /* calibrate filter for 40MHz bandwidth */ 5468203134Sthompsa sc->rf24_40mhz = 0x2f; /* default value */ 5469205042Sthompsa target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15; 5470205042Sthompsa run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz); 5471203134Sthompsa 5472203134Sthompsa /* go back to 20MHz bandwidth */ 5473203134Sthompsa run_bbp_read(sc, 4, &bbp4); 5474203134Sthompsa run_bbp_write(sc, 4, bbp4 & ~0x18); 5475203134Sthompsa 5476205042Sthompsa if (sc->mac_ver == 0x3572) { 5477205042Sthompsa /* save default BBP registers 25 and 26 values */ 5478205042Sthompsa run_bbp_read(sc, 25, &sc->bbp25); 5479205042Sthompsa run_bbp_read(sc, 26, &sc->bbp26); 5480256721Skevlo } else if (sc->mac_rev < 0x0201 || sc->mac_rev < 0x0211) 5481203134Sthompsa run_rt3070_rf_write(sc, 27, 0x03); 5482203134Sthompsa 5483203134Sthompsa run_read(sc, RT3070_OPT_14, &tmp); 5484203134Sthompsa run_write(sc, RT3070_OPT_14, tmp | 1); 5485203134Sthompsa 5486205042Sthompsa if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) { 5487205042Sthompsa run_rt3070_rf_read(sc, 17, &rf); 5488205042Sthompsa rf &= ~RT3070_TX_LO1; 5489205042Sthompsa if ((sc->mac_ver == 0x3070 || 5490205042Sthompsa (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) && 5491205042Sthompsa !sc->ext_2ghz_lna) 5492205042Sthompsa rf |= 0x20; /* fix for long range Rx issue */ 5493256722Skevlo mingain = (sc->mac_ver == 0x3070) ? 1 : 2; 5494256722Skevlo if (sc->txmixgain_2ghz >= mingain) 5495205042Sthompsa rf = (rf & ~0x7) | sc->txmixgain_2ghz; 5496205042Sthompsa run_rt3070_rf_write(sc, 17, rf); 5497205042Sthompsa } 5498205042Sthompsa 5499270643Skevlo if (sc->mac_ver == 0x3071) { 5500203134Sthompsa run_rt3070_rf_read(sc, 1, &rf); 5501203134Sthompsa rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD); 5502203134Sthompsa rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD; 5503203134Sthompsa run_rt3070_rf_write(sc, 1, rf); 5504203134Sthompsa 5505203134Sthompsa run_rt3070_rf_read(sc, 15, &rf); 5506203134Sthompsa run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2); 5507203134Sthompsa 5508203134Sthompsa run_rt3070_rf_read(sc, 20, &rf); 5509203134Sthompsa run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1); 5510203134Sthompsa 5511203134Sthompsa run_rt3070_rf_read(sc, 21, &rf); 5512203134Sthompsa run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2); 5513205042Sthompsa } 5514203134Sthompsa 5515205042Sthompsa if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) { 5516205042Sthompsa /* fix Tx to Rx IQ glitch by raising RF voltage */ 5517203134Sthompsa run_rt3070_rf_read(sc, 27, &rf); 5518203134Sthompsa rf &= ~0x77; 5519205042Sthompsa if (sc->mac_rev < 0x0211) 5520203134Sthompsa rf |= 0x03; 5521203134Sthompsa run_rt3070_rf_write(sc, 27, rf); 5522203134Sthompsa } 5523209917Sthompsa return (0); 5524203134Sthompsa} 5525203134Sthompsa 5526257955Skevlostatic void 5527260219Skevlorun_rt3593_rf_init(struct run_softc *sc) 5528260219Skevlo{ 5529260219Skevlo uint32_t tmp; 5530260219Skevlo uint8_t rf; 5531260219Skevlo int i; 5532260219Skevlo 5533260219Skevlo /* Disable the GPIO bits 4 and 7 for LNA PE control. */ 5534260219Skevlo run_read(sc, RT3070_GPIO_SWITCH, &tmp); 5535260219Skevlo tmp &= ~(1 << 4 | 1 << 7); 5536260219Skevlo run_write(sc, RT3070_GPIO_SWITCH, tmp); 5537260219Skevlo 5538260219Skevlo /* Initialize RF registers to default value. */ 5539260219Skevlo for (i = 0; i < nitems(rt3593_def_rf); i++) { 5540260219Skevlo run_rt3070_rf_write(sc, rt3593_def_rf[i].reg, 5541260219Skevlo rt3593_def_rf[i].val); 5542260219Skevlo } 5543260219Skevlo 5544260219Skevlo /* Toggle RF R2 to initiate calibration. */ 5545260219Skevlo run_rt3070_rf_write(sc, 2, RT5390_RESCAL); 5546260219Skevlo 5547260219Skevlo /* Initialize RF frequency offset. */ 5548260219Skevlo run_adjust_freq_offset(sc); 5549260219Skevlo 5550260219Skevlo run_rt3070_rf_read(sc, 18, &rf); 5551260219Skevlo run_rt3070_rf_write(sc, 18, rf | RT3593_AUTOTUNE_BYPASS); 5552260219Skevlo 5553260219Skevlo /* 5554260219Skevlo * Increase voltage from 1.2V to 1.35V, wait for 1 msec to 5555260219Skevlo * decrease voltage back to 1.2V. 5556260219Skevlo */ 5557260219Skevlo run_read(sc, RT3070_LDO_CFG0, &tmp); 5558260219Skevlo tmp = (tmp & ~0x1f000000) | 0x0d000000; 5559260219Skevlo run_write(sc, RT3070_LDO_CFG0, tmp); 5560260219Skevlo run_delay(sc, 1); 5561260219Skevlo tmp = (tmp & ~0x1f000000) | 0x01000000; 5562260219Skevlo run_write(sc, RT3070_LDO_CFG0, tmp); 5563260219Skevlo 5564260219Skevlo sc->rf24_20mhz = 0x1f; 5565260219Skevlo sc->rf24_40mhz = 0x2f; 5566260219Skevlo 5567260219Skevlo /* Save default BBP registers 25 and 26 values. */ 5568260219Skevlo run_bbp_read(sc, 25, &sc->bbp25); 5569260219Skevlo run_bbp_read(sc, 26, &sc->bbp26); 5570260219Skevlo 5571260219Skevlo run_read(sc, RT3070_OPT_14, &tmp); 5572260219Skevlo run_write(sc, RT3070_OPT_14, tmp | 1); 5573260219Skevlo} 5574260219Skevlo 5575260219Skevlostatic void 5576257955Skevlorun_rt5390_rf_init(struct run_softc *sc) 5577257955Skevlo{ 5578257955Skevlo uint32_t tmp; 5579257955Skevlo uint8_t rf; 5580257955Skevlo int i; 5581257955Skevlo 5582259030Skevlo /* Toggle RF R2 to initiate calibration. */ 5583259030Skevlo if (sc->mac_ver == 0x5390) { 5584257955Skevlo run_rt3070_rf_read(sc, 2, &rf); 5585259031Skevlo run_rt3070_rf_write(sc, 2, rf | RT5390_RESCAL); 5586257955Skevlo run_delay(sc, 10); 5587259031Skevlo run_rt3070_rf_write(sc, 2, rf & ~RT5390_RESCAL); 5588259030Skevlo } else { 5589259031Skevlo run_rt3070_rf_write(sc, 2, RT5390_RESCAL); 5590259030Skevlo run_delay(sc, 10); 5591257955Skevlo } 5592257955Skevlo 5593257955Skevlo /* Initialize RF registers to default value. */ 5594259032Skevlo if (sc->mac_ver == 0x5592) { 5595259032Skevlo for (i = 0; i < nitems(rt5592_def_rf); i++) { 5596259032Skevlo run_rt3070_rf_write(sc, rt5592_def_rf[i].reg, 5597259032Skevlo rt5592_def_rf[i].val); 5598259032Skevlo } 5599259032Skevlo /* Initialize RF frequency offset. */ 5600259032Skevlo run_adjust_freq_offset(sc); 5601259032Skevlo } else if (sc->mac_ver == 0x5392) { 5602257955Skevlo for (i = 0; i < nitems(rt5392_def_rf); i++) { 5603257955Skevlo run_rt3070_rf_write(sc, rt5392_def_rf[i].reg, 5604257955Skevlo rt5392_def_rf[i].val); 5605257955Skevlo } 5606257955Skevlo if (sc->mac_rev >= 0x0223) { 5607257955Skevlo run_rt3070_rf_write(sc, 23, 0x0f); 5608257955Skevlo run_rt3070_rf_write(sc, 24, 0x3e); 5609257955Skevlo run_rt3070_rf_write(sc, 51, 0x32); 5610257955Skevlo run_rt3070_rf_write(sc, 53, 0x22); 5611257955Skevlo run_rt3070_rf_write(sc, 56, 0xc1); 5612257955Skevlo run_rt3070_rf_write(sc, 59, 0x0f); 5613257955Skevlo } 5614257955Skevlo } else { 5615257955Skevlo for (i = 0; i < nitems(rt5390_def_rf); i++) { 5616257955Skevlo run_rt3070_rf_write(sc, rt5390_def_rf[i].reg, 5617257955Skevlo rt5390_def_rf[i].val); 5618257955Skevlo } 5619257955Skevlo if (sc->mac_rev >= 0x0502) { 5620257955Skevlo run_rt3070_rf_write(sc, 6, 0xe0); 5621257955Skevlo run_rt3070_rf_write(sc, 25, 0x80); 5622257955Skevlo run_rt3070_rf_write(sc, 46, 0x73); 5623257955Skevlo run_rt3070_rf_write(sc, 53, 0x00); 5624257955Skevlo run_rt3070_rf_write(sc, 56, 0x42); 5625257955Skevlo run_rt3070_rf_write(sc, 61, 0xd1); 5626257955Skevlo } 5627257955Skevlo } 5628257955Skevlo 5629257955Skevlo sc->rf24_20mhz = 0x1f; /* default value */ 5630259032Skevlo sc->rf24_40mhz = (sc->mac_ver == 0x5592) ? 0 : 0x2f; 5631257955Skevlo 5632257955Skevlo if (sc->mac_rev < 0x0211) 5633257955Skevlo run_rt3070_rf_write(sc, 27, 0x3); 5634257955Skevlo 5635257955Skevlo run_read(sc, RT3070_OPT_14, &tmp); 5636257955Skevlo run_write(sc, RT3070_OPT_14, tmp | 1); 5637257955Skevlo} 5638257955Skevlo 5639203134Sthompsastatic int 5640203134Sthompsarun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target, 5641203134Sthompsa uint8_t *val) 5642203134Sthompsa{ 5643203134Sthompsa uint8_t rf22, rf24; 5644203134Sthompsa uint8_t bbp55_pb, bbp55_sb, delta; 5645203134Sthompsa int ntries; 5646203134Sthompsa 5647203134Sthompsa /* program filter */ 5648205042Sthompsa run_rt3070_rf_read(sc, 24, &rf24); 5649205042Sthompsa rf24 = (rf24 & 0xc0) | init; /* initial filter value */ 5650203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 5651203134Sthompsa 5652203134Sthompsa /* enable baseband loopback mode */ 5653203134Sthompsa run_rt3070_rf_read(sc, 22, &rf22); 5654203134Sthompsa run_rt3070_rf_write(sc, 22, rf22 | 0x01); 5655203134Sthompsa 5656203134Sthompsa /* set power and frequency of passband test tone */ 5657203134Sthompsa run_bbp_write(sc, 24, 0x00); 5658203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5659203134Sthompsa /* transmit test tone */ 5660203134Sthompsa run_bbp_write(sc, 25, 0x90); 5661203134Sthompsa run_delay(sc, 10); 5662203134Sthompsa /* read received power */ 5663203134Sthompsa run_bbp_read(sc, 55, &bbp55_pb); 5664203134Sthompsa if (bbp55_pb != 0) 5665203134Sthompsa break; 5666203134Sthompsa } 5667203134Sthompsa if (ntries == 100) 5668257955Skevlo return (ETIMEDOUT); 5669203134Sthompsa 5670203134Sthompsa /* set power and frequency of stopband test tone */ 5671203134Sthompsa run_bbp_write(sc, 24, 0x06); 5672203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5673203134Sthompsa /* transmit test tone */ 5674203134Sthompsa run_bbp_write(sc, 25, 0x90); 5675203134Sthompsa run_delay(sc, 10); 5676203134Sthompsa /* read received power */ 5677203134Sthompsa run_bbp_read(sc, 55, &bbp55_sb); 5678203134Sthompsa 5679203134Sthompsa delta = bbp55_pb - bbp55_sb; 5680203134Sthompsa if (delta > target) 5681203134Sthompsa break; 5682203134Sthompsa 5683203134Sthompsa /* reprogram filter */ 5684203134Sthompsa rf24++; 5685203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 5686203134Sthompsa } 5687203134Sthompsa if (ntries < 100) { 5688203134Sthompsa if (rf24 != init) 5689203134Sthompsa rf24--; /* backtrack */ 5690203134Sthompsa *val = rf24; 5691203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 5692203134Sthompsa } 5693203134Sthompsa 5694203134Sthompsa /* restore initial state */ 5695203134Sthompsa run_bbp_write(sc, 24, 0x00); 5696203134Sthompsa 5697203134Sthompsa /* disable baseband loopback mode */ 5698203134Sthompsa run_rt3070_rf_read(sc, 22, &rf22); 5699203134Sthompsa run_rt3070_rf_write(sc, 22, rf22 & ~0x01); 5700203134Sthompsa 5701209917Sthompsa return (0); 5702203134Sthompsa} 5703203134Sthompsa 5704205042Sthompsastatic void 5705205042Sthompsarun_rt3070_rf_setup(struct run_softc *sc) 5706205042Sthompsa{ 5707205042Sthompsa uint8_t bbp, rf; 5708205042Sthompsa int i; 5709205042Sthompsa 5710260219Skevlo if (sc->mac_ver == 0x3572) { 5711205042Sthompsa /* enable DC filter */ 5712205042Sthompsa if (sc->mac_rev >= 0x0201) 5713205042Sthompsa run_bbp_write(sc, 103, 0xc0); 5714205042Sthompsa 5715205042Sthompsa run_bbp_read(sc, 138, &bbp); 5716205042Sthompsa if (sc->ntxchains == 1) 5717205042Sthompsa bbp |= 0x20; /* turn off DAC1 */ 5718205042Sthompsa if (sc->nrxchains == 1) 5719205042Sthompsa bbp &= ~0x02; /* turn off ADC1 */ 5720205042Sthompsa run_bbp_write(sc, 138, bbp); 5721205042Sthompsa 5722205042Sthompsa if (sc->mac_rev >= 0x0211) { 5723205042Sthompsa /* improve power consumption */ 5724205042Sthompsa run_bbp_read(sc, 31, &bbp); 5725205042Sthompsa run_bbp_write(sc, 31, bbp & ~0x03); 5726205042Sthompsa } 5727205042Sthompsa 5728205042Sthompsa run_rt3070_rf_read(sc, 16, &rf); 5729205042Sthompsa rf = (rf & ~0x07) | sc->txmixgain_2ghz; 5730205042Sthompsa run_rt3070_rf_write(sc, 16, rf); 5731205042Sthompsa 5732205042Sthompsa } else if (sc->mac_ver == 0x3071) { 5733257409Skevlo if (sc->mac_rev >= 0x0211) { 5734257409Skevlo /* enable DC filter */ 5735205042Sthompsa run_bbp_write(sc, 103, 0xc0); 5736205042Sthompsa 5737257409Skevlo /* improve power consumption */ 5738257409Skevlo run_bbp_read(sc, 31, &bbp); 5739257409Skevlo run_bbp_write(sc, 31, bbp & ~0x03); 5740257409Skevlo } 5741257409Skevlo 5742205042Sthompsa run_bbp_read(sc, 138, &bbp); 5743205042Sthompsa if (sc->ntxchains == 1) 5744205042Sthompsa bbp |= 0x20; /* turn off DAC1 */ 5745205042Sthompsa if (sc->nrxchains == 1) 5746205042Sthompsa bbp &= ~0x02; /* turn off ADC1 */ 5747205042Sthompsa run_bbp_write(sc, 138, bbp); 5748205042Sthompsa 5749205042Sthompsa run_write(sc, RT2860_TX_SW_CFG1, 0); 5750205042Sthompsa if (sc->mac_rev < 0x0211) { 5751205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 5752205042Sthompsa sc->patch_dac ? 0x2c : 0x0f); 5753205042Sthompsa } else 5754205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0); 5755205042Sthompsa 5756205042Sthompsa } else if (sc->mac_ver == 0x3070) { 5757205042Sthompsa if (sc->mac_rev >= 0x0201) { 5758205042Sthompsa /* enable DC filter */ 5759205042Sthompsa run_bbp_write(sc, 103, 0xc0); 5760205042Sthompsa 5761205042Sthompsa /* improve power consumption */ 5762205042Sthompsa run_bbp_read(sc, 31, &bbp); 5763205042Sthompsa run_bbp_write(sc, 31, bbp & ~0x03); 5764205042Sthompsa } 5765205042Sthompsa 5766256955Skevlo if (sc->mac_rev < 0x0201) { 5767205042Sthompsa run_write(sc, RT2860_TX_SW_CFG1, 0); 5768205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0x2c); 5769205042Sthompsa } else 5770205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0); 5771205042Sthompsa } 5772205042Sthompsa 5773205042Sthompsa /* initialize RF registers from ROM for >=RT3071*/ 5774260219Skevlo if (sc->mac_ver >= 0x3071) { 5775205042Sthompsa for (i = 0; i < 10; i++) { 5776205042Sthompsa if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff) 5777205042Sthompsa continue; 5778205042Sthompsa run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val); 5779205042Sthompsa } 5780205042Sthompsa } 5781205042Sthompsa} 5782205042Sthompsa 5783260219Skevlostatic void 5784260219Skevlorun_rt3593_rf_setup(struct run_softc *sc) 5785260219Skevlo{ 5786260219Skevlo uint8_t bbp, rf; 5787260219Skevlo 5788260219Skevlo if (sc->mac_rev >= 0x0211) { 5789260219Skevlo /* Enable DC filter. */ 5790260219Skevlo run_bbp_write(sc, 103, 0xc0); 5791260219Skevlo } 5792260219Skevlo run_write(sc, RT2860_TX_SW_CFG1, 0); 5793260219Skevlo if (sc->mac_rev < 0x0211) { 5794260219Skevlo run_write(sc, RT2860_TX_SW_CFG2, 5795260219Skevlo sc->patch_dac ? 0x2c : 0x0f); 5796260219Skevlo } else 5797260219Skevlo run_write(sc, RT2860_TX_SW_CFG2, 0); 5798260219Skevlo 5799260219Skevlo run_rt3070_rf_read(sc, 50, &rf); 5800260219Skevlo run_rt3070_rf_write(sc, 50, rf & ~RT3593_TX_LO2); 5801260219Skevlo 5802260219Skevlo run_rt3070_rf_read(sc, 51, &rf); 5803260219Skevlo rf = (rf & ~(RT3593_TX_LO1 | 0x0c)) | 5804260219Skevlo ((sc->txmixgain_2ghz & 0x07) << 2); 5805260219Skevlo run_rt3070_rf_write(sc, 51, rf); 5806260219Skevlo 5807260219Skevlo run_rt3070_rf_read(sc, 38, &rf); 5808260219Skevlo run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1); 5809260219Skevlo 5810260219Skevlo run_rt3070_rf_read(sc, 39, &rf); 5811260219Skevlo run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2); 5812260219Skevlo 5813260219Skevlo run_rt3070_rf_read(sc, 1, &rf); 5814260219Skevlo run_rt3070_rf_write(sc, 1, rf & ~(RT3070_RF_BLOCK | RT3070_PLL_PD)); 5815260219Skevlo 5816260219Skevlo run_rt3070_rf_read(sc, 30, &rf); 5817260219Skevlo rf = (rf & ~0x18) | 0x10; 5818260219Skevlo run_rt3070_rf_write(sc, 30, rf); 5819260219Skevlo 5820260219Skevlo /* Apply maximum likelihood detection for 2 stream case. */ 5821260219Skevlo run_bbp_read(sc, 105, &bbp); 5822260219Skevlo if (sc->nrxchains > 1) 5823260219Skevlo run_bbp_write(sc, 105, bbp | RT5390_MLD); 5824260219Skevlo 5825260219Skevlo /* Avoid data lost and CRC error. */ 5826260219Skevlo run_bbp_read(sc, 4, &bbp); 5827260219Skevlo run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 5828260219Skevlo 5829260219Skevlo run_bbp_write(sc, 92, 0x02); 5830260219Skevlo run_bbp_write(sc, 82, 0x82); 5831260219Skevlo run_bbp_write(sc, 106, 0x05); 5832260219Skevlo run_bbp_write(sc, 104, 0x92); 5833260219Skevlo run_bbp_write(sc, 88, 0x90); 5834260219Skevlo run_bbp_write(sc, 148, 0xc8); 5835260219Skevlo run_bbp_write(sc, 47, 0x48); 5836260219Skevlo run_bbp_write(sc, 120, 0x50); 5837260219Skevlo 5838260219Skevlo run_bbp_write(sc, 163, 0x9d); 5839260219Skevlo 5840260219Skevlo /* SNR mapping. */ 5841260219Skevlo run_bbp_write(sc, 142, 0x06); 5842260219Skevlo run_bbp_write(sc, 143, 0xa0); 5843260219Skevlo run_bbp_write(sc, 142, 0x07); 5844260219Skevlo run_bbp_write(sc, 143, 0xa1); 5845260219Skevlo run_bbp_write(sc, 142, 0x08); 5846260219Skevlo run_bbp_write(sc, 143, 0xa2); 5847260219Skevlo 5848260219Skevlo run_bbp_write(sc, 31, 0x08); 5849260219Skevlo run_bbp_write(sc, 68, 0x0b); 5850260219Skevlo run_bbp_write(sc, 105, 0x04); 5851260219Skevlo} 5852260219Skevlo 5853260219Skevlostatic void 5854260219Skevlorun_rt5390_rf_setup(struct run_softc *sc) 5855260219Skevlo{ 5856260219Skevlo uint8_t bbp, rf; 5857260219Skevlo 5858260219Skevlo if (sc->mac_rev >= 0x0211) { 5859260219Skevlo /* Enable DC filter. */ 5860260219Skevlo run_bbp_write(sc, 103, 0xc0); 5861260219Skevlo 5862260219Skevlo if (sc->mac_ver != 0x5592) { 5863260219Skevlo /* Improve power consumption. */ 5864260219Skevlo run_bbp_read(sc, 31, &bbp); 5865260219Skevlo run_bbp_write(sc, 31, bbp & ~0x03); 5866260219Skevlo } 5867260219Skevlo } 5868260219Skevlo 5869260219Skevlo run_bbp_read(sc, 138, &bbp); 5870260219Skevlo if (sc->ntxchains == 1) 5871260219Skevlo bbp |= 0x20; /* turn off DAC1 */ 5872260219Skevlo if (sc->nrxchains == 1) 5873260219Skevlo bbp &= ~0x02; /* turn off ADC1 */ 5874260219Skevlo run_bbp_write(sc, 138, bbp); 5875260219Skevlo 5876260219Skevlo run_rt3070_rf_read(sc, 38, &rf); 5877260219Skevlo run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1); 5878260219Skevlo 5879260219Skevlo run_rt3070_rf_read(sc, 39, &rf); 5880260219Skevlo run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2); 5881260219Skevlo 5882260219Skevlo /* Avoid data lost and CRC error. */ 5883260219Skevlo run_bbp_read(sc, 4, &bbp); 5884260219Skevlo run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 5885260219Skevlo 5886260219Skevlo run_rt3070_rf_read(sc, 30, &rf); 5887260219Skevlo rf = (rf & ~0x18) | 0x10; 5888260219Skevlo run_rt3070_rf_write(sc, 30, rf); 5889260219Skevlo 5890260219Skevlo if (sc->mac_ver != 0x5592) { 5891260219Skevlo run_write(sc, RT2860_TX_SW_CFG1, 0); 5892260219Skevlo if (sc->mac_rev < 0x0211) { 5893260219Skevlo run_write(sc, RT2860_TX_SW_CFG2, 5894260219Skevlo sc->patch_dac ? 0x2c : 0x0f); 5895260219Skevlo } else 5896260219Skevlo run_write(sc, RT2860_TX_SW_CFG2, 0); 5897260219Skevlo } 5898260219Skevlo} 5899260219Skevlo 5900203134Sthompsastatic int 5901203134Sthompsarun_txrx_enable(struct run_softc *sc) 5902203134Sthompsa{ 5903203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 5904203134Sthompsa uint32_t tmp; 5905203134Sthompsa int error, ntries; 5906203134Sthompsa 5907203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN); 5908203134Sthompsa for (ntries = 0; ntries < 200; ntries++) { 5909203134Sthompsa if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0) 5910257955Skevlo return (error); 5911203134Sthompsa if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 5912203134Sthompsa break; 5913203134Sthompsa run_delay(sc, 50); 5914203134Sthompsa } 5915203134Sthompsa if (ntries == 200) 5916257955Skevlo return (ETIMEDOUT); 5917203134Sthompsa 5918203134Sthompsa run_delay(sc, 50); 5919203134Sthompsa 5920203134Sthompsa tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE; 5921203134Sthompsa run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 5922203134Sthompsa 5923203134Sthompsa /* enable Rx bulk aggregation (set timeout and limit) */ 5924203134Sthompsa tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN | 5925203134Sthompsa RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2); 5926203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, tmp); 5927203134Sthompsa 5928203134Sthompsa /* set Rx filter */ 5929203134Sthompsa tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR; 5930203134Sthompsa if (ic->ic_opmode != IEEE80211_M_MONITOR) { 5931203134Sthompsa tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL | 5932203134Sthompsa RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK | 5933203134Sthompsa RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV | 5934203134Sthompsa RT2860_DROP_CFACK | RT2860_DROP_CFEND; 5935203134Sthompsa if (ic->ic_opmode == IEEE80211_M_STA) 5936203134Sthompsa tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL; 5937203134Sthompsa } 5938203134Sthompsa run_write(sc, RT2860_RX_FILTR_CFG, tmp); 5939203134Sthompsa 5940203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 5941203134Sthompsa RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 5942203134Sthompsa 5943209917Sthompsa return (0); 5944203134Sthompsa} 5945203134Sthompsa 5946203134Sthompsastatic void 5947259030Skevlorun_adjust_freq_offset(struct run_softc *sc) 5948257955Skevlo{ 5949257955Skevlo uint8_t rf, tmp; 5950257955Skevlo 5951257955Skevlo run_rt3070_rf_read(sc, 17, &rf); 5952257955Skevlo tmp = rf; 5953257955Skevlo rf = (rf & ~0x7f) | (sc->freq & 0x7f); 5954257955Skevlo rf = MIN(rf, 0x5f); 5955257955Skevlo 5956257955Skevlo if (tmp != rf) 5957257955Skevlo run_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf); 5958257955Skevlo} 5959257955Skevlo 5960257955Skevlostatic void 5961203134Sthompsarun_init_locked(struct run_softc *sc) 5962203134Sthompsa{ 5963203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 5964203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 5965203134Sthompsa uint32_t tmp; 5966203134Sthompsa uint8_t bbp1, bbp3; 5967203134Sthompsa int i; 5968203134Sthompsa int ridx; 5969203134Sthompsa int ntries; 5970203134Sthompsa 5971209917Sthompsa if (ic->ic_nrunning > 1) 5972208019Sthompsa return; 5973208019Sthompsa 5974203134Sthompsa run_stop(sc); 5975203134Sthompsa 5976233283Sbschmidt if (run_load_microcode(sc) != 0) { 5977233283Sbschmidt device_printf(sc->sc_dev, "could not load 8051 microcode\n"); 5978233283Sbschmidt goto fail; 5979233283Sbschmidt } 5980233283Sbschmidt 5981203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5982203134Sthompsa if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0) 5983203134Sthompsa goto fail; 5984203134Sthompsa if (tmp != 0 && tmp != 0xffffffff) 5985203134Sthompsa break; 5986203134Sthompsa run_delay(sc, 10); 5987203134Sthompsa } 5988203134Sthompsa if (ntries == 100) 5989203134Sthompsa goto fail; 5990203134Sthompsa 5991203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 5992203134Sthompsa run_setup_tx_list(sc, &sc->sc_epq[i]); 5993203134Sthompsa 5994203134Sthompsa run_set_macaddr(sc, IF_LLADDR(ifp)); 5995203134Sthompsa 5996203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5997203134Sthompsa if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 5998203134Sthompsa goto fail; 5999203134Sthompsa if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 6000203134Sthompsa break; 6001203134Sthompsa run_delay(sc, 10); 6002203134Sthompsa } 6003203134Sthompsa if (ntries == 100) { 6004203138Sthompsa device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); 6005203134Sthompsa goto fail; 6006203134Sthompsa } 6007203134Sthompsa tmp &= 0xff0; 6008203134Sthompsa tmp |= RT2860_TX_WB_DDONE; 6009203134Sthompsa run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 6010203134Sthompsa 6011203134Sthompsa /* turn off PME_OEN to solve high-current issue */ 6012203134Sthompsa run_read(sc, RT2860_SYS_CTRL, &tmp); 6013203134Sthompsa run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN); 6014203134Sthompsa 6015203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 6016203134Sthompsa RT2860_BBP_HRST | RT2860_MAC_SRST); 6017203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, 0); 6018203134Sthompsa 6019203134Sthompsa if (run_reset(sc) != 0) { 6020203138Sthompsa device_printf(sc->sc_dev, "could not reset chipset\n"); 6021203134Sthompsa goto fail; 6022203134Sthompsa } 6023203134Sthompsa 6024203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 0); 6025203134Sthompsa 6026203134Sthompsa /* init Tx power for all Tx rates (from EEPROM) */ 6027203134Sthompsa for (ridx = 0; ridx < 5; ridx++) { 6028203134Sthompsa if (sc->txpow20mhz[ridx] == 0xffffffff) 6029203134Sthompsa continue; 6030203134Sthompsa run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]); 6031203134Sthompsa } 6032203134Sthompsa 6033257955Skevlo for (i = 0; i < nitems(rt2870_def_mac); i++) 6034203134Sthompsa run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val); 6035203134Sthompsa run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273); 6036203134Sthompsa run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344); 6037203134Sthompsa run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa); 6038203134Sthompsa 6039259030Skevlo if (sc->mac_ver >= 0x5390) { 6040259030Skevlo run_write(sc, RT2860_TX_SW_CFG0, 6041259030Skevlo 4 << RT2860_DLY_PAPE_EN_SHIFT | 4); 6042259030Skevlo if (sc->mac_ver >= 0x5392) { 6043259030Skevlo run_write(sc, RT2860_MAX_LEN_CFG, 0x00002fff); 6044259032Skevlo if (sc->mac_ver == 0x5592) { 6045259032Skevlo run_write(sc, RT2860_HT_FBK_CFG1, 0xedcba980); 6046259032Skevlo run_write(sc, RT2860_TXOP_HLDR_ET, 0x00000082); 6047259032Skevlo } else { 6048259032Skevlo run_write(sc, RT2860_HT_FBK_CFG1, 0xedcb4980); 6049259032Skevlo run_write(sc, RT2860_LG_FBK_CFG0, 0xedcba322); 6050259032Skevlo } 6051259030Skevlo } 6052260219Skevlo } else if (sc->mac_ver == 0x3593) { 6053260219Skevlo run_write(sc, RT2860_TX_SW_CFG0, 6054260219Skevlo 4 << RT2860_DLY_PAPE_EN_SHIFT | 2); 6055257955Skevlo } else if (sc->mac_ver >= 0x3070) { 6056203134Sthompsa /* set delay of PA_PE assertion to 1us (unit of 0.25us) */ 6057203134Sthompsa run_write(sc, RT2860_TX_SW_CFG0, 6058203134Sthompsa 4 << RT2860_DLY_PAPE_EN_SHIFT); 6059203134Sthompsa } 6060203134Sthompsa 6061203134Sthompsa /* wait while MAC is busy */ 6062203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 6063203134Sthompsa if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0) 6064203134Sthompsa goto fail; 6065203134Sthompsa if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY))) 6066203134Sthompsa break; 6067203134Sthompsa run_delay(sc, 10); 6068203134Sthompsa } 6069203134Sthompsa if (ntries == 100) 6070203134Sthompsa goto fail; 6071203134Sthompsa 6072203134Sthompsa /* clear Host to MCU mailbox */ 6073203134Sthompsa run_write(sc, RT2860_H2M_BBPAGENT, 0); 6074203134Sthompsa run_write(sc, RT2860_H2M_MAILBOX, 0); 6075203134Sthompsa run_delay(sc, 10); 6076203134Sthompsa 6077203134Sthompsa if (run_bbp_init(sc) != 0) { 6078203138Sthompsa device_printf(sc->sc_dev, "could not initialize BBP\n"); 6079203134Sthompsa goto fail; 6080203134Sthompsa } 6081203134Sthompsa 6082203134Sthompsa /* abort TSF synchronization */ 6083203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 6084203134Sthompsa tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 6085203134Sthompsa RT2860_TBTT_TIMER_EN); 6086203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, tmp); 6087203134Sthompsa 6088203134Sthompsa /* clear RX WCID search table */ 6089203134Sthompsa run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512); 6090203134Sthompsa /* clear WCID attribute table */ 6091203134Sthompsa run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32); 6092203134Sthompsa 6093209144Sthompsa /* hostapd sets a key before init. So, don't clear it. */ 6094209917Sthompsa if (sc->cmdq_key_set != RUN_CMDQ_GO) { 6095209144Sthompsa /* clear shared key table */ 6096209144Sthompsa run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32); 6097209144Sthompsa /* clear shared key mode */ 6098209144Sthompsa run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4); 6099209144Sthompsa } 6100209144Sthompsa 6101203134Sthompsa run_read(sc, RT2860_US_CYC_CNT, &tmp); 6102203134Sthompsa tmp = (tmp & ~0xff) | 0x1e; 6103203134Sthompsa run_write(sc, RT2860_US_CYC_CNT, tmp); 6104203134Sthompsa 6105205042Sthompsa if (sc->mac_rev != 0x0101) 6106203134Sthompsa run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f); 6107203134Sthompsa 6108203134Sthompsa run_write(sc, RT2860_WMM_TXOP0_CFG, 0); 6109203134Sthompsa run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96); 6110203134Sthompsa 6111203134Sthompsa /* write vendor-specific BBP values (from EEPROM) */ 6112260219Skevlo if (sc->mac_ver < 0x3593) { 6113257955Skevlo for (i = 0; i < 10; i++) { 6114257955Skevlo if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff) 6115257955Skevlo continue; 6116257955Skevlo run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val); 6117257955Skevlo } 6118203134Sthompsa } 6119203134Sthompsa 6120203134Sthompsa /* select Main antenna for 1T1R devices */ 6121257955Skevlo if (sc->rf_rev == RT3070_RF_3020 || sc->rf_rev == RT5390_RF_5370) 6122203134Sthompsa run_set_rx_antenna(sc, 0); 6123203134Sthompsa 6124203134Sthompsa /* send LEDs operating mode to microcontroller */ 6125203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]); 6126203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]); 6127203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]); 6128203134Sthompsa 6129257955Skevlo if (sc->mac_ver >= 0x5390) 6130257955Skevlo run_rt5390_rf_init(sc); 6131260219Skevlo else if (sc->mac_ver == 0x3593) 6132260219Skevlo run_rt3593_rf_init(sc); 6133257955Skevlo else if (sc->mac_ver >= 0x3070) 6134205042Sthompsa run_rt3070_rf_init(sc); 6135205042Sthompsa 6136203134Sthompsa /* disable non-existing Rx chains */ 6137203134Sthompsa run_bbp_read(sc, 3, &bbp3); 6138203134Sthompsa bbp3 &= ~(1 << 3 | 1 << 4); 6139203134Sthompsa if (sc->nrxchains == 2) 6140203134Sthompsa bbp3 |= 1 << 3; 6141203134Sthompsa else if (sc->nrxchains == 3) 6142203134Sthompsa bbp3 |= 1 << 4; 6143203134Sthompsa run_bbp_write(sc, 3, bbp3); 6144203134Sthompsa 6145203134Sthompsa /* disable non-existing Tx chains */ 6146203134Sthompsa run_bbp_read(sc, 1, &bbp1); 6147203134Sthompsa if (sc->ntxchains == 1) 6148203134Sthompsa bbp1 &= ~(1 << 3 | 1 << 4); 6149203134Sthompsa run_bbp_write(sc, 1, bbp1); 6150203134Sthompsa 6151260219Skevlo if (sc->mac_ver >= 0x5390) 6152260219Skevlo run_rt5390_rf_setup(sc); 6153260219Skevlo else if (sc->mac_ver == 0x3593) 6154260219Skevlo run_rt3593_rf_setup(sc); 6155260219Skevlo else if (sc->mac_ver >= 0x3070) 6156205042Sthompsa run_rt3070_rf_setup(sc); 6157203134Sthompsa 6158203134Sthompsa /* select default channel */ 6159203134Sthompsa run_set_chan(sc, ic->ic_curchan); 6160203134Sthompsa 6161203134Sthompsa /* setup initial protection mode */ 6162218492Sbschmidt run_updateprot_cb(ic); 6163203134Sthompsa 6164203134Sthompsa /* turn radio LED on */ 6165203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO); 6166203134Sthompsa 6167203134Sthompsa ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 6168203134Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 6169208019Sthompsa sc->cmdq_run = RUN_CMDQ_GO; 6170203134Sthompsa 6171209917Sthompsa for (i = 0; i != RUN_N_XFER; i++) 6172203134Sthompsa usbd_xfer_set_stall(sc->sc_xfer[i]); 6173203134Sthompsa 6174203134Sthompsa usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]); 6175203134Sthompsa 6176203134Sthompsa if (run_txrx_enable(sc) != 0) 6177203134Sthompsa goto fail; 6178203134Sthompsa 6179203134Sthompsa return; 6180203134Sthompsa 6181203134Sthompsafail: 6182203134Sthompsa run_stop(sc); 6183203134Sthompsa} 6184203134Sthompsa 6185203134Sthompsastatic void 6186203134Sthompsarun_init(void *arg) 6187203134Sthompsa{ 6188203134Sthompsa struct run_softc *sc = arg; 6189203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 6190203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 6191203134Sthompsa 6192203134Sthompsa RUN_LOCK(sc); 6193203134Sthompsa run_init_locked(sc); 6194203134Sthompsa RUN_UNLOCK(sc); 6195203134Sthompsa 6196203134Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING) 6197208019Sthompsa ieee80211_start_all(ic); 6198203134Sthompsa} 6199203134Sthompsa 6200203134Sthompsastatic void 6201203134Sthompsarun_stop(void *arg) 6202203134Sthompsa{ 6203203134Sthompsa struct run_softc *sc = (struct run_softc *)arg; 6204203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 6205203134Sthompsa uint32_t tmp; 6206203134Sthompsa int i; 6207203134Sthompsa int ntries; 6208203134Sthompsa 6209203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 6210203134Sthompsa 6211203134Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING) 6212203134Sthompsa run_set_leds(sc, 0); /* turn all LEDs off */ 6213203134Sthompsa 6214203134Sthompsa ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 6215203134Sthompsa 6216208019Sthompsa sc->ratectl_run = RUN_RATECTL_OFF; 6217209144Sthompsa sc->cmdq_run = sc->cmdq_key_set; 6218208019Sthompsa 6219203134Sthompsa RUN_UNLOCK(sc); 6220203134Sthompsa 6221203134Sthompsa for(i = 0; i < RUN_N_XFER; i++) 6222203134Sthompsa usbd_transfer_drain(sc->sc_xfer[i]); 6223203134Sthompsa 6224203134Sthompsa RUN_LOCK(sc); 6225203134Sthompsa 6226209917Sthompsa if (sc->rx_m != NULL) { 6227203134Sthompsa m_free(sc->rx_m); 6228203134Sthompsa sc->rx_m = NULL; 6229203134Sthompsa } 6230203134Sthompsa 6231257955Skevlo /* Disable Tx/Rx DMA. */ 6232257955Skevlo if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 6233257955Skevlo return; 6234257955Skevlo tmp &= ~(RT2860_RX_DMA_EN | RT2860_TX_DMA_EN); 6235257955Skevlo run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 6236257955Skevlo 6237258643Shselasky for (ntries = 0; ntries < 100; ntries++) { 6238257955Skevlo if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 6239257955Skevlo return; 6240257955Skevlo if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 6241257955Skevlo break; 6242257955Skevlo run_delay(sc, 10); 6243257955Skevlo } 6244257955Skevlo if (ntries == 100) { 6245257955Skevlo device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); 6246257955Skevlo return; 6247257955Skevlo } 6248257955Skevlo 6249203134Sthompsa /* disable Tx/Rx */ 6250203134Sthompsa run_read(sc, RT2860_MAC_SYS_CTRL, &tmp); 6251203134Sthompsa tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 6252203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, tmp); 6253203134Sthompsa 6254203134Sthompsa /* wait for pending Tx to complete */ 6255203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 6256209917Sthompsa if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0) { 6257203134Sthompsa DPRINTF("Cannot read Tx queue count\n"); 6258203134Sthompsa break; 6259203134Sthompsa } 6260209917Sthompsa if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0) { 6261203134Sthompsa DPRINTF("All Tx cleared\n"); 6262203134Sthompsa break; 6263203134Sthompsa } 6264203134Sthompsa run_delay(sc, 10); 6265203134Sthompsa } 6266209917Sthompsa if (ntries >= 100) 6267203134Sthompsa DPRINTF("There are still pending Tx\n"); 6268203134Sthompsa run_delay(sc, 10); 6269203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, 0); 6270203134Sthompsa 6271203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST); 6272203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 0); 6273203134Sthompsa 6274203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 6275203134Sthompsa run_unsetup_tx_list(sc, &sc->sc_epq[i]); 6276203134Sthompsa} 6277203134Sthompsa 6278203134Sthompsastatic void 6279257429Shselaskyrun_delay(struct run_softc *sc, u_int ms) 6280203134Sthompsa{ 6281203134Sthompsa usb_pause_mtx(mtx_owned(&sc->sc_mtx) ? 6282203134Sthompsa &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms)); 6283203134Sthompsa} 6284203134Sthompsa 6285203134Sthompsastatic device_method_t run_methods[] = { 6286203134Sthompsa /* Device interface */ 6287203134Sthompsa DEVMETHOD(device_probe, run_match), 6288203134Sthompsa DEVMETHOD(device_attach, run_attach), 6289203134Sthompsa DEVMETHOD(device_detach, run_detach), 6290246614Shselasky DEVMETHOD_END 6291203134Sthompsa}; 6292203134Sthompsa 6293203134Sthompsastatic driver_t run_driver = { 6294233774Shselasky .name = "run", 6295233774Shselasky .methods = run_methods, 6296233774Shselasky .size = sizeof(struct run_softc) 6297203134Sthompsa}; 6298203134Sthompsa 6299203134Sthompsastatic devclass_t run_devclass; 6300203134Sthompsa 6301259812SkevloDRIVER_MODULE(run, uhub, run_driver, run_devclass, run_driver_loaded, NULL); 6302212122SthompsaMODULE_DEPEND(run, wlan, 1, 1, 1); 6303212122SthompsaMODULE_DEPEND(run, usb, 1, 1, 1); 6304212122SthompsaMODULE_DEPEND(run, firmware, 1, 1, 1); 6305212122SthompsaMODULE_VERSION(run, 1); 6306