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