if_run.c revision 293339
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 293339 2016-01-07 18:41:03Z avos $"); 22203134Sthompsa 23203134Sthompsa/*- 24257955Skevlo * Ralink Technology RT2700U/RT2800U/RT3000U/RT3900E chipset driver. 25203134Sthompsa * http://www.ralinktech.com/ 26203134Sthompsa */ 27203134Sthompsa 28203134Sthompsa#include <sys/param.h> 29203134Sthompsa#include <sys/sockio.h> 30203134Sthompsa#include <sys/sysctl.h> 31203134Sthompsa#include <sys/lock.h> 32203134Sthompsa#include <sys/mutex.h> 33203134Sthompsa#include <sys/mbuf.h> 34203134Sthompsa#include <sys/kernel.h> 35203134Sthompsa#include <sys/socket.h> 36203134Sthompsa#include <sys/systm.h> 37203134Sthompsa#include <sys/malloc.h> 38203134Sthompsa#include <sys/module.h> 39203134Sthompsa#include <sys/bus.h> 40203134Sthompsa#include <sys/endian.h> 41203134Sthompsa#include <sys/linker.h> 42203134Sthompsa#include <sys/firmware.h> 43203134Sthompsa#include <sys/kdb.h> 44203134Sthompsa 45203134Sthompsa#include <machine/bus.h> 46203134Sthompsa#include <machine/resource.h> 47203134Sthompsa#include <sys/rman.h> 48203134Sthompsa 49203134Sthompsa#include <net/bpf.h> 50203134Sthompsa#include <net/if.h> 51257176Sglebius#include <net/if_var.h> 52203134Sthompsa#include <net/if_arp.h> 53203134Sthompsa#include <net/ethernet.h> 54203134Sthompsa#include <net/if_dl.h> 55203134Sthompsa#include <net/if_media.h> 56203134Sthompsa#include <net/if_types.h> 57203134Sthompsa 58203134Sthompsa#include <netinet/in.h> 59203134Sthompsa#include <netinet/in_systm.h> 60203134Sthompsa#include <netinet/in_var.h> 61203134Sthompsa#include <netinet/if_ether.h> 62203134Sthompsa#include <netinet/ip.h> 63203134Sthompsa 64203134Sthompsa#include <net80211/ieee80211_var.h> 65203134Sthompsa#include <net80211/ieee80211_regdomain.h> 66203134Sthompsa#include <net80211/ieee80211_radiotap.h> 67206358Srpaulo#include <net80211/ieee80211_ratectl.h> 68203134Sthompsa 69203134Sthompsa#include <dev/usb/usb.h> 70203134Sthompsa#include <dev/usb/usbdi.h> 71203134Sthompsa#include "usbdevs.h" 72203134Sthompsa 73259546Skevlo#define USB_DEBUG_VAR run_debug 74203134Sthompsa#include <dev/usb/usb_debug.h> 75259812Skevlo#include <dev/usb/usb_msctest.h> 76203134Sthompsa 77220235Skevlo#include <dev/usb/wlan/if_runreg.h> 78220235Skevlo#include <dev/usb/wlan/if_runvar.h> 79203134Sthompsa 80207077Sthompsa#ifdef USB_DEBUG 81259546Skevlo#define RUN_DEBUG 82203134Sthompsa#endif 83203134Sthompsa 84203134Sthompsa#ifdef RUN_DEBUG 85203134Sthompsaint run_debug = 0; 86227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, run, CTLFLAG_RW, 0, "USB run"); 87276701ShselaskySYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RWTUN, &run_debug, 0, 88203134Sthompsa "run debug level"); 89203134Sthompsa#endif 90203134Sthompsa 91287552Skevlo#define IEEE80211_HAS_ADDR4(wh) IEEE80211_IS_DSTODS(wh) 92203134Sthompsa 93208019Sthompsa/* 94208019Sthompsa * Because of LOR in run_key_delete(), use atomic instead. 95208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[]. 96208019Sthompsa */ 97259546Skevlo#define RUN_CMDQ_GET(c) (atomic_fetchadd_32((c), 1) & RUN_CMDQ_MASQ) 98208019Sthompsa 99223486Shselaskystatic const STRUCT_USB_HOST_ID run_devs[] = { 100259546Skevlo#define RUN_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } 101259812Skevlo#define RUN_DEV_EJECT(v,p) \ 102262465Skevlo { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RUN_EJECT) } 103262465Skevlo#define RUN_EJECT 1 104209918Sthompsa RUN_DEV(ABOCOM, RT2770), 105209918Sthompsa RUN_DEV(ABOCOM, RT2870), 106209918Sthompsa RUN_DEV(ABOCOM, RT3070), 107209918Sthompsa RUN_DEV(ABOCOM, RT3071), 108209918Sthompsa RUN_DEV(ABOCOM, RT3072), 109209918Sthompsa RUN_DEV(ABOCOM2, RT2870_1), 110209918Sthompsa RUN_DEV(ACCTON, RT2770), 111209918Sthompsa RUN_DEV(ACCTON, RT2870_1), 112209918Sthompsa RUN_DEV(ACCTON, RT2870_2), 113209918Sthompsa RUN_DEV(ACCTON, RT2870_3), 114209918Sthompsa RUN_DEV(ACCTON, RT2870_4), 115209918Sthompsa RUN_DEV(ACCTON, RT2870_5), 116209918Sthompsa RUN_DEV(ACCTON, RT3070), 117209918Sthompsa RUN_DEV(ACCTON, RT3070_1), 118209918Sthompsa RUN_DEV(ACCTON, RT3070_2), 119209918Sthompsa RUN_DEV(ACCTON, RT3070_3), 120209918Sthompsa RUN_DEV(ACCTON, RT3070_4), 121209918Sthompsa RUN_DEV(ACCTON, RT3070_5), 122209918Sthompsa RUN_DEV(AIRTIES, RT3070), 123209918Sthompsa RUN_DEV(ALLWIN, RT2070), 124209918Sthompsa RUN_DEV(ALLWIN, RT2770), 125209918Sthompsa RUN_DEV(ALLWIN, RT2870), 126209918Sthompsa RUN_DEV(ALLWIN, RT3070), 127209918Sthompsa RUN_DEV(ALLWIN, RT3071), 128209918Sthompsa RUN_DEV(ALLWIN, RT3072), 129209918Sthompsa RUN_DEV(ALLWIN, RT3572), 130209918Sthompsa RUN_DEV(AMIGO, RT2870_1), 131209918Sthompsa RUN_DEV(AMIGO, RT2870_2), 132209918Sthompsa RUN_DEV(AMIT, CGWLUSB2GNR), 133209918Sthompsa RUN_DEV(AMIT, RT2870_1), 134209918Sthompsa RUN_DEV(AMIT2, RT2870), 135209918Sthompsa RUN_DEV(ASUS, RT2870_1), 136209918Sthompsa RUN_DEV(ASUS, RT2870_2), 137209918Sthompsa RUN_DEV(ASUS, RT2870_3), 138209918Sthompsa RUN_DEV(ASUS, RT2870_4), 139209918Sthompsa RUN_DEV(ASUS, RT2870_5), 140209918Sthompsa RUN_DEV(ASUS, USBN13), 141209918Sthompsa RUN_DEV(ASUS, RT3070_1), 142260219Skevlo RUN_DEV(ASUS, USBN66), 143239358Shselasky RUN_DEV(ASUS, USB_N53), 144209918Sthompsa RUN_DEV(ASUS2, USBN11), 145209918Sthompsa RUN_DEV(AZUREWAVE, RT2870_1), 146209918Sthompsa RUN_DEV(AZUREWAVE, RT2870_2), 147209918Sthompsa RUN_DEV(AZUREWAVE, RT3070_1), 148209918Sthompsa RUN_DEV(AZUREWAVE, RT3070_2), 149209918Sthompsa RUN_DEV(AZUREWAVE, RT3070_3), 150260219Skevlo RUN_DEV(BELKIN, F9L1103), 151209918Sthompsa RUN_DEV(BELKIN, F5D8053V3), 152209918Sthompsa RUN_DEV(BELKIN, F5D8055), 153226534Shselasky RUN_DEV(BELKIN, F5D8055V2), 154209918Sthompsa RUN_DEV(BELKIN, F6D4050V1), 155256500Shselasky RUN_DEV(BELKIN, F6D4050V2), 156209918Sthompsa RUN_DEV(BELKIN, RT2870_1), 157209918Sthompsa RUN_DEV(BELKIN, RT2870_2), 158226534Shselasky RUN_DEV(CISCOLINKSYS, AE1000), 159209918Sthompsa RUN_DEV(CISCOLINKSYS2, RT3070), 160209918Sthompsa RUN_DEV(CISCOLINKSYS3, RT3070), 161209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_1), 162209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_2), 163209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_3), 164209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_4), 165209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_5), 166209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_6), 167209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_7), 168209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_8), 169209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT3070_1), 170209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT3070_2), 171209918Sthompsa RUN_DEV(CONCEPTRONIC2, VIGORN61), 172209918Sthompsa RUN_DEV(COREGA, CGWLUSB300GNM), 173209918Sthompsa RUN_DEV(COREGA, RT2870_1), 174209918Sthompsa RUN_DEV(COREGA, RT2870_2), 175209918Sthompsa RUN_DEV(COREGA, RT2870_3), 176209918Sthompsa RUN_DEV(COREGA, RT3070), 177209918Sthompsa RUN_DEV(CYBERTAN, RT2870), 178209918Sthompsa RUN_DEV(DLINK, RT2870), 179209918Sthompsa RUN_DEV(DLINK, RT3072), 180255238Sbr RUN_DEV(DLINK, DWA127), 181257955Skevlo RUN_DEV(DLINK, DWA140B3), 182259032Skevlo RUN_DEV(DLINK, DWA160B2), 183267089Skevlo RUN_DEV(DLINK, DWA140D1), 184260219Skevlo RUN_DEV(DLINK, DWA162), 185209918Sthompsa RUN_DEV(DLINK2, DWA130), 186209918Sthompsa RUN_DEV(DLINK2, RT2870_1), 187209918Sthompsa RUN_DEV(DLINK2, RT2870_2), 188209918Sthompsa RUN_DEV(DLINK2, RT3070_1), 189209918Sthompsa RUN_DEV(DLINK2, RT3070_2), 190209918Sthompsa RUN_DEV(DLINK2, RT3070_3), 191209918Sthompsa RUN_DEV(DLINK2, RT3070_4), 192209918Sthompsa RUN_DEV(DLINK2, RT3070_5), 193209918Sthompsa RUN_DEV(DLINK2, RT3072), 194209918Sthompsa RUN_DEV(DLINK2, RT3072_1), 195209918Sthompsa RUN_DEV(EDIMAX, EW7717), 196209918Sthompsa RUN_DEV(EDIMAX, EW7718), 197260219Skevlo RUN_DEV(EDIMAX, EW7733UND), 198209918Sthompsa RUN_DEV(EDIMAX, RT2870_1), 199209918Sthompsa RUN_DEV(ENCORE, RT3070_1), 200209918Sthompsa RUN_DEV(ENCORE, RT3070_2), 201209918Sthompsa RUN_DEV(ENCORE, RT3070_3), 202209918Sthompsa RUN_DEV(GIGABYTE, GNWB31N), 203209918Sthompsa RUN_DEV(GIGABYTE, GNWB32L), 204209918Sthompsa RUN_DEV(GIGABYTE, RT2870_1), 205209918Sthompsa RUN_DEV(GIGASET, RT3070_1), 206209918Sthompsa RUN_DEV(GIGASET, RT3070_2), 207209918Sthompsa RUN_DEV(GUILLEMOT, HWNU300), 208209918Sthompsa RUN_DEV(HAWKING, HWUN2), 209209918Sthompsa RUN_DEV(HAWKING, RT2870_1), 210209918Sthompsa RUN_DEV(HAWKING, RT2870_2), 211209918Sthompsa RUN_DEV(HAWKING, RT3070), 212209918Sthompsa RUN_DEV(IODATA, RT3072_1), 213209918Sthompsa RUN_DEV(IODATA, RT3072_2), 214209918Sthompsa RUN_DEV(IODATA, RT3072_3), 215209918Sthompsa RUN_DEV(IODATA, RT3072_4), 216209918Sthompsa RUN_DEV(LINKSYS4, RT3070), 217209918Sthompsa RUN_DEV(LINKSYS4, WUSB100), 218209918Sthompsa RUN_DEV(LINKSYS4, WUSB54GCV3), 219209918Sthompsa RUN_DEV(LINKSYS4, WUSB600N), 220209918Sthompsa RUN_DEV(LINKSYS4, WUSB600NV2), 221209918Sthompsa RUN_DEV(LOGITEC, RT2870_1), 222209918Sthompsa RUN_DEV(LOGITEC, RT2870_2), 223209918Sthompsa RUN_DEV(LOGITEC, RT2870_3), 224230333Shselasky RUN_DEV(LOGITEC, LANW300NU2), 225238274Shrs RUN_DEV(LOGITEC, LANW150NU2), 226248458Shselasky RUN_DEV(LOGITEC, LANW300NU2S), 227281745Skevlo RUN_DEV(MELCO, WLIUCG300HP), 228209918Sthompsa RUN_DEV(MELCO, RT2870_2), 229209918Sthompsa RUN_DEV(MELCO, WLIUCAG300N), 230209918Sthompsa RUN_DEV(MELCO, WLIUCG300N), 231219257Sdaichi RUN_DEV(MELCO, WLIUCG301N), 232209918Sthompsa RUN_DEV(MELCO, WLIUCGN), 233227781Shselasky RUN_DEV(MELCO, WLIUCGNM), 234281745Skevlo RUN_DEV(MELCO, WLIUCG300HPV1), 235238274Shrs RUN_DEV(MELCO, WLIUCGNM2), 236209918Sthompsa RUN_DEV(MOTOROLA4, RT2770), 237209918Sthompsa RUN_DEV(MOTOROLA4, RT3070), 238209918Sthompsa RUN_DEV(MSI, RT3070_1), 239209918Sthompsa RUN_DEV(MSI, RT3070_2), 240209918Sthompsa RUN_DEV(MSI, RT3070_3), 241209918Sthompsa RUN_DEV(MSI, RT3070_4), 242209918Sthompsa RUN_DEV(MSI, RT3070_5), 243209918Sthompsa RUN_DEV(MSI, RT3070_6), 244209918Sthompsa RUN_DEV(MSI, RT3070_7), 245209918Sthompsa RUN_DEV(MSI, RT3070_8), 246209918Sthompsa RUN_DEV(MSI, RT3070_9), 247209918Sthompsa RUN_DEV(MSI, RT3070_10), 248209918Sthompsa RUN_DEV(MSI, RT3070_11), 249289028Sgavin RUN_DEV(NETGEAR, WNDA4100), 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_key_set_cb(void *); 385288635Sadrianstatic int run_key_set(struct ieee80211vap *, struct ieee80211_key *); 386208019Sthompsastatic void run_key_delete_cb(void *); 387208019Sthompsastatic int run_key_delete(struct ieee80211vap *, struct ieee80211_key *); 388206358Srpaulostatic void run_ratectl_to(void *); 389206358Srpaulostatic void run_ratectl_cb(void *, int); 390208019Sthompsastatic void run_drain_fifo(void *); 391203134Sthompsastatic void run_iter_func(void *, struct ieee80211_node *); 392208019Sthompsastatic void run_newassoc_cb(void *); 393203134Sthompsastatic void run_newassoc(struct ieee80211_node *, int); 394288603Sadrianstatic void run_recv_mgmt(struct ieee80211_node *, struct mbuf *, int, 395288603Sadrian const struct ieee80211_rx_stats *, int, int); 396203134Sthompsastatic void run_rx_frame(struct run_softc *, struct mbuf *, uint32_t); 397203134Sthompsastatic void run_tx_free(struct run_endpoint_queue *pq, 398203134Sthompsa struct run_tx_data *, int); 399208019Sthompsastatic void run_set_tx_desc(struct run_softc *, struct run_tx_data *); 400203134Sthompsastatic int run_tx(struct run_softc *, struct mbuf *, 401203134Sthompsa struct ieee80211_node *); 402203134Sthompsastatic int run_tx_mgt(struct run_softc *, struct mbuf *, 403203134Sthompsa struct ieee80211_node *); 404203134Sthompsastatic int run_sendprot(struct run_softc *, const struct mbuf *, 405203134Sthompsa struct ieee80211_node *, int, int); 406203134Sthompsastatic int run_tx_param(struct run_softc *, struct mbuf *, 407203134Sthompsa struct ieee80211_node *, 408203134Sthompsa const struct ieee80211_bpf_params *); 409203134Sthompsastatic int run_raw_xmit(struct ieee80211_node *, struct mbuf *, 410203134Sthompsa const struct ieee80211_bpf_params *); 411287197Sglebiusstatic int run_transmit(struct ieee80211com *, struct mbuf *); 412287197Sglebiusstatic void run_start(struct run_softc *); 413287197Sglebiusstatic void run_parent(struct ieee80211com *); 414259544Skevlostatic void run_iq_calib(struct run_softc *, u_int); 415205042Sthompsastatic void run_set_agc(struct run_softc *, uint8_t); 416203134Sthompsastatic void run_select_chan_group(struct run_softc *, int); 417203134Sthompsastatic void run_set_rx_antenna(struct run_softc *, int); 418203134Sthompsastatic void run_rt2870_set_chan(struct run_softc *, u_int); 419203134Sthompsastatic void run_rt3070_set_chan(struct run_softc *, u_int); 420205042Sthompsastatic void run_rt3572_set_chan(struct run_softc *, u_int); 421260219Skevlostatic void run_rt3593_set_chan(struct run_softc *, u_int); 422257955Skevlostatic void run_rt5390_set_chan(struct run_softc *, u_int); 423259032Skevlostatic void run_rt5592_set_chan(struct run_softc *, u_int); 424203134Sthompsastatic int run_set_chan(struct run_softc *, struct ieee80211_channel *); 425203134Sthompsastatic void run_set_channel(struct ieee80211com *); 426203134Sthompsastatic void run_scan_start(struct ieee80211com *); 427203134Sthompsastatic void run_scan_end(struct ieee80211com *); 428203134Sthompsastatic void run_update_beacon(struct ieee80211vap *, int); 429208019Sthompsastatic void run_update_beacon_cb(void *); 430203134Sthompsastatic void run_updateprot(struct ieee80211com *); 431218492Sbschmidtstatic void run_updateprot_cb(void *); 432208019Sthompsastatic void run_usb_timeout_cb(void *); 433203134Sthompsastatic void run_reset_livelock(struct run_softc *); 434203134Sthompsastatic void run_enable_tsf_sync(struct run_softc *); 435287555Skevlostatic void run_enable_tsf(struct run_softc *); 436287554Skevlostatic void run_get_tsf(struct run_softc *, uint64_t *); 437203134Sthompsastatic void run_enable_mrr(struct run_softc *); 438203134Sthompsastatic void run_set_txpreamble(struct run_softc *); 439203134Sthompsastatic void run_set_basicrates(struct run_softc *); 440203134Sthompsastatic void run_set_leds(struct run_softc *, uint16_t); 441203134Sthompsastatic void run_set_bssid(struct run_softc *, const uint8_t *); 442203134Sthompsastatic void run_set_macaddr(struct run_softc *, const uint8_t *); 443283540Sglebiusstatic void run_updateslot(struct ieee80211com *); 444218492Sbschmidtstatic void run_updateslot_cb(void *); 445283540Sglebiusstatic void run_update_mcast(struct ieee80211com *); 446203134Sthompsastatic int8_t run_rssi2dbm(struct run_softc *, uint8_t, uint8_t); 447283540Sglebiusstatic void run_update_promisc_locked(struct run_softc *); 448283540Sglebiusstatic void run_update_promisc(struct ieee80211com *); 449257955Skevlostatic void run_rt5390_bbp_init(struct run_softc *); 450203134Sthompsastatic int run_bbp_init(struct run_softc *); 451203134Sthompsastatic int run_rt3070_rf_init(struct run_softc *); 452260219Skevlostatic void run_rt3593_rf_init(struct run_softc *); 453257955Skevlostatic void run_rt5390_rf_init(struct run_softc *); 454203134Sthompsastatic int run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t, 455203134Sthompsa uint8_t *); 456205042Sthompsastatic void run_rt3070_rf_setup(struct run_softc *); 457260219Skevlostatic void run_rt3593_rf_setup(struct run_softc *); 458260219Skevlostatic void run_rt5390_rf_setup(struct run_softc *); 459203134Sthompsastatic int run_txrx_enable(struct run_softc *); 460257955Skevlostatic void run_adjust_freq_offset(struct run_softc *); 461203134Sthompsastatic void run_init_locked(struct run_softc *); 462203134Sthompsastatic void run_stop(void *); 463257429Shselaskystatic void run_delay(struct run_softc *, u_int); 464203134Sthompsa 465259812Skevlostatic eventhandler_tag run_etag; 466259812Skevlo 467259544Skevlostatic const struct rt2860_rate { 468259544Skevlo uint8_t rate; 469259544Skevlo uint8_t mcs; 470259544Skevlo enum ieee80211_phytype phy; 471259544Skevlo uint8_t ctl_ridx; 472259544Skevlo uint16_t sp_ack_dur; 473259544Skevlo uint16_t lp_ack_dur; 474259544Skevlo} rt2860_rates[] = { 475259544Skevlo { 2, 0, IEEE80211_T_DS, 0, 314, 314 }, 476259544Skevlo { 4, 1, IEEE80211_T_DS, 1, 258, 162 }, 477259544Skevlo { 11, 2, IEEE80211_T_DS, 2, 223, 127 }, 478259544Skevlo { 22, 3, IEEE80211_T_DS, 3, 213, 117 }, 479259544Skevlo { 12, 0, IEEE80211_T_OFDM, 4, 60, 60 }, 480259544Skevlo { 18, 1, IEEE80211_T_OFDM, 4, 52, 52 }, 481259544Skevlo { 24, 2, IEEE80211_T_OFDM, 6, 48, 48 }, 482259544Skevlo { 36, 3, IEEE80211_T_OFDM, 6, 44, 44 }, 483259544Skevlo { 48, 4, IEEE80211_T_OFDM, 8, 44, 44 }, 484259544Skevlo { 72, 5, IEEE80211_T_OFDM, 8, 40, 40 }, 485259544Skevlo { 96, 6, IEEE80211_T_OFDM, 8, 40, 40 }, 486259544Skevlo { 108, 7, IEEE80211_T_OFDM, 8, 40, 40 } 487259544Skevlo}; 488259544Skevlo 489203134Sthompsastatic const struct { 490208019Sthompsa uint16_t reg; 491203134Sthompsa uint32_t val; 492203134Sthompsa} rt2870_def_mac[] = { 493203134Sthompsa RT2870_DEF_MAC 494203134Sthompsa}; 495203134Sthompsa 496203134Sthompsastatic const struct { 497203134Sthompsa uint8_t reg; 498203134Sthompsa uint8_t val; 499203134Sthompsa} rt2860_def_bbp[] = { 500203134Sthompsa RT2860_DEF_BBP 501257955Skevlo},rt5390_def_bbp[] = { 502257955Skevlo RT5390_DEF_BBP 503259032Skevlo},rt5592_def_bbp[] = { 504259032Skevlo RT5592_DEF_BBP 505203134Sthompsa}; 506203134Sthompsa 507259032Skevlo/* 508259032Skevlo * Default values for BBP register R196 for RT5592. 509259032Skevlo */ 510259032Skevlostatic const uint8_t rt5592_bbp_r196[] = { 511259032Skevlo 0xe0, 0x1f, 0x38, 0x32, 0x08, 0x28, 0x19, 0x0a, 0xff, 0x00, 512259032Skevlo 0x16, 0x10, 0x10, 0x0b, 0x36, 0x2c, 0x26, 0x24, 0x42, 0x36, 513259032Skevlo 0x30, 0x2d, 0x4c, 0x46, 0x3d, 0x40, 0x3e, 0x42, 0x3d, 0x40, 514259032Skevlo 0x3c, 0x34, 0x2c, 0x2f, 0x3c, 0x35, 0x2e, 0x2a, 0x49, 0x41, 515259032Skevlo 0x36, 0x31, 0x30, 0x30, 0x0e, 0x0d, 0x28, 0x21, 0x1c, 0x16, 516259032Skevlo 0x50, 0x4a, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 517259032Skevlo 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 518259032Skevlo 0x00, 0x00, 0x7d, 0x14, 0x32, 0x2c, 0x36, 0x4c, 0x43, 0x2c, 519259032Skevlo 0x2e, 0x36, 0x30, 0x6e 520259032Skevlo}; 521259032Skevlo 522203134Sthompsastatic const struct rfprog { 523203134Sthompsa uint8_t chan; 524203134Sthompsa uint32_t r1, r2, r3, r4; 525203134Sthompsa} rt2860_rf2850[] = { 526203134Sthompsa RT2860_RF2850 527203134Sthompsa}; 528203134Sthompsa 529203134Sthompsastruct { 530203134Sthompsa uint8_t n, r, k; 531205042Sthompsa} rt3070_freqs[] = { 532205042Sthompsa RT3070_RF3052 533203134Sthompsa}; 534203134Sthompsa 535259032Skevlostatic const struct rt5592_freqs { 536259032Skevlo uint16_t n; 537259032Skevlo uint8_t k, m, r; 538259032Skevlo} rt5592_freqs_20mhz[] = { 539259032Skevlo RT5592_RF5592_20MHZ 540259032Skevlo},rt5592_freqs_40mhz[] = { 541259032Skevlo RT5592_RF5592_40MHZ 542259032Skevlo}; 543259032Skevlo 544203134Sthompsastatic const struct { 545203134Sthompsa uint8_t reg; 546203134Sthompsa uint8_t val; 547203134Sthompsa} rt3070_def_rf[] = { 548203134Sthompsa RT3070_DEF_RF 549205042Sthompsa},rt3572_def_rf[] = { 550205042Sthompsa RT3572_DEF_RF 551260219Skevlo},rt3593_def_rf[] = { 552260219Skevlo RT3593_DEF_RF 553257955Skevlo},rt5390_def_rf[] = { 554257955Skevlo RT5390_DEF_RF 555257955Skevlo},rt5392_def_rf[] = { 556257955Skevlo RT5392_DEF_RF 557259032Skevlo},rt5592_def_rf[] = { 558259032Skevlo RT5592_DEF_RF 559259032Skevlo},rt5592_2ghz_def_rf[] = { 560259032Skevlo RT5592_2GHZ_DEF_RF 561259032Skevlo},rt5592_5ghz_def_rf[] = { 562259032Skevlo RT5592_5GHZ_DEF_RF 563203134Sthompsa}; 564203134Sthompsa 565259032Skevlostatic const struct { 566259032Skevlo u_int firstchan; 567259032Skevlo u_int lastchan; 568259032Skevlo uint8_t reg; 569259032Skevlo uint8_t val; 570259032Skevlo} rt5592_chan_5ghz[] = { 571259032Skevlo RT5592_CHAN_5GHZ 572259032Skevlo}; 573259032Skevlo 574203134Sthompsastatic const struct usb_config run_config[RUN_N_XFER] = { 575203134Sthompsa [RUN_BULK_TX_BE] = { 576203134Sthompsa .type = UE_BULK, 577203134Sthompsa .endpoint = UE_ADDR_ANY, 578203134Sthompsa .ep_index = 0, 579203134Sthompsa .direction = UE_DIR_OUT, 580203134Sthompsa .bufsize = RUN_MAX_TXSZ, 581203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 582203134Sthompsa .callback = run_bulk_tx_callback0, 583203134Sthompsa .timeout = 5000, /* ms */ 584203134Sthompsa }, 585203134Sthompsa [RUN_BULK_TX_BK] = { 586203134Sthompsa .type = UE_BULK, 587203134Sthompsa .endpoint = UE_ADDR_ANY, 588203134Sthompsa .direction = UE_DIR_OUT, 589203134Sthompsa .ep_index = 1, 590203134Sthompsa .bufsize = RUN_MAX_TXSZ, 591203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 592203134Sthompsa .callback = run_bulk_tx_callback1, 593203134Sthompsa .timeout = 5000, /* ms */ 594203134Sthompsa }, 595203134Sthompsa [RUN_BULK_TX_VI] = { 596203134Sthompsa .type = UE_BULK, 597203134Sthompsa .endpoint = UE_ADDR_ANY, 598203134Sthompsa .direction = UE_DIR_OUT, 599203134Sthompsa .ep_index = 2, 600203134Sthompsa .bufsize = RUN_MAX_TXSZ, 601203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 602203134Sthompsa .callback = run_bulk_tx_callback2, 603203134Sthompsa .timeout = 5000, /* ms */ 604203134Sthompsa }, 605203134Sthompsa [RUN_BULK_TX_VO] = { 606203134Sthompsa .type = UE_BULK, 607203134Sthompsa .endpoint = UE_ADDR_ANY, 608203134Sthompsa .direction = UE_DIR_OUT, 609203134Sthompsa .ep_index = 3, 610203134Sthompsa .bufsize = RUN_MAX_TXSZ, 611203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 612203134Sthompsa .callback = run_bulk_tx_callback3, 613203134Sthompsa .timeout = 5000, /* ms */ 614203134Sthompsa }, 615203134Sthompsa [RUN_BULK_TX_HCCA] = { 616203134Sthompsa .type = UE_BULK, 617203134Sthompsa .endpoint = UE_ADDR_ANY, 618203134Sthompsa .direction = UE_DIR_OUT, 619203134Sthompsa .ep_index = 4, 620203134Sthompsa .bufsize = RUN_MAX_TXSZ, 621203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 622203134Sthompsa .callback = run_bulk_tx_callback4, 623203134Sthompsa .timeout = 5000, /* ms */ 624203134Sthompsa }, 625203134Sthompsa [RUN_BULK_TX_PRIO] = { 626203134Sthompsa .type = UE_BULK, 627203134Sthompsa .endpoint = UE_ADDR_ANY, 628203134Sthompsa .direction = UE_DIR_OUT, 629203134Sthompsa .ep_index = 5, 630203134Sthompsa .bufsize = RUN_MAX_TXSZ, 631203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 632203134Sthompsa .callback = run_bulk_tx_callback5, 633203134Sthompsa .timeout = 5000, /* ms */ 634203134Sthompsa }, 635203134Sthompsa [RUN_BULK_RX] = { 636203134Sthompsa .type = UE_BULK, 637203134Sthompsa .endpoint = UE_ADDR_ANY, 638203134Sthompsa .direction = UE_DIR_IN, 639203134Sthompsa .bufsize = RUN_MAX_RXSZ, 640203134Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 641203134Sthompsa .callback = run_bulk_rx_callback, 642203134Sthompsa } 643203134Sthompsa}; 644203134Sthompsa 645259812Skevlostatic void 646259812Skevlorun_autoinst(void *arg, struct usb_device *udev, 647259812Skevlo struct usb_attach_arg *uaa) 648259812Skevlo{ 649259812Skevlo struct usb_interface *iface; 650259812Skevlo struct usb_interface_descriptor *id; 651259812Skevlo 652259812Skevlo if (uaa->dev_state != UAA_DEV_READY) 653259812Skevlo return; 654259812Skevlo 655259812Skevlo iface = usbd_get_iface(udev, 0); 656259812Skevlo if (iface == NULL) 657259812Skevlo return; 658259812Skevlo id = iface->idesc; 659259812Skevlo if (id == NULL || id->bInterfaceClass != UICLASS_MASS) 660259812Skevlo return; 661259812Skevlo if (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa)) 662259812Skevlo return; 663259812Skevlo 664259812Skevlo if (usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT) == 0) 665259812Skevlo uaa->dev_state = UAA_DEV_EJECTING; 666259812Skevlo} 667259812Skevlo 668220235Skevlostatic int 669259812Skevlorun_driver_loaded(struct module *mod, int what, void *arg) 670259812Skevlo{ 671259812Skevlo switch (what) { 672259812Skevlo case MOD_LOAD: 673259812Skevlo run_etag = EVENTHANDLER_REGISTER(usb_dev_configured, 674259812Skevlo run_autoinst, NULL, EVENTHANDLER_PRI_ANY); 675259812Skevlo break; 676259812Skevlo case MOD_UNLOAD: 677259812Skevlo EVENTHANDLER_DEREGISTER(usb_dev_configured, run_etag); 678259812Skevlo break; 679259812Skevlo default: 680259812Skevlo return (EOPNOTSUPP); 681259812Skevlo } 682259812Skevlo return (0); 683259812Skevlo} 684259812Skevlo 685259812Skevlostatic int 686203134Sthompsarun_match(device_t self) 687203134Sthompsa{ 688203134Sthompsa struct usb_attach_arg *uaa = device_get_ivars(self); 689203134Sthompsa 690203134Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 691203134Sthompsa return (ENXIO); 692203134Sthompsa if (uaa->info.bConfigIndex != 0) 693203134Sthompsa return (ENXIO); 694203134Sthompsa if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX) 695203134Sthompsa return (ENXIO); 696203134Sthompsa 697203134Sthompsa return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa)); 698203134Sthompsa} 699203134Sthompsa 700203134Sthompsastatic int 701203134Sthompsarun_attach(device_t self) 702203134Sthompsa{ 703203134Sthompsa struct run_softc *sc = device_get_softc(self); 704203134Sthompsa struct usb_attach_arg *uaa = device_get_ivars(self); 705287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 706205042Sthompsa uint32_t ver; 707293339Savos uint8_t bands[howmany(IEEE80211_MODE_MAX, 8)]; 708293339Savos uint8_t iface_index; 709258082Skevlo int ntries, error; 710203134Sthompsa 711203134Sthompsa device_set_usb_desc(self); 712203134Sthompsa sc->sc_udev = uaa->device; 713203134Sthompsa sc->sc_dev = self; 714262465Skevlo if (USB_GET_DRIVER_INFO(uaa) != RUN_EJECT) 715262465Skevlo sc->sc_flags |= RUN_FLAG_FWLOAD_NEEDED; 716203134Sthompsa 717203134Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), 718203134Sthompsa MTX_NETWORK_LOCK, MTX_DEF); 719287197Sglebius mbufq_init(&sc->sc_snd, ifqmaxlen); 720203134Sthompsa 721203134Sthompsa iface_index = RT2860_IFACE_INDEX; 722208019Sthompsa 723203134Sthompsa error = usbd_transfer_setup(uaa->device, &iface_index, 724203134Sthompsa sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx); 725203134Sthompsa if (error) { 726205042Sthompsa device_printf(self, "could not allocate USB transfers, " 727203134Sthompsa "err=%s\n", usbd_errstr(error)); 728203134Sthompsa goto detach; 729203134Sthompsa } 730203134Sthompsa 731203134Sthompsa RUN_LOCK(sc); 732203134Sthompsa 733203134Sthompsa /* wait for the chip to settle */ 734203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 735209917Sthompsa if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0) { 736203134Sthompsa RUN_UNLOCK(sc); 737203134Sthompsa goto detach; 738203134Sthompsa } 739205042Sthompsa if (ver != 0 && ver != 0xffffffff) 740203134Sthompsa break; 741203134Sthompsa run_delay(sc, 10); 742203134Sthompsa } 743203134Sthompsa if (ntries == 100) { 744203138Sthompsa device_printf(sc->sc_dev, 745203138Sthompsa "timeout waiting for NIC to initialize\n"); 746203134Sthompsa RUN_UNLOCK(sc); 747203134Sthompsa goto detach; 748203134Sthompsa } 749205042Sthompsa sc->mac_ver = ver >> 16; 750205042Sthompsa sc->mac_rev = ver & 0xffff; 751203134Sthompsa 752203134Sthompsa /* retrieve RF rev. no and various other things from EEPROM */ 753203134Sthompsa run_read_eeprom(sc); 754203134Sthompsa 755203138Sthompsa device_printf(sc->sc_dev, 756203138Sthompsa "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n", 757205042Sthompsa sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev), 758287197Sglebius sc->ntxchains, sc->nrxchains, ether_sprintf(ic->ic_macaddr)); 759203134Sthompsa 760203134Sthompsa RUN_UNLOCK(sc); 761203134Sthompsa 762283537Sglebius ic->ic_softc = sc; 763283527Sglebius ic->ic_name = device_get_nameunit(self); 764203134Sthompsa ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 765203134Sthompsa ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 766208019Sthompsa 767203134Sthompsa /* set device capabilities */ 768203134Sthompsa ic->ic_caps = 769203134Sthompsa IEEE80211_C_STA | /* station mode supported */ 770203134Sthompsa IEEE80211_C_MONITOR | /* monitor mode supported */ 771203134Sthompsa IEEE80211_C_IBSS | 772203134Sthompsa IEEE80211_C_HOSTAP | 773208019Sthompsa IEEE80211_C_WDS | /* 4-address traffic works */ 774208019Sthompsa IEEE80211_C_MBSS | 775203134Sthompsa IEEE80211_C_SHPREAMBLE | /* short preamble supported */ 776203134Sthompsa IEEE80211_C_SHSLOT | /* short slot time supported */ 777203134Sthompsa IEEE80211_C_WME | /* WME */ 778214894Sbschmidt IEEE80211_C_WPA; /* WPA1|WPA2(RSN) */ 779203134Sthompsa 780203134Sthompsa ic->ic_cryptocaps = 781203134Sthompsa IEEE80211_CRYPTO_WEP | 782203134Sthompsa IEEE80211_CRYPTO_AES_CCM | 783203134Sthompsa IEEE80211_CRYPTO_TKIPMIC | 784203134Sthompsa IEEE80211_CRYPTO_TKIP; 785203134Sthompsa 786203134Sthompsa ic->ic_flags |= IEEE80211_F_DATAPAD; 787203134Sthompsa ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; 788203134Sthompsa 789293339Savos memset(bands, 0, sizeof(bands)); 790293339Savos setbit(bands, IEEE80211_MODE_11B); 791293339Savos setbit(bands, IEEE80211_MODE_11G); 792258082Skevlo if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850 || 793260219Skevlo sc->rf_rev == RT3070_RF_3052 || sc->rf_rev == RT3593_RF_3053 || 794260219Skevlo sc->rf_rev == RT5592_RF_5592) 795293339Savos setbit(bands, IEEE80211_MODE_11A); 796293339Savos ieee80211_init_channels(ic, NULL, bands); 797203134Sthompsa 798287197Sglebius ieee80211_ifattach(ic); 799203134Sthompsa 800203134Sthompsa ic->ic_scan_start = run_scan_start; 801203134Sthompsa ic->ic_scan_end = run_scan_end; 802203134Sthompsa ic->ic_set_channel = run_set_channel; 803203134Sthompsa ic->ic_node_alloc = run_node_alloc; 804203134Sthompsa ic->ic_newassoc = run_newassoc; 805218492Sbschmidt ic->ic_updateslot = run_updateslot; 806208019Sthompsa ic->ic_update_mcast = run_update_mcast; 807203134Sthompsa ic->ic_wme.wme_update = run_wme_update; 808203134Sthompsa ic->ic_raw_xmit = run_raw_xmit; 809203134Sthompsa ic->ic_update_promisc = run_update_promisc; 810203134Sthompsa ic->ic_vap_create = run_vap_create; 811203134Sthompsa ic->ic_vap_delete = run_vap_delete; 812287197Sglebius ic->ic_transmit = run_transmit; 813287197Sglebius ic->ic_parent = run_parent; 814203134Sthompsa 815203134Sthompsa ieee80211_radiotap_attach(ic, 816203134Sthompsa &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), 817203134Sthompsa RUN_TX_RADIOTAP_PRESENT, 818203134Sthompsa &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 819203134Sthompsa RUN_RX_RADIOTAP_PRESENT); 820203134Sthompsa 821208019Sthompsa TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc); 822208019Sthompsa TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc); 823257712Shselasky usb_callout_init_mtx(&sc->ratectl_ch, &sc->sc_mtx, 0); 824208019Sthompsa 825203134Sthompsa if (bootverbose) 826203134Sthompsa ieee80211_announce(ic); 827203134Sthompsa 828209917Sthompsa return (0); 829203134Sthompsa 830203134Sthompsadetach: 831203134Sthompsa run_detach(self); 832209917Sthompsa return (ENXIO); 833203134Sthompsa} 834203134Sthompsa 835288649Sadrianstatic void 836288649Sadrianrun_drain_mbufq(struct run_softc *sc) 837288649Sadrian{ 838288649Sadrian struct mbuf *m; 839288649Sadrian struct ieee80211_node *ni; 840288649Sadrian 841288649Sadrian RUN_LOCK_ASSERT(sc, MA_OWNED); 842288649Sadrian while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { 843288649Sadrian ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 844288649Sadrian m->m_pkthdr.rcvif = NULL; 845288649Sadrian ieee80211_free_node(ni); 846288649Sadrian m_freem(m); 847288649Sadrian } 848288649Sadrian} 849288649Sadrian 850203134Sthompsastatic int 851203134Sthompsarun_detach(device_t self) 852203134Sthompsa{ 853203134Sthompsa struct run_softc *sc = device_get_softc(self); 854287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 855203134Sthompsa int i; 856203134Sthompsa 857246614Shselasky RUN_LOCK(sc); 858246614Shselasky sc->sc_detached = 1; 859246614Shselasky RUN_UNLOCK(sc); 860246614Shselasky 861203134Sthompsa /* stop all USB transfers */ 862203134Sthompsa usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER); 863203134Sthompsa 864203134Sthompsa RUN_LOCK(sc); 865209144Sthompsa sc->ratectl_run = RUN_RATECTL_OFF; 866209144Sthompsa sc->cmdq_run = sc->cmdq_key_set = RUN_CMDQ_ABORT; 867209144Sthompsa 868203134Sthompsa /* free TX list, if any */ 869203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 870203134Sthompsa run_unsetup_tx_list(sc, &sc->sc_epq[i]); 871288649Sadrian 872288649Sadrian /* Free TX queue */ 873288649Sadrian run_drain_mbufq(sc); 874203134Sthompsa RUN_UNLOCK(sc); 875203134Sthompsa 876287197Sglebius if (sc->sc_ic.ic_softc == sc) { 877208019Sthompsa /* drain tasks */ 878208019Sthompsa usb_callout_drain(&sc->ratectl_ch); 879208019Sthompsa ieee80211_draintask(ic, &sc->cmdq_task); 880208019Sthompsa ieee80211_draintask(ic, &sc->ratectl_task); 881203134Sthompsa ieee80211_ifdetach(ic); 882203134Sthompsa } 883203134Sthompsa 884203134Sthompsa mtx_destroy(&sc->sc_mtx); 885203134Sthompsa 886203134Sthompsa return (0); 887203134Sthompsa} 888203134Sthompsa 889203134Sthompsastatic struct ieee80211vap * 890228621Sbschmidtrun_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, 891228621Sbschmidt enum ieee80211_opmode opmode, int flags, 892203134Sthompsa const uint8_t bssid[IEEE80211_ADDR_LEN], 893203134Sthompsa const uint8_t mac[IEEE80211_ADDR_LEN]) 894203134Sthompsa{ 895286950Sadrian struct run_softc *sc = ic->ic_softc; 896203134Sthompsa struct run_vap *rvp; 897203134Sthompsa struct ieee80211vap *vap; 898208019Sthompsa int i; 899203134Sthompsa 900209917Sthompsa if (sc->rvp_cnt >= RUN_VAP_MAX) { 901287197Sglebius device_printf(sc->sc_dev, "number of VAPs maxed out\n"); 902209917Sthompsa return (NULL); 903208019Sthompsa } 904208019Sthompsa 905208019Sthompsa switch (opmode) { 906208019Sthompsa case IEEE80211_M_STA: 907208019Sthompsa /* enable s/w bmiss handling for sta mode */ 908208019Sthompsa flags |= IEEE80211_CLONE_NOBEACONS; 909208019Sthompsa /* fall though */ 910208019Sthompsa case IEEE80211_M_IBSS: 911208019Sthompsa case IEEE80211_M_MONITOR: 912208019Sthompsa case IEEE80211_M_HOSTAP: 913208019Sthompsa case IEEE80211_M_MBSS: 914208019Sthompsa /* other than WDS vaps, only one at a time */ 915208019Sthompsa if (!TAILQ_EMPTY(&ic->ic_vaps)) 916209917Sthompsa return (NULL); 917208019Sthompsa break; 918208019Sthompsa case IEEE80211_M_WDS: 919208019Sthompsa TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next){ 920208019Sthompsa if(vap->iv_opmode != IEEE80211_M_HOSTAP) 921208019Sthompsa continue; 922208019Sthompsa /* WDS vap's always share the local mac address. */ 923208019Sthompsa flags &= ~IEEE80211_CLONE_BSSID; 924208019Sthompsa break; 925208019Sthompsa } 926209917Sthompsa if (vap == NULL) { 927287197Sglebius device_printf(sc->sc_dev, 928287197Sglebius "wds only supported in ap mode\n"); 929209917Sthompsa return (NULL); 930208019Sthompsa } 931208019Sthompsa break; 932208019Sthompsa default: 933287197Sglebius device_printf(sc->sc_dev, "unknown opmode %d\n", opmode); 934209917Sthompsa return (NULL); 935208019Sthompsa } 936208019Sthompsa 937287197Sglebius rvp = malloc(sizeof(struct run_vap), M_80211_VAP, M_WAITOK | M_ZERO); 938203134Sthompsa vap = &rvp->vap; 939203134Sthompsa 940287197Sglebius if (ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, 941287197Sglebius bssid) != 0) { 942257743Shselasky /* out of memory */ 943257743Shselasky free(rvp, M_80211_VAP); 944257743Shselasky return (NULL); 945257743Shselasky } 946257743Shselasky 947203134Sthompsa vap->iv_update_beacon = run_update_beacon; 948208019Sthompsa vap->iv_max_aid = RT2870_WCID_MAX; 949208019Sthompsa /* 950208019Sthompsa * To delete the right key from h/w, we need wcid. 951208019Sthompsa * Luckily, there is unused space in ieee80211_key{}, wk_pad, 952208019Sthompsa * and matching wcid will be written into there. So, cast 953208019Sthompsa * some spells to remove 'const' from ieee80211_key{} 954208019Sthompsa */ 955208019Sthompsa vap->iv_key_delete = (void *)run_key_delete; 956208019Sthompsa vap->iv_key_set = (void *)run_key_set; 957203134Sthompsa 958203134Sthompsa /* override state transition machine */ 959203134Sthompsa rvp->newstate = vap->iv_newstate; 960203134Sthompsa vap->iv_newstate = run_newstate; 961288603Sadrian if (opmode == IEEE80211_M_IBSS) { 962288603Sadrian rvp->recv_mgmt = vap->iv_recv_mgmt; 963288603Sadrian vap->iv_recv_mgmt = run_recv_mgmt; 964288603Sadrian } 965203134Sthompsa 966206358Srpaulo ieee80211_ratectl_init(vap); 967206358Srpaulo ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */); 968203134Sthompsa 969203134Sthompsa /* complete setup */ 970287197Sglebius ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status, 971287197Sglebius mac); 972208019Sthompsa 973208019Sthompsa /* make sure id is always unique */ 974209917Sthompsa for (i = 0; i < RUN_VAP_MAX; i++) { 975208019Sthompsa if((sc->rvp_bmap & 1 << i) == 0){ 976208019Sthompsa sc->rvp_bmap |= 1 << i; 977208019Sthompsa rvp->rvp_id = i; 978208019Sthompsa break; 979208019Sthompsa } 980208019Sthompsa } 981209917Sthompsa if (sc->rvp_cnt++ == 0) 982208019Sthompsa ic->ic_opmode = opmode; 983208019Sthompsa 984209917Sthompsa if (opmode == IEEE80211_M_HOSTAP) 985209144Sthompsa sc->cmdq_run = RUN_CMDQ_GO; 986209144Sthompsa 987208019Sthompsa DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n", 988208019Sthompsa rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt); 989208019Sthompsa 990209917Sthompsa return (vap); 991203134Sthompsa} 992203134Sthompsa 993203134Sthompsastatic void 994203134Sthompsarun_vap_delete(struct ieee80211vap *vap) 995203134Sthompsa{ 996203134Sthompsa struct run_vap *rvp = RUN_VAP(vap); 997203134Sthompsa struct ieee80211com *ic; 998203134Sthompsa struct run_softc *sc; 999208019Sthompsa uint8_t rvp_id; 1000203134Sthompsa 1001209917Sthompsa if (vap == NULL) 1002203134Sthompsa return; 1003203134Sthompsa 1004203134Sthompsa ic = vap->iv_ic; 1005286950Sadrian sc = ic->ic_softc; 1006203134Sthompsa 1007205042Sthompsa RUN_LOCK(sc); 1008208019Sthompsa 1009218492Sbschmidt m_freem(rvp->beacon_mbuf); 1010218492Sbschmidt rvp->beacon_mbuf = NULL; 1011218492Sbschmidt 1012208019Sthompsa rvp_id = rvp->rvp_id; 1013208019Sthompsa sc->ratectl_run &= ~(1 << rvp_id); 1014208019Sthompsa sc->rvp_bmap &= ~(1 << rvp_id); 1015208019Sthompsa run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128); 1016208019Sthompsa run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512); 1017208019Sthompsa --sc->rvp_cnt; 1018208019Sthompsa 1019208019Sthompsa DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n", 1020208019Sthompsa vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt); 1021208019Sthompsa 1022205042Sthompsa RUN_UNLOCK(sc); 1023203134Sthompsa 1024206358Srpaulo ieee80211_ratectl_deinit(vap); 1025203134Sthompsa ieee80211_vap_detach(vap); 1026203134Sthompsa free(rvp, M_80211_VAP); 1027203134Sthompsa} 1028203134Sthompsa 1029208019Sthompsa/* 1030208019Sthompsa * There are numbers of functions need to be called in context thread. 1031208019Sthompsa * Rather than creating taskqueue event for each of those functions, 1032208019Sthompsa * here is all-for-one taskqueue callback function. This function 1033208019Sthompsa * gurantees deferred functions are executed in the same order they 1034208019Sthompsa * were enqueued. 1035208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[]. 1036208019Sthompsa */ 1037203134Sthompsastatic void 1038208019Sthompsarun_cmdq_cb(void *arg, int pending) 1039208019Sthompsa{ 1040208019Sthompsa struct run_softc *sc = arg; 1041208019Sthompsa uint8_t i; 1042208019Sthompsa 1043208019Sthompsa /* call cmdq[].func locked */ 1044208019Sthompsa RUN_LOCK(sc); 1045209917Sthompsa for (i = sc->cmdq_exec; sc->cmdq[i].func && pending; 1046209917Sthompsa i = sc->cmdq_exec, pending--) { 1047208019Sthompsa DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending); 1048209917Sthompsa if (sc->cmdq_run == RUN_CMDQ_GO) { 1049208019Sthompsa /* 1050208019Sthompsa * If arg0 is NULL, callback func needs more 1051208019Sthompsa * than one arg. So, pass ptr to cmdq struct. 1052208019Sthompsa */ 1053209917Sthompsa if (sc->cmdq[i].arg0) 1054208019Sthompsa sc->cmdq[i].func(sc->cmdq[i].arg0); 1055208019Sthompsa else 1056208019Sthompsa sc->cmdq[i].func(&sc->cmdq[i]); 1057208019Sthompsa } 1058208019Sthompsa sc->cmdq[i].arg0 = NULL; 1059208019Sthompsa sc->cmdq[i].func = NULL; 1060208019Sthompsa sc->cmdq_exec++; 1061208019Sthompsa sc->cmdq_exec &= RUN_CMDQ_MASQ; 1062208019Sthompsa } 1063208019Sthompsa RUN_UNLOCK(sc); 1064208019Sthompsa} 1065208019Sthompsa 1066208019Sthompsastatic void 1067203134Sthompsarun_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq) 1068203134Sthompsa{ 1069203134Sthompsa struct run_tx_data *data; 1070203134Sthompsa 1071203134Sthompsa memset(pq, 0, sizeof(*pq)); 1072203134Sthompsa 1073203134Sthompsa STAILQ_INIT(&pq->tx_qh); 1074203134Sthompsa STAILQ_INIT(&pq->tx_fh); 1075203134Sthompsa 1076203134Sthompsa for (data = &pq->tx_data[0]; 1077203134Sthompsa data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) { 1078203134Sthompsa data->sc = sc; 1079203134Sthompsa STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); 1080203134Sthompsa } 1081203134Sthompsa pq->tx_nfree = RUN_TX_RING_COUNT; 1082203134Sthompsa} 1083203134Sthompsa 1084203134Sthompsastatic void 1085203134Sthompsarun_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq) 1086203134Sthompsa{ 1087203134Sthompsa struct run_tx_data *data; 1088203134Sthompsa 1089203134Sthompsa /* make sure any subsequent use of the queues will fail */ 1090203134Sthompsa pq->tx_nfree = 0; 1091203134Sthompsa STAILQ_INIT(&pq->tx_fh); 1092203134Sthompsa STAILQ_INIT(&pq->tx_qh); 1093203134Sthompsa 1094203134Sthompsa /* free up all node references and mbufs */ 1095203134Sthompsa for (data = &pq->tx_data[0]; 1096209917Sthompsa data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) { 1097203134Sthompsa if (data->m != NULL) { 1098203134Sthompsa m_freem(data->m); 1099203134Sthompsa data->m = NULL; 1100203134Sthompsa } 1101203134Sthompsa if (data->ni != NULL) { 1102203134Sthompsa ieee80211_free_node(data->ni); 1103203134Sthompsa data->ni = NULL; 1104203134Sthompsa } 1105203134Sthompsa } 1106203134Sthompsa} 1107203134Sthompsa 1108220235Skevlostatic int 1109203134Sthompsarun_load_microcode(struct run_softc *sc) 1110203134Sthompsa{ 1111203134Sthompsa usb_device_request_t req; 1112203137Sthompsa const struct firmware *fw; 1113203134Sthompsa const u_char *base; 1114203134Sthompsa uint32_t tmp; 1115203134Sthompsa int ntries, error; 1116203134Sthompsa const uint64_t *temp; 1117203134Sthompsa uint64_t bytes; 1118203134Sthompsa 1119205042Sthompsa RUN_UNLOCK(sc); 1120203137Sthompsa fw = firmware_get("runfw"); 1121205042Sthompsa RUN_LOCK(sc); 1122209917Sthompsa if (fw == NULL) { 1123203138Sthompsa device_printf(sc->sc_dev, 1124203138Sthompsa "failed loadfirmware of file %s\n", "runfw"); 1125203134Sthompsa return ENOENT; 1126203134Sthompsa } 1127203134Sthompsa 1128203137Sthompsa if (fw->datasize != 8192) { 1129203138Sthompsa device_printf(sc->sc_dev, 1130203138Sthompsa "invalid firmware size (should be 8KB)\n"); 1131203137Sthompsa error = EINVAL; 1132203137Sthompsa goto fail; 1133203134Sthompsa } 1134203134Sthompsa 1135203134Sthompsa /* 1136203134Sthompsa * RT3071/RT3072 use a different firmware 1137203134Sthompsa * run-rt2870 (8KB) contains both, 1138203134Sthompsa * first half (4KB) is for rt2870, 1139203134Sthompsa * last half is for rt3071. 1140203134Sthompsa */ 1141203137Sthompsa base = fw->data; 1142205042Sthompsa if ((sc->mac_ver) != 0x2860 && 1143205042Sthompsa (sc->mac_ver) != 0x2872 && 1144209917Sthompsa (sc->mac_ver) != 0x3070) { 1145203134Sthompsa base += 4096; 1146205042Sthompsa } 1147203134Sthompsa 1148203134Sthompsa /* cheap sanity check */ 1149203137Sthompsa temp = fw->data; 1150203134Sthompsa bytes = *temp; 1151257712Shselasky if (bytes != be64toh(0xffffff0210280210ULL)) { 1152203138Sthompsa device_printf(sc->sc_dev, "firmware checksum failed\n"); 1153203137Sthompsa error = EINVAL; 1154203137Sthompsa goto fail; 1155203137Sthompsa } 1156203134Sthompsa 1157203134Sthompsa /* write microcode image */ 1158262465Skevlo if (sc->sc_flags & RUN_FLAG_FWLOAD_NEEDED) { 1159260219Skevlo run_write_region_1(sc, RT2870_FW_BASE, base, 4096); 1160260219Skevlo run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff); 1161260219Skevlo run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff); 1162260219Skevlo } 1163203134Sthompsa 1164203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1165203134Sthompsa req.bRequest = RT2870_RESET; 1166203134Sthompsa USETW(req.wValue, 8); 1167203134Sthompsa USETW(req.wIndex, 0); 1168203134Sthompsa USETW(req.wLength, 0); 1169220235Skevlo if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)) 1170220235Skevlo != 0) { 1171203138Sthompsa device_printf(sc->sc_dev, "firmware reset failed\n"); 1172203137Sthompsa goto fail; 1173203137Sthompsa } 1174203134Sthompsa 1175203134Sthompsa run_delay(sc, 10); 1176203134Sthompsa 1177260219Skevlo run_write(sc, RT2860_H2M_BBPAGENT, 0); 1178203134Sthompsa run_write(sc, RT2860_H2M_MAILBOX, 0); 1179260219Skevlo run_write(sc, RT2860_H2M_INTSRC, 0); 1180205042Sthompsa if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0) 1181203137Sthompsa goto fail; 1182203134Sthompsa 1183203134Sthompsa /* wait until microcontroller is ready */ 1184203134Sthompsa for (ntries = 0; ntries < 1000; ntries++) { 1185260219Skevlo if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0) 1186203137Sthompsa goto fail; 1187203134Sthompsa if (tmp & RT2860_MCU_READY) 1188203134Sthompsa break; 1189203134Sthompsa run_delay(sc, 10); 1190203134Sthompsa } 1191203134Sthompsa if (ntries == 1000) { 1192203138Sthompsa device_printf(sc->sc_dev, 1193203138Sthompsa "timeout waiting for MCU to initialize\n"); 1194203137Sthompsa error = ETIMEDOUT; 1195203137Sthompsa goto fail; 1196203134Sthompsa } 1197233283Sbschmidt device_printf(sc->sc_dev, "firmware %s ver. %u.%u loaded\n", 1198233283Sbschmidt (base == fw->data) ? "RT2870" : "RT3071", 1199233283Sbschmidt *(base + 4092), *(base + 4093)); 1200203134Sthompsa 1201203137Sthompsafail: 1202203137Sthompsa firmware_put(fw, FIRMWARE_UNLOAD); 1203203137Sthompsa return (error); 1204203134Sthompsa} 1205203134Sthompsa 1206258641Shselaskystatic int 1207203134Sthompsarun_reset(struct run_softc *sc) 1208203134Sthompsa{ 1209203134Sthompsa usb_device_request_t req; 1210203134Sthompsa 1211203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1212203134Sthompsa req.bRequest = RT2870_RESET; 1213203134Sthompsa USETW(req.wValue, 1); 1214203134Sthompsa USETW(req.wIndex, 0); 1215203134Sthompsa USETW(req.wLength, 0); 1216209917Sthompsa return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)); 1217203134Sthompsa} 1218203134Sthompsa 1219203134Sthompsastatic usb_error_t 1220203134Sthompsarun_do_request(struct run_softc *sc, 1221203134Sthompsa struct usb_device_request *req, void *data) 1222203134Sthompsa{ 1223203134Sthompsa usb_error_t err; 1224203134Sthompsa int ntries = 10; 1225203134Sthompsa 1226203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 1227203134Sthompsa 1228203134Sthompsa while (ntries--) { 1229203134Sthompsa err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, 1230203134Sthompsa req, data, 0, NULL, 250 /* ms */); 1231203134Sthompsa if (err == 0) 1232203134Sthompsa break; 1233203134Sthompsa DPRINTFN(1, "Control request failed, %s (retrying)\n", 1234203134Sthompsa usbd_errstr(err)); 1235203134Sthompsa run_delay(sc, 10); 1236203134Sthompsa } 1237203134Sthompsa return (err); 1238203134Sthompsa} 1239203134Sthompsa 1240203134Sthompsastatic int 1241203134Sthompsarun_read(struct run_softc *sc, uint16_t reg, uint32_t *val) 1242203134Sthompsa{ 1243203134Sthompsa uint32_t tmp; 1244203134Sthompsa int error; 1245203134Sthompsa 1246203134Sthompsa error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp); 1247203134Sthompsa if (error == 0) 1248203134Sthompsa *val = le32toh(tmp); 1249203134Sthompsa else 1250203134Sthompsa *val = 0xffffffff; 1251209917Sthompsa return (error); 1252203134Sthompsa} 1253203134Sthompsa 1254203134Sthompsastatic int 1255203134Sthompsarun_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len) 1256203134Sthompsa{ 1257203134Sthompsa usb_device_request_t req; 1258203134Sthompsa 1259203134Sthompsa req.bmRequestType = UT_READ_VENDOR_DEVICE; 1260203134Sthompsa req.bRequest = RT2870_READ_REGION_1; 1261203134Sthompsa USETW(req.wValue, 0); 1262203134Sthompsa USETW(req.wIndex, reg); 1263203134Sthompsa USETW(req.wLength, len); 1264203134Sthompsa 1265209917Sthompsa return (run_do_request(sc, &req, buf)); 1266203134Sthompsa} 1267203134Sthompsa 1268203134Sthompsastatic int 1269203134Sthompsarun_write_2(struct run_softc *sc, uint16_t reg, uint16_t val) 1270203134Sthompsa{ 1271203134Sthompsa usb_device_request_t req; 1272203134Sthompsa 1273203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1274203134Sthompsa req.bRequest = RT2870_WRITE_2; 1275203134Sthompsa USETW(req.wValue, val); 1276203134Sthompsa USETW(req.wIndex, reg); 1277203134Sthompsa USETW(req.wLength, 0); 1278203134Sthompsa 1279209917Sthompsa return (run_do_request(sc, &req, NULL)); 1280203134Sthompsa} 1281203134Sthompsa 1282203134Sthompsastatic int 1283203134Sthompsarun_write(struct run_softc *sc, uint16_t reg, uint32_t val) 1284203134Sthompsa{ 1285203134Sthompsa int error; 1286203134Sthompsa 1287203134Sthompsa if ((error = run_write_2(sc, reg, val & 0xffff)) == 0) 1288203134Sthompsa error = run_write_2(sc, reg + 2, val >> 16); 1289209917Sthompsa return (error); 1290203134Sthompsa} 1291203134Sthompsa 1292203134Sthompsastatic int 1293203134Sthompsarun_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf, 1294203134Sthompsa int len) 1295203134Sthompsa{ 1296203134Sthompsa#if 1 1297203134Sthompsa int i, error = 0; 1298203134Sthompsa /* 1299203134Sthompsa * NB: the WRITE_REGION_1 command is not stable on RT2860. 1300203134Sthompsa * We thus issue multiple WRITE_2 commands instead. 1301203134Sthompsa */ 1302203134Sthompsa KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n")); 1303203134Sthompsa for (i = 0; i < len && error == 0; i += 2) 1304203134Sthompsa error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8); 1305209917Sthompsa return (error); 1306203134Sthompsa#else 1307203134Sthompsa usb_device_request_t req; 1308257958Skevlo int error = 0; 1309203134Sthompsa 1310257958Skevlo /* 1311257958Skevlo * NOTE: It appears the WRITE_REGION_1 command cannot be 1312257958Skevlo * passed a huge amount of data, which will crash the 1313257958Skevlo * firmware. Limit amount of data passed to 64-bytes at a 1314257958Skevlo * time. 1315257958Skevlo */ 1316257958Skevlo while (len > 0) { 1317257958Skevlo int delta = 64; 1318257958Skevlo if (delta > len) 1319257958Skevlo delta = len; 1320257958Skevlo 1321257958Skevlo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1322257958Skevlo req.bRequest = RT2870_WRITE_REGION_1; 1323257958Skevlo USETW(req.wValue, 0); 1324257958Skevlo USETW(req.wIndex, reg); 1325257958Skevlo USETW(req.wLength, delta); 1326257958Skevlo error = run_do_request(sc, &req, __DECONST(uint8_t *, buf)); 1327257958Skevlo if (error != 0) 1328257958Skevlo break; 1329257958Skevlo reg += delta; 1330257958Skevlo buf += delta; 1331257958Skevlo len -= delta; 1332257958Skevlo } 1333257958Skevlo return (error); 1334203134Sthompsa#endif 1335203134Sthompsa} 1336203134Sthompsa 1337203134Sthompsastatic int 1338203134Sthompsarun_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len) 1339203134Sthompsa{ 1340203134Sthompsa int i, error = 0; 1341203134Sthompsa 1342203134Sthompsa KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n")); 1343203134Sthompsa for (i = 0; i < len && error == 0; i += 4) 1344203134Sthompsa error = run_write(sc, reg + i, val); 1345209917Sthompsa return (error); 1346203134Sthompsa} 1347203134Sthompsa 1348203134Sthompsastatic int 1349259544Skevlorun_efuse_read(struct run_softc *sc, uint16_t addr, uint16_t *val, int count) 1350203134Sthompsa{ 1351203134Sthompsa uint32_t tmp; 1352203134Sthompsa uint16_t reg; 1353203134Sthompsa int error, ntries; 1354203134Sthompsa 1355203134Sthompsa if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0) 1356209917Sthompsa return (error); 1357203134Sthompsa 1358261076Shselasky if (count == 2) 1359261076Shselasky addr *= 2; 1360203134Sthompsa /*- 1361203134Sthompsa * Read one 16-byte block into registers EFUSE_DATA[0-3]: 1362203134Sthompsa * DATA0: F E D C 1363203134Sthompsa * DATA1: B A 9 8 1364203134Sthompsa * DATA2: 7 6 5 4 1365203134Sthompsa * DATA3: 3 2 1 0 1366203134Sthompsa */ 1367203134Sthompsa tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK); 1368203134Sthompsa tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK; 1369203134Sthompsa run_write(sc, RT3070_EFUSE_CTRL, tmp); 1370203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1371203134Sthompsa if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0) 1372209917Sthompsa return (error); 1373203134Sthompsa if (!(tmp & RT3070_EFSROM_KICK)) 1374203134Sthompsa break; 1375203134Sthompsa run_delay(sc, 2); 1376203134Sthompsa } 1377203134Sthompsa if (ntries == 100) 1378209917Sthompsa return (ETIMEDOUT); 1379203134Sthompsa 1380261076Shselasky if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) { 1381261076Shselasky *val = 0xffff; /* address not found */ 1382209917Sthompsa return (0); 1383261076Shselasky } 1384203134Sthompsa /* determine to which 32-bit register our 16-bit word belongs */ 1385203134Sthompsa reg = RT3070_EFUSE_DATA3 - (addr & 0xc); 1386203134Sthompsa if ((error = run_read(sc, reg, &tmp)) != 0) 1387209917Sthompsa return (error); 1388203134Sthompsa 1389261118Skevlo tmp >>= (8 * (addr & 0x3)); 1390261118Skevlo *val = (addr & 1) ? tmp >> 16 : tmp & 0xffff; 1391261118Skevlo 1392209917Sthompsa return (0); 1393203134Sthompsa} 1394203134Sthompsa 1395261124Skevlo/* Read 16-bit from eFUSE ROM for RT3xxx. */ 1396203134Sthompsastatic int 1397259544Skevlorun_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val) 1398259544Skevlo{ 1399259544Skevlo return (run_efuse_read(sc, addr, val, 2)); 1400259544Skevlo} 1401259544Skevlo 1402259544Skevlostatic int 1403203134Sthompsarun_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val) 1404203134Sthompsa{ 1405203134Sthompsa usb_device_request_t req; 1406203134Sthompsa uint16_t tmp; 1407203134Sthompsa int error; 1408203134Sthompsa 1409203134Sthompsa addr *= 2; 1410203134Sthompsa req.bmRequestType = UT_READ_VENDOR_DEVICE; 1411203134Sthompsa req.bRequest = RT2870_EEPROM_READ; 1412203134Sthompsa USETW(req.wValue, 0); 1413203134Sthompsa USETW(req.wIndex, addr); 1414260219Skevlo USETW(req.wLength, sizeof(tmp)); 1415203134Sthompsa 1416203134Sthompsa error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp); 1417203134Sthompsa if (error == 0) 1418203134Sthompsa *val = le16toh(tmp); 1419203134Sthompsa else 1420203134Sthompsa *val = 0xffff; 1421209917Sthompsa return (error); 1422203134Sthompsa} 1423203134Sthompsa 1424203134Sthompsastatic __inline int 1425203134Sthompsarun_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val) 1426203134Sthompsa{ 1427203134Sthompsa /* either eFUSE ROM or EEPROM */ 1428203134Sthompsa return sc->sc_srom_read(sc, addr, val); 1429203134Sthompsa} 1430203134Sthompsa 1431203134Sthompsastatic int 1432258733Skevlorun_rt2870_rf_write(struct run_softc *sc, uint32_t val) 1433203134Sthompsa{ 1434203134Sthompsa uint32_t tmp; 1435203134Sthompsa int error, ntries; 1436203134Sthompsa 1437203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1438203134Sthompsa if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0) 1439209917Sthompsa return (error); 1440203134Sthompsa if (!(tmp & RT2860_RF_REG_CTRL)) 1441203134Sthompsa break; 1442203134Sthompsa } 1443203134Sthompsa if (ntries == 10) 1444209917Sthompsa return (ETIMEDOUT); 1445203134Sthompsa 1446258732Skevlo return (run_write(sc, RT2860_RF_CSR_CFG0, val)); 1447203134Sthompsa} 1448203134Sthompsa 1449203134Sthompsastatic int 1450203134Sthompsarun_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val) 1451203134Sthompsa{ 1452203134Sthompsa uint32_t tmp; 1453203134Sthompsa int error, ntries; 1454203134Sthompsa 1455203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1456203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1457209917Sthompsa return (error); 1458203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1459203134Sthompsa break; 1460203134Sthompsa } 1461203134Sthompsa if (ntries == 100) 1462209917Sthompsa return (ETIMEDOUT); 1463203134Sthompsa 1464203134Sthompsa tmp = RT3070_RF_KICK | reg << 8; 1465203134Sthompsa if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0) 1466209917Sthompsa return (error); 1467203134Sthompsa 1468203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1469203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1470209917Sthompsa return (error); 1471203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1472203134Sthompsa break; 1473203134Sthompsa } 1474203134Sthompsa if (ntries == 100) 1475209917Sthompsa return (ETIMEDOUT); 1476203134Sthompsa 1477203134Sthompsa *val = tmp & 0xff; 1478209917Sthompsa return (0); 1479203134Sthompsa} 1480203134Sthompsa 1481203134Sthompsastatic int 1482203134Sthompsarun_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val) 1483203134Sthompsa{ 1484203134Sthompsa uint32_t tmp; 1485203134Sthompsa int error, ntries; 1486203134Sthompsa 1487203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1488203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1489209917Sthompsa return (error); 1490203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1491203134Sthompsa break; 1492203134Sthompsa } 1493203134Sthompsa if (ntries == 10) 1494209917Sthompsa return (ETIMEDOUT); 1495203134Sthompsa 1496203134Sthompsa tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val; 1497209917Sthompsa return (run_write(sc, RT3070_RF_CSR_CFG, tmp)); 1498203134Sthompsa} 1499203134Sthompsa 1500203134Sthompsastatic int 1501203134Sthompsarun_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val) 1502203134Sthompsa{ 1503203134Sthompsa uint32_t tmp; 1504203134Sthompsa int ntries, error; 1505203134Sthompsa 1506203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1507203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1508209917Sthompsa return (error); 1509203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1510203134Sthompsa break; 1511203134Sthompsa } 1512203134Sthompsa if (ntries == 10) 1513209917Sthompsa return (ETIMEDOUT); 1514203134Sthompsa 1515203134Sthompsa tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8; 1516203134Sthompsa if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0) 1517209917Sthompsa return (error); 1518203134Sthompsa 1519203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1520203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1521209917Sthompsa return (error); 1522203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1523203134Sthompsa break; 1524203134Sthompsa } 1525203134Sthompsa if (ntries == 10) 1526209917Sthompsa return (ETIMEDOUT); 1527203134Sthompsa 1528203134Sthompsa *val = tmp & 0xff; 1529209917Sthompsa return (0); 1530203134Sthompsa} 1531203134Sthompsa 1532203134Sthompsastatic int 1533203134Sthompsarun_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val) 1534203134Sthompsa{ 1535203134Sthompsa uint32_t tmp; 1536203134Sthompsa int ntries, error; 1537203134Sthompsa 1538203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1539203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1540209917Sthompsa return (error); 1541203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1542203134Sthompsa break; 1543203134Sthompsa } 1544203134Sthompsa if (ntries == 10) 1545209917Sthompsa return (ETIMEDOUT); 1546203134Sthompsa 1547203134Sthompsa tmp = RT2860_BBP_CSR_KICK | reg << 8 | val; 1548209917Sthompsa return (run_write(sc, RT2860_BBP_CSR_CFG, tmp)); 1549203134Sthompsa} 1550203134Sthompsa 1551203134Sthompsa/* 1552203134Sthompsa * Send a command to the 8051 microcontroller unit. 1553203134Sthompsa */ 1554203134Sthompsastatic int 1555203134Sthompsarun_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg) 1556203134Sthompsa{ 1557203134Sthompsa uint32_t tmp; 1558203134Sthompsa int error, ntries; 1559203134Sthompsa 1560203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1561203134Sthompsa if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0) 1562203134Sthompsa return error; 1563203134Sthompsa if (!(tmp & RT2860_H2M_BUSY)) 1564203134Sthompsa break; 1565203134Sthompsa } 1566203134Sthompsa if (ntries == 100) 1567203134Sthompsa return ETIMEDOUT; 1568203134Sthompsa 1569203134Sthompsa tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg; 1570203134Sthompsa if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0) 1571203134Sthompsa error = run_write(sc, RT2860_HOST_CMD, cmd); 1572209917Sthompsa return (error); 1573203134Sthompsa} 1574203134Sthompsa 1575203134Sthompsa/* 1576203134Sthompsa * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word. 1577203134Sthompsa * Used to adjust per-rate Tx power registers. 1578203134Sthompsa */ 1579203134Sthompsastatic __inline uint32_t 1580203134Sthompsab4inc(uint32_t b32, int8_t delta) 1581203134Sthompsa{ 1582203134Sthompsa int8_t i, b4; 1583203134Sthompsa 1584203134Sthompsa for (i = 0; i < 8; i++) { 1585203134Sthompsa b4 = b32 & 0xf; 1586203134Sthompsa b4 += delta; 1587203134Sthompsa if (b4 < 0) 1588203134Sthompsa b4 = 0; 1589203134Sthompsa else if (b4 > 0xf) 1590203134Sthompsa b4 = 0xf; 1591203134Sthompsa b32 = b32 >> 4 | b4 << 28; 1592203134Sthompsa } 1593209917Sthompsa return (b32); 1594203134Sthompsa} 1595203134Sthompsa 1596203134Sthompsastatic const char * 1597257955Skevlorun_get_rf(uint16_t rev) 1598203134Sthompsa{ 1599203134Sthompsa switch (rev) { 1600203134Sthompsa case RT2860_RF_2820: return "RT2820"; 1601203134Sthompsa case RT2860_RF_2850: return "RT2850"; 1602203134Sthompsa case RT2860_RF_2720: return "RT2720"; 1603203134Sthompsa case RT2860_RF_2750: return "RT2750"; 1604203134Sthompsa case RT3070_RF_3020: return "RT3020"; 1605203134Sthompsa case RT3070_RF_2020: return "RT2020"; 1606203134Sthompsa case RT3070_RF_3021: return "RT3021"; 1607203134Sthompsa case RT3070_RF_3022: return "RT3022"; 1608203134Sthompsa case RT3070_RF_3052: return "RT3052"; 1609260219Skevlo case RT3593_RF_3053: return "RT3053"; 1610259032Skevlo case RT5592_RF_5592: return "RT5592"; 1611257955Skevlo case RT5390_RF_5370: return "RT5370"; 1612257955Skevlo case RT5390_RF_5372: return "RT5372"; 1613203134Sthompsa } 1614209917Sthompsa return ("unknown"); 1615203134Sthompsa} 1616203134Sthompsa 1617260219Skevlostatic void 1618260219Skevlorun_rt3593_get_txpower(struct run_softc *sc) 1619260219Skevlo{ 1620260219Skevlo uint16_t addr, val; 1621260219Skevlo int i; 1622260219Skevlo 1623260219Skevlo /* Read power settings for 2GHz channels. */ 1624260219Skevlo for (i = 0; i < 14; i += 2) { 1625260219Skevlo addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE1 : 1626260219Skevlo RT2860_EEPROM_PWR2GHZ_BASE1; 1627260219Skevlo run_srom_read(sc, addr + i / 2, &val); 1628260219Skevlo sc->txpow1[i + 0] = (int8_t)(val & 0xff); 1629260219Skevlo sc->txpow1[i + 1] = (int8_t)(val >> 8); 1630260219Skevlo 1631260219Skevlo addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE2 : 1632260219Skevlo RT2860_EEPROM_PWR2GHZ_BASE2; 1633260219Skevlo run_srom_read(sc, addr + i / 2, &val); 1634260219Skevlo sc->txpow2[i + 0] = (int8_t)(val & 0xff); 1635260219Skevlo sc->txpow2[i + 1] = (int8_t)(val >> 8); 1636260219Skevlo 1637260219Skevlo if (sc->ntxchains == 3) { 1638260219Skevlo run_srom_read(sc, RT3593_EEPROM_PWR2GHZ_BASE3 + i / 2, 1639260219Skevlo &val); 1640260219Skevlo sc->txpow3[i + 0] = (int8_t)(val & 0xff); 1641260219Skevlo sc->txpow3[i + 1] = (int8_t)(val >> 8); 1642260219Skevlo } 1643260219Skevlo } 1644260219Skevlo /* Fix broken Tx power entries. */ 1645260219Skevlo for (i = 0; i < 14; i++) { 1646260542Skevlo if (sc->txpow1[i] > 31) 1647260219Skevlo sc->txpow1[i] = 5; 1648260542Skevlo if (sc->txpow2[i] > 31) 1649260219Skevlo sc->txpow2[i] = 5; 1650260219Skevlo if (sc->ntxchains == 3) { 1651260542Skevlo if (sc->txpow3[i] > 31) 1652260219Skevlo sc->txpow3[i] = 5; 1653260219Skevlo } 1654260219Skevlo } 1655260219Skevlo /* Read power settings for 5GHz channels. */ 1656260219Skevlo for (i = 0; i < 40; i += 2) { 1657260219Skevlo run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE1 + i / 2, &val); 1658260219Skevlo sc->txpow1[i + 14] = (int8_t)(val & 0xff); 1659260219Skevlo sc->txpow1[i + 15] = (int8_t)(val >> 8); 1660260219Skevlo 1661260219Skevlo run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE2 + i / 2, &val); 1662260219Skevlo sc->txpow2[i + 14] = (int8_t)(val & 0xff); 1663260219Skevlo sc->txpow2[i + 15] = (int8_t)(val >> 8); 1664260219Skevlo 1665260219Skevlo if (sc->ntxchains == 3) { 1666260219Skevlo run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE3 + i / 2, 1667260219Skevlo &val); 1668260219Skevlo sc->txpow3[i + 14] = (int8_t)(val & 0xff); 1669260219Skevlo sc->txpow3[i + 15] = (int8_t)(val >> 8); 1670260219Skevlo } 1671260219Skevlo } 1672260219Skevlo} 1673260219Skevlo 1674260219Skevlostatic void 1675260219Skevlorun_get_txpower(struct run_softc *sc) 1676260219Skevlo{ 1677260219Skevlo uint16_t val; 1678260219Skevlo int i; 1679260219Skevlo 1680260219Skevlo /* Read power settings for 2GHz channels. */ 1681260219Skevlo for (i = 0; i < 14; i += 2) { 1682260219Skevlo run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val); 1683260219Skevlo sc->txpow1[i + 0] = (int8_t)(val & 0xff); 1684260219Skevlo sc->txpow1[i + 1] = (int8_t)(val >> 8); 1685260219Skevlo 1686260219Skevlo if (sc->mac_ver != 0x5390) { 1687260219Skevlo run_srom_read(sc, 1688260219Skevlo RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val); 1689260219Skevlo sc->txpow2[i + 0] = (int8_t)(val & 0xff); 1690260219Skevlo sc->txpow2[i + 1] = (int8_t)(val >> 8); 1691260219Skevlo } 1692260219Skevlo } 1693260219Skevlo /* Fix broken Tx power entries. */ 1694260219Skevlo for (i = 0; i < 14; i++) { 1695260219Skevlo if (sc->mac_ver >= 0x5390) { 1696288666Skevlo if (sc->txpow1[i] < 0 || sc->txpow1[i] > 39) 1697260219Skevlo sc->txpow1[i] = 5; 1698260219Skevlo } else { 1699260219Skevlo if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31) 1700260219Skevlo sc->txpow1[i] = 5; 1701260219Skevlo } 1702260219Skevlo if (sc->mac_ver > 0x5390) { 1703288666Skevlo if (sc->txpow2[i] < 0 || sc->txpow2[i] > 39) 1704260219Skevlo sc->txpow2[i] = 5; 1705260219Skevlo } else if (sc->mac_ver < 0x5390) { 1706260219Skevlo if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31) 1707260219Skevlo sc->txpow2[i] = 5; 1708260219Skevlo } 1709260219Skevlo DPRINTF("chan %d: power1=%d, power2=%d\n", 1710260219Skevlo rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]); 1711260219Skevlo } 1712260219Skevlo /* Read power settings for 5GHz channels. */ 1713260219Skevlo for (i = 0; i < 40; i += 2) { 1714260219Skevlo run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val); 1715260219Skevlo sc->txpow1[i + 14] = (int8_t)(val & 0xff); 1716260219Skevlo sc->txpow1[i + 15] = (int8_t)(val >> 8); 1717260219Skevlo 1718260219Skevlo run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val); 1719260219Skevlo sc->txpow2[i + 14] = (int8_t)(val & 0xff); 1720260219Skevlo sc->txpow2[i + 15] = (int8_t)(val >> 8); 1721260219Skevlo } 1722260219Skevlo /* Fix broken Tx power entries. */ 1723260219Skevlo for (i = 0; i < 40; i++ ) { 1724260219Skevlo if (sc->mac_ver != 0x5592) { 1725260219Skevlo if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15) 1726260219Skevlo sc->txpow1[14 + i] = 5; 1727260219Skevlo if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15) 1728260219Skevlo sc->txpow2[14 + i] = 5; 1729260219Skevlo } 1730260219Skevlo DPRINTF("chan %d: power1=%d, power2=%d\n", 1731260219Skevlo rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i], 1732260219Skevlo sc->txpow2[14 + i]); 1733260219Skevlo } 1734260219Skevlo} 1735260219Skevlo 1736258641Shselaskystatic int 1737203134Sthompsarun_read_eeprom(struct run_softc *sc) 1738203134Sthompsa{ 1739287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 1740203134Sthompsa int8_t delta_2ghz, delta_5ghz; 1741203134Sthompsa uint32_t tmp; 1742203134Sthompsa uint16_t val; 1743203134Sthompsa int ridx, ant, i; 1744203134Sthompsa 1745203134Sthompsa /* check whether the ROM is eFUSE ROM or EEPROM */ 1746203134Sthompsa sc->sc_srom_read = run_eeprom_read_2; 1747205042Sthompsa if (sc->mac_ver >= 0x3070) { 1748203134Sthompsa run_read(sc, RT3070_EFUSE_CTRL, &tmp); 1749203134Sthompsa DPRINTF("EFUSE_CTRL=0x%08x\n", tmp); 1750261118Skevlo if ((tmp & RT3070_SEL_EFUSE) || sc->mac_ver == 0x3593) 1751203134Sthompsa sc->sc_srom_read = run_efuse_read_2; 1752203134Sthompsa } 1753203134Sthompsa 1754203134Sthompsa /* read ROM version */ 1755203134Sthompsa run_srom_read(sc, RT2860_EEPROM_VERSION, &val); 1756287853Skevlo DPRINTF("EEPROM rev=%d, FAE=%d\n", val >> 8, val & 0xff); 1757203134Sthompsa 1758203134Sthompsa /* read MAC address */ 1759203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC01, &val); 1760287197Sglebius ic->ic_macaddr[0] = val & 0xff; 1761287197Sglebius ic->ic_macaddr[1] = val >> 8; 1762203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC23, &val); 1763287197Sglebius ic->ic_macaddr[2] = val & 0xff; 1764287197Sglebius ic->ic_macaddr[3] = val >> 8; 1765203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC45, &val); 1766287197Sglebius ic->ic_macaddr[4] = val & 0xff; 1767287197Sglebius ic->ic_macaddr[5] = val >> 8; 1768203134Sthompsa 1769260219Skevlo if (sc->mac_ver < 0x3593) { 1770257955Skevlo /* read vender BBP settings */ 1771205042Sthompsa for (i = 0; i < 10; i++) { 1772257955Skevlo run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val); 1773257955Skevlo sc->bbp[i].val = val & 0xff; 1774257955Skevlo sc->bbp[i].reg = val >> 8; 1775257955Skevlo DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg, 1776257955Skevlo sc->bbp[i].val); 1777205042Sthompsa } 1778257955Skevlo if (sc->mac_ver >= 0x3071) { 1779257955Skevlo /* read vendor RF settings */ 1780257955Skevlo for (i = 0; i < 10; i++) { 1781257955Skevlo run_srom_read(sc, RT3071_EEPROM_RF_BASE + i, 1782257955Skevlo &val); 1783257955Skevlo sc->rf[i].val = val & 0xff; 1784257955Skevlo sc->rf[i].reg = val >> 8; 1785257955Skevlo DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg, 1786257955Skevlo sc->rf[i].val); 1787257955Skevlo } 1788257955Skevlo } 1789205042Sthompsa } 1790203134Sthompsa 1791203134Sthompsa /* read RF frequency offset from EEPROM */ 1792260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS : 1793260219Skevlo RT3593_EEPROM_FREQ, &val); 1794203134Sthompsa sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0; 1795203134Sthompsa DPRINTF("EEPROM freq offset %d\n", sc->freq & 0xff); 1796203134Sthompsa 1797260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS : 1798260219Skevlo RT3593_EEPROM_FREQ_LEDS, &val); 1799205042Sthompsa if (val >> 8 != 0xff) { 1800203134Sthompsa /* read LEDs operating mode */ 1801205042Sthompsa sc->leds = val >> 8; 1802260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED1 : 1803260219Skevlo RT3593_EEPROM_LED1, &sc->led[0]); 1804260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED2 : 1805260219Skevlo RT3593_EEPROM_LED2, &sc->led[1]); 1806260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED3 : 1807260219Skevlo RT3593_EEPROM_LED3, &sc->led[2]); 1808203134Sthompsa } else { 1809203134Sthompsa /* broken EEPROM, use default settings */ 1810203134Sthompsa sc->leds = 0x01; 1811203134Sthompsa sc->led[0] = 0x5555; 1812203134Sthompsa sc->led[1] = 0x2221; 1813203134Sthompsa sc->led[2] = 0x5627; /* differs from RT2860 */ 1814203134Sthompsa } 1815203134Sthompsa DPRINTF("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n", 1816203134Sthompsa sc->leds, sc->led[0], sc->led[1], sc->led[2]); 1817203134Sthompsa 1818203134Sthompsa /* read RF information */ 1819259032Skevlo if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) 1820257955Skevlo run_srom_read(sc, 0x00, &val); 1821257955Skevlo else 1822257955Skevlo run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val); 1823257955Skevlo 1824203134Sthompsa if (val == 0xffff) { 1825260219Skevlo device_printf(sc->sc_dev, 1826260219Skevlo "invalid EEPROM antenna info, using default\n"); 1827203134Sthompsa DPRINTF("invalid EEPROM antenna info, using default\n"); 1828205042Sthompsa if (sc->mac_ver == 0x3572) { 1829205042Sthompsa /* default to RF3052 2T2R */ 1830205042Sthompsa sc->rf_rev = RT3070_RF_3052; 1831205042Sthompsa sc->ntxchains = 2; 1832205042Sthompsa sc->nrxchains = 2; 1833205042Sthompsa } else if (sc->mac_ver >= 0x3070) { 1834203134Sthompsa /* default to RF3020 1T1R */ 1835203134Sthompsa sc->rf_rev = RT3070_RF_3020; 1836203134Sthompsa sc->ntxchains = 1; 1837203134Sthompsa sc->nrxchains = 1; 1838203134Sthompsa } else { 1839203134Sthompsa /* default to RF2820 1T2R */ 1840203134Sthompsa sc->rf_rev = RT2860_RF_2820; 1841203134Sthompsa sc->ntxchains = 1; 1842203134Sthompsa sc->nrxchains = 2; 1843203134Sthompsa } 1844203134Sthompsa } else { 1845259032Skevlo if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) { 1846257955Skevlo sc->rf_rev = val; 1847257955Skevlo run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val); 1848257955Skevlo } else 1849257955Skevlo sc->rf_rev = (val >> 8) & 0xf; 1850203134Sthompsa sc->ntxchains = (val >> 4) & 0xf; 1851203134Sthompsa sc->nrxchains = val & 0xf; 1852203134Sthompsa } 1853257955Skevlo DPRINTF("EEPROM RF rev=0x%04x chains=%dT%dR\n", 1854203134Sthompsa sc->rf_rev, sc->ntxchains, sc->nrxchains); 1855203134Sthompsa 1856208019Sthompsa /* check if RF supports automatic Tx access gain control */ 1857203134Sthompsa run_srom_read(sc, RT2860_EEPROM_CONFIG, &val); 1858203134Sthompsa DPRINTF("EEPROM CFG 0x%04x\n", val); 1859205042Sthompsa /* check if driver should patch the DAC issue */ 1860205042Sthompsa if ((val >> 8) != 0xff) 1861205042Sthompsa sc->patch_dac = (val >> 15) & 1; 1862203134Sthompsa if ((val & 0xff) != 0xff) { 1863203134Sthompsa sc->ext_5ghz_lna = (val >> 3) & 1; 1864203134Sthompsa sc->ext_2ghz_lna = (val >> 2) & 1; 1865205042Sthompsa /* check if RF supports automatic Tx access gain control */ 1866203134Sthompsa sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1; 1867205042Sthompsa /* check if we have a hardware radio switch */ 1868205042Sthompsa sc->rfswitch = val & 1; 1869203134Sthompsa } 1870203134Sthompsa 1871260219Skevlo /* Read Tx power settings. */ 1872260219Skevlo if (sc->mac_ver == 0x3593) 1873260219Skevlo run_rt3593_get_txpower(sc); 1874260219Skevlo else 1875260219Skevlo run_get_txpower(sc); 1876203134Sthompsa 1877203134Sthompsa /* read Tx power compensation for each Tx rate */ 1878203134Sthompsa run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val); 1879203134Sthompsa delta_2ghz = delta_5ghz = 0; 1880203134Sthompsa if ((val & 0xff) != 0xff && (val & 0x80)) { 1881203134Sthompsa delta_2ghz = val & 0xf; 1882203134Sthompsa if (!(val & 0x40)) /* negative number */ 1883203134Sthompsa delta_2ghz = -delta_2ghz; 1884203134Sthompsa } 1885203134Sthompsa val >>= 8; 1886203134Sthompsa if ((val & 0xff) != 0xff && (val & 0x80)) { 1887203134Sthompsa delta_5ghz = val & 0xf; 1888203134Sthompsa if (!(val & 0x40)) /* negative number */ 1889203134Sthompsa delta_5ghz = -delta_5ghz; 1890203134Sthompsa } 1891203134Sthompsa DPRINTF("power compensation=%d (2GHz), %d (5GHz)\n", 1892203134Sthompsa delta_2ghz, delta_5ghz); 1893203134Sthompsa 1894203134Sthompsa for (ridx = 0; ridx < 5; ridx++) { 1895203134Sthompsa uint32_t reg; 1896203134Sthompsa 1897208019Sthompsa run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val); 1898208019Sthompsa reg = val; 1899208019Sthompsa run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val); 1900208019Sthompsa reg |= (uint32_t)val << 16; 1901203134Sthompsa 1902203134Sthompsa sc->txpow20mhz[ridx] = reg; 1903203134Sthompsa sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz); 1904203134Sthompsa sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz); 1905203134Sthompsa 1906203134Sthompsa DPRINTF("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, " 1907203134Sthompsa "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx], 1908203134Sthompsa sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]); 1909203134Sthompsa } 1910203134Sthompsa 1911260219Skevlo /* Read RSSI offsets and LNA gains from EEPROM. */ 1912260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_2GHZ : 1913260219Skevlo RT3593_EEPROM_RSSI1_2GHZ, &val); 1914203134Sthompsa sc->rssi_2ghz[0] = val & 0xff; /* Ant A */ 1915203134Sthompsa sc->rssi_2ghz[1] = val >> 8; /* Ant B */ 1916260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_2GHZ : 1917260219Skevlo RT3593_EEPROM_RSSI2_2GHZ, &val); 1918205042Sthompsa if (sc->mac_ver >= 0x3070) { 1919260219Skevlo if (sc->mac_ver == 0x3593) { 1920260219Skevlo sc->txmixgain_2ghz = 0; 1921260219Skevlo sc->rssi_2ghz[2] = val & 0xff; /* Ant C */ 1922260219Skevlo } else { 1923260219Skevlo /* 1924260219Skevlo * On RT3070 chips (limited to 2 Rx chains), this ROM 1925260219Skevlo * field contains the Tx mixer gain for the 2GHz band. 1926260219Skevlo */ 1927260219Skevlo if ((val & 0xff) != 0xff) 1928260219Skevlo sc->txmixgain_2ghz = val & 0x7; 1929260219Skevlo } 1930205042Sthompsa DPRINTF("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz); 1931205042Sthompsa } else 1932205042Sthompsa sc->rssi_2ghz[2] = val & 0xff; /* Ant C */ 1933260219Skevlo if (sc->mac_ver == 0x3593) 1934260219Skevlo run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val); 1935203134Sthompsa sc->lna[2] = val >> 8; /* channel group 2 */ 1936203134Sthompsa 1937260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_5GHZ : 1938260219Skevlo RT3593_EEPROM_RSSI1_5GHZ, &val); 1939203134Sthompsa sc->rssi_5ghz[0] = val & 0xff; /* Ant A */ 1940203134Sthompsa sc->rssi_5ghz[1] = val >> 8; /* Ant B */ 1941260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_5GHZ : 1942260219Skevlo RT3593_EEPROM_RSSI2_5GHZ, &val); 1943205042Sthompsa if (sc->mac_ver == 0x3572) { 1944205042Sthompsa /* 1945205042Sthompsa * On RT3572 chips (limited to 2 Rx chains), this ROM 1946205042Sthompsa * field contains the Tx mixer gain for the 5GHz band. 1947205042Sthompsa */ 1948205042Sthompsa if ((val & 0xff) != 0xff) 1949205042Sthompsa sc->txmixgain_5ghz = val & 0x7; 1950205042Sthompsa DPRINTF("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz); 1951205042Sthompsa } else 1952205042Sthompsa sc->rssi_5ghz[2] = val & 0xff; /* Ant C */ 1953260219Skevlo if (sc->mac_ver == 0x3593) { 1954260219Skevlo sc->txmixgain_5ghz = 0; 1955260219Skevlo run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val); 1956260219Skevlo } 1957203134Sthompsa sc->lna[3] = val >> 8; /* channel group 3 */ 1958203134Sthompsa 1959260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LNA : 1960260219Skevlo RT3593_EEPROM_LNA, &val); 1961203134Sthompsa sc->lna[0] = val & 0xff; /* channel group 0 */ 1962203134Sthompsa sc->lna[1] = val >> 8; /* channel group 1 */ 1963203134Sthompsa 1964203134Sthompsa /* fix broken 5GHz LNA entries */ 1965203134Sthompsa if (sc->lna[2] == 0 || sc->lna[2] == 0xff) { 1966203134Sthompsa DPRINTF("invalid LNA for channel group %d\n", 2); 1967203134Sthompsa sc->lna[2] = sc->lna[1]; 1968203134Sthompsa } 1969203134Sthompsa if (sc->lna[3] == 0 || sc->lna[3] == 0xff) { 1970203134Sthompsa DPRINTF("invalid LNA for channel group %d\n", 3); 1971203134Sthompsa sc->lna[3] = sc->lna[1]; 1972203134Sthompsa } 1973203134Sthompsa 1974203134Sthompsa /* fix broken RSSI offset entries */ 1975203134Sthompsa for (ant = 0; ant < 3; ant++) { 1976203134Sthompsa if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) { 1977203134Sthompsa DPRINTF("invalid RSSI%d offset: %d (2GHz)\n", 1978203134Sthompsa ant + 1, sc->rssi_2ghz[ant]); 1979203134Sthompsa sc->rssi_2ghz[ant] = 0; 1980203134Sthompsa } 1981203134Sthompsa if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) { 1982203134Sthompsa DPRINTF("invalid RSSI%d offset: %d (5GHz)\n", 1983203134Sthompsa ant + 1, sc->rssi_5ghz[ant]); 1984203134Sthompsa sc->rssi_5ghz[ant] = 0; 1985203134Sthompsa } 1986203134Sthompsa } 1987209917Sthompsa return (0); 1988203134Sthompsa} 1989203134Sthompsa 1990218676Shselaskystatic struct ieee80211_node * 1991203134Sthompsarun_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) 1992203134Sthompsa{ 1993203134Sthompsa return malloc(sizeof (struct run_node), M_DEVBUF, M_NOWAIT | M_ZERO); 1994203134Sthompsa} 1995203134Sthompsa 1996203134Sthompsastatic int 1997203134Sthompsarun_media_change(struct ifnet *ifp) 1998203134Sthompsa{ 1999208019Sthompsa struct ieee80211vap *vap = ifp->if_softc; 2000208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 2001203134Sthompsa const struct ieee80211_txparam *tp; 2002286950Sadrian struct run_softc *sc = ic->ic_softc; 2003203134Sthompsa uint8_t rate, ridx; 2004203134Sthompsa int error; 2005203134Sthompsa 2006203134Sthompsa RUN_LOCK(sc); 2007203134Sthompsa 2008203134Sthompsa error = ieee80211_media_change(ifp); 2009209917Sthompsa if (error != ENETRESET) { 2010203134Sthompsa RUN_UNLOCK(sc); 2011209917Sthompsa return (error); 2012208019Sthompsa } 2013203134Sthompsa 2014203134Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 2015203134Sthompsa if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 2016212127Sthompsa struct ieee80211_node *ni; 2017212127Sthompsa struct run_node *rn; 2018212127Sthompsa 2019203134Sthompsa rate = ic->ic_sup_rates[ic->ic_curmode]. 2020203134Sthompsa rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL; 2021203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2022203134Sthompsa if (rt2860_rates[ridx].rate == rate) 2023203134Sthompsa break; 2024212127Sthompsa ni = ieee80211_ref_node(vap->iv_bss); 2025287552Skevlo rn = RUN_NODE(ni); 2026208019Sthompsa rn->fix_ridx = ridx; 2027208019Sthompsa DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx); 2028212127Sthompsa ieee80211_free_node(ni); 2029203134Sthompsa } 2030203134Sthompsa 2031208019Sthompsa#if 0 2032203134Sthompsa if ((ifp->if_flags & IFF_UP) && 2033287197Sglebius (ifp->if_drv_flags & RUN_RUNNING)){ 2034203134Sthompsa run_init_locked(sc); 2035203134Sthompsa } 2036208019Sthompsa#endif 2037203134Sthompsa 2038203134Sthompsa RUN_UNLOCK(sc); 2039203134Sthompsa 2040209917Sthompsa return (0); 2041203134Sthompsa} 2042203134Sthompsa 2043203134Sthompsastatic int 2044203134Sthompsarun_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 2045203134Sthompsa{ 2046203134Sthompsa const struct ieee80211_txparam *tp; 2047203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2048286950Sadrian struct run_softc *sc = ic->ic_softc; 2049203134Sthompsa struct run_vap *rvp = RUN_VAP(vap); 2050203134Sthompsa enum ieee80211_state ostate; 2051208019Sthompsa uint32_t sta[3]; 2052203134Sthompsa uint32_t tmp; 2053208019Sthompsa uint8_t ratectl; 2054208019Sthompsa uint8_t restart_ratectl = 0; 2055208019Sthompsa uint8_t bid = 1 << rvp->rvp_id; 2056203134Sthompsa 2057203134Sthompsa ostate = vap->iv_state; 2058203134Sthompsa DPRINTF("%s -> %s\n", 2059203134Sthompsa ieee80211_state_name[ostate], 2060203134Sthompsa ieee80211_state_name[nstate]); 2061203134Sthompsa 2062203134Sthompsa IEEE80211_UNLOCK(ic); 2063203134Sthompsa RUN_LOCK(sc); 2064203134Sthompsa 2065208019Sthompsa ratectl = sc->ratectl_run; /* remember current state */ 2066208019Sthompsa sc->ratectl_run = RUN_RATECTL_OFF; 2067208019Sthompsa usb_callout_stop(&sc->ratectl_ch); 2068203134Sthompsa 2069203134Sthompsa if (ostate == IEEE80211_S_RUN) { 2070203134Sthompsa /* turn link LED off */ 2071203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO); 2072203134Sthompsa } 2073203134Sthompsa 2074203134Sthompsa switch (nstate) { 2075203134Sthompsa case IEEE80211_S_INIT: 2076208019Sthompsa restart_ratectl = 1; 2077208019Sthompsa 2078208019Sthompsa if (ostate != IEEE80211_S_RUN) 2079208019Sthompsa break; 2080208019Sthompsa 2081208019Sthompsa ratectl &= ~bid; 2082208019Sthompsa sc->runbmap &= ~bid; 2083208019Sthompsa 2084208019Sthompsa /* abort TSF synchronization if there is no vap running */ 2085209917Sthompsa if (--sc->running == 0) { 2086203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 2087203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, 2088203134Sthompsa tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 2089203134Sthompsa RT2860_TBTT_TIMER_EN)); 2090203134Sthompsa } 2091203134Sthompsa break; 2092203134Sthompsa 2093203134Sthompsa case IEEE80211_S_RUN: 2094209917Sthompsa if (!(sc->runbmap & bid)) { 2095208019Sthompsa if(sc->running++) 2096208019Sthompsa restart_ratectl = 1; 2097208019Sthompsa sc->runbmap |= bid; 2098208019Sthompsa } 2099203134Sthompsa 2100218492Sbschmidt m_freem(rvp->beacon_mbuf); 2101218492Sbschmidt rvp->beacon_mbuf = NULL; 2102218492Sbschmidt 2103209917Sthompsa switch (vap->iv_opmode) { 2104208019Sthompsa case IEEE80211_M_HOSTAP: 2105208019Sthompsa case IEEE80211_M_MBSS: 2106208019Sthompsa sc->ap_running |= bid; 2107208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2108208019Sthompsa run_update_beacon_cb(vap); 2109208019Sthompsa break; 2110208019Sthompsa case IEEE80211_M_IBSS: 2111208019Sthompsa sc->adhoc_running |= bid; 2112209917Sthompsa if (!sc->ap_running) 2113208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2114208019Sthompsa run_update_beacon_cb(vap); 2115208019Sthompsa break; 2116208019Sthompsa case IEEE80211_M_STA: 2117208019Sthompsa sc->sta_running |= bid; 2118209917Sthompsa if (!sc->ap_running && !sc->adhoc_running) 2119208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2120208019Sthompsa 2121208019Sthompsa /* read statistic counters (clear on read) */ 2122208019Sthompsa run_read_region_1(sc, RT2860_TX_STA_CNT0, 2123208019Sthompsa (uint8_t *)sta, sizeof sta); 2124208019Sthompsa 2125208019Sthompsa break; 2126208019Sthompsa default: 2127208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2128208019Sthompsa break; 2129208019Sthompsa } 2130208019Sthompsa 2131203134Sthompsa if (vap->iv_opmode != IEEE80211_M_MONITOR) { 2132212127Sthompsa struct ieee80211_node *ni; 2133212127Sthompsa 2134236439Shselasky if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) { 2135236439Shselasky RUN_UNLOCK(sc); 2136236439Shselasky IEEE80211_LOCK(ic); 2137236439Shselasky return (-1); 2138236439Shselasky } 2139283540Sglebius run_updateslot(ic); 2140203134Sthompsa run_enable_mrr(sc); 2141203134Sthompsa run_set_txpreamble(sc); 2142203134Sthompsa run_set_basicrates(sc); 2143212127Sthompsa ni = ieee80211_ref_node(vap->iv_bss); 2144287197Sglebius IEEE80211_ADDR_COPY(ic->ic_macaddr, ni->ni_bssid); 2145203134Sthompsa run_set_bssid(sc, ni->ni_bssid); 2146212127Sthompsa ieee80211_free_node(ni); 2147208019Sthompsa run_enable_tsf_sync(sc); 2148203134Sthompsa 2149208019Sthompsa /* enable automatic rate adaptation */ 2150208019Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 2151208019Sthompsa if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) 2152208019Sthompsa ratectl |= bid; 2153287555Skevlo } else 2154287555Skevlo run_enable_tsf(sc); 2155203134Sthompsa 2156203134Sthompsa /* turn link LED on */ 2157203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO | 2158208019Sthompsa (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 2159203134Sthompsa RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ)); 2160203134Sthompsa 2161203134Sthompsa break; 2162203134Sthompsa default: 2163203134Sthompsa DPRINTFN(6, "undefined case\n"); 2164203134Sthompsa break; 2165203134Sthompsa } 2166203134Sthompsa 2167208019Sthompsa /* restart amrr for running VAPs */ 2168209917Sthompsa if ((sc->ratectl_run = ratectl) && restart_ratectl) 2169208019Sthompsa usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2170208019Sthompsa 2171203134Sthompsa RUN_UNLOCK(sc); 2172203134Sthompsa IEEE80211_LOCK(ic); 2173203134Sthompsa 2174203134Sthompsa return(rvp->newstate(vap, nstate, arg)); 2175203134Sthompsa} 2176203134Sthompsa 2177290407Savosstatic int 2178290407Savosrun_wme_update(struct ieee80211com *ic) 2179203134Sthompsa{ 2180286950Sadrian struct run_softc *sc = ic->ic_softc; 2181288646Sadrian const struct wmeParams *ac = 2182288646Sadrian ic->ic_wme.wme_chanParams.cap_wmeParams; 2183203134Sthompsa int aci, error = 0; 2184203134Sthompsa 2185203134Sthompsa /* update MAC TX configuration registers */ 2186290407Savos RUN_LOCK(sc); 2187203134Sthompsa for (aci = 0; aci < WME_NUM_AC; aci++) { 2188203134Sthompsa error = run_write(sc, RT2860_EDCA_AC_CFG(aci), 2189288646Sadrian ac[aci].wmep_logcwmax << 16 | 2190288646Sadrian ac[aci].wmep_logcwmin << 12 | 2191288646Sadrian ac[aci].wmep_aifsn << 8 | 2192288646Sadrian ac[aci].wmep_txopLimit); 2193209917Sthompsa if (error) goto err; 2194203134Sthompsa } 2195203134Sthompsa 2196203134Sthompsa /* update SCH/DMA registers too */ 2197203134Sthompsa error = run_write(sc, RT2860_WMM_AIFSN_CFG, 2198288646Sadrian ac[WME_AC_VO].wmep_aifsn << 12 | 2199288646Sadrian ac[WME_AC_VI].wmep_aifsn << 8 | 2200288646Sadrian ac[WME_AC_BK].wmep_aifsn << 4 | 2201288646Sadrian ac[WME_AC_BE].wmep_aifsn); 2202209917Sthompsa if (error) goto err; 2203203134Sthompsa error = run_write(sc, RT2860_WMM_CWMIN_CFG, 2204288646Sadrian ac[WME_AC_VO].wmep_logcwmin << 12 | 2205288646Sadrian ac[WME_AC_VI].wmep_logcwmin << 8 | 2206288646Sadrian ac[WME_AC_BK].wmep_logcwmin << 4 | 2207288646Sadrian ac[WME_AC_BE].wmep_logcwmin); 2208209917Sthompsa if (error) goto err; 2209203134Sthompsa error = run_write(sc, RT2860_WMM_CWMAX_CFG, 2210288646Sadrian ac[WME_AC_VO].wmep_logcwmax << 12 | 2211288646Sadrian ac[WME_AC_VI].wmep_logcwmax << 8 | 2212288646Sadrian ac[WME_AC_BK].wmep_logcwmax << 4 | 2213288646Sadrian ac[WME_AC_BE].wmep_logcwmax); 2214209917Sthompsa if (error) goto err; 2215203134Sthompsa error = run_write(sc, RT2860_WMM_TXOP0_CFG, 2216288646Sadrian ac[WME_AC_BK].wmep_txopLimit << 16 | 2217288646Sadrian ac[WME_AC_BE].wmep_txopLimit); 2218209917Sthompsa if (error) goto err; 2219203134Sthompsa error = run_write(sc, RT2860_WMM_TXOP1_CFG, 2220288646Sadrian ac[WME_AC_VO].wmep_txopLimit << 16 | 2221288646Sadrian ac[WME_AC_VI].wmep_txopLimit); 2222203134Sthompsa 2223203134Sthompsaerr: 2224290407Savos RUN_UNLOCK(sc); 2225209917Sthompsa if (error) 2226203134Sthompsa DPRINTF("WME update failed\n"); 2227203134Sthompsa 2228290407Savos return (error); 2229203134Sthompsa} 2230203134Sthompsa 2231203134Sthompsastatic void 2232208019Sthompsarun_key_set_cb(void *arg) 2233203134Sthompsa{ 2234208019Sthompsa struct run_cmdq *cmdq = arg; 2235208019Sthompsa struct ieee80211vap *vap = cmdq->arg1; 2236208019Sthompsa struct ieee80211_key *k = cmdq->k; 2237203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2238286950Sadrian struct run_softc *sc = ic->ic_softc; 2239203134Sthompsa struct ieee80211_node *ni; 2240287553Skevlo u_int cipher = k->wk_cipher->ic_cipher; 2241203134Sthompsa uint32_t attr; 2242203134Sthompsa uint16_t base, associd; 2243209144Sthompsa uint8_t mode, wcid, iv[8]; 2244203134Sthompsa 2245208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2246203134Sthompsa 2247209917Sthompsa if (vap->iv_opmode == IEEE80211_M_HOSTAP) 2248208019Sthompsa ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac); 2249209144Sthompsa else 2250203134Sthompsa ni = vap->iv_bss; 2251208019Sthompsa associd = (ni != NULL) ? ni->ni_associd : 0; 2252203134Sthompsa 2253203134Sthompsa /* map net80211 cipher to RT2860 security mode */ 2254287553Skevlo switch (cipher) { 2255203134Sthompsa case IEEE80211_CIPHER_WEP: 2256203134Sthompsa if(k->wk_keylen < 8) 2257203134Sthompsa mode = RT2860_MODE_WEP40; 2258203134Sthompsa else 2259203134Sthompsa mode = RT2860_MODE_WEP104; 2260203134Sthompsa break; 2261203134Sthompsa case IEEE80211_CIPHER_TKIP: 2262203134Sthompsa mode = RT2860_MODE_TKIP; 2263203134Sthompsa break; 2264203134Sthompsa case IEEE80211_CIPHER_AES_CCM: 2265203134Sthompsa mode = RT2860_MODE_AES_CCMP; 2266203134Sthompsa break; 2267203134Sthompsa default: 2268203134Sthompsa DPRINTF("undefined case\n"); 2269208019Sthompsa return; 2270203134Sthompsa } 2271203134Sthompsa 2272208019Sthompsa DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n", 2273203134Sthompsa associd, k->wk_keyix, mode, 2274208019Sthompsa (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise", 2275208019Sthompsa (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off", 2276208019Sthompsa (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off"); 2277203134Sthompsa 2278203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 2279203134Sthompsa wcid = 0; /* NB: update WCID0 for group keys */ 2280208019Sthompsa base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix); 2281203134Sthompsa } else { 2282245047Shselasky wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 2283245047Shselasky 1 : RUN_AID2WCID(associd); 2284203134Sthompsa base = RT2860_PKEY(wcid); 2285203134Sthompsa } 2286203134Sthompsa 2287287553Skevlo if (cipher == IEEE80211_CIPHER_TKIP) { 2288203134Sthompsa if(run_write_region_1(sc, base, k->wk_key, 16)) 2289208019Sthompsa return; 2290209144Sthompsa if(run_write_region_1(sc, base + 16, &k->wk_key[16], 8)) /* wk_txmic */ 2291208019Sthompsa return; 2292209144Sthompsa if(run_write_region_1(sc, base + 24, &k->wk_key[24], 8)) /* wk_rxmic */ 2293208019Sthompsa return; 2294203134Sthompsa } else { 2295203134Sthompsa /* roundup len to 16-bit: XXX fix write_region_1() instead */ 2296203134Sthompsa if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1)) 2297208019Sthompsa return; 2298203134Sthompsa } 2299203134Sthompsa 2300203134Sthompsa if (!(k->wk_flags & IEEE80211_KEY_GROUP) || 2301203134Sthompsa (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) { 2302203134Sthompsa /* set initial packet number in IV+EIV */ 2303287553Skevlo if (cipher == IEEE80211_CIPHER_WEP) { 2304203134Sthompsa memset(iv, 0, sizeof iv); 2305208019Sthompsa iv[3] = vap->iv_def_txkey << 6; 2306203134Sthompsa } else { 2307287553Skevlo if (cipher == IEEE80211_CIPHER_TKIP) { 2308203134Sthompsa iv[0] = k->wk_keytsc >> 8; 2309203134Sthompsa iv[1] = (iv[0] | 0x20) & 0x7f; 2310203134Sthompsa iv[2] = k->wk_keytsc; 2311203134Sthompsa } else /* CCMP */ { 2312203134Sthompsa iv[0] = k->wk_keytsc; 2313203134Sthompsa iv[1] = k->wk_keytsc >> 8; 2314203134Sthompsa iv[2] = 0; 2315203134Sthompsa } 2316203134Sthompsa iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV; 2317203134Sthompsa iv[4] = k->wk_keytsc >> 16; 2318203134Sthompsa iv[5] = k->wk_keytsc >> 24; 2319203134Sthompsa iv[6] = k->wk_keytsc >> 32; 2320203134Sthompsa iv[7] = k->wk_keytsc >> 40; 2321203134Sthompsa } 2322209917Sthompsa if (run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8)) 2323208019Sthompsa return; 2324203134Sthompsa } 2325203134Sthompsa 2326203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 2327203134Sthompsa /* install group key */ 2328209917Sthompsa if (run_read(sc, RT2860_SKEY_MODE_0_7, &attr)) 2329208019Sthompsa return; 2330203134Sthompsa attr &= ~(0xf << (k->wk_keyix * 4)); 2331203134Sthompsa attr |= mode << (k->wk_keyix * 4); 2332209917Sthompsa if (run_write(sc, RT2860_SKEY_MODE_0_7, attr)) 2333208019Sthompsa return; 2334203134Sthompsa } else { 2335203134Sthompsa /* install pairwise key */ 2336209917Sthompsa if (run_read(sc, RT2860_WCID_ATTR(wcid), &attr)) 2337208019Sthompsa return; 2338203134Sthompsa attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN; 2339209917Sthompsa if (run_write(sc, RT2860_WCID_ATTR(wcid), attr)) 2340208019Sthompsa return; 2341203134Sthompsa } 2342203134Sthompsa 2343203134Sthompsa /* TODO create a pass-thru key entry? */ 2344203134Sthompsa 2345208019Sthompsa /* need wcid to delete the right key later */ 2346208019Sthompsa k->wk_pad = wcid; 2347203134Sthompsa} 2348203134Sthompsa 2349203134Sthompsa/* 2350208019Sthompsa * Don't have to be deferred, but in order to keep order of 2351208019Sthompsa * execution, i.e. with run_key_delete(), defer this and let 2352208019Sthompsa * run_cmdq_cb() maintain the order. 2353208019Sthompsa * 2354203134Sthompsa * return 0 on error 2355203134Sthompsa */ 2356203134Sthompsastatic int 2357288635Sadrianrun_key_set(struct ieee80211vap *vap, struct ieee80211_key *k) 2358203134Sthompsa{ 2359203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2360286950Sadrian struct run_softc *sc = ic->ic_softc; 2361208019Sthompsa uint32_t i; 2362208019Sthompsa 2363208019Sthompsa i = RUN_CMDQ_GET(&sc->cmdq_store); 2364208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 2365208019Sthompsa sc->cmdq[i].func = run_key_set_cb; 2366208019Sthompsa sc->cmdq[i].arg0 = NULL; 2367208019Sthompsa sc->cmdq[i].arg1 = vap; 2368208019Sthompsa sc->cmdq[i].k = k; 2369288635Sadrian IEEE80211_ADDR_COPY(sc->cmdq[i].mac, k->wk_macaddr); 2370208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2371208019Sthompsa 2372209144Sthompsa /* 2373209144Sthompsa * To make sure key will be set when hostapd 2374209144Sthompsa * calls iv_key_set() before if_init(). 2375209144Sthompsa */ 2376209917Sthompsa if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 2377209144Sthompsa RUN_LOCK(sc); 2378209144Sthompsa sc->cmdq_key_set = RUN_CMDQ_GO; 2379209144Sthompsa RUN_UNLOCK(sc); 2380209144Sthompsa } 2381209144Sthompsa 2382209917Sthompsa return (1); 2383208019Sthompsa} 2384208019Sthompsa 2385208019Sthompsa/* 2386208019Sthompsa * If wlan is destroyed without being brought down i.e. without 2387208019Sthompsa * wlan down or wpa_cli terminate, this function is called after 2388208019Sthompsa * vap is gone. Don't refer it. 2389208019Sthompsa */ 2390208019Sthompsastatic void 2391208019Sthompsarun_key_delete_cb(void *arg) 2392208019Sthompsa{ 2393208019Sthompsa struct run_cmdq *cmdq = arg; 2394208019Sthompsa struct run_softc *sc = cmdq->arg1; 2395208019Sthompsa struct ieee80211_key *k = &cmdq->key; 2396203134Sthompsa uint32_t attr; 2397203134Sthompsa uint8_t wcid; 2398203134Sthompsa 2399208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2400203134Sthompsa 2401203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 2402203134Sthompsa /* remove group key */ 2403208019Sthompsa DPRINTF("removing group key\n"); 2404208019Sthompsa run_read(sc, RT2860_SKEY_MODE_0_7, &attr); 2405203134Sthompsa attr &= ~(0xf << (k->wk_keyix * 4)); 2406208019Sthompsa run_write(sc, RT2860_SKEY_MODE_0_7, attr); 2407203134Sthompsa } else { 2408203134Sthompsa /* remove pairwise key */ 2409208019Sthompsa DPRINTF("removing key for wcid %x\n", k->wk_pad); 2410208019Sthompsa /* matching wcid was written to wk_pad in run_key_set() */ 2411208019Sthompsa wcid = k->wk_pad; 2412208019Sthompsa run_read(sc, RT2860_WCID_ATTR(wcid), &attr); 2413203134Sthompsa attr &= ~0xf; 2414208019Sthompsa run_write(sc, RT2860_WCID_ATTR(wcid), attr); 2415208019Sthompsa run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8); 2416203134Sthompsa } 2417203134Sthompsa 2418208019Sthompsa k->wk_pad = 0; 2419203134Sthompsa} 2420203134Sthompsa 2421208019Sthompsa/* 2422208019Sthompsa * return 0 on error 2423208019Sthompsa */ 2424208019Sthompsastatic int 2425208019Sthompsarun_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k) 2426203134Sthompsa{ 2427208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 2428286950Sadrian struct run_softc *sc = ic->ic_softc; 2429208019Sthompsa struct ieee80211_key *k0; 2430208019Sthompsa uint32_t i; 2431203134Sthompsa 2432208019Sthompsa /* 2433208019Sthompsa * When called back, key might be gone. So, make a copy 2434208019Sthompsa * of some values need to delete keys before deferring. 2435208019Sthompsa * But, because of LOR with node lock, cannot use lock here. 2436208019Sthompsa * So, use atomic instead. 2437208019Sthompsa */ 2438208019Sthompsa i = RUN_CMDQ_GET(&sc->cmdq_store); 2439208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 2440208019Sthompsa sc->cmdq[i].func = run_key_delete_cb; 2441208019Sthompsa sc->cmdq[i].arg0 = NULL; 2442208019Sthompsa sc->cmdq[i].arg1 = sc; 2443208019Sthompsa k0 = &sc->cmdq[i].key; 2444208019Sthompsa k0->wk_flags = k->wk_flags; 2445208019Sthompsa k0->wk_keyix = k->wk_keyix; 2446208019Sthompsa /* matching wcid was written to wk_pad in run_key_set() */ 2447208019Sthompsa k0->wk_pad = k->wk_pad; 2448208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2449208019Sthompsa return (1); /* return fake success */ 2450203134Sthompsa 2451203134Sthompsa} 2452203134Sthompsa 2453203134Sthompsastatic void 2454206358Srpaulorun_ratectl_to(void *arg) 2455203134Sthompsa{ 2456208019Sthompsa struct run_softc *sc = arg; 2457203134Sthompsa 2458203134Sthompsa /* do it in a process context, so it can go sleep */ 2459287197Sglebius ieee80211_runtask(&sc->sc_ic, &sc->ratectl_task); 2460203134Sthompsa /* next timeout will be rescheduled in the callback task */ 2461203134Sthompsa} 2462203134Sthompsa 2463203134Sthompsa/* ARGSUSED */ 2464203134Sthompsastatic void 2465206358Srpaulorun_ratectl_cb(void *arg, int pending) 2466203134Sthompsa{ 2467208019Sthompsa struct run_softc *sc = arg; 2468287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2469208019Sthompsa struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2470203134Sthompsa 2471209917Sthompsa if (vap == NULL) 2472208019Sthompsa return; 2473208019Sthompsa 2474262795Shselasky if (sc->rvp_cnt > 1 || vap->iv_opmode != IEEE80211_M_STA) { 2475203134Sthompsa /* 2476203134Sthompsa * run_reset_livelock() doesn't do anything with AMRR, 2477203134Sthompsa * but Ralink wants us to call it every 1 sec. So, we 2478203134Sthompsa * piggyback here rather than creating another callout. 2479203134Sthompsa * Livelock may occur only in HOSTAP or IBSS mode 2480203134Sthompsa * (when h/w is sending beacons). 2481203134Sthompsa */ 2482203134Sthompsa RUN_LOCK(sc); 2483203134Sthompsa run_reset_livelock(sc); 2484208019Sthompsa /* just in case, there are some stats to drain */ 2485208019Sthompsa run_drain_fifo(sc); 2486203134Sthompsa RUN_UNLOCK(sc); 2487203134Sthompsa } 2488203134Sthompsa 2489262795Shselasky ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc); 2490262795Shselasky 2491257712Shselasky RUN_LOCK(sc); 2492208019Sthompsa if(sc->ratectl_run != RUN_RATECTL_OFF) 2493208019Sthompsa usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2494257712Shselasky RUN_UNLOCK(sc); 2495203134Sthompsa} 2496203134Sthompsa 2497203134Sthompsastatic void 2498208019Sthompsarun_drain_fifo(void *arg) 2499203134Sthompsa{ 2500208019Sthompsa struct run_softc *sc = arg; 2501208019Sthompsa uint32_t stat; 2502218676Shselasky uint16_t (*wstat)[3]; 2503203134Sthompsa uint8_t wcid, mcs, pid; 2504218676Shselasky int8_t retry; 2505203134Sthompsa 2506208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2507203134Sthompsa 2508208019Sthompsa for (;;) { 2509203134Sthompsa /* drain Tx status FIFO (maxsize = 16) */ 2510203134Sthompsa run_read(sc, RT2860_TX_STAT_FIFO, &stat); 2511208019Sthompsa DPRINTFN(4, "tx stat 0x%08x\n", stat); 2512209917Sthompsa if (!(stat & RT2860_TXQ_VLD)) 2513208019Sthompsa break; 2514203134Sthompsa 2515208019Sthompsa wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff; 2516203134Sthompsa 2517208019Sthompsa /* if no ACK was requested, no feedback is available */ 2518208019Sthompsa if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX || 2519208019Sthompsa wcid == 0) 2520208019Sthompsa continue; 2521203134Sthompsa 2522218676Shselasky /* 2523218676Shselasky * Even though each stat is Tx-complete-status like format, 2524218676Shselasky * the device can poll stats. Because there is no guarantee 2525218676Shselasky * that the referring node is still around when read the stats. 2526218676Shselasky * So that, if we use ieee80211_ratectl_tx_update(), we will 2527218676Shselasky * have hard time not to refer already freed node. 2528218676Shselasky * 2529218676Shselasky * To eliminate such page faults, we poll stats in softc. 2530218676Shselasky * Then, update the rates later with ieee80211_ratectl_tx_update(). 2531218676Shselasky */ 2532218676Shselasky wstat = &(sc->wcid_stats[wcid]); 2533218676Shselasky (*wstat)[RUN_TXCNT]++; 2534218676Shselasky if (stat & RT2860_TXQ_OK) 2535218676Shselasky (*wstat)[RUN_SUCCESS]++; 2536218676Shselasky else 2537287197Sglebius counter_u64_add(sc->sc_ic.ic_oerrors, 1); 2538218676Shselasky /* 2539218676Shselasky * Check if there were retries, ie if the Tx success rate is 2540218676Shselasky * different from the requested rate. Note that it works only 2541218676Shselasky * because we do not allow rate fallback from OFDM to CCK. 2542218676Shselasky */ 2543218676Shselasky mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f; 2544218676Shselasky pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf; 2545218676Shselasky if ((retry = pid -1 - mcs) > 0) { 2546218676Shselasky (*wstat)[RUN_TXCNT] += retry; 2547218676Shselasky (*wstat)[RUN_RETRY] += retry; 2548203134Sthompsa } 2549208019Sthompsa } 2550208019Sthompsa DPRINTFN(3, "count=%d\n", sc->fifo_cnt); 2551208019Sthompsa 2552208019Sthompsa sc->fifo_cnt = 0; 2553208019Sthompsa} 2554208019Sthompsa 2555208019Sthompsastatic void 2556208019Sthompsarun_iter_func(void *arg, struct ieee80211_node *ni) 2557208019Sthompsa{ 2558208019Sthompsa struct run_softc *sc = arg; 2559208019Sthompsa struct ieee80211vap *vap = ni->ni_vap; 2560287552Skevlo struct run_node *rn = RUN_NODE(ni); 2561218676Shselasky union run_stats sta[2]; 2562218676Shselasky uint16_t (*wstat)[3]; 2563218676Shselasky int txcnt, success, retrycnt, error; 2564208019Sthompsa 2565218676Shselasky RUN_LOCK(sc); 2566218676Shselasky 2567262795Shselasky /* Check for special case */ 2568262795Shselasky if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA && 2569262795Shselasky ni != vap->iv_bss) 2570262795Shselasky goto fail; 2571262795Shselasky 2572209917Sthompsa if (sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS || 2573209917Sthompsa vap->iv_opmode == IEEE80211_M_STA)) { 2574203134Sthompsa /* read statistic counters (clear on read) and update AMRR state */ 2575203134Sthompsa error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta, 2576203134Sthompsa sizeof sta); 2577203134Sthompsa if (error != 0) 2578218676Shselasky goto fail; 2579203134Sthompsa 2580203134Sthompsa /* count failed TX as errors */ 2581287197Sglebius if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS, 2582287197Sglebius le16toh(sta[0].error.fail)); 2583203134Sthompsa 2584218676Shselasky retrycnt = le16toh(sta[1].tx.retry); 2585218676Shselasky success = le16toh(sta[1].tx.success); 2586218676Shselasky txcnt = retrycnt + success + le16toh(sta[0].error.fail); 2587203134Sthompsa 2588218676Shselasky DPRINTFN(3, "retrycnt=%d success=%d failcnt=%d\n", 2589218676Shselasky retrycnt, success, le16toh(sta[0].error.fail)); 2590218676Shselasky } else { 2591218676Shselasky wstat = &(sc->wcid_stats[RUN_AID2WCID(ni->ni_associd)]); 2592203134Sthompsa 2593218676Shselasky if (wstat == &(sc->wcid_stats[0]) || 2594218676Shselasky wstat > &(sc->wcid_stats[RT2870_WCID_MAX])) 2595218676Shselasky goto fail; 2596208019Sthompsa 2597218676Shselasky txcnt = (*wstat)[RUN_TXCNT]; 2598218676Shselasky success = (*wstat)[RUN_SUCCESS]; 2599218676Shselasky retrycnt = (*wstat)[RUN_RETRY]; 2600218676Shselasky DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n", 2601218676Shselasky retrycnt, txcnt, success); 2602208019Sthompsa 2603218676Shselasky memset(wstat, 0, sizeof(*wstat)); 2604203134Sthompsa } 2605203134Sthompsa 2606218676Shselasky ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt); 2607208019Sthompsa rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0); 2608218676Shselasky 2609218676Shselaskyfail: 2610218676Shselasky RUN_UNLOCK(sc); 2611218676Shselasky 2612208019Sthompsa DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx); 2613208019Sthompsa} 2614203134Sthompsa 2615208019Sthompsastatic void 2616208019Sthompsarun_newassoc_cb(void *arg) 2617208019Sthompsa{ 2618208019Sthompsa struct run_cmdq *cmdq = arg; 2619208019Sthompsa struct ieee80211_node *ni = cmdq->arg1; 2620286950Sadrian struct run_softc *sc = ni->ni_vap->iv_ic->ic_softc; 2621208019Sthompsa uint8_t wcid = cmdq->wcid; 2622203134Sthompsa 2623208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2624208019Sthompsa 2625208019Sthompsa run_write_region_1(sc, RT2860_WCID_ENTRY(wcid), 2626208019Sthompsa ni->ni_macaddr, IEEE80211_ADDR_LEN); 2627218676Shselasky 2628218676Shselasky memset(&(sc->wcid_stats[wcid]), 0, sizeof(sc->wcid_stats[wcid])); 2629203134Sthompsa} 2630203134Sthompsa 2631203134Sthompsastatic void 2632203134Sthompsarun_newassoc(struct ieee80211_node *ni, int isnew) 2633203134Sthompsa{ 2634287552Skevlo struct run_node *rn = RUN_NODE(ni); 2635203134Sthompsa struct ieee80211_rateset *rs = &ni->ni_rates; 2636208019Sthompsa struct ieee80211vap *vap = ni->ni_vap; 2637208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 2638286950Sadrian struct run_softc *sc = ic->ic_softc; 2639203134Sthompsa uint8_t rate; 2640208019Sthompsa uint8_t ridx; 2641245047Shselasky uint8_t wcid; 2642208019Sthompsa int i, j; 2643203134Sthompsa 2644245047Shselasky wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 2645245047Shselasky 1 : RUN_AID2WCID(ni->ni_associd); 2646245047Shselasky 2647209917Sthompsa if (wcid > RT2870_WCID_MAX) { 2648208019Sthompsa device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid); 2649208019Sthompsa return; 2650208019Sthompsa } 2651203134Sthompsa 2652208019Sthompsa /* only interested in true associations */ 2653209917Sthompsa if (isnew && ni->ni_associd != 0) { 2654208019Sthompsa 2655208019Sthompsa /* 2656208019Sthompsa * This function could is called though timeout function. 2657208019Sthompsa * Need to defer. 2658208019Sthompsa */ 2659208019Sthompsa uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store); 2660208019Sthompsa DPRINTF("cmdq_store=%d\n", cnt); 2661208019Sthompsa sc->cmdq[cnt].func = run_newassoc_cb; 2662208019Sthompsa sc->cmdq[cnt].arg0 = NULL; 2663208019Sthompsa sc->cmdq[cnt].arg1 = ni; 2664208019Sthompsa sc->cmdq[cnt].wcid = wcid; 2665208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2666208019Sthompsa } 2667208019Sthompsa 2668208019Sthompsa DPRINTF("new assoc isnew=%d associd=%x addr=%s\n", 2669208019Sthompsa isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr)); 2670208019Sthompsa 2671203134Sthompsa for (i = 0; i < rs->rs_nrates; i++) { 2672203134Sthompsa rate = rs->rs_rates[i] & IEEE80211_RATE_VAL; 2673203134Sthompsa /* convert 802.11 rate to hardware rate index */ 2674203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2675203134Sthompsa if (rt2860_rates[ridx].rate == rate) 2676203134Sthompsa break; 2677203134Sthompsa rn->ridx[i] = ridx; 2678203134Sthompsa /* determine rate of control response frames */ 2679203134Sthompsa for (j = i; j >= 0; j--) { 2680203134Sthompsa if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) && 2681203134Sthompsa rt2860_rates[rn->ridx[i]].phy == 2682203134Sthompsa rt2860_rates[rn->ridx[j]].phy) 2683203134Sthompsa break; 2684203134Sthompsa } 2685203134Sthompsa if (j >= 0) { 2686203134Sthompsa rn->ctl_ridx[i] = rn->ridx[j]; 2687203134Sthompsa } else { 2688203134Sthompsa /* no basic rate found, use mandatory one */ 2689203134Sthompsa rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx; 2690203134Sthompsa } 2691203134Sthompsa DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n", 2692203134Sthompsa rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]); 2693203134Sthompsa } 2694208019Sthompsa rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate; 2695208019Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2696208019Sthompsa if (rt2860_rates[ridx].rate == rate) 2697208019Sthompsa break; 2698208019Sthompsa rn->mgt_ridx = ridx; 2699208019Sthompsa DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx); 2700208019Sthompsa 2701262795Shselasky RUN_LOCK(sc); 2702262795Shselasky if(sc->ratectl_run != RUN_RATECTL_OFF) 2703262795Shselasky usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2704262795Shselasky RUN_UNLOCK(sc); 2705203134Sthompsa} 2706203134Sthompsa 2707203134Sthompsa/* 2708203134Sthompsa * Return the Rx chain with the highest RSSI for a given frame. 2709203134Sthompsa */ 2710203134Sthompsastatic __inline uint8_t 2711203134Sthompsarun_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi) 2712203134Sthompsa{ 2713203134Sthompsa uint8_t rxchain = 0; 2714203134Sthompsa 2715203134Sthompsa if (sc->nrxchains > 1) { 2716203134Sthompsa if (rxwi->rssi[1] > rxwi->rssi[rxchain]) 2717203134Sthompsa rxchain = 1; 2718203134Sthompsa if (sc->nrxchains > 2) 2719203134Sthompsa if (rxwi->rssi[2] > rxwi->rssi[rxchain]) 2720203134Sthompsa rxchain = 2; 2721203134Sthompsa } 2722209917Sthompsa return (rxchain); 2723203134Sthompsa} 2724203134Sthompsa 2725203134Sthompsastatic void 2726288603Sadrianrun_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, 2727288603Sadrian const struct ieee80211_rx_stats *rxs, int rssi, int nf) 2728288603Sadrian{ 2729288603Sadrian struct ieee80211vap *vap = ni->ni_vap; 2730288603Sadrian struct run_softc *sc = vap->iv_ic->ic_softc; 2731288603Sadrian struct run_vap *rvp = RUN_VAP(vap); 2732288603Sadrian uint64_t ni_tstamp, rx_tstamp; 2733288603Sadrian 2734288603Sadrian rvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf); 2735288603Sadrian 2736288603Sadrian if (vap->iv_state == IEEE80211_S_RUN && 2737288603Sadrian (subtype == IEEE80211_FC0_SUBTYPE_BEACON || 2738288603Sadrian subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) { 2739288603Sadrian ni_tstamp = le64toh(ni->ni_tstamp.tsf); 2740288603Sadrian RUN_LOCK(sc); 2741288603Sadrian run_get_tsf(sc, &rx_tstamp); 2742288603Sadrian RUN_UNLOCK(sc); 2743288603Sadrian rx_tstamp = le64toh(rx_tstamp); 2744288603Sadrian 2745288603Sadrian if (ni_tstamp >= rx_tstamp) { 2746288603Sadrian DPRINTF("ibss merge, tsf %ju tstamp %ju\n", 2747288603Sadrian (uintmax_t)rx_tstamp, (uintmax_t)ni_tstamp); 2748288603Sadrian (void) ieee80211_ibss_merge(ni); 2749288603Sadrian } 2750288603Sadrian } 2751288603Sadrian} 2752288603Sadrian 2753288603Sadrianstatic void 2754203134Sthompsarun_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) 2755203134Sthompsa{ 2756287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2757203134Sthompsa struct ieee80211_frame *wh; 2758203134Sthompsa struct ieee80211_node *ni; 2759203134Sthompsa struct rt2870_rxd *rxd; 2760203134Sthompsa struct rt2860_rxwi *rxwi; 2761203134Sthompsa uint32_t flags; 2762259032Skevlo uint16_t len, rxwisize; 2763203134Sthompsa uint8_t ant, rssi; 2764203134Sthompsa int8_t nf; 2765203134Sthompsa 2766203134Sthompsa rxwi = mtod(m, struct rt2860_rxwi *); 2767203134Sthompsa len = le16toh(rxwi->len) & 0xfff; 2768260219Skevlo rxwisize = sizeof(struct rt2860_rxwi); 2769260219Skevlo if (sc->mac_ver == 0x5592) 2770260219Skevlo rxwisize += sizeof(uint64_t); 2771260219Skevlo else if (sc->mac_ver == 0x3593) 2772260219Skevlo rxwisize += sizeof(uint32_t); 2773203134Sthompsa if (__predict_false(len > dmalen)) { 2774203134Sthompsa m_freem(m); 2775287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 2776203134Sthompsa DPRINTF("bad RXWI length %u > %u\n", len, dmalen); 2777203134Sthompsa return; 2778203134Sthompsa } 2779203134Sthompsa /* Rx descriptor is located at the end */ 2780203134Sthompsa rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen); 2781203134Sthompsa flags = le32toh(rxd->flags); 2782203134Sthompsa 2783203134Sthompsa if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) { 2784203134Sthompsa m_freem(m); 2785287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 2786203134Sthompsa DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV"); 2787203134Sthompsa return; 2788203134Sthompsa } 2789203134Sthompsa 2790259032Skevlo m->m_data += rxwisize; 2791259032Skevlo m->m_pkthdr.len = m->m_len -= rxwisize; 2792203134Sthompsa 2793203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 2794203134Sthompsa 2795260444Skevlo if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 2796260444Skevlo wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; 2797203134Sthompsa m->m_flags |= M_WEP; 2798203134Sthompsa } 2799203134Sthompsa 2800209917Sthompsa if (flags & RT2860_RX_L2PAD) { 2801203134Sthompsa DPRINTFN(8, "received RT2860_RX_L2PAD frame\n"); 2802203134Sthompsa len += 2; 2803203134Sthompsa } 2804203134Sthompsa 2805208019Sthompsa ni = ieee80211_find_rxnode(ic, 2806208019Sthompsa mtod(m, struct ieee80211_frame_min *)); 2807208019Sthompsa 2808203134Sthompsa if (__predict_false(flags & RT2860_RX_MICERR)) { 2809203134Sthompsa /* report MIC failures to net80211 for TKIP */ 2810209917Sthompsa if (ni != NULL) 2811259032Skevlo ieee80211_notify_michael_failure(ni->ni_vap, wh, 2812259032Skevlo rxwi->keyidx); 2813203134Sthompsa m_freem(m); 2814287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 2815203134Sthompsa DPRINTF("MIC error. Someone is lying.\n"); 2816203134Sthompsa return; 2817203134Sthompsa } 2818203134Sthompsa 2819203134Sthompsa ant = run_maxrssi_chain(sc, rxwi); 2820203134Sthompsa rssi = rxwi->rssi[ant]; 2821203134Sthompsa nf = run_rssi2dbm(sc, rssi, ant); 2822203134Sthompsa 2823203134Sthompsa m->m_pkthdr.len = m->m_len = len; 2824203134Sthompsa 2825209917Sthompsa if (__predict_false(ieee80211_radiotap_active(ic))) { 2826203134Sthompsa struct run_rx_radiotap_header *tap = &sc->sc_rxtap; 2827258643Shselasky uint16_t phy; 2828203134Sthompsa 2829203134Sthompsa tap->wr_flags = 0; 2830236439Shselasky tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); 2831236439Shselasky tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); 2832203134Sthompsa tap->wr_antsignal = rssi; 2833203134Sthompsa tap->wr_antenna = ant; 2834203134Sthompsa tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant); 2835203134Sthompsa tap->wr_rate = 2; /* in case it can't be found below */ 2836287554Skevlo run_get_tsf(sc, &tap->wr_tsf); 2837203134Sthompsa phy = le16toh(rxwi->phy); 2838203134Sthompsa switch (phy & RT2860_PHY_MODE) { 2839203134Sthompsa case RT2860_PHY_CCK: 2840203134Sthompsa switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) { 2841203134Sthompsa case 0: tap->wr_rate = 2; break; 2842203134Sthompsa case 1: tap->wr_rate = 4; break; 2843203134Sthompsa case 2: tap->wr_rate = 11; break; 2844203134Sthompsa case 3: tap->wr_rate = 22; break; 2845203134Sthompsa } 2846203134Sthompsa if (phy & RT2860_PHY_SHPRE) 2847203134Sthompsa tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 2848203134Sthompsa break; 2849203134Sthompsa case RT2860_PHY_OFDM: 2850203134Sthompsa switch (phy & RT2860_PHY_MCS) { 2851203134Sthompsa case 0: tap->wr_rate = 12; break; 2852203134Sthompsa case 1: tap->wr_rate = 18; break; 2853203134Sthompsa case 2: tap->wr_rate = 24; break; 2854203134Sthompsa case 3: tap->wr_rate = 36; break; 2855203134Sthompsa case 4: tap->wr_rate = 48; break; 2856203134Sthompsa case 5: tap->wr_rate = 72; break; 2857203134Sthompsa case 6: tap->wr_rate = 96; break; 2858203134Sthompsa case 7: tap->wr_rate = 108; break; 2859203134Sthompsa } 2860203134Sthompsa break; 2861203134Sthompsa } 2862203134Sthompsa } 2863289753Savos 2864289753Savos if (ni != NULL) { 2865289753Savos (void)ieee80211_input(ni, m, rssi, nf); 2866289753Savos ieee80211_free_node(ni); 2867289753Savos } else { 2868289753Savos (void)ieee80211_input_all(ic, m, rssi, nf); 2869289753Savos } 2870203134Sthompsa} 2871203134Sthompsa 2872203134Sthompsastatic void 2873203134Sthompsarun_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) 2874203134Sthompsa{ 2875203134Sthompsa struct run_softc *sc = usbd_xfer_softc(xfer); 2876287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2877203134Sthompsa struct mbuf *m = NULL; 2878203134Sthompsa struct mbuf *m0; 2879203134Sthompsa uint32_t dmalen; 2880259032Skevlo uint16_t rxwisize; 2881203134Sthompsa int xferlen; 2882203134Sthompsa 2883260219Skevlo rxwisize = sizeof(struct rt2860_rxwi); 2884260219Skevlo if (sc->mac_ver == 0x5592) 2885260219Skevlo rxwisize += sizeof(uint64_t); 2886260219Skevlo else if (sc->mac_ver == 0x3593) 2887260219Skevlo rxwisize += sizeof(uint32_t); 2888259032Skevlo 2889203134Sthompsa usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL); 2890203134Sthompsa 2891203134Sthompsa switch (USB_GET_STATE(xfer)) { 2892203134Sthompsa case USB_ST_TRANSFERRED: 2893203134Sthompsa 2894203134Sthompsa DPRINTFN(15, "rx done, actlen=%d\n", xferlen); 2895203134Sthompsa 2896259032Skevlo if (xferlen < (int)(sizeof(uint32_t) + rxwisize + 2897259032Skevlo sizeof(struct rt2870_rxd))) { 2898203134Sthompsa DPRINTF("xfer too short %d\n", xferlen); 2899203134Sthompsa goto tr_setup; 2900203134Sthompsa } 2901203134Sthompsa 2902203134Sthompsa m = sc->rx_m; 2903203134Sthompsa sc->rx_m = NULL; 2904203134Sthompsa 2905203134Sthompsa /* FALLTHROUGH */ 2906203134Sthompsa case USB_ST_SETUP: 2907203134Sthompsatr_setup: 2908203134Sthompsa if (sc->rx_m == NULL) { 2909243857Sglebius sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, 2910203134Sthompsa MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */); 2911203134Sthompsa } 2912203134Sthompsa if (sc->rx_m == NULL) { 2913203134Sthompsa DPRINTF("could not allocate mbuf - idle with stall\n"); 2914287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 2915203134Sthompsa usbd_xfer_set_stall(xfer); 2916203134Sthompsa usbd_xfer_set_frames(xfer, 0); 2917203134Sthompsa } else { 2918203134Sthompsa /* 2919203134Sthompsa * Directly loading a mbuf cluster into DMA to 2920203134Sthompsa * save some data copying. This works because 2921203134Sthompsa * there is only one cluster. 2922203134Sthompsa */ 2923203134Sthompsa usbd_xfer_set_frame_data(xfer, 0, 2924203134Sthompsa mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ); 2925203134Sthompsa usbd_xfer_set_frames(xfer, 1); 2926203134Sthompsa } 2927203134Sthompsa usbd_transfer_submit(xfer); 2928203134Sthompsa break; 2929203134Sthompsa 2930203134Sthompsa default: /* Error */ 2931203134Sthompsa if (error != USB_ERR_CANCELLED) { 2932203134Sthompsa /* try to clear stall first */ 2933203134Sthompsa usbd_xfer_set_stall(xfer); 2934203134Sthompsa if (error == USB_ERR_TIMEOUT) 2935203134Sthompsa device_printf(sc->sc_dev, "device timeout\n"); 2936287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 2937203134Sthompsa goto tr_setup; 2938203134Sthompsa } 2939209917Sthompsa if (sc->rx_m != NULL) { 2940203134Sthompsa m_freem(sc->rx_m); 2941203134Sthompsa sc->rx_m = NULL; 2942203134Sthompsa } 2943203134Sthompsa break; 2944203134Sthompsa } 2945203134Sthompsa 2946203134Sthompsa if (m == NULL) 2947203134Sthompsa return; 2948203134Sthompsa 2949203134Sthompsa /* inputting all the frames must be last */ 2950203134Sthompsa 2951203134Sthompsa RUN_UNLOCK(sc); 2952203134Sthompsa 2953203134Sthompsa m->m_pkthdr.len = m->m_len = xferlen; 2954203134Sthompsa 2955203134Sthompsa /* HW can aggregate multiple 802.11 frames in a single USB xfer */ 2956203134Sthompsa for(;;) { 2957203134Sthompsa dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff; 2958203134Sthompsa 2959233774Shselasky if ((dmalen >= (uint32_t)-8) || (dmalen == 0) || 2960233774Shselasky ((dmalen & 3) != 0)) { 2961203134Sthompsa DPRINTF("bad DMA length %u\n", dmalen); 2962203134Sthompsa break; 2963203134Sthompsa } 2964233774Shselasky if ((dmalen + 8) > (uint32_t)xferlen) { 2965203134Sthompsa DPRINTF("bad DMA length %u > %d\n", 2966203134Sthompsa dmalen + 8, xferlen); 2967203134Sthompsa break; 2968203134Sthompsa } 2969203134Sthompsa 2970203134Sthompsa /* If it is the last one or a single frame, we won't copy. */ 2971209917Sthompsa if ((xferlen -= dmalen + 8) <= 8) { 2972203134Sthompsa /* trim 32-bit DMA-len header */ 2973203134Sthompsa m->m_data += 4; 2974203134Sthompsa m->m_pkthdr.len = m->m_len -= 4; 2975203134Sthompsa run_rx_frame(sc, m, dmalen); 2976257435Shselasky m = NULL; /* don't free source buffer */ 2977203134Sthompsa break; 2978203134Sthompsa } 2979203134Sthompsa 2980203134Sthompsa /* copy aggregated frames to another mbuf */ 2981243857Sglebius m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 2982203134Sthompsa if (__predict_false(m0 == NULL)) { 2983203134Sthompsa DPRINTF("could not allocate mbuf\n"); 2984287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 2985203134Sthompsa break; 2986203134Sthompsa } 2987203134Sthompsa m_copydata(m, 4 /* skip 32-bit DMA-len header */, 2988203134Sthompsa dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t)); 2989203134Sthompsa m0->m_pkthdr.len = m0->m_len = 2990203134Sthompsa dmalen + sizeof(struct rt2870_rxd); 2991203134Sthompsa run_rx_frame(sc, m0, dmalen); 2992203134Sthompsa 2993203134Sthompsa /* update data ptr */ 2994203134Sthompsa m->m_data += dmalen + 8; 2995203134Sthompsa m->m_pkthdr.len = m->m_len -= dmalen + 8; 2996203134Sthompsa } 2997203134Sthompsa 2998257435Shselasky /* make sure we free the source buffer, if any */ 2999257435Shselasky m_freem(m); 3000257435Shselasky 3001203134Sthompsa RUN_LOCK(sc); 3002203134Sthompsa} 3003203134Sthompsa 3004203134Sthompsastatic void 3005203134Sthompsarun_tx_free(struct run_endpoint_queue *pq, 3006203134Sthompsa struct run_tx_data *data, int txerr) 3007203134Sthompsa{ 3008203134Sthompsa 3009289841Savos ieee80211_tx_complete(data->ni, data->m, txerr); 3010203134Sthompsa 3011289841Savos data->m = NULL; 3012289841Savos data->ni = NULL; 3013289841Savos 3014203134Sthompsa STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); 3015203134Sthompsa pq->tx_nfree++; 3016203134Sthompsa} 3017203134Sthompsa 3018203134Sthompsastatic void 3019257429Shselaskyrun_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index) 3020203134Sthompsa{ 3021203134Sthompsa struct run_softc *sc = usbd_xfer_softc(xfer); 3022287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3023203134Sthompsa struct run_tx_data *data; 3024203134Sthompsa struct ieee80211vap *vap = NULL; 3025203134Sthompsa struct usb_page_cache *pc; 3026203134Sthompsa struct run_endpoint_queue *pq = &sc->sc_epq[index]; 3027203134Sthompsa struct mbuf *m; 3028203134Sthompsa usb_frlength_t size; 3029203134Sthompsa int actlen; 3030203134Sthompsa int sumlen; 3031203134Sthompsa 3032203134Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 3033203134Sthompsa 3034209917Sthompsa switch (USB_GET_STATE(xfer)) { 3035203134Sthompsa case USB_ST_TRANSFERRED: 3036203134Sthompsa DPRINTFN(11, "transfer complete: %d " 3037203134Sthompsa "bytes @ index %d\n", actlen, index); 3038203134Sthompsa 3039203134Sthompsa data = usbd_xfer_get_priv(xfer); 3040203134Sthompsa run_tx_free(pq, data, 0); 3041203134Sthompsa usbd_xfer_set_priv(xfer, NULL); 3042203134Sthompsa 3043203134Sthompsa /* FALLTHROUGH */ 3044203134Sthompsa case USB_ST_SETUP: 3045203134Sthompsatr_setup: 3046203134Sthompsa data = STAILQ_FIRST(&pq->tx_qh); 3047209917Sthompsa if (data == NULL) 3048203134Sthompsa break; 3049203134Sthompsa 3050203134Sthompsa STAILQ_REMOVE_HEAD(&pq->tx_qh, next); 3051203134Sthompsa 3052203134Sthompsa m = data->m; 3053261330Shselasky size = (sc->mac_ver == 0x5592) ? 3054261330Shselasky sizeof(data->desc) + sizeof(uint32_t) : sizeof(data->desc); 3055261076Shselasky if ((m->m_pkthdr.len + 3056261330Shselasky size + 3 + 8) > RUN_MAX_TXSZ) { 3057203134Sthompsa DPRINTF("data overflow, %u bytes\n", 3058203134Sthompsa m->m_pkthdr.len); 3059203134Sthompsa run_tx_free(pq, data, 1); 3060203134Sthompsa goto tr_setup; 3061203134Sthompsa } 3062203134Sthompsa 3063203134Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 3064203134Sthompsa usbd_copy_in(pc, 0, &data->desc, size); 3065203134Sthompsa usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len); 3066228508Shselasky size += m->m_pkthdr.len; 3067228508Shselasky /* 3068228508Shselasky * Align end on a 4-byte boundary, pad 8 bytes (CRC + 3069228508Shselasky * 4-byte padding), and be sure to zero those trailing 3070228508Shselasky * bytes: 3071228508Shselasky */ 3072228508Shselasky usbd_frame_zero(pc, size, ((-size) & 3) + 8); 3073228508Shselasky size += ((-size) & 3) + 8; 3074203134Sthompsa 3075203134Sthompsa vap = data->ni->ni_vap; 3076203134Sthompsa if (ieee80211_radiotap_active_vap(vap)) { 3077203134Sthompsa struct run_tx_radiotap_header *tap = &sc->sc_txtap; 3078259032Skevlo struct rt2860_txwi *txwi = 3079208019Sthompsa (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd)); 3080203134Sthompsa tap->wt_flags = 0; 3081203134Sthompsa tap->wt_rate = rt2860_rates[data->ridx].rate; 3082287554Skevlo run_get_tsf(sc, &tap->wt_tsf); 3083236439Shselasky tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 3084236439Shselasky tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 3085203134Sthompsa tap->wt_hwqueue = index; 3086208019Sthompsa if (le16toh(txwi->phy) & RT2860_PHY_SHPRE) 3087203134Sthompsa tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 3088203134Sthompsa 3089203134Sthompsa ieee80211_radiotap_tx(vap, m); 3090203134Sthompsa } 3091203134Sthompsa 3092228508Shselasky DPRINTFN(11, "sending frame len=%u/%u @ index %d\n", 3093228508Shselasky m->m_pkthdr.len, size, index); 3094203134Sthompsa 3095228508Shselasky usbd_xfer_set_frame_len(xfer, 0, size); 3096203134Sthompsa usbd_xfer_set_priv(xfer, data); 3097203134Sthompsa usbd_transfer_submit(xfer); 3098287197Sglebius run_start(sc); 3099203134Sthompsa 3100203134Sthompsa break; 3101203134Sthompsa 3102203134Sthompsa default: 3103203134Sthompsa DPRINTF("USB transfer error, %s\n", 3104203134Sthompsa usbd_errstr(error)); 3105203134Sthompsa 3106203134Sthompsa data = usbd_xfer_get_priv(xfer); 3107203134Sthompsa 3108203134Sthompsa if (data != NULL) { 3109208019Sthompsa if(data->ni != NULL) 3110208019Sthompsa vap = data->ni->ni_vap; 3111203134Sthompsa run_tx_free(pq, data, error); 3112203134Sthompsa usbd_xfer_set_priv(xfer, NULL); 3113203134Sthompsa } 3114287197Sglebius 3115209917Sthompsa if (vap == NULL) 3116208019Sthompsa vap = TAILQ_FIRST(&ic->ic_vaps); 3117203134Sthompsa 3118203134Sthompsa if (error != USB_ERR_CANCELLED) { 3119203134Sthompsa if (error == USB_ERR_TIMEOUT) { 3120203134Sthompsa device_printf(sc->sc_dev, "device timeout\n"); 3121208019Sthompsa uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 3122208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 3123208019Sthompsa sc->cmdq[i].func = run_usb_timeout_cb; 3124208019Sthompsa sc->cmdq[i].arg0 = vap; 3125208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 3126203134Sthompsa } 3127203134Sthompsa 3128203134Sthompsa /* 3129203134Sthompsa * Try to clear stall first, also if other 3130203134Sthompsa * errors occur, hence clearing stall 3131203134Sthompsa * introduces a 50 ms delay: 3132203134Sthompsa */ 3133203134Sthompsa usbd_xfer_set_stall(xfer); 3134203134Sthompsa goto tr_setup; 3135203134Sthompsa } 3136203134Sthompsa break; 3137203134Sthompsa } 3138203134Sthompsa} 3139203134Sthompsa 3140203134Sthompsastatic void 3141203134Sthompsarun_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error) 3142203134Sthompsa{ 3143203134Sthompsa run_bulk_tx_callbackN(xfer, error, 0); 3144203134Sthompsa} 3145203134Sthompsa 3146203134Sthompsastatic void 3147203134Sthompsarun_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error) 3148203134Sthompsa{ 3149203134Sthompsa run_bulk_tx_callbackN(xfer, error, 1); 3150203134Sthompsa} 3151203134Sthompsa 3152203134Sthompsastatic void 3153203134Sthompsarun_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error) 3154203134Sthompsa{ 3155203134Sthompsa run_bulk_tx_callbackN(xfer, error, 2); 3156203134Sthompsa} 3157203134Sthompsa 3158203134Sthompsastatic void 3159203134Sthompsarun_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error) 3160203134Sthompsa{ 3161203134Sthompsa run_bulk_tx_callbackN(xfer, error, 3); 3162203134Sthompsa} 3163203134Sthompsa 3164203134Sthompsastatic void 3165203134Sthompsarun_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error) 3166203134Sthompsa{ 3167203134Sthompsa run_bulk_tx_callbackN(xfer, error, 4); 3168203134Sthompsa} 3169203134Sthompsa 3170203134Sthompsastatic void 3171203134Sthompsarun_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error) 3172203134Sthompsa{ 3173203134Sthompsa run_bulk_tx_callbackN(xfer, error, 5); 3174203134Sthompsa} 3175203134Sthompsa 3176203134Sthompsastatic void 3177208019Sthompsarun_set_tx_desc(struct run_softc *sc, struct run_tx_data *data) 3178203134Sthompsa{ 3179203134Sthompsa struct mbuf *m = data->m; 3180287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3181208019Sthompsa struct ieee80211vap *vap = data->ni->ni_vap; 3182203134Sthompsa struct ieee80211_frame *wh; 3183203134Sthompsa struct rt2870_txd *txd; 3184203134Sthompsa struct rt2860_txwi *txwi; 3185259032Skevlo uint16_t xferlen, txwisize; 3186208019Sthompsa uint16_t mcs; 3187203134Sthompsa uint8_t ridx = data->ridx; 3188208019Sthompsa uint8_t pad; 3189203134Sthompsa 3190203134Sthompsa /* get MCS code from rate index */ 3191208019Sthompsa mcs = rt2860_rates[ridx].mcs; 3192203134Sthompsa 3193259032Skevlo txwisize = (sc->mac_ver == 0x5592) ? 3194259032Skevlo sizeof(*txwi) + sizeof(uint32_t) : sizeof(*txwi); 3195259032Skevlo xferlen = txwisize + m->m_pkthdr.len; 3196203134Sthompsa 3197203134Sthompsa /* roundup to 32-bit alignment */ 3198203134Sthompsa xferlen = (xferlen + 3) & ~3; 3199203134Sthompsa 3200203134Sthompsa txd = (struct rt2870_txd *)&data->desc; 3201203134Sthompsa txd->len = htole16(xferlen); 3202203134Sthompsa 3203208019Sthompsa wh = mtod(m, struct ieee80211_frame *); 3204208019Sthompsa 3205208019Sthompsa /* 3206208019Sthompsa * Ether both are true or both are false, the header 3207208019Sthompsa * are nicely aligned to 32-bit. So, no L2 padding. 3208208019Sthompsa */ 3209208019Sthompsa if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh)) 3210208019Sthompsa pad = 0; 3211208019Sthompsa else 3212208019Sthompsa pad = 2; 3213208019Sthompsa 3214203134Sthompsa /* setup TX Wireless Information */ 3215203134Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3216203134Sthompsa txwi->len = htole16(m->m_pkthdr.len - pad); 3217203134Sthompsa if (rt2860_rates[ridx].phy == IEEE80211_T_DS) { 3218270192Skevlo mcs |= RT2860_PHY_CCK; 3219203134Sthompsa if (ridx != RT2860_RIDX_CCK1 && 3220203134Sthompsa (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 3221203134Sthompsa mcs |= RT2860_PHY_SHPRE; 3222203134Sthompsa } else 3223270192Skevlo mcs |= RT2860_PHY_OFDM; 3224270192Skevlo txwi->phy = htole16(mcs); 3225203134Sthompsa 3226203134Sthompsa /* check if RTS/CTS or CTS-to-self protection is required */ 3227203134Sthompsa if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 3228203134Sthompsa (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold || 3229203134Sthompsa ((ic->ic_flags & IEEE80211_F_USEPROT) && 3230203134Sthompsa rt2860_rates[ridx].phy == IEEE80211_T_OFDM))) 3231208019Sthompsa txwi->txop |= RT2860_TX_TXOP_HT; 3232203134Sthompsa else 3233208019Sthompsa txwi->txop |= RT2860_TX_TXOP_BACKOFF; 3234209144Sthompsa 3235209917Sthompsa if (vap->iv_opmode != IEEE80211_M_STA && !IEEE80211_QOS_HAS_SEQ(wh)) 3236209144Sthompsa txwi->xflags |= RT2860_TX_NSEQ; 3237203134Sthompsa} 3238203134Sthompsa 3239203134Sthompsa/* This function must be called locked */ 3240203134Sthompsastatic int 3241203134Sthompsarun_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) 3242203134Sthompsa{ 3243287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3244208019Sthompsa struct ieee80211vap *vap = ni->ni_vap; 3245203134Sthompsa struct ieee80211_frame *wh; 3246208019Sthompsa struct ieee80211_channel *chan; 3247203134Sthompsa const struct ieee80211_txparam *tp; 3248287552Skevlo struct run_node *rn = RUN_NODE(ni); 3249203134Sthompsa struct run_tx_data *data; 3250208019Sthompsa struct rt2870_txd *txd; 3251208019Sthompsa struct rt2860_txwi *txwi; 3252203134Sthompsa uint16_t qos; 3253203134Sthompsa uint16_t dur; 3254208019Sthompsa uint16_t qid; 3255203134Sthompsa uint8_t type; 3256203134Sthompsa uint8_t tid; 3257208019Sthompsa uint8_t ridx; 3258208019Sthompsa uint8_t ctl_ridx; 3259203134Sthompsa uint8_t qflags; 3260203134Sthompsa uint8_t xflags = 0; 3261203134Sthompsa int hasqos; 3262203134Sthompsa 3263203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3264203134Sthompsa 3265203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3266203134Sthompsa 3267203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3268203134Sthompsa 3269203134Sthompsa /* 3270203134Sthompsa * There are 7 bulk endpoints: 1 for RX 3271203134Sthompsa * and 6 for TX (4 EDCAs + HCCA + Prio). 3272203134Sthompsa * Update 03-14-2009: some devices like the Planex GW-US300MiniS 3273203134Sthompsa * seem to have only 4 TX bulk endpoints (Fukaumi Naoki). 3274203134Sthompsa */ 3275203134Sthompsa if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) { 3276203134Sthompsa uint8_t *frm; 3277203134Sthompsa 3278203134Sthompsa if(IEEE80211_HAS_ADDR4(wh)) 3279203134Sthompsa frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos; 3280203134Sthompsa else 3281203134Sthompsa frm =((struct ieee80211_qosframe *)wh)->i_qos; 3282203134Sthompsa 3283203134Sthompsa qos = le16toh(*(const uint16_t *)frm); 3284203134Sthompsa tid = qos & IEEE80211_QOS_TID; 3285203134Sthompsa qid = TID_TO_WME_AC(tid); 3286203134Sthompsa } else { 3287203134Sthompsa qos = 0; 3288203134Sthompsa tid = 0; 3289203134Sthompsa qid = WME_AC_BE; 3290203134Sthompsa } 3291203134Sthompsa qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA; 3292203134Sthompsa 3293203134Sthompsa DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n", 3294203134Sthompsa qos, qid, tid, qflags); 3295203134Sthompsa 3296208019Sthompsa chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan; 3297208019Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(chan)]; 3298203134Sthompsa 3299203134Sthompsa /* pickup a rate index */ 3300203134Sthompsa if (IEEE80211_IS_MULTICAST(wh->i_addr1) || 3301270192Skevlo type != IEEE80211_FC0_TYPE_DATA || m->m_flags & M_EAPOL) { 3302203134Sthompsa ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? 3303203134Sthompsa RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; 3304203134Sthompsa ctl_ridx = rt2860_rates[ridx].ctl_ridx; 3305203134Sthompsa } else { 3306208019Sthompsa if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) 3307208019Sthompsa ridx = rn->fix_ridx; 3308208019Sthompsa else 3309208019Sthompsa ridx = rn->amrr_ridx; 3310203134Sthompsa ctl_ridx = rt2860_rates[ridx].ctl_ridx; 3311203134Sthompsa } 3312203134Sthompsa 3313203134Sthompsa if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 3314203134Sthompsa (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) != 3315203134Sthompsa IEEE80211_QOS_ACKPOLICY_NOACK)) { 3316209144Sthompsa xflags |= RT2860_TX_ACK; 3317203134Sthompsa if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 3318208019Sthompsa dur = rt2860_rates[ctl_ridx].sp_ack_dur; 3319203134Sthompsa else 3320208019Sthompsa dur = rt2860_rates[ctl_ridx].lp_ack_dur; 3321258919Shselasky USETW(wh->i_dur, dur); 3322203134Sthompsa } 3323203134Sthompsa 3324203134Sthompsa /* reserve slots for mgmt packets, just in case */ 3325203134Sthompsa if (sc->sc_epq[qid].tx_nfree < 3) { 3326203134Sthompsa DPRINTFN(10, "tx ring %d is full\n", qid); 3327203134Sthompsa return (-1); 3328203134Sthompsa } 3329203134Sthompsa 3330203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh); 3331203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next); 3332203134Sthompsa sc->sc_epq[qid].tx_nfree--; 3333203134Sthompsa 3334208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3335208019Sthompsa txd->flags = qflags; 3336208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3337208019Sthompsa txwi->xflags = xflags; 3338259032Skevlo if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 3339245047Shselasky txwi->wcid = 0; 3340259032Skevlo else 3341245047Shselasky txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 3342245047Shselasky 1 : RUN_AID2WCID(ni->ni_associd); 3343259032Skevlo 3344208019Sthompsa /* clear leftover garbage bits */ 3345208019Sthompsa txwi->flags = 0; 3346208019Sthompsa txwi->txop = 0; 3347208019Sthompsa 3348203134Sthompsa data->m = m; 3349203134Sthompsa data->ni = ni; 3350203134Sthompsa data->ridx = ridx; 3351203134Sthompsa 3352208019Sthompsa run_set_tx_desc(sc, data); 3353203134Sthompsa 3354208019Sthompsa /* 3355208019Sthompsa * The chip keeps track of 2 kind of Tx stats, 3356208019Sthompsa * * TX_STAT_FIFO, for per WCID stats, and 3357208019Sthompsa * * TX_STA_CNT0 for all-TX-in-one stats. 3358208019Sthompsa * 3359208019Sthompsa * To use FIFO stats, we need to store MCS into the driver-private 3360208019Sthompsa * PacketID field. So that, we can tell whose stats when we read them. 3361208019Sthompsa * We add 1 to the MCS because setting the PacketID field to 0 means 3362208019Sthompsa * that we don't want feedback in TX_STAT_FIFO. 3363208019Sthompsa * And, that's what we want for STA mode, since TX_STA_CNT0 does the job. 3364208019Sthompsa * 3365208019Sthompsa * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx(). 3366208019Sthompsa */ 3367209917Sthompsa if (sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP || 3368209917Sthompsa vap->iv_opmode == IEEE80211_M_MBSS) { 3369208019Sthompsa uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf; 3370208019Sthompsa txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT); 3371208019Sthompsa 3372208019Sthompsa /* 3373208019Sthompsa * Unlike PCI based devices, we don't get any interrupt from 3374208019Sthompsa * USB devices, so we simulate FIFO-is-full interrupt here. 3375208019Sthompsa * Ralink recomends to drain FIFO stats every 100 ms, but 16 slots 3376208019Sthompsa * quickly get fulled. To prevent overflow, increment a counter on 3377208019Sthompsa * every FIFO stat request, so we know how many slots are left. 3378208019Sthompsa * We do this only in HOSTAP or multiple vap mode since FIFO stats 3379208019Sthompsa * are used only in those modes. 3380208019Sthompsa * We just drain stats. AMRR gets updated every 1 sec by 3381208019Sthompsa * run_ratectl_cb() via callout. 3382208019Sthompsa * Call it early. Otherwise overflow. 3383208019Sthompsa */ 3384209917Sthompsa if (sc->fifo_cnt++ == 10) { 3385208019Sthompsa /* 3386208019Sthompsa * With multiple vaps or if_bridge, if_start() is called 3387208019Sthompsa * with a non-sleepable lock, tcpinp. So, need to defer. 3388208019Sthompsa */ 3389208019Sthompsa uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 3390208019Sthompsa DPRINTFN(6, "cmdq_store=%d\n", i); 3391208019Sthompsa sc->cmdq[i].func = run_drain_fifo; 3392208019Sthompsa sc->cmdq[i].arg0 = sc; 3393208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 3394208019Sthompsa } 3395208019Sthompsa } 3396208019Sthompsa 3397203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next); 3398203134Sthompsa 3399203134Sthompsa usbd_transfer_start(sc->sc_xfer[qid]); 3400203134Sthompsa 3401258840Skevlo DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n", 3402259032Skevlo m->m_pkthdr.len + (int)(sizeof(struct rt2870_txd) + 3403259046Shselasky sizeof(struct rt2860_txwi)), rt2860_rates[ridx].rate, qid); 3404203134Sthompsa 3405203134Sthompsa return (0); 3406203134Sthompsa} 3407203134Sthompsa 3408203134Sthompsastatic int 3409203134Sthompsarun_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) 3410203134Sthompsa{ 3411287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3412287552Skevlo struct run_node *rn = RUN_NODE(ni); 3413203134Sthompsa struct run_tx_data *data; 3414203134Sthompsa struct ieee80211_frame *wh; 3415208019Sthompsa struct rt2870_txd *txd; 3416208019Sthompsa struct rt2860_txwi *txwi; 3417203134Sthompsa uint16_t dur; 3418208019Sthompsa uint8_t ridx = rn->mgt_ridx; 3419203134Sthompsa uint8_t type; 3420203134Sthompsa uint8_t xflags = 0; 3421208019Sthompsa uint8_t wflags = 0; 3422203134Sthompsa 3423203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3424203134Sthompsa 3425203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3426203134Sthompsa 3427203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3428203134Sthompsa 3429208019Sthompsa /* tell hardware to add timestamp for probe responses */ 3430208019Sthompsa if ((wh->i_fc[0] & 3431208019Sthompsa (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == 3432208019Sthompsa (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) 3433208019Sthompsa wflags |= RT2860_TX_TS; 3434208019Sthompsa else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 3435203134Sthompsa xflags |= RT2860_TX_ACK; 3436203134Sthompsa 3437208019Sthompsa dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate, 3438203134Sthompsa ic->ic_flags & IEEE80211_F_SHPREAMBLE); 3439258919Shselasky USETW(wh->i_dur, dur); 3440203134Sthompsa } 3441203134Sthompsa 3442287197Sglebius if (sc->sc_epq[0].tx_nfree == 0) 3443203134Sthompsa /* let caller free mbuf */ 3444203134Sthompsa return (EIO); 3445203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3446203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3447203134Sthompsa sc->sc_epq[0].tx_nfree--; 3448203134Sthompsa 3449208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3450208019Sthompsa txd->flags = RT2860_TX_QSEL_EDCA; 3451208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3452208019Sthompsa txwi->wcid = 0xff; 3453208019Sthompsa txwi->flags = wflags; 3454208019Sthompsa txwi->xflags = xflags; 3455208019Sthompsa txwi->txop = 0; /* clear leftover garbage bits */ 3456208019Sthompsa 3457203134Sthompsa data->m = m; 3458203134Sthompsa data->ni = ni; 3459203134Sthompsa data->ridx = ridx; 3460203134Sthompsa 3461208019Sthompsa run_set_tx_desc(sc, data); 3462203134Sthompsa 3463203134Sthompsa DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len + 3464258840Skevlo (int)(sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi)), 3465208019Sthompsa rt2860_rates[ridx].rate); 3466203134Sthompsa 3467203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3468203134Sthompsa 3469203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 3470203134Sthompsa 3471203134Sthompsa return (0); 3472203134Sthompsa} 3473203134Sthompsa 3474203134Sthompsastatic int 3475203134Sthompsarun_sendprot(struct run_softc *sc, 3476203134Sthompsa const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) 3477203134Sthompsa{ 3478203134Sthompsa struct ieee80211com *ic = ni->ni_ic; 3479203134Sthompsa struct ieee80211_frame *wh; 3480203134Sthompsa struct run_tx_data *data; 3481208019Sthompsa struct rt2870_txd *txd; 3482208019Sthompsa struct rt2860_txwi *txwi; 3483203134Sthompsa struct mbuf *mprot; 3484203134Sthompsa int ridx; 3485203134Sthompsa int protrate; 3486203134Sthompsa int ackrate; 3487203134Sthompsa int pktlen; 3488203134Sthompsa int isshort; 3489203134Sthompsa uint16_t dur; 3490203134Sthompsa uint8_t type; 3491208019Sthompsa uint8_t wflags = 0; 3492208019Sthompsa uint8_t xflags = 0; 3493203134Sthompsa 3494203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3495203134Sthompsa 3496203134Sthompsa KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, 3497203134Sthompsa ("protection %d", prot)); 3498203134Sthompsa 3499203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3500203134Sthompsa pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; 3501203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3502203134Sthompsa 3503203134Sthompsa protrate = ieee80211_ctl_rate(ic->ic_rt, rate); 3504203134Sthompsa ackrate = ieee80211_ack_rate(ic->ic_rt, rate); 3505203134Sthompsa 3506203134Sthompsa isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; 3507209189Sjkim dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort) 3508203134Sthompsa + ieee80211_ack_duration(ic->ic_rt, rate, isshort); 3509203134Sthompsa wflags = RT2860_TX_FRAG; 3510203134Sthompsa 3511203134Sthompsa /* check that there are free slots before allocating the mbuf */ 3512287197Sglebius if (sc->sc_epq[0].tx_nfree == 0) 3513203134Sthompsa /* let caller free mbuf */ 3514203134Sthompsa return (ENOBUFS); 3515203134Sthompsa 3516203134Sthompsa if (prot == IEEE80211_PROT_RTSCTS) { 3517203134Sthompsa /* NB: CTS is the same size as an ACK */ 3518203134Sthompsa dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); 3519208019Sthompsa xflags |= RT2860_TX_ACK; 3520203134Sthompsa mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); 3521203134Sthompsa } else { 3522203134Sthompsa mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); 3523203134Sthompsa } 3524203134Sthompsa if (mprot == NULL) { 3525287197Sglebius if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); 3526203134Sthompsa DPRINTF("could not allocate mbuf\n"); 3527203134Sthompsa return (ENOBUFS); 3528203134Sthompsa } 3529203134Sthompsa 3530203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3531203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3532203134Sthompsa sc->sc_epq[0].tx_nfree--; 3533203134Sthompsa 3534208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3535208019Sthompsa txd->flags = RT2860_TX_QSEL_EDCA; 3536208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3537208019Sthompsa txwi->wcid = 0xff; 3538208019Sthompsa txwi->flags = wflags; 3539208019Sthompsa txwi->xflags = xflags; 3540208019Sthompsa txwi->txop = 0; /* clear leftover garbage bits */ 3541208019Sthompsa 3542203134Sthompsa data->m = mprot; 3543203134Sthompsa data->ni = ieee80211_ref_node(ni); 3544203134Sthompsa 3545203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 3546203134Sthompsa if (rt2860_rates[ridx].rate == protrate) 3547203134Sthompsa break; 3548203134Sthompsa data->ridx = ridx; 3549203134Sthompsa 3550208019Sthompsa run_set_tx_desc(sc, data); 3551203134Sthompsa 3552203134Sthompsa DPRINTFN(1, "sending prot len=%u rate=%u\n", 3553203134Sthompsa m->m_pkthdr.len, rate); 3554203134Sthompsa 3555203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3556203134Sthompsa 3557203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 3558203134Sthompsa 3559203134Sthompsa return (0); 3560203134Sthompsa} 3561203134Sthompsa 3562203134Sthompsastatic int 3563203134Sthompsarun_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, 3564203134Sthompsa const struct ieee80211_bpf_params *params) 3565203134Sthompsa{ 3566203134Sthompsa struct ieee80211com *ic = ni->ni_ic; 3567203134Sthompsa struct ieee80211_frame *wh; 3568203134Sthompsa struct run_tx_data *data; 3569208019Sthompsa struct rt2870_txd *txd; 3570208019Sthompsa struct rt2860_txwi *txwi; 3571203134Sthompsa uint8_t type; 3572208019Sthompsa uint8_t ridx; 3573208019Sthompsa uint8_t rate; 3574208019Sthompsa uint8_t opflags = 0; 3575208019Sthompsa uint8_t xflags = 0; 3576203134Sthompsa int error; 3577203134Sthompsa 3578203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3579203134Sthompsa 3580203134Sthompsa KASSERT(params != NULL, ("no raw xmit params")); 3581203134Sthompsa 3582203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3583203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3584203134Sthompsa 3585203134Sthompsa rate = params->ibp_rate0; 3586203134Sthompsa if (!ieee80211_isratevalid(ic->ic_rt, rate)) { 3587203134Sthompsa /* let caller free mbuf */ 3588203134Sthompsa return (EINVAL); 3589203134Sthompsa } 3590203134Sthompsa 3591203134Sthompsa if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) 3592208019Sthompsa xflags |= RT2860_TX_ACK; 3593203134Sthompsa if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { 3594203134Sthompsa error = run_sendprot(sc, m, ni, 3595203134Sthompsa params->ibp_flags & IEEE80211_BPF_RTS ? 3596203134Sthompsa IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, 3597203134Sthompsa rate); 3598203134Sthompsa if (error) { 3599203134Sthompsa /* let caller free mbuf */ 3600209917Sthompsa return error; 3601203134Sthompsa } 3602203134Sthompsa opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS; 3603203134Sthompsa } 3604203134Sthompsa 3605203134Sthompsa if (sc->sc_epq[0].tx_nfree == 0) { 3606203134Sthompsa /* let caller free mbuf */ 3607203134Sthompsa DPRINTF("sending raw frame, but tx ring is full\n"); 3608203134Sthompsa return (EIO); 3609203134Sthompsa } 3610203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3611203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3612203134Sthompsa sc->sc_epq[0].tx_nfree--; 3613203134Sthompsa 3614208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3615208019Sthompsa txd->flags = RT2860_TX_QSEL_EDCA; 3616208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3617208019Sthompsa txwi->wcid = 0xff; 3618208019Sthompsa txwi->xflags = xflags; 3619208019Sthompsa txwi->txop = opflags; 3620208019Sthompsa txwi->flags = 0; /* clear leftover garbage bits */ 3621208019Sthompsa 3622203134Sthompsa data->m = m; 3623203134Sthompsa data->ni = ni; 3624203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 3625203134Sthompsa if (rt2860_rates[ridx].rate == rate) 3626203134Sthompsa break; 3627203134Sthompsa data->ridx = ridx; 3628203134Sthompsa 3629208019Sthompsa run_set_tx_desc(sc, data); 3630203134Sthompsa 3631203134Sthompsa DPRINTFN(10, "sending raw frame len=%u rate=%u\n", 3632203134Sthompsa m->m_pkthdr.len, rate); 3633203134Sthompsa 3634203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3635203134Sthompsa 3636203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 3637203134Sthompsa 3638209917Sthompsa return (0); 3639203134Sthompsa} 3640203134Sthompsa 3641203134Sthompsastatic int 3642203134Sthompsarun_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 3643203134Sthompsa const struct ieee80211_bpf_params *params) 3644203134Sthompsa{ 3645286950Sadrian struct run_softc *sc = ni->ni_ic->ic_softc; 3646208019Sthompsa int error = 0; 3647208019Sthompsa 3648203134Sthompsa RUN_LOCK(sc); 3649203134Sthompsa 3650203134Sthompsa /* prevent management frames from being sent if we're not ready */ 3651287197Sglebius if (!(sc->sc_flags & RUN_RUNNING)) { 3652287197Sglebius error = ENETDOWN; 3653208019Sthompsa goto done; 3654203134Sthompsa } 3655203134Sthompsa 3656203134Sthompsa if (params == NULL) { 3657203134Sthompsa /* tx mgt packet */ 3658209917Sthompsa if ((error = run_tx_mgt(sc, m, ni)) != 0) { 3659203134Sthompsa DPRINTF("mgt tx failed\n"); 3660208019Sthompsa goto done; 3661203134Sthompsa } 3662203134Sthompsa } else { 3663203134Sthompsa /* tx raw packet with param */ 3664209917Sthompsa if ((error = run_tx_param(sc, m, ni, params)) != 0) { 3665203134Sthompsa DPRINTF("tx with param failed\n"); 3666208019Sthompsa goto done; 3667203134Sthompsa } 3668203134Sthompsa } 3669203134Sthompsa 3670208019Sthompsadone: 3671203134Sthompsa RUN_UNLOCK(sc); 3672203134Sthompsa 3673209917Sthompsa if (error != 0) { 3674208019Sthompsa if(m != NULL) 3675208019Sthompsa m_freem(m); 3676208019Sthompsa } 3677203134Sthompsa 3678203134Sthompsa return (error); 3679203134Sthompsa} 3680203134Sthompsa 3681287197Sglebiusstatic int 3682287197Sglebiusrun_transmit(struct ieee80211com *ic, struct mbuf *m) 3683287197Sglebius{ 3684287197Sglebius struct run_softc *sc = ic->ic_softc; 3685287197Sglebius int error; 3686287197Sglebius 3687287197Sglebius RUN_LOCK(sc); 3688287197Sglebius if ((sc->sc_flags & RUN_RUNNING) == 0) { 3689287197Sglebius RUN_UNLOCK(sc); 3690287197Sglebius return (ENXIO); 3691287197Sglebius } 3692287197Sglebius error = mbufq_enqueue(&sc->sc_snd, m); 3693287197Sglebius if (error) { 3694287197Sglebius RUN_UNLOCK(sc); 3695287197Sglebius return (error); 3696287197Sglebius } 3697287197Sglebius run_start(sc); 3698287197Sglebius RUN_UNLOCK(sc); 3699287197Sglebius 3700287197Sglebius return (0); 3701287197Sglebius} 3702287197Sglebius 3703203134Sthompsastatic void 3704287197Sglebiusrun_start(struct run_softc *sc) 3705203134Sthompsa{ 3706203134Sthompsa struct ieee80211_node *ni; 3707203134Sthompsa struct mbuf *m; 3708203134Sthompsa 3709287197Sglebius RUN_LOCK_ASSERT(sc, MA_OWNED); 3710203134Sthompsa 3711287197Sglebius if ((sc->sc_flags & RUN_RUNNING) == 0) 3712203134Sthompsa return; 3713203134Sthompsa 3714287197Sglebius while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { 3715203134Sthompsa ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 3716203134Sthompsa if (run_tx(sc, m, ni) != 0) { 3717287197Sglebius mbufq_prepend(&sc->sc_snd, m); 3718203134Sthompsa break; 3719203134Sthompsa } 3720203134Sthompsa } 3721203134Sthompsa} 3722203134Sthompsa 3723287197Sglebiusstatic void 3724287197Sglebiusrun_parent(struct ieee80211com *ic) 3725203134Sthompsa{ 3726286950Sadrian struct run_softc *sc = ic->ic_softc; 3727208019Sthompsa int startall = 0; 3728203134Sthompsa 3729246614Shselasky RUN_LOCK(sc); 3730287197Sglebius if (sc->sc_detached) { 3731203134Sthompsa RUN_UNLOCK(sc); 3732287197Sglebius return; 3733203134Sthompsa } 3734203134Sthompsa 3735287197Sglebius if (ic->ic_nrunning > 0) { 3736287197Sglebius if (!(sc->sc_flags & RUN_RUNNING)) { 3737287197Sglebius startall = 1; 3738287197Sglebius run_init_locked(sc); 3739287197Sglebius } else 3740287197Sglebius run_update_promisc_locked(sc); 3741287197Sglebius } else if ((sc->sc_flags & RUN_RUNNING) && sc->rvp_cnt <= 1) 3742287197Sglebius run_stop(sc); 3743287197Sglebius RUN_UNLOCK(sc); 3744287197Sglebius if (startall) 3745287197Sglebius ieee80211_start_all(ic); 3746203134Sthompsa} 3747203134Sthompsa 3748203134Sthompsastatic void 3749259544Skevlorun_iq_calib(struct run_softc *sc, u_int chan) 3750259544Skevlo{ 3751259544Skevlo uint16_t val; 3752259544Skevlo 3753259544Skevlo /* Tx0 IQ gain. */ 3754259544Skevlo run_bbp_write(sc, 158, 0x2c); 3755259544Skevlo if (chan <= 14) 3756259544Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX0_2GHZ, &val, 1); 3757259544Skevlo else if (chan <= 64) { 3758259544Skevlo run_efuse_read(sc, 3759259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5GHZ, 3760259544Skevlo &val, 1); 3761259544Skevlo } else if (chan <= 138) { 3762259544Skevlo run_efuse_read(sc, 3763259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5GHZ, 3764259544Skevlo &val, 1); 3765259544Skevlo } else if (chan <= 165) { 3766259544Skevlo run_efuse_read(sc, 3767259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5GHZ, 3768259544Skevlo &val, 1); 3769259544Skevlo } else 3770259544Skevlo val = 0; 3771259547Skevlo run_bbp_write(sc, 159, val); 3772259544Skevlo 3773259544Skevlo /* Tx0 IQ phase. */ 3774259544Skevlo run_bbp_write(sc, 158, 0x2d); 3775259544Skevlo if (chan <= 14) { 3776259544Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX0_2GHZ, 3777259544Skevlo &val, 1); 3778259544Skevlo } else if (chan <= 64) { 3779259544Skevlo run_efuse_read(sc, 3780259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5GHZ, 3781259544Skevlo &val, 1); 3782259544Skevlo } else if (chan <= 138) { 3783259544Skevlo run_efuse_read(sc, 3784259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5GHZ, 3785259544Skevlo &val, 1); 3786259544Skevlo } else if (chan <= 165) { 3787259544Skevlo run_efuse_read(sc, 3788259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5GHZ, 3789259544Skevlo &val, 1); 3790259544Skevlo } else 3791259544Skevlo val = 0; 3792259547Skevlo run_bbp_write(sc, 159, val); 3793259544Skevlo 3794259544Skevlo /* Tx1 IQ gain. */ 3795259544Skevlo run_bbp_write(sc, 158, 0x4a); 3796259544Skevlo if (chan <= 14) { 3797259544Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX1_2GHZ, 3798259544Skevlo &val, 1); 3799259544Skevlo } else if (chan <= 64) { 3800259544Skevlo run_efuse_read(sc, 3801259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5GHZ, 3802259544Skevlo &val, 1); 3803259544Skevlo } else if (chan <= 138) { 3804259544Skevlo run_efuse_read(sc, 3805259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5GHZ, 3806259544Skevlo &val, 1); 3807259544Skevlo } else if (chan <= 165) { 3808259544Skevlo run_efuse_read(sc, 3809259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5GHZ, 3810259544Skevlo &val, 1); 3811259544Skevlo } else 3812259544Skevlo val = 0; 3813259547Skevlo run_bbp_write(sc, 159, val); 3814259544Skevlo 3815259544Skevlo /* Tx1 IQ phase. */ 3816259544Skevlo run_bbp_write(sc, 158, 0x4b); 3817259544Skevlo if (chan <= 14) { 3818259544Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX1_2GHZ, 3819259544Skevlo &val, 1); 3820259544Skevlo } else if (chan <= 64) { 3821259544Skevlo run_efuse_read(sc, 3822259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5GHZ, 3823259544Skevlo &val, 1); 3824259544Skevlo } else if (chan <= 138) { 3825259544Skevlo run_efuse_read(sc, 3826259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5GHZ, 3827259544Skevlo &val, 1); 3828259544Skevlo } else if (chan <= 165) { 3829259544Skevlo run_efuse_read(sc, 3830259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5GHZ, 3831259544Skevlo &val, 1); 3832259544Skevlo } else 3833259544Skevlo val = 0; 3834259547Skevlo run_bbp_write(sc, 159, val); 3835259544Skevlo 3836259544Skevlo /* RF IQ compensation control. */ 3837259544Skevlo run_bbp_write(sc, 158, 0x04); 3838259544Skevlo run_efuse_read(sc, RT5390_EEPROM_RF_IQ_COMPENSATION_CTL, 3839259544Skevlo &val, 1); 3840259547Skevlo run_bbp_write(sc, 159, val); 3841259544Skevlo 3842259544Skevlo /* RF IQ imbalance compensation control. */ 3843259544Skevlo run_bbp_write(sc, 158, 0x03); 3844259544Skevlo run_efuse_read(sc, 3845259544Skevlo RT5390_EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CTL, &val, 1); 3846259547Skevlo run_bbp_write(sc, 159, val); 3847259544Skevlo} 3848259544Skevlo 3849259544Skevlostatic void 3850205042Sthompsarun_set_agc(struct run_softc *sc, uint8_t agc) 3851205042Sthompsa{ 3852205042Sthompsa uint8_t bbp; 3853205042Sthompsa 3854205042Sthompsa if (sc->mac_ver == 0x3572) { 3855205042Sthompsa run_bbp_read(sc, 27, &bbp); 3856205042Sthompsa bbp &= ~(0x3 << 5); 3857205042Sthompsa run_bbp_write(sc, 27, bbp | 0 << 5); /* select Rx0 */ 3858205042Sthompsa run_bbp_write(sc, 66, agc); 3859205042Sthompsa run_bbp_write(sc, 27, bbp | 1 << 5); /* select Rx1 */ 3860205042Sthompsa run_bbp_write(sc, 66, agc); 3861205042Sthompsa } else 3862205042Sthompsa run_bbp_write(sc, 66, agc); 3863205042Sthompsa} 3864205042Sthompsa 3865205042Sthompsastatic void 3866203134Sthompsarun_select_chan_group(struct run_softc *sc, int group) 3867203134Sthompsa{ 3868203134Sthompsa uint32_t tmp; 3869205042Sthompsa uint8_t agc; 3870203134Sthompsa 3871203134Sthompsa run_bbp_write(sc, 62, 0x37 - sc->lna[group]); 3872203134Sthompsa run_bbp_write(sc, 63, 0x37 - sc->lna[group]); 3873203134Sthompsa run_bbp_write(sc, 64, 0x37 - sc->lna[group]); 3874258082Skevlo if (sc->mac_ver < 0x3572) 3875257955Skevlo run_bbp_write(sc, 86, 0x00); 3876203134Sthompsa 3877260219Skevlo if (sc->mac_ver == 0x3593) { 3878260219Skevlo run_bbp_write(sc, 77, 0x98); 3879260219Skevlo run_bbp_write(sc, 83, (group == 0) ? 0x8a : 0x9a); 3880260219Skevlo } 3881260219Skevlo 3882203134Sthompsa if (group == 0) { 3883203134Sthompsa if (sc->ext_2ghz_lna) { 3884257955Skevlo if (sc->mac_ver >= 0x5390) 3885257955Skevlo run_bbp_write(sc, 75, 0x52); 3886257955Skevlo else { 3887257955Skevlo run_bbp_write(sc, 82, 0x62); 3888257955Skevlo run_bbp_write(sc, 75, 0x46); 3889257955Skevlo } 3890203134Sthompsa } else { 3891259032Skevlo if (sc->mac_ver == 0x5592) { 3892259032Skevlo run_bbp_write(sc, 79, 0x1c); 3893259032Skevlo run_bbp_write(sc, 80, 0x0e); 3894259032Skevlo run_bbp_write(sc, 81, 0x3a); 3895259032Skevlo run_bbp_write(sc, 82, 0x62); 3896259032Skevlo 3897259032Skevlo run_bbp_write(sc, 195, 0x80); 3898259032Skevlo run_bbp_write(sc, 196, 0xe0); 3899259032Skevlo run_bbp_write(sc, 195, 0x81); 3900259032Skevlo run_bbp_write(sc, 196, 0x1f); 3901259032Skevlo run_bbp_write(sc, 195, 0x82); 3902259032Skevlo run_bbp_write(sc, 196, 0x38); 3903259032Skevlo run_bbp_write(sc, 195, 0x83); 3904259032Skevlo run_bbp_write(sc, 196, 0x32); 3905259032Skevlo run_bbp_write(sc, 195, 0x85); 3906259032Skevlo run_bbp_write(sc, 196, 0x28); 3907259032Skevlo run_bbp_write(sc, 195, 0x86); 3908259032Skevlo run_bbp_write(sc, 196, 0x19); 3909259032Skevlo } else if (sc->mac_ver >= 0x5390) 3910257955Skevlo run_bbp_write(sc, 75, 0x50); 3911257955Skevlo else { 3912260219Skevlo run_bbp_write(sc, 82, 3913260219Skevlo (sc->mac_ver == 0x3593) ? 0x62 : 0x84); 3914257955Skevlo run_bbp_write(sc, 75, 0x50); 3915257955Skevlo } 3916203134Sthompsa } 3917203134Sthompsa } else { 3918259032Skevlo if (sc->mac_ver == 0x5592) { 3919259032Skevlo run_bbp_write(sc, 79, 0x18); 3920259032Skevlo run_bbp_write(sc, 80, 0x08); 3921259032Skevlo run_bbp_write(sc, 81, 0x38); 3922259032Skevlo run_bbp_write(sc, 82, 0x92); 3923259032Skevlo 3924259032Skevlo run_bbp_write(sc, 195, 0x80); 3925259032Skevlo run_bbp_write(sc, 196, 0xf0); 3926259032Skevlo run_bbp_write(sc, 195, 0x81); 3927259032Skevlo run_bbp_write(sc, 196, 0x1e); 3928259032Skevlo run_bbp_write(sc, 195, 0x82); 3929259032Skevlo run_bbp_write(sc, 196, 0x28); 3930259032Skevlo run_bbp_write(sc, 195, 0x83); 3931259032Skevlo run_bbp_write(sc, 196, 0x20); 3932259032Skevlo run_bbp_write(sc, 195, 0x85); 3933259032Skevlo run_bbp_write(sc, 196, 0x7f); 3934259032Skevlo run_bbp_write(sc, 195, 0x86); 3935259032Skevlo run_bbp_write(sc, 196, 0x7f); 3936259032Skevlo } else if (sc->mac_ver == 0x3572) 3937205042Sthompsa run_bbp_write(sc, 82, 0x94); 3938205042Sthompsa else 3939260219Skevlo run_bbp_write(sc, 82, 3940260219Skevlo (sc->mac_ver == 0x3593) ? 0x82 : 0xf2); 3941205042Sthompsa if (sc->ext_5ghz_lna) 3942203134Sthompsa run_bbp_write(sc, 75, 0x46); 3943205042Sthompsa else 3944203134Sthompsa run_bbp_write(sc, 75, 0x50); 3945203134Sthompsa } 3946203134Sthompsa 3947203134Sthompsa run_read(sc, RT2860_TX_BAND_CFG, &tmp); 3948203134Sthompsa tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P); 3949203134Sthompsa tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P; 3950203134Sthompsa run_write(sc, RT2860_TX_BAND_CFG, tmp); 3951203134Sthompsa 3952203134Sthompsa /* enable appropriate Power Amplifiers and Low Noise Amplifiers */ 3953208019Sthompsa tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN; 3954260219Skevlo if (sc->mac_ver == 0x3593) 3955260219Skevlo tmp |= 1 << 29 | 1 << 28; 3956208019Sthompsa if (sc->nrxchains > 1) 3957208019Sthompsa tmp |= RT2860_LNA_PE1_EN; 3958203134Sthompsa if (group == 0) { /* 2GHz */ 3959208019Sthompsa tmp |= RT2860_PA_PE_G0_EN; 3960203134Sthompsa if (sc->ntxchains > 1) 3961203134Sthompsa tmp |= RT2860_PA_PE_G1_EN; 3962260219Skevlo if (sc->mac_ver == 0x3593) { 3963260219Skevlo if (sc->ntxchains > 2) 3964260219Skevlo tmp |= 1 << 25; 3965260219Skevlo } 3966203134Sthompsa } else { /* 5GHz */ 3967208019Sthompsa tmp |= RT2860_PA_PE_A0_EN; 3968203134Sthompsa if (sc->ntxchains > 1) 3969203134Sthompsa tmp |= RT2860_PA_PE_A1_EN; 3970203134Sthompsa } 3971205042Sthompsa if (sc->mac_ver == 0x3572) { 3972205042Sthompsa run_rt3070_rf_write(sc, 8, 0x00); 3973205042Sthompsa run_write(sc, RT2860_TX_PIN_CFG, tmp); 3974205042Sthompsa run_rt3070_rf_write(sc, 8, 0x80); 3975205042Sthompsa } else 3976205042Sthompsa run_write(sc, RT2860_TX_PIN_CFG, tmp); 3977203134Sthompsa 3978259032Skevlo if (sc->mac_ver == 0x5592) { 3979259032Skevlo run_bbp_write(sc, 195, 0x8d); 3980259032Skevlo run_bbp_write(sc, 196, 0x1a); 3981259032Skevlo } 3982259032Skevlo 3983260219Skevlo if (sc->mac_ver == 0x3593) { 3984260219Skevlo run_read(sc, RT2860_GPIO_CTRL, &tmp); 3985260219Skevlo tmp &= ~0x01010000; 3986260219Skevlo if (group == 0) 3987260219Skevlo tmp |= 0x00010000; 3988260219Skevlo tmp = (tmp & ~0x00009090) | 0x00000090; 3989260219Skevlo run_write(sc, RT2860_GPIO_CTRL, tmp); 3990260219Skevlo } 3991260219Skevlo 3992203134Sthompsa /* set initial AGC value */ 3993205042Sthompsa if (group == 0) { /* 2GHz band */ 3994205042Sthompsa if (sc->mac_ver >= 0x3070) 3995205042Sthompsa agc = 0x1c + sc->lna[0] * 2; 3996205042Sthompsa else 3997205042Sthompsa agc = 0x2e + sc->lna[0]; 3998205042Sthompsa } else { /* 5GHz band */ 3999259032Skevlo if (sc->mac_ver == 0x5592) 4000259032Skevlo agc = 0x24 + sc->lna[group] * 2; 4001260219Skevlo else if (sc->mac_ver == 0x3572 || sc->mac_ver == 0x3593) 4002205042Sthompsa agc = 0x22 + (sc->lna[group] * 5) / 3; 4003205042Sthompsa else 4004205042Sthompsa agc = 0x32 + (sc->lna[group] * 5) / 3; 4005205042Sthompsa } 4006205042Sthompsa run_set_agc(sc, agc); 4007203134Sthompsa} 4008203134Sthompsa 4009203134Sthompsastatic void 4010257429Shselaskyrun_rt2870_set_chan(struct run_softc *sc, u_int chan) 4011203134Sthompsa{ 4012203134Sthompsa const struct rfprog *rfprog = rt2860_rf2850; 4013203134Sthompsa uint32_t r2, r3, r4; 4014203134Sthompsa int8_t txpow1, txpow2; 4015203134Sthompsa int i; 4016203134Sthompsa 4017203134Sthompsa /* find the settings for this channel (we know it exists) */ 4018203134Sthompsa for (i = 0; rfprog[i].chan != chan; i++); 4019203134Sthompsa 4020203134Sthompsa r2 = rfprog[i].r2; 4021203134Sthompsa if (sc->ntxchains == 1) 4022258732Skevlo r2 |= 1 << 14; /* 1T: disable Tx chain 2 */ 4023203134Sthompsa if (sc->nrxchains == 1) 4024258732Skevlo r2 |= 1 << 17 | 1 << 6; /* 1R: disable Rx chains 2 & 3 */ 4025203134Sthompsa else if (sc->nrxchains == 2) 4026258732Skevlo r2 |= 1 << 6; /* 2R: disable Rx chain 3 */ 4027203134Sthompsa 4028203134Sthompsa /* use Tx power values from EEPROM */ 4029203134Sthompsa txpow1 = sc->txpow1[i]; 4030203134Sthompsa txpow2 = sc->txpow2[i]; 4031258732Skevlo 4032258732Skevlo /* Initialize RF R3 and R4. */ 4033258732Skevlo r3 = rfprog[i].r3 & 0xffffc1ff; 4034258732Skevlo r4 = (rfprog[i].r4 & ~(0x001f87c0)) | (sc->freq << 15); 4035203134Sthompsa if (chan > 14) { 4036258732Skevlo if (txpow1 >= 0) { 4037258732Skevlo txpow1 = (txpow1 > 0xf) ? (0xf) : (txpow1); 4038258732Skevlo r3 |= (txpow1 << 10) | (1 << 9); 4039258732Skevlo } else { 4040258732Skevlo txpow1 += 7; 4041258732Skevlo 4042258732Skevlo /* txpow1 is not possible larger than 15. */ 4043258732Skevlo r3 |= (txpow1 << 10); 4044258732Skevlo } 4045258732Skevlo if (txpow2 >= 0) { 4046258732Skevlo txpow2 = (txpow2 > 0xf) ? (0xf) : (txpow2); 4047258921Shselasky r4 |= (txpow2 << 7) | (1 << 6); 4048258732Skevlo } else { 4049258732Skevlo txpow2 += 7; 4050258732Skevlo r4 |= (txpow2 << 7); 4051258732Skevlo } 4052258732Skevlo } else { 4053258732Skevlo /* Set Tx0 power. */ 4054258732Skevlo r3 |= (txpow1 << 9); 4055258732Skevlo 4056258732Skevlo /* Set frequency offset and Tx1 power. */ 4057258732Skevlo r4 |= (txpow2 << 6); 4058203134Sthompsa } 4059203134Sthompsa 4060258733Skevlo run_rt2870_rf_write(sc, rfprog[i].r1); 4061258733Skevlo run_rt2870_rf_write(sc, r2); 4062258733Skevlo run_rt2870_rf_write(sc, r3 & ~(1 << 2)); 4063258733Skevlo run_rt2870_rf_write(sc, r4); 4064203134Sthompsa 4065203134Sthompsa run_delay(sc, 10); 4066203134Sthompsa 4067258733Skevlo run_rt2870_rf_write(sc, rfprog[i].r1); 4068258733Skevlo run_rt2870_rf_write(sc, r2); 4069258733Skevlo run_rt2870_rf_write(sc, r3 | (1 << 2)); 4070258733Skevlo run_rt2870_rf_write(sc, r4); 4071203134Sthompsa 4072203134Sthompsa run_delay(sc, 10); 4073203134Sthompsa 4074258733Skevlo run_rt2870_rf_write(sc, rfprog[i].r1); 4075258733Skevlo run_rt2870_rf_write(sc, r2); 4076258733Skevlo run_rt2870_rf_write(sc, r3 & ~(1 << 2)); 4077258733Skevlo run_rt2870_rf_write(sc, r4); 4078203134Sthompsa} 4079203134Sthompsa 4080203134Sthompsastatic void 4081257429Shselaskyrun_rt3070_set_chan(struct run_softc *sc, u_int chan) 4082203134Sthompsa{ 4083203134Sthompsa int8_t txpow1, txpow2; 4084203134Sthompsa uint8_t rf; 4085205042Sthompsa int i; 4086203134Sthompsa 4087205042Sthompsa /* find the settings for this channel (we know it exists) */ 4088205042Sthompsa for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4089205042Sthompsa 4090203134Sthompsa /* use Tx power values from EEPROM */ 4091205042Sthompsa txpow1 = sc->txpow1[i]; 4092205042Sthompsa txpow2 = sc->txpow2[i]; 4093203134Sthompsa 4094205042Sthompsa run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n); 4095256720Skevlo 4096256720Skevlo /* RT3370/RT3390: RF R3 [7:4] is not reserved bits. */ 4097256720Skevlo run_rt3070_rf_read(sc, 3, &rf); 4098256720Skevlo rf = (rf & ~0x0f) | rt3070_freqs[i].k; 4099256720Skevlo run_rt3070_rf_write(sc, 3, rf); 4100256720Skevlo 4101203134Sthompsa run_rt3070_rf_read(sc, 6, &rf); 4102205042Sthompsa rf = (rf & ~0x03) | rt3070_freqs[i].r; 4103203134Sthompsa run_rt3070_rf_write(sc, 6, rf); 4104203134Sthompsa 4105203134Sthompsa /* set Tx0 power */ 4106203134Sthompsa run_rt3070_rf_read(sc, 12, &rf); 4107203134Sthompsa rf = (rf & ~0x1f) | txpow1; 4108203134Sthompsa run_rt3070_rf_write(sc, 12, rf); 4109203134Sthompsa 4110203134Sthompsa /* set Tx1 power */ 4111203134Sthompsa run_rt3070_rf_read(sc, 13, &rf); 4112203134Sthompsa rf = (rf & ~0x1f) | txpow2; 4113203134Sthompsa run_rt3070_rf_write(sc, 13, rf); 4114203134Sthompsa 4115203134Sthompsa run_rt3070_rf_read(sc, 1, &rf); 4116203134Sthompsa rf &= ~0xfc; 4117203134Sthompsa if (sc->ntxchains == 1) 4118203134Sthompsa rf |= 1 << 7 | 1 << 5; /* 1T: disable Tx chains 2 & 3 */ 4119203134Sthompsa else if (sc->ntxchains == 2) 4120203134Sthompsa rf |= 1 << 7; /* 2T: disable Tx chain 3 */ 4121203134Sthompsa if (sc->nrxchains == 1) 4122203134Sthompsa rf |= 1 << 6 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 4123203134Sthompsa else if (sc->nrxchains == 2) 4124203134Sthompsa rf |= 1 << 6; /* 2R: disable Rx chain 3 */ 4125203134Sthompsa run_rt3070_rf_write(sc, 1, rf); 4126203134Sthompsa 4127203134Sthompsa /* set RF offset */ 4128203134Sthompsa run_rt3070_rf_read(sc, 23, &rf); 4129203134Sthompsa rf = (rf & ~0x7f) | sc->freq; 4130203134Sthompsa run_rt3070_rf_write(sc, 23, rf); 4131203134Sthompsa 4132203134Sthompsa /* program RF filter */ 4133205042Sthompsa run_rt3070_rf_read(sc, 24, &rf); /* Tx */ 4134205042Sthompsa rf = (rf & ~0x3f) | sc->rf24_20mhz; 4135205042Sthompsa run_rt3070_rf_write(sc, 24, rf); 4136205042Sthompsa run_rt3070_rf_read(sc, 31, &rf); /* Rx */ 4137205042Sthompsa rf = (rf & ~0x3f) | sc->rf24_20mhz; 4138205042Sthompsa run_rt3070_rf_write(sc, 31, rf); 4139203134Sthompsa 4140203134Sthompsa /* enable RF tuning */ 4141203134Sthompsa run_rt3070_rf_read(sc, 7, &rf); 4142203134Sthompsa run_rt3070_rf_write(sc, 7, rf | 0x01); 4143203134Sthompsa} 4144203134Sthompsa 4145203134Sthompsastatic void 4146205042Sthompsarun_rt3572_set_chan(struct run_softc *sc, u_int chan) 4147205042Sthompsa{ 4148205042Sthompsa int8_t txpow1, txpow2; 4149205042Sthompsa uint32_t tmp; 4150205042Sthompsa uint8_t rf; 4151205042Sthompsa int i; 4152205042Sthompsa 4153205042Sthompsa /* find the settings for this channel (we know it exists) */ 4154205042Sthompsa for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4155205042Sthompsa 4156205042Sthompsa /* use Tx power values from EEPROM */ 4157205042Sthompsa txpow1 = sc->txpow1[i]; 4158205042Sthompsa txpow2 = sc->txpow2[i]; 4159205042Sthompsa 4160205042Sthompsa if (chan <= 14) { 4161205042Sthompsa run_bbp_write(sc, 25, sc->bbp25); 4162205042Sthompsa run_bbp_write(sc, 26, sc->bbp26); 4163205042Sthompsa } else { 4164205042Sthompsa /* enable IQ phase correction */ 4165205042Sthompsa run_bbp_write(sc, 25, 0x09); 4166205042Sthompsa run_bbp_write(sc, 26, 0xff); 4167205042Sthompsa } 4168205042Sthompsa 4169205042Sthompsa run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n); 4170205042Sthompsa run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k); 4171205042Sthompsa run_rt3070_rf_read(sc, 6, &rf); 4172205042Sthompsa rf = (rf & ~0x0f) | rt3070_freqs[i].r; 4173205042Sthompsa rf |= (chan <= 14) ? 0x08 : 0x04; 4174205042Sthompsa run_rt3070_rf_write(sc, 6, rf); 4175205042Sthompsa 4176205042Sthompsa /* set PLL mode */ 4177205042Sthompsa run_rt3070_rf_read(sc, 5, &rf); 4178205042Sthompsa rf &= ~(0x08 | 0x04); 4179205042Sthompsa rf |= (chan <= 14) ? 0x04 : 0x08; 4180205042Sthompsa run_rt3070_rf_write(sc, 5, rf); 4181205042Sthompsa 4182205042Sthompsa /* set Tx power for chain 0 */ 4183205042Sthompsa if (chan <= 14) 4184205042Sthompsa rf = 0x60 | txpow1; 4185205042Sthompsa else 4186205042Sthompsa rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3); 4187205042Sthompsa run_rt3070_rf_write(sc, 12, rf); 4188205042Sthompsa 4189205042Sthompsa /* set Tx power for chain 1 */ 4190205042Sthompsa if (chan <= 14) 4191205042Sthompsa rf = 0x60 | txpow2; 4192205042Sthompsa else 4193205042Sthompsa rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3); 4194205042Sthompsa run_rt3070_rf_write(sc, 13, rf); 4195205042Sthompsa 4196205042Sthompsa /* set Tx/Rx streams */ 4197205042Sthompsa run_rt3070_rf_read(sc, 1, &rf); 4198205042Sthompsa rf &= ~0xfc; 4199205042Sthompsa if (sc->ntxchains == 1) 4200205042Sthompsa rf |= 1 << 7 | 1 << 5; /* 1T: disable Tx chains 2 & 3 */ 4201205042Sthompsa else if (sc->ntxchains == 2) 4202205042Sthompsa rf |= 1 << 7; /* 2T: disable Tx chain 3 */ 4203205042Sthompsa if (sc->nrxchains == 1) 4204205042Sthompsa rf |= 1 << 6 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 4205205042Sthompsa else if (sc->nrxchains == 2) 4206205042Sthompsa rf |= 1 << 6; /* 2R: disable Rx chain 3 */ 4207205042Sthompsa run_rt3070_rf_write(sc, 1, rf); 4208205042Sthompsa 4209205042Sthompsa /* set RF offset */ 4210205042Sthompsa run_rt3070_rf_read(sc, 23, &rf); 4211205042Sthompsa rf = (rf & ~0x7f) | sc->freq; 4212205042Sthompsa run_rt3070_rf_write(sc, 23, rf); 4213205042Sthompsa 4214205042Sthompsa /* program RF filter */ 4215205042Sthompsa rf = sc->rf24_20mhz; 4216205042Sthompsa run_rt3070_rf_write(sc, 24, rf); /* Tx */ 4217205042Sthompsa run_rt3070_rf_write(sc, 31, rf); /* Rx */ 4218205042Sthompsa 4219205042Sthompsa /* enable RF tuning */ 4220205042Sthompsa run_rt3070_rf_read(sc, 7, &rf); 4221205042Sthompsa rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14); 4222205042Sthompsa run_rt3070_rf_write(sc, 7, rf); 4223205042Sthompsa 4224205042Sthompsa /* TSSI */ 4225205042Sthompsa rf = (chan <= 14) ? 0xc3 : 0xc0; 4226205042Sthompsa run_rt3070_rf_write(sc, 9, rf); 4227205042Sthompsa 4228205042Sthompsa /* set loop filter 1 */ 4229205042Sthompsa run_rt3070_rf_write(sc, 10, 0xf1); 4230205042Sthompsa /* set loop filter 2 */ 4231205042Sthompsa run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00); 4232205042Sthompsa 4233205042Sthompsa /* set tx_mx2_ic */ 4234205042Sthompsa run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43); 4235205042Sthompsa /* set tx_mx1_ic */ 4236205042Sthompsa if (chan <= 14) 4237205042Sthompsa rf = 0x48 | sc->txmixgain_2ghz; 4238205042Sthompsa else 4239205042Sthompsa rf = 0x78 | sc->txmixgain_5ghz; 4240205042Sthompsa run_rt3070_rf_write(sc, 16, rf); 4241205042Sthompsa 4242205042Sthompsa /* set tx_lo1 */ 4243205042Sthompsa run_rt3070_rf_write(sc, 17, 0x23); 4244205042Sthompsa /* set tx_lo2 */ 4245205042Sthompsa if (chan <= 14) 4246205042Sthompsa rf = 0x93; 4247205042Sthompsa else if (chan <= 64) 4248205042Sthompsa rf = 0xb7; 4249205042Sthompsa else if (chan <= 128) 4250205042Sthompsa rf = 0x74; 4251205042Sthompsa else 4252205042Sthompsa rf = 0x72; 4253205042Sthompsa run_rt3070_rf_write(sc, 19, rf); 4254205042Sthompsa 4255205042Sthompsa /* set rx_lo1 */ 4256205042Sthompsa if (chan <= 14) 4257205042Sthompsa rf = 0xb3; 4258205042Sthompsa else if (chan <= 64) 4259205042Sthompsa rf = 0xf6; 4260205042Sthompsa else if (chan <= 128) 4261205042Sthompsa rf = 0xf4; 4262205042Sthompsa else 4263205042Sthompsa rf = 0xf3; 4264205042Sthompsa run_rt3070_rf_write(sc, 20, rf); 4265205042Sthompsa 4266205042Sthompsa /* set pfd_delay */ 4267205042Sthompsa if (chan <= 14) 4268205042Sthompsa rf = 0x15; 4269205042Sthompsa else if (chan <= 64) 4270205042Sthompsa rf = 0x3d; 4271205042Sthompsa else 4272205042Sthompsa rf = 0x01; 4273205042Sthompsa run_rt3070_rf_write(sc, 25, rf); 4274205042Sthompsa 4275205042Sthompsa /* set rx_lo2 */ 4276205042Sthompsa run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87); 4277205042Sthompsa /* set ldo_rf_vc */ 4278205042Sthompsa run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01); 4279205042Sthompsa /* set drv_cc */ 4280205042Sthompsa run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f); 4281205042Sthompsa 4282205042Sthompsa run_read(sc, RT2860_GPIO_CTRL, &tmp); 4283205042Sthompsa tmp &= ~0x8080; 4284205042Sthompsa if (chan <= 14) 4285205042Sthompsa tmp |= 0x80; 4286205042Sthompsa run_write(sc, RT2860_GPIO_CTRL, tmp); 4287205042Sthompsa 4288205042Sthompsa /* enable RF tuning */ 4289205042Sthompsa run_rt3070_rf_read(sc, 7, &rf); 4290205042Sthompsa run_rt3070_rf_write(sc, 7, rf | 0x01); 4291205042Sthompsa 4292205042Sthompsa run_delay(sc, 2); 4293205042Sthompsa} 4294205042Sthompsa 4295205042Sthompsastatic void 4296260219Skevlorun_rt3593_set_chan(struct run_softc *sc, u_int chan) 4297260219Skevlo{ 4298260219Skevlo int8_t txpow1, txpow2, txpow3; 4299260219Skevlo uint8_t h20mhz, rf; 4300260219Skevlo int i; 4301260219Skevlo 4302260219Skevlo /* find the settings for this channel (we know it exists) */ 4303260219Skevlo for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4304260219Skevlo 4305260219Skevlo /* use Tx power values from EEPROM */ 4306260219Skevlo txpow1 = sc->txpow1[i]; 4307260219Skevlo txpow2 = sc->txpow2[i]; 4308260219Skevlo txpow3 = (sc->ntxchains == 3) ? sc->txpow3[i] : 0; 4309260219Skevlo 4310260219Skevlo if (chan <= 14) { 4311260219Skevlo run_bbp_write(sc, 25, sc->bbp25); 4312260219Skevlo run_bbp_write(sc, 26, sc->bbp26); 4313260219Skevlo } else { 4314260219Skevlo /* Enable IQ phase correction. */ 4315260219Skevlo run_bbp_write(sc, 25, 0x09); 4316260219Skevlo run_bbp_write(sc, 26, 0xff); 4317260219Skevlo } 4318260219Skevlo 4319260219Skevlo run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n); 4320260219Skevlo run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f); 4321260219Skevlo run_rt3070_rf_read(sc, 11, &rf); 4322260219Skevlo rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03); 4323260219Skevlo run_rt3070_rf_write(sc, 11, rf); 4324260219Skevlo 4325260219Skevlo /* Set pll_idoh. */ 4326260219Skevlo run_rt3070_rf_read(sc, 11, &rf); 4327260219Skevlo rf &= ~0x4c; 4328260219Skevlo rf |= (chan <= 14) ? 0x44 : 0x48; 4329260219Skevlo run_rt3070_rf_write(sc, 11, rf); 4330260219Skevlo 4331260219Skevlo if (chan <= 14) 4332260219Skevlo rf = txpow1 & 0x1f; 4333260219Skevlo else 4334260219Skevlo rf = 0x40 | ((txpow1 & 0x18) << 1) | (txpow1 & 0x07); 4335260219Skevlo run_rt3070_rf_write(sc, 53, rf); 4336260219Skevlo 4337260219Skevlo if (chan <= 14) 4338260219Skevlo rf = txpow2 & 0x1f; 4339260219Skevlo else 4340260219Skevlo rf = 0x40 | ((txpow2 & 0x18) << 1) | (txpow2 & 0x07); 4341260219Skevlo run_rt3070_rf_write(sc, 55, rf); 4342260219Skevlo 4343260219Skevlo if (chan <= 14) 4344260219Skevlo rf = txpow3 & 0x1f; 4345260219Skevlo else 4346260219Skevlo rf = 0x40 | ((txpow3 & 0x18) << 1) | (txpow3 & 0x07); 4347260219Skevlo run_rt3070_rf_write(sc, 54, rf); 4348260219Skevlo 4349260219Skevlo rf = RT3070_RF_BLOCK | RT3070_PLL_PD; 4350260219Skevlo if (sc->ntxchains == 3) 4351260219Skevlo rf |= RT3070_TX0_PD | RT3070_TX1_PD | RT3070_TX2_PD; 4352260219Skevlo else 4353260219Skevlo rf |= RT3070_TX0_PD | RT3070_TX1_PD; 4354260219Skevlo rf |= RT3070_RX0_PD | RT3070_RX1_PD | RT3070_RX2_PD; 4355260219Skevlo run_rt3070_rf_write(sc, 1, rf); 4356260219Skevlo 4357260219Skevlo run_adjust_freq_offset(sc); 4358260219Skevlo 4359260219Skevlo run_rt3070_rf_write(sc, 31, (chan <= 14) ? 0xa0 : 0x80); 4360260219Skevlo 4361260219Skevlo h20mhz = (sc->rf24_20mhz & 0x20) >> 5; 4362260219Skevlo run_rt3070_rf_read(sc, 30, &rf); 4363260219Skevlo rf = (rf & ~0x06) | (h20mhz << 1) | (h20mhz << 2); 4364260219Skevlo run_rt3070_rf_write(sc, 30, rf); 4365260219Skevlo 4366260219Skevlo run_rt3070_rf_read(sc, 36, &rf); 4367260219Skevlo if (chan <= 14) 4368260219Skevlo rf |= 0x80; 4369260219Skevlo else 4370260219Skevlo rf &= ~0x80; 4371260219Skevlo run_rt3070_rf_write(sc, 36, rf); 4372260219Skevlo 4373260219Skevlo /* Set vcolo_bs. */ 4374260219Skevlo run_rt3070_rf_write(sc, 34, (chan <= 14) ? 0x3c : 0x20); 4375260219Skevlo /* Set pfd_delay. */ 4376260219Skevlo run_rt3070_rf_write(sc, 12, (chan <= 14) ? 0x1a : 0x12); 4377260219Skevlo 4378260219Skevlo /* Set vco bias current control. */ 4379260219Skevlo run_rt3070_rf_read(sc, 6, &rf); 4380260219Skevlo rf &= ~0xc0; 4381260219Skevlo if (chan <= 14) 4382260219Skevlo rf |= 0x40; 4383260219Skevlo else if (chan <= 128) 4384260219Skevlo rf |= 0x80; 4385260219Skevlo else 4386260219Skevlo rf |= 0x40; 4387260219Skevlo run_rt3070_rf_write(sc, 6, rf); 4388260219Skevlo 4389260219Skevlo run_rt3070_rf_read(sc, 30, &rf); 4390260219Skevlo rf = (rf & ~0x18) | 0x10; 4391260219Skevlo run_rt3070_rf_write(sc, 30, rf); 4392260219Skevlo 4393260219Skevlo run_rt3070_rf_write(sc, 10, (chan <= 14) ? 0xd3 : 0xd8); 4394260219Skevlo run_rt3070_rf_write(sc, 13, (chan <= 14) ? 0x12 : 0x23); 4395260219Skevlo 4396260219Skevlo run_rt3070_rf_read(sc, 51, &rf); 4397260219Skevlo rf = (rf & ~0x03) | 0x01; 4398260219Skevlo run_rt3070_rf_write(sc, 51, rf); 4399260219Skevlo /* Set tx_mx1_cc. */ 4400260219Skevlo run_rt3070_rf_read(sc, 51, &rf); 4401260219Skevlo rf &= ~0x1c; 4402260219Skevlo rf |= (chan <= 14) ? 0x14 : 0x10; 4403260219Skevlo run_rt3070_rf_write(sc, 51, rf); 4404260219Skevlo /* Set tx_mx1_ic. */ 4405260219Skevlo run_rt3070_rf_read(sc, 51, &rf); 4406260219Skevlo rf &= ~0xe0; 4407260219Skevlo rf |= (chan <= 14) ? 0x60 : 0x40; 4408260219Skevlo run_rt3070_rf_write(sc, 51, rf); 4409260219Skevlo /* Set tx_lo1_ic. */ 4410260219Skevlo run_rt3070_rf_read(sc, 49, &rf); 4411260219Skevlo rf &= ~0x1c; 4412260219Skevlo rf |= (chan <= 14) ? 0x0c : 0x08; 4413260219Skevlo run_rt3070_rf_write(sc, 49, rf); 4414260219Skevlo /* Set tx_lo1_en. */ 4415260219Skevlo run_rt3070_rf_read(sc, 50, &rf); 4416260219Skevlo run_rt3070_rf_write(sc, 50, rf & ~0x20); 4417260219Skevlo /* Set drv_cc. */ 4418260219Skevlo run_rt3070_rf_read(sc, 57, &rf); 4419260219Skevlo rf &= ~0xfc; 4420260219Skevlo rf |= (chan <= 14) ? 0x6c : 0x3c; 4421260219Skevlo run_rt3070_rf_write(sc, 57, rf); 4422260219Skevlo /* Set rx_mix1_ic, rxa_lnactr, lna_vc, lna_inbias_en and lna_en. */ 4423260219Skevlo run_rt3070_rf_write(sc, 44, (chan <= 14) ? 0x93 : 0x9b); 4424260219Skevlo /* Set drv_gnd_a, tx_vga_cc_a and tx_mx2_gain. */ 4425260219Skevlo run_rt3070_rf_write(sc, 52, (chan <= 14) ? 0x45 : 0x05); 4426260219Skevlo /* Enable VCO calibration. */ 4427260219Skevlo run_rt3070_rf_read(sc, 3, &rf); 4428260219Skevlo rf &= ~RT5390_VCOCAL; 4429260219Skevlo rf |= (chan <= 14) ? RT5390_VCOCAL : 0xbe; 4430260219Skevlo run_rt3070_rf_write(sc, 3, rf); 4431260219Skevlo 4432260219Skevlo if (chan <= 14) 4433260219Skevlo rf = 0x23; 4434260219Skevlo else if (chan <= 64) 4435260219Skevlo rf = 0x36; 4436260219Skevlo else if (chan <= 128) 4437260219Skevlo rf = 0x32; 4438260219Skevlo else 4439260219Skevlo rf = 0x30; 4440260219Skevlo run_rt3070_rf_write(sc, 39, rf); 4441260219Skevlo if (chan <= 14) 4442260219Skevlo rf = 0xbb; 4443260219Skevlo else if (chan <= 64) 4444260219Skevlo rf = 0xeb; 4445260219Skevlo else if (chan <= 128) 4446260219Skevlo rf = 0xb3; 4447260219Skevlo else 4448260219Skevlo rf = 0x9b; 4449260219Skevlo run_rt3070_rf_write(sc, 45, rf); 4450260219Skevlo 4451260219Skevlo /* Set FEQ/AEQ control. */ 4452260219Skevlo run_bbp_write(sc, 105, 0x34); 4453260219Skevlo} 4454260219Skevlo 4455260219Skevlostatic void 4456257955Skevlorun_rt5390_set_chan(struct run_softc *sc, u_int chan) 4457257955Skevlo{ 4458257955Skevlo int8_t txpow1, txpow2; 4459257955Skevlo uint8_t rf; 4460257955Skevlo int i; 4461257955Skevlo 4462257955Skevlo /* find the settings for this channel (we know it exists) */ 4463257955Skevlo for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4464257955Skevlo 4465257955Skevlo /* use Tx power values from EEPROM */ 4466257955Skevlo txpow1 = sc->txpow1[i]; 4467257955Skevlo txpow2 = sc->txpow2[i]; 4468257955Skevlo 4469257955Skevlo run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n); 4470257955Skevlo run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f); 4471257955Skevlo run_rt3070_rf_read(sc, 11, &rf); 4472257955Skevlo rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03); 4473257955Skevlo run_rt3070_rf_write(sc, 11, rf); 4474257955Skevlo 4475257955Skevlo run_rt3070_rf_read(sc, 49, &rf); 4476257955Skevlo rf = (rf & ~0x3f) | (txpow1 & 0x3f); 4477257955Skevlo /* The valid range of the RF R49 is 0x00 to 0x27. */ 4478257955Skevlo if ((rf & 0x3f) > 0x27) 4479257955Skevlo rf = (rf & ~0x3f) | 0x27; 4480257955Skevlo run_rt3070_rf_write(sc, 49, rf); 4481257955Skevlo 4482257955Skevlo if (sc->mac_ver == 0x5392) { 4483257955Skevlo run_rt3070_rf_read(sc, 50, &rf); 4484257955Skevlo rf = (rf & ~0x3f) | (txpow2 & 0x3f); 4485257955Skevlo /* The valid range of the RF R50 is 0x00 to 0x27. */ 4486257955Skevlo if ((rf & 0x3f) > 0x27) 4487257955Skevlo rf = (rf & ~0x3f) | 0x27; 4488257955Skevlo run_rt3070_rf_write(sc, 50, rf); 4489257955Skevlo } 4490257955Skevlo 4491257955Skevlo run_rt3070_rf_read(sc, 1, &rf); 4492257955Skevlo rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD; 4493257955Skevlo if (sc->mac_ver == 0x5392) 4494257955Skevlo rf |= RT3070_RX1_PD | RT3070_TX1_PD; 4495257955Skevlo run_rt3070_rf_write(sc, 1, rf); 4496257955Skevlo 4497257955Skevlo if (sc->mac_ver != 0x5392) { 4498257955Skevlo run_rt3070_rf_read(sc, 2, &rf); 4499257955Skevlo rf |= 0x80; 4500257955Skevlo run_rt3070_rf_write(sc, 2, rf); 4501257955Skevlo run_delay(sc, 10); 4502257955Skevlo rf &= 0x7f; 4503257955Skevlo run_rt3070_rf_write(sc, 2, rf); 4504257955Skevlo } 4505257955Skevlo 4506257955Skevlo run_adjust_freq_offset(sc); 4507257955Skevlo 4508257955Skevlo if (sc->mac_ver == 0x5392) { 4509257955Skevlo /* Fix for RT5392C. */ 4510257955Skevlo if (sc->mac_rev >= 0x0223) { 4511259030Skevlo if (chan <= 4) 4512257955Skevlo rf = 0x0f; 4513259030Skevlo else if (chan >= 5 && chan <= 7) 4514257955Skevlo rf = 0x0e; 4515259030Skevlo else 4516257955Skevlo rf = 0x0d; 4517257955Skevlo run_rt3070_rf_write(sc, 23, rf); 4518257955Skevlo 4519259030Skevlo if (chan <= 4) 4520257955Skevlo rf = 0x0c; 4521257955Skevlo else if (chan == 5) 4522257955Skevlo rf = 0x0b; 4523259030Skevlo else if (chan >= 6 && chan <= 7) 4524257955Skevlo rf = 0x0a; 4525259030Skevlo else if (chan >= 8 && chan <= 10) 4526257955Skevlo rf = 0x09; 4527259030Skevlo else 4528257955Skevlo rf = 0x08; 4529257955Skevlo run_rt3070_rf_write(sc, 59, rf); 4530257955Skevlo } else { 4531259030Skevlo if (chan <= 11) 4532257955Skevlo rf = 0x0f; 4533259030Skevlo else 4534257955Skevlo rf = 0x0b; 4535257955Skevlo run_rt3070_rf_write(sc, 59, rf); 4536257955Skevlo } 4537257955Skevlo } else { 4538257955Skevlo /* Fix for RT5390F. */ 4539257955Skevlo if (sc->mac_rev >= 0x0502) { 4540259030Skevlo if (chan <= 11) 4541257955Skevlo rf = 0x43; 4542259030Skevlo else 4543257955Skevlo rf = 0x23; 4544257955Skevlo run_rt3070_rf_write(sc, 55, rf); 4545257955Skevlo 4546259030Skevlo if (chan <= 11) 4547257955Skevlo rf = 0x0f; 4548257955Skevlo else if (chan == 12) 4549257955Skevlo rf = 0x0d; 4550259030Skevlo else 4551257955Skevlo rf = 0x0b; 4552257955Skevlo run_rt3070_rf_write(sc, 59, rf); 4553257955Skevlo } else { 4554257955Skevlo run_rt3070_rf_write(sc, 55, 0x44); 4555257955Skevlo run_rt3070_rf_write(sc, 59, 0x8f); 4556257955Skevlo } 4557257955Skevlo } 4558257955Skevlo 4559257955Skevlo /* Enable VCO calibration. */ 4560257955Skevlo run_rt3070_rf_read(sc, 3, &rf); 4561257955Skevlo rf |= RT5390_VCOCAL; 4562257955Skevlo run_rt3070_rf_write(sc, 3, rf); 4563257955Skevlo} 4564257955Skevlo 4565257955Skevlostatic void 4566259032Skevlorun_rt5592_set_chan(struct run_softc *sc, u_int chan) 4567259032Skevlo{ 4568259032Skevlo const struct rt5592_freqs *freqs; 4569259032Skevlo uint32_t tmp; 4570259032Skevlo uint8_t reg, rf, txpow_bound; 4571259032Skevlo int8_t txpow1, txpow2; 4572259032Skevlo int i; 4573259032Skevlo 4574259032Skevlo run_read(sc, RT5592_DEBUG_INDEX, &tmp); 4575259032Skevlo freqs = (tmp & RT5592_SEL_XTAL) ? 4576259032Skevlo rt5592_freqs_40mhz : rt5592_freqs_20mhz; 4577259032Skevlo 4578259032Skevlo /* find the settings for this channel (we know it exists) */ 4579259032Skevlo for (i = 0; rt2860_rf2850[i].chan != chan; i++, freqs++); 4580259032Skevlo 4581259032Skevlo /* use Tx power values from EEPROM */ 4582259032Skevlo txpow1 = sc->txpow1[i]; 4583259032Skevlo txpow2 = sc->txpow2[i]; 4584259032Skevlo 4585259032Skevlo run_read(sc, RT3070_LDO_CFG0, &tmp); 4586259032Skevlo tmp &= ~0x1c000000; 4587259032Skevlo if (chan > 14) 4588259032Skevlo tmp |= 0x14000000; 4589259032Skevlo run_write(sc, RT3070_LDO_CFG0, tmp); 4590259032Skevlo 4591259032Skevlo /* N setting. */ 4592259032Skevlo run_rt3070_rf_write(sc, 8, freqs->n & 0xff); 4593259032Skevlo run_rt3070_rf_read(sc, 9, &rf); 4594259032Skevlo rf &= ~(1 << 4); 4595259032Skevlo rf |= ((freqs->n & 0x0100) >> 8) << 4; 4596259032Skevlo run_rt3070_rf_write(sc, 9, rf); 4597259032Skevlo 4598259032Skevlo /* K setting. */ 4599259032Skevlo run_rt3070_rf_read(sc, 9, &rf); 4600259032Skevlo rf &= ~0x0f; 4601259032Skevlo rf |= (freqs->k & 0x0f); 4602259032Skevlo run_rt3070_rf_write(sc, 9, rf); 4603259032Skevlo 4604259032Skevlo /* Mode setting. */ 4605259032Skevlo run_rt3070_rf_read(sc, 11, &rf); 4606259032Skevlo rf &= ~0x0c; 4607259032Skevlo rf |= ((freqs->m - 0x8) & 0x3) << 2; 4608259032Skevlo run_rt3070_rf_write(sc, 11, rf); 4609259032Skevlo run_rt3070_rf_read(sc, 9, &rf); 4610259032Skevlo rf &= ~(1 << 7); 4611259032Skevlo rf |= (((freqs->m - 0x8) & 0x4) >> 2) << 7; 4612259032Skevlo run_rt3070_rf_write(sc, 9, rf); 4613259032Skevlo 4614259032Skevlo /* R setting. */ 4615259032Skevlo run_rt3070_rf_read(sc, 11, &rf); 4616259032Skevlo rf &= ~0x03; 4617259032Skevlo rf |= (freqs->r - 0x1); 4618259032Skevlo run_rt3070_rf_write(sc, 11, rf); 4619259032Skevlo 4620259032Skevlo if (chan <= 14) { 4621259032Skevlo /* Initialize RF registers for 2GHZ. */ 4622259032Skevlo for (i = 0; i < nitems(rt5592_2ghz_def_rf); i++) { 4623259032Skevlo run_rt3070_rf_write(sc, rt5592_2ghz_def_rf[i].reg, 4624259032Skevlo rt5592_2ghz_def_rf[i].val); 4625259032Skevlo } 4626259032Skevlo 4627259032Skevlo rf = (chan <= 10) ? 0x07 : 0x06; 4628259032Skevlo run_rt3070_rf_write(sc, 23, rf); 4629259032Skevlo run_rt3070_rf_write(sc, 59, rf); 4630259032Skevlo 4631259032Skevlo run_rt3070_rf_write(sc, 55, 0x43); 4632259032Skevlo 4633259032Skevlo /* 4634259032Skevlo * RF R49/R50 Tx power ALC code. 4635259032Skevlo * G-band bit<7:6>=1:0, bit<5:0> range from 0x0 ~ 0x27. 4636259032Skevlo */ 4637259032Skevlo reg = 2; 4638259032Skevlo txpow_bound = 0x27; 4639259032Skevlo } else { 4640259032Skevlo /* Initialize RF registers for 5GHZ. */ 4641259032Skevlo for (i = 0; i < nitems(rt5592_5ghz_def_rf); i++) { 4642259032Skevlo run_rt3070_rf_write(sc, rt5592_5ghz_def_rf[i].reg, 4643259032Skevlo rt5592_5ghz_def_rf[i].val); 4644259032Skevlo } 4645259032Skevlo for (i = 0; i < nitems(rt5592_chan_5ghz); i++) { 4646259032Skevlo if (chan >= rt5592_chan_5ghz[i].firstchan && 4647259032Skevlo chan <= rt5592_chan_5ghz[i].lastchan) { 4648259032Skevlo run_rt3070_rf_write(sc, rt5592_chan_5ghz[i].reg, 4649259032Skevlo rt5592_chan_5ghz[i].val); 4650259032Skevlo } 4651259032Skevlo } 4652259032Skevlo 4653259032Skevlo /* 4654259032Skevlo * RF R49/R50 Tx power ALC code. 4655259032Skevlo * A-band bit<7:6>=1:1, bit<5:0> range from 0x0 ~ 0x2b. 4656259032Skevlo */ 4657259032Skevlo reg = 3; 4658259032Skevlo txpow_bound = 0x2b; 4659259032Skevlo } 4660259032Skevlo 4661259032Skevlo /* RF R49 ch0 Tx power ALC code. */ 4662259032Skevlo run_rt3070_rf_read(sc, 49, &rf); 4663259032Skevlo rf &= ~0xc0; 4664259032Skevlo rf |= (reg << 6); 4665259032Skevlo rf = (rf & ~0x3f) | (txpow1 & 0x3f); 4666259032Skevlo if ((rf & 0x3f) > txpow_bound) 4667259032Skevlo rf = (rf & ~0x3f) | txpow_bound; 4668259032Skevlo run_rt3070_rf_write(sc, 49, rf); 4669259032Skevlo 4670259032Skevlo /* RF R50 ch1 Tx power ALC code. */ 4671259032Skevlo run_rt3070_rf_read(sc, 50, &rf); 4672259032Skevlo rf &= ~(1 << 7 | 1 << 6); 4673259032Skevlo rf |= (reg << 6); 4674259032Skevlo rf = (rf & ~0x3f) | (txpow2 & 0x3f); 4675259032Skevlo if ((rf & 0x3f) > txpow_bound) 4676259032Skevlo rf = (rf & ~0x3f) | txpow_bound; 4677259032Skevlo run_rt3070_rf_write(sc, 50, rf); 4678259032Skevlo 4679259032Skevlo /* Enable RF_BLOCK, PLL_PD, RX0_PD, and TX0_PD. */ 4680259032Skevlo run_rt3070_rf_read(sc, 1, &rf); 4681259032Skevlo rf |= (RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD); 4682259032Skevlo if (sc->ntxchains > 1) 4683259032Skevlo rf |= RT3070_TX1_PD; 4684259032Skevlo if (sc->nrxchains > 1) 4685259032Skevlo rf |= RT3070_RX1_PD; 4686259032Skevlo run_rt3070_rf_write(sc, 1, rf); 4687259032Skevlo 4688259032Skevlo run_rt3070_rf_write(sc, 6, 0xe4); 4689259032Skevlo 4690259032Skevlo run_rt3070_rf_write(sc, 30, 0x10); 4691259032Skevlo run_rt3070_rf_write(sc, 31, 0x80); 4692259032Skevlo run_rt3070_rf_write(sc, 32, 0x80); 4693259032Skevlo 4694259032Skevlo run_adjust_freq_offset(sc); 4695259032Skevlo 4696259032Skevlo /* Enable VCO calibration. */ 4697259032Skevlo run_rt3070_rf_read(sc, 3, &rf); 4698259032Skevlo rf |= RT5390_VCOCAL; 4699259032Skevlo run_rt3070_rf_write(sc, 3, rf); 4700259032Skevlo} 4701259032Skevlo 4702259032Skevlostatic void 4703203134Sthompsarun_set_rx_antenna(struct run_softc *sc, int aux) 4704203134Sthompsa{ 4705203134Sthompsa uint32_t tmp; 4706257955Skevlo uint8_t bbp152; 4707203134Sthompsa 4708203134Sthompsa if (aux) { 4709257955Skevlo if (sc->rf_rev == RT5390_RF_5370) { 4710257955Skevlo run_bbp_read(sc, 152, &bbp152); 4711257955Skevlo run_bbp_write(sc, 152, bbp152 & ~0x80); 4712259030Skevlo } else { 4713257955Skevlo run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0); 4714257955Skevlo run_read(sc, RT2860_GPIO_CTRL, &tmp); 4715257955Skevlo run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08); 4716257955Skevlo } 4717203134Sthompsa } else { 4718257955Skevlo if (sc->rf_rev == RT5390_RF_5370) { 4719257955Skevlo run_bbp_read(sc, 152, &bbp152); 4720257955Skevlo run_bbp_write(sc, 152, bbp152 | 0x80); 4721259030Skevlo } else { 4722257955Skevlo run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1); 4723257955Skevlo run_read(sc, RT2860_GPIO_CTRL, &tmp); 4724257955Skevlo run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808); 4725257955Skevlo } 4726203134Sthompsa } 4727203134Sthompsa} 4728203134Sthompsa 4729203134Sthompsastatic int 4730203134Sthompsarun_set_chan(struct run_softc *sc, struct ieee80211_channel *c) 4731203134Sthompsa{ 4732287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 4733257429Shselasky u_int chan, group; 4734203134Sthompsa 4735203134Sthompsa chan = ieee80211_chan2ieee(ic, c); 4736203134Sthompsa if (chan == 0 || chan == IEEE80211_CHAN_ANY) 4737209917Sthompsa return (EINVAL); 4738203134Sthompsa 4739259032Skevlo if (sc->mac_ver == 0x5592) 4740259032Skevlo run_rt5592_set_chan(sc, chan); 4741259032Skevlo else if (sc->mac_ver >= 0x5390) 4742257955Skevlo run_rt5390_set_chan(sc, chan); 4743260219Skevlo else if (sc->mac_ver == 0x3593) 4744260219Skevlo run_rt3593_set_chan(sc, chan); 4745257955Skevlo else if (sc->mac_ver == 0x3572) 4746205042Sthompsa run_rt3572_set_chan(sc, chan); 4747205042Sthompsa else if (sc->mac_ver >= 0x3070) 4748203134Sthompsa run_rt3070_set_chan(sc, chan); 4749203134Sthompsa else 4750203134Sthompsa run_rt2870_set_chan(sc, chan); 4751203134Sthompsa 4752203134Sthompsa /* determine channel group */ 4753203134Sthompsa if (chan <= 14) 4754203134Sthompsa group = 0; 4755203134Sthompsa else if (chan <= 64) 4756203134Sthompsa group = 1; 4757203134Sthompsa else if (chan <= 128) 4758203134Sthompsa group = 2; 4759203134Sthompsa else 4760203134Sthompsa group = 3; 4761203134Sthompsa 4762203134Sthompsa /* XXX necessary only when group has changed! */ 4763203134Sthompsa run_select_chan_group(sc, group); 4764203134Sthompsa 4765203134Sthompsa run_delay(sc, 10); 4766203134Sthompsa 4767259545Skevlo /* Perform IQ calibration. */ 4768259544Skevlo if (sc->mac_ver >= 0x5392) 4769259544Skevlo run_iq_calib(sc, chan); 4770259544Skevlo 4771209917Sthompsa return (0); 4772203134Sthompsa} 4773203134Sthompsa 4774203134Sthompsastatic void 4775203134Sthompsarun_set_channel(struct ieee80211com *ic) 4776203134Sthompsa{ 4777286950Sadrian struct run_softc *sc = ic->ic_softc; 4778203134Sthompsa 4779203134Sthompsa RUN_LOCK(sc); 4780203134Sthompsa run_set_chan(sc, ic->ic_curchan); 4781203134Sthompsa RUN_UNLOCK(sc); 4782203134Sthompsa 4783203134Sthompsa return; 4784203134Sthompsa} 4785203134Sthompsa 4786203134Sthompsastatic void 4787203134Sthompsarun_scan_start(struct ieee80211com *ic) 4788203134Sthompsa{ 4789286950Sadrian struct run_softc *sc = ic->ic_softc; 4790203134Sthompsa uint32_t tmp; 4791203134Sthompsa 4792203134Sthompsa RUN_LOCK(sc); 4793203134Sthompsa 4794203134Sthompsa /* abort TSF synchronization */ 4795203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 4796203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, 4797203134Sthompsa tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 4798203134Sthompsa RT2860_TBTT_TIMER_EN)); 4799287197Sglebius run_set_bssid(sc, ieee80211broadcastaddr); 4800203134Sthompsa 4801203134Sthompsa RUN_UNLOCK(sc); 4802203134Sthompsa 4803203134Sthompsa return; 4804203134Sthompsa} 4805203134Sthompsa 4806203134Sthompsastatic void 4807203134Sthompsarun_scan_end(struct ieee80211com *ic) 4808203134Sthompsa{ 4809286950Sadrian struct run_softc *sc = ic->ic_softc; 4810203134Sthompsa 4811203134Sthompsa RUN_LOCK(sc); 4812203134Sthompsa 4813203134Sthompsa run_enable_tsf_sync(sc); 4814203134Sthompsa /* XXX keep local copy */ 4815287197Sglebius run_set_bssid(sc, ic->ic_macaddr); 4816203134Sthompsa 4817203134Sthompsa RUN_UNLOCK(sc); 4818203134Sthompsa 4819203134Sthompsa return; 4820203134Sthompsa} 4821203134Sthompsa 4822208019Sthompsa/* 4823208019Sthompsa * Could be called from ieee80211_node_timeout() 4824208019Sthompsa * (non-sleepable thread) 4825208019Sthompsa */ 4826208019Sthompsastatic void 4827208019Sthompsarun_update_beacon(struct ieee80211vap *vap, int item) 4828203134Sthompsa{ 4829208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 4830288095Sadrian struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; 4831288095Sadrian struct ieee80211_node *ni = vap->iv_bss; 4832286950Sadrian struct run_softc *sc = ic->ic_softc; 4833218492Sbschmidt struct run_vap *rvp = RUN_VAP(vap); 4834218492Sbschmidt int mcast = 0; 4835208019Sthompsa uint32_t i; 4836208019Sthompsa 4837218492Sbschmidt switch (item) { 4838218492Sbschmidt case IEEE80211_BEACON_ERP: 4839283540Sglebius run_updateslot(ic); 4840218492Sbschmidt break; 4841218492Sbschmidt case IEEE80211_BEACON_HTINFO: 4842218492Sbschmidt run_updateprot(ic); 4843218492Sbschmidt break; 4844218492Sbschmidt case IEEE80211_BEACON_TIM: 4845218492Sbschmidt mcast = 1; /*TODO*/ 4846218492Sbschmidt break; 4847218492Sbschmidt default: 4848218492Sbschmidt break; 4849218492Sbschmidt } 4850218492Sbschmidt 4851288095Sadrian setbit(bo->bo_flags, item); 4852273448Skevlo if (rvp->beacon_mbuf == NULL) { 4853288636Sadrian rvp->beacon_mbuf = ieee80211_beacon_alloc(ni); 4854273448Skevlo if (rvp->beacon_mbuf == NULL) 4855273448Skevlo return; 4856273448Skevlo } 4857288636Sadrian ieee80211_beacon_update(ni, 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; 4872288095Sadrian struct ieee80211_node *ni = vap->iv_bss; 4873218492Sbschmidt struct run_vap *rvp = RUN_VAP(vap); 4874203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 4875286950Sadrian struct run_softc *sc = ic->ic_softc; 4876203134Sthompsa struct rt2860_txwi txwi; 4877203134Sthompsa struct mbuf *m; 4878259032Skevlo uint16_t txwisize; 4879208019Sthompsa uint8_t ridx; 4880203134Sthompsa 4881288095Sadrian if (ni->ni_chan == IEEE80211_CHAN_ANYC) 4882208019Sthompsa return; 4883236439Shselasky if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) 4884236439Shselasky return; 4885208019Sthompsa 4886218492Sbschmidt /* 4887218492Sbschmidt * No need to call ieee80211_beacon_update(), run_update_beacon() 4888218492Sbschmidt * is taking care of apropriate calls. 4889218492Sbschmidt */ 4890218492Sbschmidt if (rvp->beacon_mbuf == NULL) { 4891288636Sadrian rvp->beacon_mbuf = ieee80211_beacon_alloc(ni); 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 5070287555Skevlorun_enable_tsf(struct run_softc *sc) 5071287555Skevlo{ 5072287555Skevlo uint32_t tmp; 5073287555Skevlo 5074287555Skevlo if (run_read(sc, RT2860_BCN_TIME_CFG, &tmp) == 0) { 5075287555Skevlo tmp &= ~(RT2860_BCN_TX_EN | RT2860_TBTT_TIMER_EN); 5076287555Skevlo tmp |= RT2860_TSF_TIMER_EN; 5077287555Skevlo run_write(sc, RT2860_BCN_TIME_CFG, tmp); 5078287555Skevlo } 5079287555Skevlo} 5080287555Skevlo 5081287555Skevlostatic void 5082287554Skevlorun_get_tsf(struct run_softc *sc, uint64_t *buf) 5083287554Skevlo{ 5084287554Skevlo run_read_region_1(sc, RT2860_TSF_TIMER_DW0, (uint8_t *)buf, 5085287554Skevlo sizeof(*buf)); 5086287554Skevlo} 5087287554Skevlo 5088287554Skevlostatic void 5089203134Sthompsarun_enable_mrr(struct run_softc *sc) 5090203134Sthompsa{ 5091259546Skevlo#define CCK(mcs) (mcs) 5092259546Skevlo#define OFDM(mcs) (1 << 3 | (mcs)) 5093203134Sthompsa run_write(sc, RT2860_LG_FBK_CFG0, 5094203134Sthompsa OFDM(6) << 28 | /* 54->48 */ 5095203134Sthompsa OFDM(5) << 24 | /* 48->36 */ 5096203134Sthompsa OFDM(4) << 20 | /* 36->24 */ 5097203134Sthompsa OFDM(3) << 16 | /* 24->18 */ 5098203134Sthompsa OFDM(2) << 12 | /* 18->12 */ 5099203134Sthompsa OFDM(1) << 8 | /* 12-> 9 */ 5100203134Sthompsa OFDM(0) << 4 | /* 9-> 6 */ 5101203134Sthompsa OFDM(0)); /* 6-> 6 */ 5102203134Sthompsa 5103203134Sthompsa run_write(sc, RT2860_LG_FBK_CFG1, 5104203134Sthompsa CCK(2) << 12 | /* 11->5.5 */ 5105203134Sthompsa CCK(1) << 8 | /* 5.5-> 2 */ 5106203134Sthompsa CCK(0) << 4 | /* 2-> 1 */ 5107203134Sthompsa CCK(0)); /* 1-> 1 */ 5108203134Sthompsa#undef OFDM 5109203134Sthompsa#undef CCK 5110203134Sthompsa} 5111203134Sthompsa 5112203134Sthompsastatic void 5113203134Sthompsarun_set_txpreamble(struct run_softc *sc) 5114203134Sthompsa{ 5115287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 5116203134Sthompsa uint32_t tmp; 5117203134Sthompsa 5118203134Sthompsa run_read(sc, RT2860_AUTO_RSP_CFG, &tmp); 5119203134Sthompsa if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 5120203134Sthompsa tmp |= RT2860_CCK_SHORT_EN; 5121203134Sthompsa else 5122203134Sthompsa tmp &= ~RT2860_CCK_SHORT_EN; 5123203134Sthompsa run_write(sc, RT2860_AUTO_RSP_CFG, tmp); 5124203134Sthompsa} 5125203134Sthompsa 5126203134Sthompsastatic void 5127203134Sthompsarun_set_basicrates(struct run_softc *sc) 5128203134Sthompsa{ 5129287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 5130203134Sthompsa 5131203134Sthompsa /* set basic rates mask */ 5132203134Sthompsa if (ic->ic_curmode == IEEE80211_MODE_11B) 5133203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003); 5134203134Sthompsa else if (ic->ic_curmode == IEEE80211_MODE_11A) 5135203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150); 5136203134Sthompsa else /* 11g */ 5137203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f); 5138203134Sthompsa} 5139203134Sthompsa 5140203134Sthompsastatic void 5141203134Sthompsarun_set_leds(struct run_softc *sc, uint16_t which) 5142203134Sthompsa{ 5143203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS, 5144203134Sthompsa which | (sc->leds & 0x7f)); 5145203134Sthompsa} 5146203134Sthompsa 5147203134Sthompsastatic void 5148203134Sthompsarun_set_bssid(struct run_softc *sc, const uint8_t *bssid) 5149203134Sthompsa{ 5150203134Sthompsa run_write(sc, RT2860_MAC_BSSID_DW0, 5151203134Sthompsa bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24); 5152203134Sthompsa run_write(sc, RT2860_MAC_BSSID_DW1, 5153203134Sthompsa bssid[4] | bssid[5] << 8); 5154203134Sthompsa} 5155203134Sthompsa 5156203134Sthompsastatic void 5157203134Sthompsarun_set_macaddr(struct run_softc *sc, const uint8_t *addr) 5158203134Sthompsa{ 5159203134Sthompsa run_write(sc, RT2860_MAC_ADDR_DW0, 5160203134Sthompsa addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24); 5161203134Sthompsa run_write(sc, RT2860_MAC_ADDR_DW1, 5162203134Sthompsa addr[4] | addr[5] << 8 | 0xff << 16); 5163203134Sthompsa} 5164203134Sthompsa 5165203134Sthompsastatic void 5166283540Sglebiusrun_updateslot(struct ieee80211com *ic) 5167203134Sthompsa{ 5168283540Sglebius struct run_softc *sc = ic->ic_softc; 5169218492Sbschmidt uint32_t i; 5170218492Sbschmidt 5171218492Sbschmidt i = RUN_CMDQ_GET(&sc->cmdq_store); 5172218492Sbschmidt DPRINTF("cmdq_store=%d\n", i); 5173218492Sbschmidt sc->cmdq[i].func = run_updateslot_cb; 5174287197Sglebius sc->cmdq[i].arg0 = ic; 5175218492Sbschmidt ieee80211_runtask(ic, &sc->cmdq_task); 5176218492Sbschmidt 5177218492Sbschmidt return; 5178218492Sbschmidt} 5179218492Sbschmidt 5180218492Sbschmidt/* ARGSUSED */ 5181218492Sbschmidtstatic void 5182218492Sbschmidtrun_updateslot_cb(void *arg) 5183218492Sbschmidt{ 5184287197Sglebius struct ieee80211com *ic = arg; 5185286950Sadrian struct run_softc *sc = ic->ic_softc; 5186203134Sthompsa uint32_t tmp; 5187203134Sthompsa 5188203134Sthompsa run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp); 5189203134Sthompsa tmp &= ~0xff; 5190292165Savos tmp |= IEEE80211_GET_SLOTTIME(ic); 5191203134Sthompsa run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp); 5192203134Sthompsa} 5193203134Sthompsa 5194208019Sthompsastatic void 5195283540Sglebiusrun_update_mcast(struct ieee80211com *ic) 5196208019Sthompsa{ 5197208019Sthompsa} 5198208019Sthompsa 5199203134Sthompsastatic int8_t 5200203134Sthompsarun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain) 5201203134Sthompsa{ 5202287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 5203203134Sthompsa struct ieee80211_channel *c = ic->ic_curchan; 5204203134Sthompsa int delta; 5205203134Sthompsa 5206203134Sthompsa if (IEEE80211_IS_CHAN_5GHZ(c)) { 5207257429Shselasky u_int chan = ieee80211_chan2ieee(ic, c); 5208203134Sthompsa delta = sc->rssi_5ghz[rxchain]; 5209203134Sthompsa 5210203134Sthompsa /* determine channel group */ 5211203134Sthompsa if (chan <= 64) 5212203134Sthompsa delta -= sc->lna[1]; 5213203134Sthompsa else if (chan <= 128) 5214203134Sthompsa delta -= sc->lna[2]; 5215203134Sthompsa else 5216203134Sthompsa delta -= sc->lna[3]; 5217203134Sthompsa } else 5218203134Sthompsa delta = sc->rssi_2ghz[rxchain] - sc->lna[0]; 5219203134Sthompsa 5220209917Sthompsa return (-12 - delta - rssi); 5221203134Sthompsa} 5222203134Sthompsa 5223257955Skevlostatic void 5224257955Skevlorun_rt5390_bbp_init(struct run_softc *sc) 5225257955Skevlo{ 5226257955Skevlo int i; 5227259032Skevlo uint8_t bbp; 5228257955Skevlo 5229259032Skevlo /* Apply maximum likelihood detection for 2 stream case. */ 5230259032Skevlo run_bbp_read(sc, 105, &bbp); 5231259032Skevlo if (sc->nrxchains > 1) 5232259032Skevlo run_bbp_write(sc, 105, bbp | RT5390_MLD); 5233259032Skevlo 5234257955Skevlo /* Avoid data lost and CRC error. */ 5235259032Skevlo run_bbp_read(sc, 4, &bbp); 5236259031Skevlo run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 5237257955Skevlo 5238259032Skevlo if (sc->mac_ver == 0x5592) { 5239259032Skevlo for (i = 0; i < nitems(rt5592_def_bbp); i++) { 5240259032Skevlo run_bbp_write(sc, rt5592_def_bbp[i].reg, 5241259032Skevlo rt5592_def_bbp[i].val); 5242259032Skevlo } 5243259032Skevlo for (i = 0; i < nitems(rt5592_bbp_r196); i++) { 5244259032Skevlo run_bbp_write(sc, 195, i + 0x80); 5245259032Skevlo run_bbp_write(sc, 196, rt5592_bbp_r196[i]); 5246259032Skevlo } 5247259032Skevlo } else { 5248259032Skevlo for (i = 0; i < nitems(rt5390_def_bbp); i++) { 5249259032Skevlo run_bbp_write(sc, rt5390_def_bbp[i].reg, 5250259032Skevlo rt5390_def_bbp[i].val); 5251259032Skevlo } 5252257955Skevlo } 5253257955Skevlo if (sc->mac_ver == 0x5392) { 5254257955Skevlo run_bbp_write(sc, 88, 0x90); 5255257955Skevlo run_bbp_write(sc, 95, 0x9a); 5256257955Skevlo run_bbp_write(sc, 98, 0x12); 5257257955Skevlo run_bbp_write(sc, 106, 0x12); 5258257955Skevlo run_bbp_write(sc, 134, 0xd0); 5259257955Skevlo run_bbp_write(sc, 135, 0xf6); 5260257955Skevlo run_bbp_write(sc, 148, 0x84); 5261257955Skevlo } 5262257955Skevlo 5263259032Skevlo run_bbp_read(sc, 152, &bbp); 5264259032Skevlo run_bbp_write(sc, 152, bbp | 0x80); 5265259032Skevlo 5266259032Skevlo /* Fix BBP254 for RT5592C. */ 5267259032Skevlo if (sc->mac_ver == 0x5592 && sc->mac_rev >= 0x0221) { 5268259032Skevlo run_bbp_read(sc, 254, &bbp); 5269259032Skevlo run_bbp_write(sc, 254, bbp | 0x80); 5270259032Skevlo } 5271259032Skevlo 5272257955Skevlo /* Disable hardware antenna diversity. */ 5273257955Skevlo if (sc->mac_ver == 0x5390) 5274257955Skevlo run_bbp_write(sc, 154, 0); 5275259032Skevlo 5276259032Skevlo /* Initialize Rx CCK/OFDM frequency offset report. */ 5277259032Skevlo run_bbp_write(sc, 142, 1); 5278259032Skevlo run_bbp_write(sc, 143, 57); 5279257955Skevlo} 5280257955Skevlo 5281203134Sthompsastatic int 5282203134Sthompsarun_bbp_init(struct run_softc *sc) 5283203134Sthompsa{ 5284203134Sthompsa int i, error, ntries; 5285203134Sthompsa uint8_t bbp0; 5286203134Sthompsa 5287203134Sthompsa /* wait for BBP to wake up */ 5288203134Sthompsa for (ntries = 0; ntries < 20; ntries++) { 5289203134Sthompsa if ((error = run_bbp_read(sc, 0, &bbp0)) != 0) 5290203134Sthompsa return error; 5291203134Sthompsa if (bbp0 != 0 && bbp0 != 0xff) 5292203134Sthompsa break; 5293203134Sthompsa } 5294203134Sthompsa if (ntries == 20) 5295209917Sthompsa return (ETIMEDOUT); 5296203134Sthompsa 5297203134Sthompsa /* initialize BBP registers to default values */ 5298257955Skevlo if (sc->mac_ver >= 0x5390) 5299257955Skevlo run_rt5390_bbp_init(sc); 5300257955Skevlo else { 5301257955Skevlo for (i = 0; i < nitems(rt2860_def_bbp); i++) { 5302257955Skevlo run_bbp_write(sc, rt2860_def_bbp[i].reg, 5303257955Skevlo rt2860_def_bbp[i].val); 5304257955Skevlo } 5305203134Sthompsa } 5306203134Sthompsa 5307260219Skevlo if (sc->mac_ver == 0x3593) { 5308260219Skevlo run_bbp_write(sc, 79, 0x13); 5309260219Skevlo run_bbp_write(sc, 80, 0x05); 5310260219Skevlo run_bbp_write(sc, 81, 0x33); 5311260219Skevlo run_bbp_write(sc, 86, 0x46); 5312260219Skevlo run_bbp_write(sc, 137, 0x0f); 5313260219Skevlo } 5314260219Skevlo 5315203134Sthompsa /* fix BBP84 for RT2860E */ 5316205042Sthompsa if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101) 5317205042Sthompsa run_bbp_write(sc, 84, 0x19); 5318203134Sthompsa 5319260219Skevlo if (sc->mac_ver >= 0x3070 && (sc->mac_ver != 0x3593 && 5320260219Skevlo sc->mac_ver != 0x5592)) { 5321203134Sthompsa run_bbp_write(sc, 79, 0x13); 5322203134Sthompsa run_bbp_write(sc, 80, 0x05); 5323203134Sthompsa run_bbp_write(sc, 81, 0x33); 5324205042Sthompsa } else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) { 5325203134Sthompsa run_bbp_write(sc, 69, 0x16); 5326203134Sthompsa run_bbp_write(sc, 73, 0x12); 5327203134Sthompsa } 5328209917Sthompsa return (0); 5329203134Sthompsa} 5330203134Sthompsa 5331203134Sthompsastatic int 5332203134Sthompsarun_rt3070_rf_init(struct run_softc *sc) 5333203134Sthompsa{ 5334203134Sthompsa uint32_t tmp; 5335256722Skevlo uint8_t bbp4, mingain, rf, target; 5336203134Sthompsa int i; 5337203134Sthompsa 5338203134Sthompsa run_rt3070_rf_read(sc, 30, &rf); 5339203134Sthompsa /* toggle RF R30 bit 7 */ 5340203134Sthompsa run_rt3070_rf_write(sc, 30, rf | 0x80); 5341203134Sthompsa run_delay(sc, 10); 5342203134Sthompsa run_rt3070_rf_write(sc, 30, rf & ~0x80); 5343203134Sthompsa 5344203134Sthompsa /* initialize RF registers to default value */ 5345205042Sthompsa if (sc->mac_ver == 0x3572) { 5346257955Skevlo for (i = 0; i < nitems(rt3572_def_rf); i++) { 5347205042Sthompsa run_rt3070_rf_write(sc, rt3572_def_rf[i].reg, 5348205042Sthompsa rt3572_def_rf[i].val); 5349205042Sthompsa } 5350205042Sthompsa } else { 5351257955Skevlo for (i = 0; i < nitems(rt3070_def_rf); i++) { 5352205042Sthompsa run_rt3070_rf_write(sc, rt3070_def_rf[i].reg, 5353205042Sthompsa rt3070_def_rf[i].val); 5354205042Sthompsa } 5355203134Sthompsa } 5356205042Sthompsa 5357256721Skevlo if (sc->mac_ver == 0x3070 && sc->mac_rev < 0x0201) { 5358256721Skevlo /* 5359256721Skevlo * Change voltage from 1.2V to 1.35V for RT3070. 5360256721Skevlo * The DAC issue (RT3070_LDO_CFG0) has been fixed 5361256721Skevlo * in RT3070(F). 5362256721Skevlo */ 5363203134Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 5364203134Sthompsa tmp = (tmp & ~0x0f000000) | 0x0d000000; 5365203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5366203134Sthompsa 5367205042Sthompsa } else if (sc->mac_ver == 0x3071) { 5368203134Sthompsa run_rt3070_rf_read(sc, 6, &rf); 5369203134Sthompsa run_rt3070_rf_write(sc, 6, rf | 0x40); 5370203134Sthompsa run_rt3070_rf_write(sc, 31, 0x14); 5371203134Sthompsa 5372203134Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 5373203134Sthompsa tmp &= ~0x1f000000; 5374205042Sthompsa if (sc->mac_rev < 0x0211) 5375205042Sthompsa tmp |= 0x0d000000; /* 1.3V */ 5376203134Sthompsa else 5377205042Sthompsa tmp |= 0x01000000; /* 1.2V */ 5378203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5379203134Sthompsa 5380203134Sthompsa /* patch LNA_PE_G1 */ 5381203134Sthompsa run_read(sc, RT3070_GPIO_SWITCH, &tmp); 5382203134Sthompsa run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20); 5383208019Sthompsa 5384209917Sthompsa } else if (sc->mac_ver == 0x3572) { 5385205042Sthompsa run_rt3070_rf_read(sc, 6, &rf); 5386205042Sthompsa run_rt3070_rf_write(sc, 6, rf | 0x40); 5387205042Sthompsa 5388208019Sthompsa /* increase voltage from 1.2V to 1.35V */ 5389208019Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 5390208019Sthompsa tmp = (tmp & ~0x1f000000) | 0x0d000000; 5391208019Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5392203134Sthompsa 5393209917Sthompsa if (sc->mac_rev < 0x0211 || !sc->patch_dac) { 5394203134Sthompsa run_delay(sc, 1); /* wait for 1msec */ 5395205042Sthompsa /* decrease voltage back to 1.2V */ 5396203134Sthompsa tmp = (tmp & ~0x1f000000) | 0x01000000; 5397203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5398203134Sthompsa } 5399203134Sthompsa } 5400203134Sthompsa 5401203134Sthompsa /* select 20MHz bandwidth */ 5402203134Sthompsa run_rt3070_rf_read(sc, 31, &rf); 5403203134Sthompsa run_rt3070_rf_write(sc, 31, rf & ~0x20); 5404203134Sthompsa 5405203134Sthompsa /* calibrate filter for 20MHz bandwidth */ 5406203134Sthompsa sc->rf24_20mhz = 0x1f; /* default value */ 5407205042Sthompsa target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13; 5408205042Sthompsa run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz); 5409203134Sthompsa 5410203134Sthompsa /* select 40MHz bandwidth */ 5411203134Sthompsa run_bbp_read(sc, 4, &bbp4); 5412256721Skevlo run_bbp_write(sc, 4, (bbp4 & ~0x18) | 0x10); 5413205042Sthompsa run_rt3070_rf_read(sc, 31, &rf); 5414205042Sthompsa run_rt3070_rf_write(sc, 31, rf | 0x20); 5415203134Sthompsa 5416203134Sthompsa /* calibrate filter for 40MHz bandwidth */ 5417203134Sthompsa sc->rf24_40mhz = 0x2f; /* default value */ 5418205042Sthompsa target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15; 5419205042Sthompsa run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz); 5420203134Sthompsa 5421203134Sthompsa /* go back to 20MHz bandwidth */ 5422203134Sthompsa run_bbp_read(sc, 4, &bbp4); 5423203134Sthompsa run_bbp_write(sc, 4, bbp4 & ~0x18); 5424203134Sthompsa 5425205042Sthompsa if (sc->mac_ver == 0x3572) { 5426205042Sthompsa /* save default BBP registers 25 and 26 values */ 5427205042Sthompsa run_bbp_read(sc, 25, &sc->bbp25); 5428205042Sthompsa run_bbp_read(sc, 26, &sc->bbp26); 5429256721Skevlo } else if (sc->mac_rev < 0x0201 || sc->mac_rev < 0x0211) 5430203134Sthompsa run_rt3070_rf_write(sc, 27, 0x03); 5431203134Sthompsa 5432203134Sthompsa run_read(sc, RT3070_OPT_14, &tmp); 5433203134Sthompsa run_write(sc, RT3070_OPT_14, tmp | 1); 5434203134Sthompsa 5435205042Sthompsa if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) { 5436205042Sthompsa run_rt3070_rf_read(sc, 17, &rf); 5437205042Sthompsa rf &= ~RT3070_TX_LO1; 5438205042Sthompsa if ((sc->mac_ver == 0x3070 || 5439205042Sthompsa (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) && 5440205042Sthompsa !sc->ext_2ghz_lna) 5441205042Sthompsa rf |= 0x20; /* fix for long range Rx issue */ 5442256722Skevlo mingain = (sc->mac_ver == 0x3070) ? 1 : 2; 5443256722Skevlo if (sc->txmixgain_2ghz >= mingain) 5444205042Sthompsa rf = (rf & ~0x7) | sc->txmixgain_2ghz; 5445205042Sthompsa run_rt3070_rf_write(sc, 17, rf); 5446205042Sthompsa } 5447205042Sthompsa 5448270643Skevlo if (sc->mac_ver == 0x3071) { 5449203134Sthompsa run_rt3070_rf_read(sc, 1, &rf); 5450203134Sthompsa rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD); 5451203134Sthompsa rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD; 5452203134Sthompsa run_rt3070_rf_write(sc, 1, rf); 5453203134Sthompsa 5454203134Sthompsa run_rt3070_rf_read(sc, 15, &rf); 5455203134Sthompsa run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2); 5456203134Sthompsa 5457203134Sthompsa run_rt3070_rf_read(sc, 20, &rf); 5458203134Sthompsa run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1); 5459203134Sthompsa 5460203134Sthompsa run_rt3070_rf_read(sc, 21, &rf); 5461203134Sthompsa run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2); 5462205042Sthompsa } 5463203134Sthompsa 5464205042Sthompsa if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) { 5465205042Sthompsa /* fix Tx to Rx IQ glitch by raising RF voltage */ 5466203134Sthompsa run_rt3070_rf_read(sc, 27, &rf); 5467203134Sthompsa rf &= ~0x77; 5468205042Sthompsa if (sc->mac_rev < 0x0211) 5469203134Sthompsa rf |= 0x03; 5470203134Sthompsa run_rt3070_rf_write(sc, 27, rf); 5471203134Sthompsa } 5472209917Sthompsa return (0); 5473203134Sthompsa} 5474203134Sthompsa 5475257955Skevlostatic void 5476260219Skevlorun_rt3593_rf_init(struct run_softc *sc) 5477260219Skevlo{ 5478260219Skevlo uint32_t tmp; 5479260219Skevlo uint8_t rf; 5480260219Skevlo int i; 5481260219Skevlo 5482260219Skevlo /* Disable the GPIO bits 4 and 7 for LNA PE control. */ 5483260219Skevlo run_read(sc, RT3070_GPIO_SWITCH, &tmp); 5484260219Skevlo tmp &= ~(1 << 4 | 1 << 7); 5485260219Skevlo run_write(sc, RT3070_GPIO_SWITCH, tmp); 5486260219Skevlo 5487260219Skevlo /* Initialize RF registers to default value. */ 5488260219Skevlo for (i = 0; i < nitems(rt3593_def_rf); i++) { 5489260219Skevlo run_rt3070_rf_write(sc, rt3593_def_rf[i].reg, 5490260219Skevlo rt3593_def_rf[i].val); 5491260219Skevlo } 5492260219Skevlo 5493260219Skevlo /* Toggle RF R2 to initiate calibration. */ 5494260219Skevlo run_rt3070_rf_write(sc, 2, RT5390_RESCAL); 5495260219Skevlo 5496260219Skevlo /* Initialize RF frequency offset. */ 5497260219Skevlo run_adjust_freq_offset(sc); 5498260219Skevlo 5499260219Skevlo run_rt3070_rf_read(sc, 18, &rf); 5500260219Skevlo run_rt3070_rf_write(sc, 18, rf | RT3593_AUTOTUNE_BYPASS); 5501260219Skevlo 5502260219Skevlo /* 5503260219Skevlo * Increase voltage from 1.2V to 1.35V, wait for 1 msec to 5504260219Skevlo * decrease voltage back to 1.2V. 5505260219Skevlo */ 5506260219Skevlo run_read(sc, RT3070_LDO_CFG0, &tmp); 5507260219Skevlo tmp = (tmp & ~0x1f000000) | 0x0d000000; 5508260219Skevlo run_write(sc, RT3070_LDO_CFG0, tmp); 5509260219Skevlo run_delay(sc, 1); 5510260219Skevlo tmp = (tmp & ~0x1f000000) | 0x01000000; 5511260219Skevlo run_write(sc, RT3070_LDO_CFG0, tmp); 5512260219Skevlo 5513260219Skevlo sc->rf24_20mhz = 0x1f; 5514260219Skevlo sc->rf24_40mhz = 0x2f; 5515260219Skevlo 5516260219Skevlo /* Save default BBP registers 25 and 26 values. */ 5517260219Skevlo run_bbp_read(sc, 25, &sc->bbp25); 5518260219Skevlo run_bbp_read(sc, 26, &sc->bbp26); 5519260219Skevlo 5520260219Skevlo run_read(sc, RT3070_OPT_14, &tmp); 5521260219Skevlo run_write(sc, RT3070_OPT_14, tmp | 1); 5522260219Skevlo} 5523260219Skevlo 5524260219Skevlostatic void 5525257955Skevlorun_rt5390_rf_init(struct run_softc *sc) 5526257955Skevlo{ 5527257955Skevlo uint32_t tmp; 5528257955Skevlo uint8_t rf; 5529257955Skevlo int i; 5530257955Skevlo 5531259030Skevlo /* Toggle RF R2 to initiate calibration. */ 5532259030Skevlo if (sc->mac_ver == 0x5390) { 5533257955Skevlo run_rt3070_rf_read(sc, 2, &rf); 5534259031Skevlo run_rt3070_rf_write(sc, 2, rf | RT5390_RESCAL); 5535257955Skevlo run_delay(sc, 10); 5536259031Skevlo run_rt3070_rf_write(sc, 2, rf & ~RT5390_RESCAL); 5537259030Skevlo } else { 5538259031Skevlo run_rt3070_rf_write(sc, 2, RT5390_RESCAL); 5539259030Skevlo run_delay(sc, 10); 5540257955Skevlo } 5541257955Skevlo 5542257955Skevlo /* Initialize RF registers to default value. */ 5543259032Skevlo if (sc->mac_ver == 0x5592) { 5544259032Skevlo for (i = 0; i < nitems(rt5592_def_rf); i++) { 5545259032Skevlo run_rt3070_rf_write(sc, rt5592_def_rf[i].reg, 5546259032Skevlo rt5592_def_rf[i].val); 5547259032Skevlo } 5548259032Skevlo /* Initialize RF frequency offset. */ 5549259032Skevlo run_adjust_freq_offset(sc); 5550259032Skevlo } else if (sc->mac_ver == 0x5392) { 5551257955Skevlo for (i = 0; i < nitems(rt5392_def_rf); i++) { 5552257955Skevlo run_rt3070_rf_write(sc, rt5392_def_rf[i].reg, 5553257955Skevlo rt5392_def_rf[i].val); 5554257955Skevlo } 5555257955Skevlo if (sc->mac_rev >= 0x0223) { 5556257955Skevlo run_rt3070_rf_write(sc, 23, 0x0f); 5557257955Skevlo run_rt3070_rf_write(sc, 24, 0x3e); 5558257955Skevlo run_rt3070_rf_write(sc, 51, 0x32); 5559257955Skevlo run_rt3070_rf_write(sc, 53, 0x22); 5560257955Skevlo run_rt3070_rf_write(sc, 56, 0xc1); 5561257955Skevlo run_rt3070_rf_write(sc, 59, 0x0f); 5562257955Skevlo } 5563257955Skevlo } else { 5564257955Skevlo for (i = 0; i < nitems(rt5390_def_rf); i++) { 5565257955Skevlo run_rt3070_rf_write(sc, rt5390_def_rf[i].reg, 5566257955Skevlo rt5390_def_rf[i].val); 5567257955Skevlo } 5568257955Skevlo if (sc->mac_rev >= 0x0502) { 5569257955Skevlo run_rt3070_rf_write(sc, 6, 0xe0); 5570257955Skevlo run_rt3070_rf_write(sc, 25, 0x80); 5571257955Skevlo run_rt3070_rf_write(sc, 46, 0x73); 5572257955Skevlo run_rt3070_rf_write(sc, 53, 0x00); 5573257955Skevlo run_rt3070_rf_write(sc, 56, 0x42); 5574257955Skevlo run_rt3070_rf_write(sc, 61, 0xd1); 5575257955Skevlo } 5576257955Skevlo } 5577257955Skevlo 5578257955Skevlo sc->rf24_20mhz = 0x1f; /* default value */ 5579259032Skevlo sc->rf24_40mhz = (sc->mac_ver == 0x5592) ? 0 : 0x2f; 5580257955Skevlo 5581257955Skevlo if (sc->mac_rev < 0x0211) 5582257955Skevlo run_rt3070_rf_write(sc, 27, 0x3); 5583257955Skevlo 5584257955Skevlo run_read(sc, RT3070_OPT_14, &tmp); 5585257955Skevlo run_write(sc, RT3070_OPT_14, tmp | 1); 5586257955Skevlo} 5587257955Skevlo 5588203134Sthompsastatic int 5589203134Sthompsarun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target, 5590203134Sthompsa uint8_t *val) 5591203134Sthompsa{ 5592203134Sthompsa uint8_t rf22, rf24; 5593203134Sthompsa uint8_t bbp55_pb, bbp55_sb, delta; 5594203134Sthompsa int ntries; 5595203134Sthompsa 5596203134Sthompsa /* program filter */ 5597205042Sthompsa run_rt3070_rf_read(sc, 24, &rf24); 5598205042Sthompsa rf24 = (rf24 & 0xc0) | init; /* initial filter value */ 5599203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 5600203134Sthompsa 5601203134Sthompsa /* enable baseband loopback mode */ 5602203134Sthompsa run_rt3070_rf_read(sc, 22, &rf22); 5603203134Sthompsa run_rt3070_rf_write(sc, 22, rf22 | 0x01); 5604203134Sthompsa 5605203134Sthompsa /* set power and frequency of passband test tone */ 5606203134Sthompsa run_bbp_write(sc, 24, 0x00); 5607203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5608203134Sthompsa /* transmit test tone */ 5609203134Sthompsa run_bbp_write(sc, 25, 0x90); 5610203134Sthompsa run_delay(sc, 10); 5611203134Sthompsa /* read received power */ 5612203134Sthompsa run_bbp_read(sc, 55, &bbp55_pb); 5613203134Sthompsa if (bbp55_pb != 0) 5614203134Sthompsa break; 5615203134Sthompsa } 5616203134Sthompsa if (ntries == 100) 5617257955Skevlo return (ETIMEDOUT); 5618203134Sthompsa 5619203134Sthompsa /* set power and frequency of stopband test tone */ 5620203134Sthompsa run_bbp_write(sc, 24, 0x06); 5621203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5622203134Sthompsa /* transmit test tone */ 5623203134Sthompsa run_bbp_write(sc, 25, 0x90); 5624203134Sthompsa run_delay(sc, 10); 5625203134Sthompsa /* read received power */ 5626203134Sthompsa run_bbp_read(sc, 55, &bbp55_sb); 5627203134Sthompsa 5628203134Sthompsa delta = bbp55_pb - bbp55_sb; 5629203134Sthompsa if (delta > target) 5630203134Sthompsa break; 5631203134Sthompsa 5632203134Sthompsa /* reprogram filter */ 5633203134Sthompsa rf24++; 5634203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 5635203134Sthompsa } 5636203134Sthompsa if (ntries < 100) { 5637203134Sthompsa if (rf24 != init) 5638203134Sthompsa rf24--; /* backtrack */ 5639203134Sthompsa *val = rf24; 5640203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 5641203134Sthompsa } 5642203134Sthompsa 5643203134Sthompsa /* restore initial state */ 5644203134Sthompsa run_bbp_write(sc, 24, 0x00); 5645203134Sthompsa 5646203134Sthompsa /* disable baseband loopback mode */ 5647203134Sthompsa run_rt3070_rf_read(sc, 22, &rf22); 5648203134Sthompsa run_rt3070_rf_write(sc, 22, rf22 & ~0x01); 5649203134Sthompsa 5650209917Sthompsa return (0); 5651203134Sthompsa} 5652203134Sthompsa 5653205042Sthompsastatic void 5654205042Sthompsarun_rt3070_rf_setup(struct run_softc *sc) 5655205042Sthompsa{ 5656205042Sthompsa uint8_t bbp, rf; 5657205042Sthompsa int i; 5658205042Sthompsa 5659260219Skevlo if (sc->mac_ver == 0x3572) { 5660205042Sthompsa /* enable DC filter */ 5661205042Sthompsa if (sc->mac_rev >= 0x0201) 5662205042Sthompsa run_bbp_write(sc, 103, 0xc0); 5663205042Sthompsa 5664205042Sthompsa run_bbp_read(sc, 138, &bbp); 5665205042Sthompsa if (sc->ntxchains == 1) 5666205042Sthompsa bbp |= 0x20; /* turn off DAC1 */ 5667205042Sthompsa if (sc->nrxchains == 1) 5668205042Sthompsa bbp &= ~0x02; /* turn off ADC1 */ 5669205042Sthompsa run_bbp_write(sc, 138, bbp); 5670205042Sthompsa 5671205042Sthompsa if (sc->mac_rev >= 0x0211) { 5672205042Sthompsa /* improve power consumption */ 5673205042Sthompsa run_bbp_read(sc, 31, &bbp); 5674205042Sthompsa run_bbp_write(sc, 31, bbp & ~0x03); 5675205042Sthompsa } 5676205042Sthompsa 5677205042Sthompsa run_rt3070_rf_read(sc, 16, &rf); 5678205042Sthompsa rf = (rf & ~0x07) | sc->txmixgain_2ghz; 5679205042Sthompsa run_rt3070_rf_write(sc, 16, rf); 5680205042Sthompsa 5681205042Sthompsa } else if (sc->mac_ver == 0x3071) { 5682257409Skevlo if (sc->mac_rev >= 0x0211) { 5683257409Skevlo /* enable DC filter */ 5684205042Sthompsa run_bbp_write(sc, 103, 0xc0); 5685205042Sthompsa 5686257409Skevlo /* improve power consumption */ 5687257409Skevlo run_bbp_read(sc, 31, &bbp); 5688257409Skevlo run_bbp_write(sc, 31, bbp & ~0x03); 5689257409Skevlo } 5690257409Skevlo 5691205042Sthompsa run_bbp_read(sc, 138, &bbp); 5692205042Sthompsa if (sc->ntxchains == 1) 5693205042Sthompsa bbp |= 0x20; /* turn off DAC1 */ 5694205042Sthompsa if (sc->nrxchains == 1) 5695205042Sthompsa bbp &= ~0x02; /* turn off ADC1 */ 5696205042Sthompsa run_bbp_write(sc, 138, bbp); 5697205042Sthompsa 5698205042Sthompsa run_write(sc, RT2860_TX_SW_CFG1, 0); 5699205042Sthompsa if (sc->mac_rev < 0x0211) { 5700205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 5701205042Sthompsa sc->patch_dac ? 0x2c : 0x0f); 5702205042Sthompsa } else 5703205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0); 5704205042Sthompsa 5705205042Sthompsa } else if (sc->mac_ver == 0x3070) { 5706205042Sthompsa if (sc->mac_rev >= 0x0201) { 5707205042Sthompsa /* enable DC filter */ 5708205042Sthompsa run_bbp_write(sc, 103, 0xc0); 5709205042Sthompsa 5710205042Sthompsa /* improve power consumption */ 5711205042Sthompsa run_bbp_read(sc, 31, &bbp); 5712205042Sthompsa run_bbp_write(sc, 31, bbp & ~0x03); 5713205042Sthompsa } 5714205042Sthompsa 5715256955Skevlo if (sc->mac_rev < 0x0201) { 5716205042Sthompsa run_write(sc, RT2860_TX_SW_CFG1, 0); 5717205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0x2c); 5718205042Sthompsa } else 5719205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0); 5720205042Sthompsa } 5721205042Sthompsa 5722205042Sthompsa /* initialize RF registers from ROM for >=RT3071*/ 5723260219Skevlo if (sc->mac_ver >= 0x3071) { 5724205042Sthompsa for (i = 0; i < 10; i++) { 5725205042Sthompsa if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff) 5726205042Sthompsa continue; 5727205042Sthompsa run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val); 5728205042Sthompsa } 5729205042Sthompsa } 5730205042Sthompsa} 5731205042Sthompsa 5732260219Skevlostatic void 5733260219Skevlorun_rt3593_rf_setup(struct run_softc *sc) 5734260219Skevlo{ 5735260219Skevlo uint8_t bbp, rf; 5736260219Skevlo 5737260219Skevlo if (sc->mac_rev >= 0x0211) { 5738260219Skevlo /* Enable DC filter. */ 5739260219Skevlo run_bbp_write(sc, 103, 0xc0); 5740260219Skevlo } 5741260219Skevlo run_write(sc, RT2860_TX_SW_CFG1, 0); 5742260219Skevlo if (sc->mac_rev < 0x0211) { 5743260219Skevlo run_write(sc, RT2860_TX_SW_CFG2, 5744260219Skevlo sc->patch_dac ? 0x2c : 0x0f); 5745260219Skevlo } else 5746260219Skevlo run_write(sc, RT2860_TX_SW_CFG2, 0); 5747260219Skevlo 5748260219Skevlo run_rt3070_rf_read(sc, 50, &rf); 5749260219Skevlo run_rt3070_rf_write(sc, 50, rf & ~RT3593_TX_LO2); 5750260219Skevlo 5751260219Skevlo run_rt3070_rf_read(sc, 51, &rf); 5752260219Skevlo rf = (rf & ~(RT3593_TX_LO1 | 0x0c)) | 5753260219Skevlo ((sc->txmixgain_2ghz & 0x07) << 2); 5754260219Skevlo run_rt3070_rf_write(sc, 51, rf); 5755260219Skevlo 5756260219Skevlo run_rt3070_rf_read(sc, 38, &rf); 5757260219Skevlo run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1); 5758260219Skevlo 5759260219Skevlo run_rt3070_rf_read(sc, 39, &rf); 5760260219Skevlo run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2); 5761260219Skevlo 5762260219Skevlo run_rt3070_rf_read(sc, 1, &rf); 5763260219Skevlo run_rt3070_rf_write(sc, 1, rf & ~(RT3070_RF_BLOCK | RT3070_PLL_PD)); 5764260219Skevlo 5765260219Skevlo run_rt3070_rf_read(sc, 30, &rf); 5766260219Skevlo rf = (rf & ~0x18) | 0x10; 5767260219Skevlo run_rt3070_rf_write(sc, 30, rf); 5768260219Skevlo 5769260219Skevlo /* Apply maximum likelihood detection for 2 stream case. */ 5770260219Skevlo run_bbp_read(sc, 105, &bbp); 5771260219Skevlo if (sc->nrxchains > 1) 5772260219Skevlo run_bbp_write(sc, 105, bbp | RT5390_MLD); 5773260219Skevlo 5774260219Skevlo /* Avoid data lost and CRC error. */ 5775260219Skevlo run_bbp_read(sc, 4, &bbp); 5776260219Skevlo run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 5777260219Skevlo 5778260219Skevlo run_bbp_write(sc, 92, 0x02); 5779260219Skevlo run_bbp_write(sc, 82, 0x82); 5780260219Skevlo run_bbp_write(sc, 106, 0x05); 5781260219Skevlo run_bbp_write(sc, 104, 0x92); 5782260219Skevlo run_bbp_write(sc, 88, 0x90); 5783260219Skevlo run_bbp_write(sc, 148, 0xc8); 5784260219Skevlo run_bbp_write(sc, 47, 0x48); 5785260219Skevlo run_bbp_write(sc, 120, 0x50); 5786260219Skevlo 5787260219Skevlo run_bbp_write(sc, 163, 0x9d); 5788260219Skevlo 5789260219Skevlo /* SNR mapping. */ 5790260219Skevlo run_bbp_write(sc, 142, 0x06); 5791260219Skevlo run_bbp_write(sc, 143, 0xa0); 5792260219Skevlo run_bbp_write(sc, 142, 0x07); 5793260219Skevlo run_bbp_write(sc, 143, 0xa1); 5794260219Skevlo run_bbp_write(sc, 142, 0x08); 5795260219Skevlo run_bbp_write(sc, 143, 0xa2); 5796260219Skevlo 5797260219Skevlo run_bbp_write(sc, 31, 0x08); 5798260219Skevlo run_bbp_write(sc, 68, 0x0b); 5799260219Skevlo run_bbp_write(sc, 105, 0x04); 5800260219Skevlo} 5801260219Skevlo 5802260219Skevlostatic void 5803260219Skevlorun_rt5390_rf_setup(struct run_softc *sc) 5804260219Skevlo{ 5805260219Skevlo uint8_t bbp, rf; 5806260219Skevlo 5807260219Skevlo if (sc->mac_rev >= 0x0211) { 5808260219Skevlo /* Enable DC filter. */ 5809260219Skevlo run_bbp_write(sc, 103, 0xc0); 5810260219Skevlo 5811260219Skevlo if (sc->mac_ver != 0x5592) { 5812260219Skevlo /* Improve power consumption. */ 5813260219Skevlo run_bbp_read(sc, 31, &bbp); 5814260219Skevlo run_bbp_write(sc, 31, bbp & ~0x03); 5815260219Skevlo } 5816260219Skevlo } 5817260219Skevlo 5818260219Skevlo run_bbp_read(sc, 138, &bbp); 5819260219Skevlo if (sc->ntxchains == 1) 5820260219Skevlo bbp |= 0x20; /* turn off DAC1 */ 5821260219Skevlo if (sc->nrxchains == 1) 5822260219Skevlo bbp &= ~0x02; /* turn off ADC1 */ 5823260219Skevlo run_bbp_write(sc, 138, bbp); 5824260219Skevlo 5825260219Skevlo run_rt3070_rf_read(sc, 38, &rf); 5826260219Skevlo run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1); 5827260219Skevlo 5828260219Skevlo run_rt3070_rf_read(sc, 39, &rf); 5829260219Skevlo run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2); 5830260219Skevlo 5831260219Skevlo /* Avoid data lost and CRC error. */ 5832260219Skevlo run_bbp_read(sc, 4, &bbp); 5833260219Skevlo run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 5834260219Skevlo 5835260219Skevlo run_rt3070_rf_read(sc, 30, &rf); 5836260219Skevlo rf = (rf & ~0x18) | 0x10; 5837260219Skevlo run_rt3070_rf_write(sc, 30, rf); 5838260219Skevlo 5839260219Skevlo if (sc->mac_ver != 0x5592) { 5840260219Skevlo run_write(sc, RT2860_TX_SW_CFG1, 0); 5841260219Skevlo if (sc->mac_rev < 0x0211) { 5842260219Skevlo run_write(sc, RT2860_TX_SW_CFG2, 5843260219Skevlo sc->patch_dac ? 0x2c : 0x0f); 5844260219Skevlo } else 5845260219Skevlo run_write(sc, RT2860_TX_SW_CFG2, 0); 5846260219Skevlo } 5847260219Skevlo} 5848260219Skevlo 5849203134Sthompsastatic int 5850203134Sthompsarun_txrx_enable(struct run_softc *sc) 5851203134Sthompsa{ 5852287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 5853203134Sthompsa uint32_t tmp; 5854203134Sthompsa int error, ntries; 5855203134Sthompsa 5856203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN); 5857203134Sthompsa for (ntries = 0; ntries < 200; ntries++) { 5858203134Sthompsa if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0) 5859257955Skevlo return (error); 5860203134Sthompsa if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 5861203134Sthompsa break; 5862203134Sthompsa run_delay(sc, 50); 5863203134Sthompsa } 5864203134Sthompsa if (ntries == 200) 5865257955Skevlo return (ETIMEDOUT); 5866203134Sthompsa 5867203134Sthompsa run_delay(sc, 50); 5868203134Sthompsa 5869203134Sthompsa tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE; 5870203134Sthompsa run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 5871203134Sthompsa 5872203134Sthompsa /* enable Rx bulk aggregation (set timeout and limit) */ 5873203134Sthompsa tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN | 5874203134Sthompsa RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2); 5875203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, tmp); 5876203134Sthompsa 5877203134Sthompsa /* set Rx filter */ 5878203134Sthompsa tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR; 5879203134Sthompsa if (ic->ic_opmode != IEEE80211_M_MONITOR) { 5880203134Sthompsa tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL | 5881203134Sthompsa RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK | 5882203134Sthompsa RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV | 5883203134Sthompsa RT2860_DROP_CFACK | RT2860_DROP_CFEND; 5884203134Sthompsa if (ic->ic_opmode == IEEE80211_M_STA) 5885203134Sthompsa tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL; 5886203134Sthompsa } 5887203134Sthompsa run_write(sc, RT2860_RX_FILTR_CFG, tmp); 5888203134Sthompsa 5889203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 5890203134Sthompsa RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 5891203134Sthompsa 5892209917Sthompsa return (0); 5893203134Sthompsa} 5894203134Sthompsa 5895203134Sthompsastatic void 5896259030Skevlorun_adjust_freq_offset(struct run_softc *sc) 5897257955Skevlo{ 5898257955Skevlo uint8_t rf, tmp; 5899257955Skevlo 5900257955Skevlo run_rt3070_rf_read(sc, 17, &rf); 5901257955Skevlo tmp = rf; 5902257955Skevlo rf = (rf & ~0x7f) | (sc->freq & 0x7f); 5903257955Skevlo rf = MIN(rf, 0x5f); 5904257955Skevlo 5905257955Skevlo if (tmp != rf) 5906257955Skevlo run_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf); 5907257955Skevlo} 5908257955Skevlo 5909257955Skevlostatic void 5910203134Sthompsarun_init_locked(struct run_softc *sc) 5911203134Sthompsa{ 5912287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 5913287197Sglebius struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 5914203134Sthompsa uint32_t tmp; 5915203134Sthompsa uint8_t bbp1, bbp3; 5916203134Sthompsa int i; 5917203134Sthompsa int ridx; 5918203134Sthompsa int ntries; 5919203134Sthompsa 5920209917Sthompsa if (ic->ic_nrunning > 1) 5921208019Sthompsa return; 5922208019Sthompsa 5923203134Sthompsa run_stop(sc); 5924203134Sthompsa 5925233283Sbschmidt if (run_load_microcode(sc) != 0) { 5926233283Sbschmidt device_printf(sc->sc_dev, "could not load 8051 microcode\n"); 5927233283Sbschmidt goto fail; 5928233283Sbschmidt } 5929233283Sbschmidt 5930203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5931203134Sthompsa if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0) 5932203134Sthompsa goto fail; 5933203134Sthompsa if (tmp != 0 && tmp != 0xffffffff) 5934203134Sthompsa break; 5935203134Sthompsa run_delay(sc, 10); 5936203134Sthompsa } 5937203134Sthompsa if (ntries == 100) 5938203134Sthompsa goto fail; 5939203134Sthompsa 5940203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 5941203134Sthompsa run_setup_tx_list(sc, &sc->sc_epq[i]); 5942203134Sthompsa 5943287197Sglebius run_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); 5944203134Sthompsa 5945203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5946203134Sthompsa if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 5947203134Sthompsa goto fail; 5948203134Sthompsa if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 5949203134Sthompsa break; 5950203134Sthompsa run_delay(sc, 10); 5951203134Sthompsa } 5952203134Sthompsa if (ntries == 100) { 5953203138Sthompsa device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); 5954203134Sthompsa goto fail; 5955203134Sthompsa } 5956203134Sthompsa tmp &= 0xff0; 5957203134Sthompsa tmp |= RT2860_TX_WB_DDONE; 5958203134Sthompsa run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 5959203134Sthompsa 5960203134Sthompsa /* turn off PME_OEN to solve high-current issue */ 5961203134Sthompsa run_read(sc, RT2860_SYS_CTRL, &tmp); 5962203134Sthompsa run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN); 5963203134Sthompsa 5964203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 5965203134Sthompsa RT2860_BBP_HRST | RT2860_MAC_SRST); 5966203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, 0); 5967203134Sthompsa 5968203134Sthompsa if (run_reset(sc) != 0) { 5969203138Sthompsa device_printf(sc->sc_dev, "could not reset chipset\n"); 5970203134Sthompsa goto fail; 5971203134Sthompsa } 5972203134Sthompsa 5973203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 0); 5974203134Sthompsa 5975203134Sthompsa /* init Tx power for all Tx rates (from EEPROM) */ 5976203134Sthompsa for (ridx = 0; ridx < 5; ridx++) { 5977203134Sthompsa if (sc->txpow20mhz[ridx] == 0xffffffff) 5978203134Sthompsa continue; 5979203134Sthompsa run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]); 5980203134Sthompsa } 5981203134Sthompsa 5982257955Skevlo for (i = 0; i < nitems(rt2870_def_mac); i++) 5983203134Sthompsa run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val); 5984203134Sthompsa run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273); 5985203134Sthompsa run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344); 5986203134Sthompsa run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa); 5987203134Sthompsa 5988259030Skevlo if (sc->mac_ver >= 0x5390) { 5989259030Skevlo run_write(sc, RT2860_TX_SW_CFG0, 5990259030Skevlo 4 << RT2860_DLY_PAPE_EN_SHIFT | 4); 5991259030Skevlo if (sc->mac_ver >= 0x5392) { 5992259030Skevlo run_write(sc, RT2860_MAX_LEN_CFG, 0x00002fff); 5993259032Skevlo if (sc->mac_ver == 0x5592) { 5994259032Skevlo run_write(sc, RT2860_HT_FBK_CFG1, 0xedcba980); 5995259032Skevlo run_write(sc, RT2860_TXOP_HLDR_ET, 0x00000082); 5996259032Skevlo } else { 5997259032Skevlo run_write(sc, RT2860_HT_FBK_CFG1, 0xedcb4980); 5998259032Skevlo run_write(sc, RT2860_LG_FBK_CFG0, 0xedcba322); 5999259032Skevlo } 6000259030Skevlo } 6001260219Skevlo } else if (sc->mac_ver == 0x3593) { 6002260219Skevlo run_write(sc, RT2860_TX_SW_CFG0, 6003260219Skevlo 4 << RT2860_DLY_PAPE_EN_SHIFT | 2); 6004257955Skevlo } else if (sc->mac_ver >= 0x3070) { 6005203134Sthompsa /* set delay of PA_PE assertion to 1us (unit of 0.25us) */ 6006203134Sthompsa run_write(sc, RT2860_TX_SW_CFG0, 6007203134Sthompsa 4 << RT2860_DLY_PAPE_EN_SHIFT); 6008203134Sthompsa } 6009203134Sthompsa 6010203134Sthompsa /* wait while MAC is busy */ 6011203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 6012203134Sthompsa if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0) 6013203134Sthompsa goto fail; 6014203134Sthompsa if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY))) 6015203134Sthompsa break; 6016203134Sthompsa run_delay(sc, 10); 6017203134Sthompsa } 6018203134Sthompsa if (ntries == 100) 6019203134Sthompsa goto fail; 6020203134Sthompsa 6021203134Sthompsa /* clear Host to MCU mailbox */ 6022203134Sthompsa run_write(sc, RT2860_H2M_BBPAGENT, 0); 6023203134Sthompsa run_write(sc, RT2860_H2M_MAILBOX, 0); 6024203134Sthompsa run_delay(sc, 10); 6025203134Sthompsa 6026203134Sthompsa if (run_bbp_init(sc) != 0) { 6027203138Sthompsa device_printf(sc->sc_dev, "could not initialize BBP\n"); 6028203134Sthompsa goto fail; 6029203134Sthompsa } 6030203134Sthompsa 6031203134Sthompsa /* abort TSF synchronization */ 6032203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 6033203134Sthompsa tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 6034203134Sthompsa RT2860_TBTT_TIMER_EN); 6035203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, tmp); 6036203134Sthompsa 6037203134Sthompsa /* clear RX WCID search table */ 6038203134Sthompsa run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512); 6039203134Sthompsa /* clear WCID attribute table */ 6040203134Sthompsa run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32); 6041203134Sthompsa 6042209144Sthompsa /* hostapd sets a key before init. So, don't clear it. */ 6043209917Sthompsa if (sc->cmdq_key_set != RUN_CMDQ_GO) { 6044209144Sthompsa /* clear shared key table */ 6045209144Sthompsa run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32); 6046209144Sthompsa /* clear shared key mode */ 6047209144Sthompsa run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4); 6048209144Sthompsa } 6049209144Sthompsa 6050203134Sthompsa run_read(sc, RT2860_US_CYC_CNT, &tmp); 6051203134Sthompsa tmp = (tmp & ~0xff) | 0x1e; 6052203134Sthompsa run_write(sc, RT2860_US_CYC_CNT, tmp); 6053203134Sthompsa 6054205042Sthompsa if (sc->mac_rev != 0x0101) 6055203134Sthompsa run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f); 6056203134Sthompsa 6057203134Sthompsa run_write(sc, RT2860_WMM_TXOP0_CFG, 0); 6058203134Sthompsa run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96); 6059203134Sthompsa 6060203134Sthompsa /* write vendor-specific BBP values (from EEPROM) */ 6061260219Skevlo if (sc->mac_ver < 0x3593) { 6062257955Skevlo for (i = 0; i < 10; i++) { 6063257955Skevlo if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff) 6064257955Skevlo continue; 6065257955Skevlo run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val); 6066257955Skevlo } 6067203134Sthompsa } 6068203134Sthompsa 6069203134Sthompsa /* select Main antenna for 1T1R devices */ 6070257955Skevlo if (sc->rf_rev == RT3070_RF_3020 || sc->rf_rev == RT5390_RF_5370) 6071203134Sthompsa run_set_rx_antenna(sc, 0); 6072203134Sthompsa 6073203134Sthompsa /* send LEDs operating mode to microcontroller */ 6074203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]); 6075203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]); 6076203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]); 6077203134Sthompsa 6078257955Skevlo if (sc->mac_ver >= 0x5390) 6079257955Skevlo run_rt5390_rf_init(sc); 6080260219Skevlo else if (sc->mac_ver == 0x3593) 6081260219Skevlo run_rt3593_rf_init(sc); 6082257955Skevlo else if (sc->mac_ver >= 0x3070) 6083205042Sthompsa run_rt3070_rf_init(sc); 6084205042Sthompsa 6085203134Sthompsa /* disable non-existing Rx chains */ 6086203134Sthompsa run_bbp_read(sc, 3, &bbp3); 6087203134Sthompsa bbp3 &= ~(1 << 3 | 1 << 4); 6088203134Sthompsa if (sc->nrxchains == 2) 6089203134Sthompsa bbp3 |= 1 << 3; 6090203134Sthompsa else if (sc->nrxchains == 3) 6091203134Sthompsa bbp3 |= 1 << 4; 6092203134Sthompsa run_bbp_write(sc, 3, bbp3); 6093203134Sthompsa 6094203134Sthompsa /* disable non-existing Tx chains */ 6095203134Sthompsa run_bbp_read(sc, 1, &bbp1); 6096203134Sthompsa if (sc->ntxchains == 1) 6097203134Sthompsa bbp1 &= ~(1 << 3 | 1 << 4); 6098203134Sthompsa run_bbp_write(sc, 1, bbp1); 6099203134Sthompsa 6100260219Skevlo if (sc->mac_ver >= 0x5390) 6101260219Skevlo run_rt5390_rf_setup(sc); 6102260219Skevlo else if (sc->mac_ver == 0x3593) 6103260219Skevlo run_rt3593_rf_setup(sc); 6104260219Skevlo else if (sc->mac_ver >= 0x3070) 6105205042Sthompsa run_rt3070_rf_setup(sc); 6106203134Sthompsa 6107203134Sthompsa /* select default channel */ 6108203134Sthompsa run_set_chan(sc, ic->ic_curchan); 6109203134Sthompsa 6110203134Sthompsa /* setup initial protection mode */ 6111218492Sbschmidt run_updateprot_cb(ic); 6112203134Sthompsa 6113203134Sthompsa /* turn radio LED on */ 6114203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO); 6115203134Sthompsa 6116287197Sglebius sc->sc_flags |= RUN_RUNNING; 6117208019Sthompsa sc->cmdq_run = RUN_CMDQ_GO; 6118203134Sthompsa 6119209917Sthompsa for (i = 0; i != RUN_N_XFER; i++) 6120203134Sthompsa usbd_xfer_set_stall(sc->sc_xfer[i]); 6121203134Sthompsa 6122203134Sthompsa usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]); 6123203134Sthompsa 6124203134Sthompsa if (run_txrx_enable(sc) != 0) 6125203134Sthompsa goto fail; 6126203134Sthompsa 6127203134Sthompsa return; 6128203134Sthompsa 6129203134Sthompsafail: 6130203134Sthompsa run_stop(sc); 6131203134Sthompsa} 6132203134Sthompsa 6133203134Sthompsastatic void 6134203134Sthompsarun_stop(void *arg) 6135203134Sthompsa{ 6136203134Sthompsa struct run_softc *sc = (struct run_softc *)arg; 6137203134Sthompsa uint32_t tmp; 6138203134Sthompsa int i; 6139203134Sthompsa int ntries; 6140203134Sthompsa 6141203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 6142203134Sthompsa 6143287197Sglebius if (sc->sc_flags & RUN_RUNNING) 6144203134Sthompsa run_set_leds(sc, 0); /* turn all LEDs off */ 6145203134Sthompsa 6146287197Sglebius sc->sc_flags &= ~RUN_RUNNING; 6147203134Sthompsa 6148208019Sthompsa sc->ratectl_run = RUN_RATECTL_OFF; 6149209144Sthompsa sc->cmdq_run = sc->cmdq_key_set; 6150208019Sthompsa 6151203134Sthompsa RUN_UNLOCK(sc); 6152203134Sthompsa 6153203134Sthompsa for(i = 0; i < RUN_N_XFER; i++) 6154203134Sthompsa usbd_transfer_drain(sc->sc_xfer[i]); 6155203134Sthompsa 6156203134Sthompsa RUN_LOCK(sc); 6157203134Sthompsa 6158288649Sadrian run_drain_mbufq(sc); 6159288649Sadrian 6160209917Sthompsa if (sc->rx_m != NULL) { 6161203134Sthompsa m_free(sc->rx_m); 6162203134Sthompsa sc->rx_m = NULL; 6163203134Sthompsa } 6164203134Sthompsa 6165257955Skevlo /* Disable Tx/Rx DMA. */ 6166257955Skevlo if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 6167257955Skevlo return; 6168257955Skevlo tmp &= ~(RT2860_RX_DMA_EN | RT2860_TX_DMA_EN); 6169257955Skevlo run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 6170257955Skevlo 6171258643Shselasky for (ntries = 0; ntries < 100; ntries++) { 6172257955Skevlo if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 6173257955Skevlo return; 6174257955Skevlo if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 6175257955Skevlo break; 6176257955Skevlo run_delay(sc, 10); 6177257955Skevlo } 6178257955Skevlo if (ntries == 100) { 6179257955Skevlo device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); 6180257955Skevlo return; 6181257955Skevlo } 6182257955Skevlo 6183203134Sthompsa /* disable Tx/Rx */ 6184203134Sthompsa run_read(sc, RT2860_MAC_SYS_CTRL, &tmp); 6185203134Sthompsa tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 6186203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, tmp); 6187203134Sthompsa 6188203134Sthompsa /* wait for pending Tx to complete */ 6189203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 6190209917Sthompsa if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0) { 6191203134Sthompsa DPRINTF("Cannot read Tx queue count\n"); 6192203134Sthompsa break; 6193203134Sthompsa } 6194209917Sthompsa if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0) { 6195203134Sthompsa DPRINTF("All Tx cleared\n"); 6196203134Sthompsa break; 6197203134Sthompsa } 6198203134Sthompsa run_delay(sc, 10); 6199203134Sthompsa } 6200209917Sthompsa if (ntries >= 100) 6201203134Sthompsa DPRINTF("There are still pending Tx\n"); 6202203134Sthompsa run_delay(sc, 10); 6203203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, 0); 6204203134Sthompsa 6205203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST); 6206203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 0); 6207203134Sthompsa 6208203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 6209203134Sthompsa run_unsetup_tx_list(sc, &sc->sc_epq[i]); 6210203134Sthompsa} 6211203134Sthompsa 6212203134Sthompsastatic void 6213257429Shselaskyrun_delay(struct run_softc *sc, u_int ms) 6214203134Sthompsa{ 6215203134Sthompsa usb_pause_mtx(mtx_owned(&sc->sc_mtx) ? 6216203134Sthompsa &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms)); 6217203134Sthompsa} 6218203134Sthompsa 6219203134Sthompsastatic device_method_t run_methods[] = { 6220203134Sthompsa /* Device interface */ 6221203134Sthompsa DEVMETHOD(device_probe, run_match), 6222203134Sthompsa DEVMETHOD(device_attach, run_attach), 6223203134Sthompsa DEVMETHOD(device_detach, run_detach), 6224246614Shselasky DEVMETHOD_END 6225203134Sthompsa}; 6226203134Sthompsa 6227203134Sthompsastatic driver_t run_driver = { 6228233774Shselasky .name = "run", 6229233774Shselasky .methods = run_methods, 6230233774Shselasky .size = sizeof(struct run_softc) 6231203134Sthompsa}; 6232203134Sthompsa 6233203134Sthompsastatic devclass_t run_devclass; 6234203134Sthompsa 6235259812SkevloDRIVER_MODULE(run, uhub, run_driver, run_devclass, run_driver_loaded, NULL); 6236212122SthompsaMODULE_DEPEND(run, wlan, 1, 1, 1); 6237212122SthompsaMODULE_DEPEND(run, usb, 1, 1, 1); 6238212122SthompsaMODULE_DEPEND(run, firmware, 1, 1, 1); 6239212122SthompsaMODULE_VERSION(run, 1); 6240292080SimpUSB_PNP_HOST_INFO(run_devs); 6241