if_run.c revision 287553
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 287553 2015-09-08 07:53:10Z kevlo $"); 22203134Sthompsa 23203134Sthompsa/*- 24257955Skevlo * Ralink Technology RT2700U/RT2800U/RT3000U/RT3900E chipset driver. 25203134Sthompsa * http://www.ralinktech.com/ 26203134Sthompsa */ 27203134Sthompsa 28203134Sthompsa#include <sys/param.h> 29203134Sthompsa#include <sys/sockio.h> 30203134Sthompsa#include <sys/sysctl.h> 31203134Sthompsa#include <sys/lock.h> 32203134Sthompsa#include <sys/mutex.h> 33203134Sthompsa#include <sys/mbuf.h> 34203134Sthompsa#include <sys/kernel.h> 35203134Sthompsa#include <sys/socket.h> 36203134Sthompsa#include <sys/systm.h> 37203134Sthompsa#include <sys/malloc.h> 38203134Sthompsa#include <sys/module.h> 39203134Sthompsa#include <sys/bus.h> 40203134Sthompsa#include <sys/endian.h> 41203134Sthompsa#include <sys/linker.h> 42203134Sthompsa#include <sys/firmware.h> 43203134Sthompsa#include <sys/kdb.h> 44203134Sthompsa 45203134Sthompsa#include <machine/bus.h> 46203134Sthompsa#include <machine/resource.h> 47203134Sthompsa#include <sys/rman.h> 48203134Sthompsa 49203134Sthompsa#include <net/bpf.h> 50203134Sthompsa#include <net/if.h> 51257176Sglebius#include <net/if_var.h> 52203134Sthompsa#include <net/if_arp.h> 53203134Sthompsa#include <net/ethernet.h> 54203134Sthompsa#include <net/if_dl.h> 55203134Sthompsa#include <net/if_media.h> 56203134Sthompsa#include <net/if_types.h> 57203134Sthompsa 58203134Sthompsa#include <netinet/in.h> 59203134Sthompsa#include <netinet/in_systm.h> 60203134Sthompsa#include <netinet/in_var.h> 61203134Sthompsa#include <netinet/if_ether.h> 62203134Sthompsa#include <netinet/ip.h> 63203134Sthompsa 64203134Sthompsa#include <net80211/ieee80211_var.h> 65203134Sthompsa#include <net80211/ieee80211_regdomain.h> 66203134Sthompsa#include <net80211/ieee80211_radiotap.h> 67206358Srpaulo#include <net80211/ieee80211_ratectl.h> 68203134Sthompsa 69203134Sthompsa#include <dev/usb/usb.h> 70203134Sthompsa#include <dev/usb/usbdi.h> 71203134Sthompsa#include "usbdevs.h" 72203134Sthompsa 73259546Skevlo#define USB_DEBUG_VAR run_debug 74203134Sthompsa#include <dev/usb/usb_debug.h> 75259812Skevlo#include <dev/usb/usb_msctest.h> 76203134Sthompsa 77220235Skevlo#include <dev/usb/wlan/if_runreg.h> 78220235Skevlo#include <dev/usb/wlan/if_runvar.h> 79203134Sthompsa 80207077Sthompsa#ifdef USB_DEBUG 81259546Skevlo#define RUN_DEBUG 82203134Sthompsa#endif 83203134Sthompsa 84203134Sthompsa#ifdef RUN_DEBUG 85203134Sthompsaint run_debug = 0; 86227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, run, CTLFLAG_RW, 0, "USB run"); 87276701ShselaskySYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RWTUN, &run_debug, 0, 88203134Sthompsa "run debug level"); 89203134Sthompsa#endif 90203134Sthompsa 91287552Skevlo#define IEEE80211_HAS_ADDR4(wh) IEEE80211_IS_DSTODS(wh) 92203134Sthompsa 93208019Sthompsa/* 94208019Sthompsa * Because of LOR in run_key_delete(), use atomic instead. 95208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[]. 96208019Sthompsa */ 97259546Skevlo#define RUN_CMDQ_GET(c) (atomic_fetchadd_32((c), 1) & RUN_CMDQ_MASQ) 98208019Sthompsa 99223486Shselaskystatic const STRUCT_USB_HOST_ID run_devs[] = { 100259546Skevlo#define RUN_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } 101259812Skevlo#define RUN_DEV_EJECT(v,p) \ 102262465Skevlo { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RUN_EJECT) } 103262465Skevlo#define RUN_EJECT 1 104209918Sthompsa RUN_DEV(ABOCOM, RT2770), 105209918Sthompsa RUN_DEV(ABOCOM, RT2870), 106209918Sthompsa RUN_DEV(ABOCOM, RT3070), 107209918Sthompsa RUN_DEV(ABOCOM, RT3071), 108209918Sthompsa RUN_DEV(ABOCOM, RT3072), 109209918Sthompsa RUN_DEV(ABOCOM2, RT2870_1), 110209918Sthompsa RUN_DEV(ACCTON, RT2770), 111209918Sthompsa RUN_DEV(ACCTON, RT2870_1), 112209918Sthompsa RUN_DEV(ACCTON, RT2870_2), 113209918Sthompsa RUN_DEV(ACCTON, RT2870_3), 114209918Sthompsa RUN_DEV(ACCTON, RT2870_4), 115209918Sthompsa RUN_DEV(ACCTON, RT2870_5), 116209918Sthompsa RUN_DEV(ACCTON, RT3070), 117209918Sthompsa RUN_DEV(ACCTON, RT3070_1), 118209918Sthompsa RUN_DEV(ACCTON, RT3070_2), 119209918Sthompsa RUN_DEV(ACCTON, RT3070_3), 120209918Sthompsa RUN_DEV(ACCTON, RT3070_4), 121209918Sthompsa RUN_DEV(ACCTON, RT3070_5), 122209918Sthompsa RUN_DEV(AIRTIES, RT3070), 123209918Sthompsa RUN_DEV(ALLWIN, RT2070), 124209918Sthompsa RUN_DEV(ALLWIN, RT2770), 125209918Sthompsa RUN_DEV(ALLWIN, RT2870), 126209918Sthompsa RUN_DEV(ALLWIN, RT3070), 127209918Sthompsa RUN_DEV(ALLWIN, RT3071), 128209918Sthompsa RUN_DEV(ALLWIN, RT3072), 129209918Sthompsa RUN_DEV(ALLWIN, RT3572), 130209918Sthompsa RUN_DEV(AMIGO, RT2870_1), 131209918Sthompsa RUN_DEV(AMIGO, RT2870_2), 132209918Sthompsa RUN_DEV(AMIT, CGWLUSB2GNR), 133209918Sthompsa RUN_DEV(AMIT, RT2870_1), 134209918Sthompsa RUN_DEV(AMIT2, RT2870), 135209918Sthompsa RUN_DEV(ASUS, RT2870_1), 136209918Sthompsa RUN_DEV(ASUS, RT2870_2), 137209918Sthompsa RUN_DEV(ASUS, RT2870_3), 138209918Sthompsa RUN_DEV(ASUS, RT2870_4), 139209918Sthompsa RUN_DEV(ASUS, RT2870_5), 140209918Sthompsa RUN_DEV(ASUS, USBN13), 141209918Sthompsa RUN_DEV(ASUS, RT3070_1), 142260219Skevlo RUN_DEV(ASUS, USBN66), 143239358Shselasky RUN_DEV(ASUS, USB_N53), 144209918Sthompsa RUN_DEV(ASUS2, USBN11), 145209918Sthompsa RUN_DEV(AZUREWAVE, RT2870_1), 146209918Sthompsa RUN_DEV(AZUREWAVE, RT2870_2), 147209918Sthompsa RUN_DEV(AZUREWAVE, RT3070_1), 148209918Sthompsa RUN_DEV(AZUREWAVE, RT3070_2), 149209918Sthompsa RUN_DEV(AZUREWAVE, RT3070_3), 150260219Skevlo RUN_DEV(BELKIN, F9L1103), 151209918Sthompsa RUN_DEV(BELKIN, F5D8053V3), 152209918Sthompsa RUN_DEV(BELKIN, F5D8055), 153226534Shselasky RUN_DEV(BELKIN, F5D8055V2), 154209918Sthompsa RUN_DEV(BELKIN, F6D4050V1), 155256500Shselasky RUN_DEV(BELKIN, F6D4050V2), 156209918Sthompsa RUN_DEV(BELKIN, RT2870_1), 157209918Sthompsa RUN_DEV(BELKIN, RT2870_2), 158226534Shselasky RUN_DEV(CISCOLINKSYS, AE1000), 159209918Sthompsa RUN_DEV(CISCOLINKSYS2, RT3070), 160209918Sthompsa RUN_DEV(CISCOLINKSYS3, RT3070), 161209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_1), 162209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_2), 163209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_3), 164209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_4), 165209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_5), 166209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_6), 167209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_7), 168209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_8), 169209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT3070_1), 170209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT3070_2), 171209918Sthompsa RUN_DEV(CONCEPTRONIC2, VIGORN61), 172209918Sthompsa RUN_DEV(COREGA, CGWLUSB300GNM), 173209918Sthompsa RUN_DEV(COREGA, RT2870_1), 174209918Sthompsa RUN_DEV(COREGA, RT2870_2), 175209918Sthompsa RUN_DEV(COREGA, RT2870_3), 176209918Sthompsa RUN_DEV(COREGA, RT3070), 177209918Sthompsa RUN_DEV(CYBERTAN, RT2870), 178209918Sthompsa RUN_DEV(DLINK, RT2870), 179209918Sthompsa RUN_DEV(DLINK, RT3072), 180255238Sbr RUN_DEV(DLINK, DWA127), 181257955Skevlo RUN_DEV(DLINK, DWA140B3), 182259032Skevlo RUN_DEV(DLINK, DWA160B2), 183267089Skevlo RUN_DEV(DLINK, DWA140D1), 184260219Skevlo RUN_DEV(DLINK, DWA162), 185209918Sthompsa RUN_DEV(DLINK2, DWA130), 186209918Sthompsa RUN_DEV(DLINK2, RT2870_1), 187209918Sthompsa RUN_DEV(DLINK2, RT2870_2), 188209918Sthompsa RUN_DEV(DLINK2, RT3070_1), 189209918Sthompsa RUN_DEV(DLINK2, RT3070_2), 190209918Sthompsa RUN_DEV(DLINK2, RT3070_3), 191209918Sthompsa RUN_DEV(DLINK2, RT3070_4), 192209918Sthompsa RUN_DEV(DLINK2, RT3070_5), 193209918Sthompsa RUN_DEV(DLINK2, RT3072), 194209918Sthompsa RUN_DEV(DLINK2, RT3072_1), 195209918Sthompsa RUN_DEV(EDIMAX, EW7717), 196209918Sthompsa RUN_DEV(EDIMAX, EW7718), 197260219Skevlo RUN_DEV(EDIMAX, EW7733UND), 198209918Sthompsa RUN_DEV(EDIMAX, RT2870_1), 199209918Sthompsa RUN_DEV(ENCORE, RT3070_1), 200209918Sthompsa RUN_DEV(ENCORE, RT3070_2), 201209918Sthompsa RUN_DEV(ENCORE, RT3070_3), 202209918Sthompsa RUN_DEV(GIGABYTE, GNWB31N), 203209918Sthompsa RUN_DEV(GIGABYTE, GNWB32L), 204209918Sthompsa RUN_DEV(GIGABYTE, RT2870_1), 205209918Sthompsa RUN_DEV(GIGASET, RT3070_1), 206209918Sthompsa RUN_DEV(GIGASET, RT3070_2), 207209918Sthompsa RUN_DEV(GUILLEMOT, HWNU300), 208209918Sthompsa RUN_DEV(HAWKING, HWUN2), 209209918Sthompsa RUN_DEV(HAWKING, RT2870_1), 210209918Sthompsa RUN_DEV(HAWKING, RT2870_2), 211209918Sthompsa RUN_DEV(HAWKING, RT3070), 212209918Sthompsa RUN_DEV(IODATA, RT3072_1), 213209918Sthompsa RUN_DEV(IODATA, RT3072_2), 214209918Sthompsa RUN_DEV(IODATA, RT3072_3), 215209918Sthompsa RUN_DEV(IODATA, RT3072_4), 216209918Sthompsa RUN_DEV(LINKSYS4, RT3070), 217209918Sthompsa RUN_DEV(LINKSYS4, WUSB100), 218209918Sthompsa RUN_DEV(LINKSYS4, WUSB54GCV3), 219209918Sthompsa RUN_DEV(LINKSYS4, WUSB600N), 220209918Sthompsa RUN_DEV(LINKSYS4, WUSB600NV2), 221209918Sthompsa RUN_DEV(LOGITEC, RT2870_1), 222209918Sthompsa RUN_DEV(LOGITEC, RT2870_2), 223209918Sthompsa RUN_DEV(LOGITEC, RT2870_3), 224230333Shselasky RUN_DEV(LOGITEC, LANW300NU2), 225238274Shrs RUN_DEV(LOGITEC, LANW150NU2), 226248458Shselasky RUN_DEV(LOGITEC, LANW300NU2S), 227281745Skevlo RUN_DEV(MELCO, WLIUCG300HP), 228209918Sthompsa RUN_DEV(MELCO, RT2870_2), 229209918Sthompsa RUN_DEV(MELCO, WLIUCAG300N), 230209918Sthompsa RUN_DEV(MELCO, WLIUCG300N), 231219257Sdaichi RUN_DEV(MELCO, WLIUCG301N), 232209918Sthompsa RUN_DEV(MELCO, WLIUCGN), 233227781Shselasky RUN_DEV(MELCO, WLIUCGNM), 234281745Skevlo RUN_DEV(MELCO, WLIUCG300HPV1), 235238274Shrs RUN_DEV(MELCO, WLIUCGNM2), 236209918Sthompsa RUN_DEV(MOTOROLA4, RT2770), 237209918Sthompsa RUN_DEV(MOTOROLA4, RT3070), 238209918Sthompsa RUN_DEV(MSI, RT3070_1), 239209918Sthompsa RUN_DEV(MSI, RT3070_2), 240209918Sthompsa RUN_DEV(MSI, RT3070_3), 241209918Sthompsa RUN_DEV(MSI, RT3070_4), 242209918Sthompsa RUN_DEV(MSI, RT3070_5), 243209918Sthompsa RUN_DEV(MSI, RT3070_6), 244209918Sthompsa RUN_DEV(MSI, RT3070_7), 245209918Sthompsa RUN_DEV(MSI, RT3070_8), 246209918Sthompsa RUN_DEV(MSI, RT3070_9), 247209918Sthompsa RUN_DEV(MSI, RT3070_10), 248209918Sthompsa RUN_DEV(MSI, RT3070_11), 249209918Sthompsa RUN_DEV(OVISLINK, RT3072), 250209918Sthompsa RUN_DEV(PARA, RT3070), 251209918Sthompsa RUN_DEV(PEGATRON, RT2870), 252209918Sthompsa RUN_DEV(PEGATRON, RT3070), 253209918Sthompsa RUN_DEV(PEGATRON, RT3070_2), 254209918Sthompsa RUN_DEV(PEGATRON, RT3070_3), 255209918Sthompsa RUN_DEV(PHILIPS, RT2870), 256209918Sthompsa RUN_DEV(PLANEX2, GWUS300MINIS), 257209918Sthompsa RUN_DEV(PLANEX2, GWUSMICRON), 258209918Sthompsa RUN_DEV(PLANEX2, RT2870), 259209918Sthompsa RUN_DEV(PLANEX2, RT3070), 260209918Sthompsa RUN_DEV(QCOM, RT2870), 261209918Sthompsa RUN_DEV(QUANTA, RT3070), 262209918Sthompsa RUN_DEV(RALINK, RT2070), 263209918Sthompsa RUN_DEV(RALINK, RT2770), 264209918Sthompsa RUN_DEV(RALINK, RT2870), 265209918Sthompsa RUN_DEV(RALINK, RT3070), 266209918Sthompsa RUN_DEV(RALINK, RT3071), 267209918Sthompsa RUN_DEV(RALINK, RT3072), 268209918Sthompsa RUN_DEV(RALINK, RT3370), 269209918Sthompsa RUN_DEV(RALINK, RT3572), 270260219Skevlo RUN_DEV(RALINK, RT3573), 271257955Skevlo RUN_DEV(RALINK, RT5370), 272259032Skevlo RUN_DEV(RALINK, RT5572), 273209918Sthompsa RUN_DEV(RALINK, RT8070), 274226534Shselasky RUN_DEV(SAMSUNG, WIS09ABGN), 275209918Sthompsa RUN_DEV(SAMSUNG2, RT2870_1), 276209918Sthompsa RUN_DEV(SENAO, RT2870_1), 277209918Sthompsa RUN_DEV(SENAO, RT2870_2), 278209918Sthompsa RUN_DEV(SENAO, RT2870_3), 279209918Sthompsa RUN_DEV(SENAO, RT2870_4), 280209918Sthompsa RUN_DEV(SENAO, RT3070), 281209918Sthompsa RUN_DEV(SENAO, RT3071), 282209918Sthompsa RUN_DEV(SENAO, RT3072_1), 283209918Sthompsa RUN_DEV(SENAO, RT3072_2), 284209918Sthompsa RUN_DEV(SENAO, RT3072_3), 285209918Sthompsa RUN_DEV(SENAO, RT3072_4), 286209918Sthompsa RUN_DEV(SENAO, RT3072_5), 287209918Sthompsa RUN_DEV(SITECOMEU, RT2770), 288209918Sthompsa RUN_DEV(SITECOMEU, RT2870_1), 289209918Sthompsa RUN_DEV(SITECOMEU, RT2870_2), 290209918Sthompsa RUN_DEV(SITECOMEU, RT2870_3), 291209918Sthompsa RUN_DEV(SITECOMEU, RT2870_4), 292209918Sthompsa RUN_DEV(SITECOMEU, RT3070), 293209918Sthompsa RUN_DEV(SITECOMEU, RT3070_2), 294209918Sthompsa RUN_DEV(SITECOMEU, RT3070_3), 295209918Sthompsa RUN_DEV(SITECOMEU, RT3070_4), 296209918Sthompsa RUN_DEV(SITECOMEU, RT3071), 297209918Sthompsa RUN_DEV(SITECOMEU, RT3072_1), 298209918Sthompsa RUN_DEV(SITECOMEU, RT3072_2), 299209918Sthompsa RUN_DEV(SITECOMEU, RT3072_3), 300209918Sthompsa RUN_DEV(SITECOMEU, RT3072_4), 301209918Sthompsa RUN_DEV(SITECOMEU, RT3072_5), 302209918Sthompsa RUN_DEV(SITECOMEU, RT3072_6), 303209918Sthompsa RUN_DEV(SITECOMEU, WL608), 304209918Sthompsa RUN_DEV(SPARKLAN, RT2870_1), 305209918Sthompsa RUN_DEV(SPARKLAN, RT3070), 306209918Sthompsa RUN_DEV(SWEEX2, LW153), 307209918Sthompsa RUN_DEV(SWEEX2, LW303), 308209918Sthompsa RUN_DEV(SWEEX2, LW313), 309209918Sthompsa RUN_DEV(TOSHIBA, RT3070), 310209918Sthompsa RUN_DEV(UMEDIA, RT2870_1), 311209918Sthompsa RUN_DEV(ZCOM, RT2870_1), 312209918Sthompsa RUN_DEV(ZCOM, RT2870_2), 313209918Sthompsa RUN_DEV(ZINWELL, RT2870_1), 314209918Sthompsa RUN_DEV(ZINWELL, RT2870_2), 315209918Sthompsa RUN_DEV(ZINWELL, RT3070), 316209918Sthompsa RUN_DEV(ZINWELL, RT3072_1), 317209918Sthompsa RUN_DEV(ZINWELL, RT3072_2), 318209918Sthompsa RUN_DEV(ZYXEL, RT2870_1), 319209918Sthompsa RUN_DEV(ZYXEL, RT2870_2), 320263985Shselasky RUN_DEV(ZYXEL, RT3070), 321262465Skevlo RUN_DEV_EJECT(ZYXEL, NWD2705), 322259812Skevlo RUN_DEV_EJECT(RALINK, RT_STOR), 323259812Skevlo#undef RUN_DEV_EJECT 324209918Sthompsa#undef RUN_DEV 325203134Sthompsa}; 326203134Sthompsa 327203134Sthompsastatic device_probe_t run_match; 328203134Sthompsastatic device_attach_t run_attach; 329203134Sthompsastatic device_detach_t run_detach; 330203134Sthompsa 331203134Sthompsastatic usb_callback_t run_bulk_rx_callback; 332203134Sthompsastatic usb_callback_t run_bulk_tx_callback0; 333203134Sthompsastatic usb_callback_t run_bulk_tx_callback1; 334203134Sthompsastatic usb_callback_t run_bulk_tx_callback2; 335203134Sthompsastatic usb_callback_t run_bulk_tx_callback3; 336203134Sthompsastatic usb_callback_t run_bulk_tx_callback4; 337203134Sthompsastatic usb_callback_t run_bulk_tx_callback5; 338203134Sthompsa 339259812Skevlostatic void run_autoinst(void *, struct usb_device *, 340259812Skevlo struct usb_attach_arg *); 341259812Skevlostatic int run_driver_loaded(struct module *, int, void *); 342203134Sthompsastatic void run_bulk_tx_callbackN(struct usb_xfer *xfer, 343257429Shselasky usb_error_t error, u_int index); 344203134Sthompsastatic struct ieee80211vap *run_vap_create(struct ieee80211com *, 345228621Sbschmidt const char [IFNAMSIZ], int, enum ieee80211_opmode, int, 346228621Sbschmidt const uint8_t [IEEE80211_ADDR_LEN], 347228621Sbschmidt const uint8_t [IEEE80211_ADDR_LEN]); 348203134Sthompsastatic void run_vap_delete(struct ieee80211vap *); 349208019Sthompsastatic void run_cmdq_cb(void *, int); 350203134Sthompsastatic void run_setup_tx_list(struct run_softc *, 351203134Sthompsa struct run_endpoint_queue *); 352203134Sthompsastatic void run_unsetup_tx_list(struct run_softc *, 353203134Sthompsa struct run_endpoint_queue *); 354203134Sthompsastatic int run_load_microcode(struct run_softc *); 355203134Sthompsastatic int run_reset(struct run_softc *); 356203134Sthompsastatic usb_error_t run_do_request(struct run_softc *, 357203134Sthompsa struct usb_device_request *, void *); 358203134Sthompsastatic int run_read(struct run_softc *, uint16_t, uint32_t *); 359203134Sthompsastatic int run_read_region_1(struct run_softc *, uint16_t, uint8_t *, int); 360203134Sthompsastatic int run_write_2(struct run_softc *, uint16_t, uint16_t); 361203134Sthompsastatic int run_write(struct run_softc *, uint16_t, uint32_t); 362203134Sthompsastatic int run_write_region_1(struct run_softc *, uint16_t, 363203134Sthompsa const uint8_t *, int); 364203134Sthompsastatic int run_set_region_4(struct run_softc *, uint16_t, uint32_t, int); 365259544Skevlostatic int run_efuse_read(struct run_softc *, uint16_t, uint16_t *, int); 366203134Sthompsastatic int run_efuse_read_2(struct run_softc *, uint16_t, uint16_t *); 367203134Sthompsastatic int run_eeprom_read_2(struct run_softc *, uint16_t, uint16_t *); 368258733Skevlostatic int run_rt2870_rf_write(struct run_softc *, uint32_t); 369203134Sthompsastatic int run_rt3070_rf_read(struct run_softc *, uint8_t, uint8_t *); 370203134Sthompsastatic int run_rt3070_rf_write(struct run_softc *, uint8_t, uint8_t); 371203134Sthompsastatic int run_bbp_read(struct run_softc *, uint8_t, uint8_t *); 372203134Sthompsastatic int run_bbp_write(struct run_softc *, uint8_t, uint8_t); 373203134Sthompsastatic int run_mcu_cmd(struct run_softc *, uint8_t, uint16_t); 374257955Skevlostatic const char *run_get_rf(uint16_t); 375260219Skevlostatic void run_rt3593_get_txpower(struct run_softc *); 376260219Skevlostatic void run_get_txpower(struct run_softc *); 377203134Sthompsastatic int run_read_eeprom(struct run_softc *); 378203134Sthompsastatic struct ieee80211_node *run_node_alloc(struct ieee80211vap *, 379203134Sthompsa const uint8_t mac[IEEE80211_ADDR_LEN]); 380203134Sthompsastatic int run_media_change(struct ifnet *); 381203134Sthompsastatic int run_newstate(struct ieee80211vap *, enum ieee80211_state, int); 382203134Sthompsastatic int run_wme_update(struct ieee80211com *); 383208019Sthompsastatic void run_wme_update_cb(void *); 384208019Sthompsastatic void run_key_set_cb(void *); 385208019Sthompsastatic int run_key_set(struct ieee80211vap *, struct ieee80211_key *, 386257955Skevlo const uint8_t mac[IEEE80211_ADDR_LEN]); 387208019Sthompsastatic void run_key_delete_cb(void *); 388208019Sthompsastatic int run_key_delete(struct ieee80211vap *, struct ieee80211_key *); 389206358Srpaulostatic void run_ratectl_to(void *); 390206358Srpaulostatic void run_ratectl_cb(void *, int); 391208019Sthompsastatic void run_drain_fifo(void *); 392203134Sthompsastatic void run_iter_func(void *, struct ieee80211_node *); 393208019Sthompsastatic void run_newassoc_cb(void *); 394203134Sthompsastatic void run_newassoc(struct ieee80211_node *, int); 395203134Sthompsastatic void run_rx_frame(struct run_softc *, struct mbuf *, uint32_t); 396203134Sthompsastatic void run_tx_free(struct run_endpoint_queue *pq, 397203134Sthompsa struct run_tx_data *, int); 398208019Sthompsastatic void run_set_tx_desc(struct run_softc *, struct run_tx_data *); 399203134Sthompsastatic int run_tx(struct run_softc *, struct mbuf *, 400203134Sthompsa struct ieee80211_node *); 401203134Sthompsastatic int run_tx_mgt(struct run_softc *, struct mbuf *, 402203134Sthompsa struct ieee80211_node *); 403203134Sthompsastatic int run_sendprot(struct run_softc *, const struct mbuf *, 404203134Sthompsa struct ieee80211_node *, int, int); 405203134Sthompsastatic int run_tx_param(struct run_softc *, struct mbuf *, 406203134Sthompsa struct ieee80211_node *, 407203134Sthompsa const struct ieee80211_bpf_params *); 408203134Sthompsastatic int run_raw_xmit(struct ieee80211_node *, struct mbuf *, 409203134Sthompsa const struct ieee80211_bpf_params *); 410287197Sglebiusstatic int run_transmit(struct ieee80211com *, struct mbuf *); 411287197Sglebiusstatic void run_start(struct run_softc *); 412287197Sglebiusstatic void run_parent(struct ieee80211com *); 413259544Skevlostatic void run_iq_calib(struct run_softc *, u_int); 414205042Sthompsastatic void run_set_agc(struct run_softc *, uint8_t); 415203134Sthompsastatic void run_select_chan_group(struct run_softc *, int); 416203134Sthompsastatic void run_set_rx_antenna(struct run_softc *, int); 417203134Sthompsastatic void run_rt2870_set_chan(struct run_softc *, u_int); 418203134Sthompsastatic void run_rt3070_set_chan(struct run_softc *, u_int); 419205042Sthompsastatic void run_rt3572_set_chan(struct run_softc *, u_int); 420260219Skevlostatic void run_rt3593_set_chan(struct run_softc *, u_int); 421257955Skevlostatic void run_rt5390_set_chan(struct run_softc *, u_int); 422259032Skevlostatic void run_rt5592_set_chan(struct run_softc *, u_int); 423203134Sthompsastatic int run_set_chan(struct run_softc *, struct ieee80211_channel *); 424203134Sthompsastatic void run_set_channel(struct ieee80211com *); 425203134Sthompsastatic void run_scan_start(struct ieee80211com *); 426203134Sthompsastatic void run_scan_end(struct ieee80211com *); 427203134Sthompsastatic void run_update_beacon(struct ieee80211vap *, int); 428208019Sthompsastatic void run_update_beacon_cb(void *); 429203134Sthompsastatic void run_updateprot(struct ieee80211com *); 430218492Sbschmidtstatic void run_updateprot_cb(void *); 431208019Sthompsastatic void run_usb_timeout_cb(void *); 432203134Sthompsastatic void run_reset_livelock(struct run_softc *); 433203134Sthompsastatic void run_enable_tsf_sync(struct run_softc *); 434203134Sthompsastatic void run_enable_mrr(struct run_softc *); 435203134Sthompsastatic void run_set_txpreamble(struct run_softc *); 436203134Sthompsastatic void run_set_basicrates(struct run_softc *); 437203134Sthompsastatic void run_set_leds(struct run_softc *, uint16_t); 438203134Sthompsastatic void run_set_bssid(struct run_softc *, const uint8_t *); 439203134Sthompsastatic void run_set_macaddr(struct run_softc *, const uint8_t *); 440283540Sglebiusstatic void run_updateslot(struct ieee80211com *); 441218492Sbschmidtstatic void run_updateslot_cb(void *); 442283540Sglebiusstatic void run_update_mcast(struct ieee80211com *); 443203134Sthompsastatic int8_t run_rssi2dbm(struct run_softc *, uint8_t, uint8_t); 444283540Sglebiusstatic void run_update_promisc_locked(struct run_softc *); 445283540Sglebiusstatic void run_update_promisc(struct ieee80211com *); 446257955Skevlostatic void run_rt5390_bbp_init(struct run_softc *); 447203134Sthompsastatic int run_bbp_init(struct run_softc *); 448203134Sthompsastatic int run_rt3070_rf_init(struct run_softc *); 449260219Skevlostatic void run_rt3593_rf_init(struct run_softc *); 450257955Skevlostatic void run_rt5390_rf_init(struct run_softc *); 451203134Sthompsastatic int run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t, 452203134Sthompsa uint8_t *); 453205042Sthompsastatic void run_rt3070_rf_setup(struct run_softc *); 454260219Skevlostatic void run_rt3593_rf_setup(struct run_softc *); 455260219Skevlostatic void run_rt5390_rf_setup(struct run_softc *); 456203134Sthompsastatic int run_txrx_enable(struct run_softc *); 457257955Skevlostatic void run_adjust_freq_offset(struct run_softc *); 458203134Sthompsastatic void run_init_locked(struct run_softc *); 459203134Sthompsastatic void run_stop(void *); 460257429Shselaskystatic void run_delay(struct run_softc *, u_int); 461203134Sthompsa 462259812Skevlostatic eventhandler_tag run_etag; 463259812Skevlo 464259544Skevlostatic const struct rt2860_rate { 465259544Skevlo uint8_t rate; 466259544Skevlo uint8_t mcs; 467259544Skevlo enum ieee80211_phytype phy; 468259544Skevlo uint8_t ctl_ridx; 469259544Skevlo uint16_t sp_ack_dur; 470259544Skevlo uint16_t lp_ack_dur; 471259544Skevlo} rt2860_rates[] = { 472259544Skevlo { 2, 0, IEEE80211_T_DS, 0, 314, 314 }, 473259544Skevlo { 4, 1, IEEE80211_T_DS, 1, 258, 162 }, 474259544Skevlo { 11, 2, IEEE80211_T_DS, 2, 223, 127 }, 475259544Skevlo { 22, 3, IEEE80211_T_DS, 3, 213, 117 }, 476259544Skevlo { 12, 0, IEEE80211_T_OFDM, 4, 60, 60 }, 477259544Skevlo { 18, 1, IEEE80211_T_OFDM, 4, 52, 52 }, 478259544Skevlo { 24, 2, IEEE80211_T_OFDM, 6, 48, 48 }, 479259544Skevlo { 36, 3, IEEE80211_T_OFDM, 6, 44, 44 }, 480259544Skevlo { 48, 4, IEEE80211_T_OFDM, 8, 44, 44 }, 481259544Skevlo { 72, 5, IEEE80211_T_OFDM, 8, 40, 40 }, 482259544Skevlo { 96, 6, IEEE80211_T_OFDM, 8, 40, 40 }, 483259544Skevlo { 108, 7, IEEE80211_T_OFDM, 8, 40, 40 } 484259544Skevlo}; 485259544Skevlo 486203134Sthompsastatic const struct { 487208019Sthompsa uint16_t reg; 488203134Sthompsa uint32_t val; 489203134Sthompsa} rt2870_def_mac[] = { 490203134Sthompsa RT2870_DEF_MAC 491203134Sthompsa}; 492203134Sthompsa 493203134Sthompsastatic const struct { 494203134Sthompsa uint8_t reg; 495203134Sthompsa uint8_t val; 496203134Sthompsa} rt2860_def_bbp[] = { 497203134Sthompsa RT2860_DEF_BBP 498257955Skevlo},rt5390_def_bbp[] = { 499257955Skevlo RT5390_DEF_BBP 500259032Skevlo},rt5592_def_bbp[] = { 501259032Skevlo RT5592_DEF_BBP 502203134Sthompsa}; 503203134Sthompsa 504259032Skevlo/* 505259032Skevlo * Default values for BBP register R196 for RT5592. 506259032Skevlo */ 507259032Skevlostatic const uint8_t rt5592_bbp_r196[] = { 508259032Skevlo 0xe0, 0x1f, 0x38, 0x32, 0x08, 0x28, 0x19, 0x0a, 0xff, 0x00, 509259032Skevlo 0x16, 0x10, 0x10, 0x0b, 0x36, 0x2c, 0x26, 0x24, 0x42, 0x36, 510259032Skevlo 0x30, 0x2d, 0x4c, 0x46, 0x3d, 0x40, 0x3e, 0x42, 0x3d, 0x40, 511259032Skevlo 0x3c, 0x34, 0x2c, 0x2f, 0x3c, 0x35, 0x2e, 0x2a, 0x49, 0x41, 512259032Skevlo 0x36, 0x31, 0x30, 0x30, 0x0e, 0x0d, 0x28, 0x21, 0x1c, 0x16, 513259032Skevlo 0x50, 0x4a, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 514259032Skevlo 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 515259032Skevlo 0x00, 0x00, 0x7d, 0x14, 0x32, 0x2c, 0x36, 0x4c, 0x43, 0x2c, 516259032Skevlo 0x2e, 0x36, 0x30, 0x6e 517259032Skevlo}; 518259032Skevlo 519203134Sthompsastatic const struct rfprog { 520203134Sthompsa uint8_t chan; 521203134Sthompsa uint32_t r1, r2, r3, r4; 522203134Sthompsa} rt2860_rf2850[] = { 523203134Sthompsa RT2860_RF2850 524203134Sthompsa}; 525203134Sthompsa 526203134Sthompsastruct { 527203134Sthompsa uint8_t n, r, k; 528205042Sthompsa} rt3070_freqs[] = { 529205042Sthompsa RT3070_RF3052 530203134Sthompsa}; 531203134Sthompsa 532259032Skevlostatic const struct rt5592_freqs { 533259032Skevlo uint16_t n; 534259032Skevlo uint8_t k, m, r; 535259032Skevlo} rt5592_freqs_20mhz[] = { 536259032Skevlo RT5592_RF5592_20MHZ 537259032Skevlo},rt5592_freqs_40mhz[] = { 538259032Skevlo RT5592_RF5592_40MHZ 539259032Skevlo}; 540259032Skevlo 541203134Sthompsastatic const struct { 542203134Sthompsa uint8_t reg; 543203134Sthompsa uint8_t val; 544203134Sthompsa} rt3070_def_rf[] = { 545203134Sthompsa RT3070_DEF_RF 546205042Sthompsa},rt3572_def_rf[] = { 547205042Sthompsa RT3572_DEF_RF 548260219Skevlo},rt3593_def_rf[] = { 549260219Skevlo RT3593_DEF_RF 550257955Skevlo},rt5390_def_rf[] = { 551257955Skevlo RT5390_DEF_RF 552257955Skevlo},rt5392_def_rf[] = { 553257955Skevlo RT5392_DEF_RF 554259032Skevlo},rt5592_def_rf[] = { 555259032Skevlo RT5592_DEF_RF 556259032Skevlo},rt5592_2ghz_def_rf[] = { 557259032Skevlo RT5592_2GHZ_DEF_RF 558259032Skevlo},rt5592_5ghz_def_rf[] = { 559259032Skevlo RT5592_5GHZ_DEF_RF 560203134Sthompsa}; 561203134Sthompsa 562259032Skevlostatic const struct { 563259032Skevlo u_int firstchan; 564259032Skevlo u_int lastchan; 565259032Skevlo uint8_t reg; 566259032Skevlo uint8_t val; 567259032Skevlo} rt5592_chan_5ghz[] = { 568259032Skevlo RT5592_CHAN_5GHZ 569259032Skevlo}; 570259032Skevlo 571203134Sthompsastatic const struct usb_config run_config[RUN_N_XFER] = { 572203134Sthompsa [RUN_BULK_TX_BE] = { 573203134Sthompsa .type = UE_BULK, 574203134Sthompsa .endpoint = UE_ADDR_ANY, 575203134Sthompsa .ep_index = 0, 576203134Sthompsa .direction = UE_DIR_OUT, 577203134Sthompsa .bufsize = RUN_MAX_TXSZ, 578203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 579203134Sthompsa .callback = run_bulk_tx_callback0, 580203134Sthompsa .timeout = 5000, /* ms */ 581203134Sthompsa }, 582203134Sthompsa [RUN_BULK_TX_BK] = { 583203134Sthompsa .type = UE_BULK, 584203134Sthompsa .endpoint = UE_ADDR_ANY, 585203134Sthompsa .direction = UE_DIR_OUT, 586203134Sthompsa .ep_index = 1, 587203134Sthompsa .bufsize = RUN_MAX_TXSZ, 588203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 589203134Sthompsa .callback = run_bulk_tx_callback1, 590203134Sthompsa .timeout = 5000, /* ms */ 591203134Sthompsa }, 592203134Sthompsa [RUN_BULK_TX_VI] = { 593203134Sthompsa .type = UE_BULK, 594203134Sthompsa .endpoint = UE_ADDR_ANY, 595203134Sthompsa .direction = UE_DIR_OUT, 596203134Sthompsa .ep_index = 2, 597203134Sthompsa .bufsize = RUN_MAX_TXSZ, 598203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 599203134Sthompsa .callback = run_bulk_tx_callback2, 600203134Sthompsa .timeout = 5000, /* ms */ 601203134Sthompsa }, 602203134Sthompsa [RUN_BULK_TX_VO] = { 603203134Sthompsa .type = UE_BULK, 604203134Sthompsa .endpoint = UE_ADDR_ANY, 605203134Sthompsa .direction = UE_DIR_OUT, 606203134Sthompsa .ep_index = 3, 607203134Sthompsa .bufsize = RUN_MAX_TXSZ, 608203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 609203134Sthompsa .callback = run_bulk_tx_callback3, 610203134Sthompsa .timeout = 5000, /* ms */ 611203134Sthompsa }, 612203134Sthompsa [RUN_BULK_TX_HCCA] = { 613203134Sthompsa .type = UE_BULK, 614203134Sthompsa .endpoint = UE_ADDR_ANY, 615203134Sthompsa .direction = UE_DIR_OUT, 616203134Sthompsa .ep_index = 4, 617203134Sthompsa .bufsize = RUN_MAX_TXSZ, 618203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 619203134Sthompsa .callback = run_bulk_tx_callback4, 620203134Sthompsa .timeout = 5000, /* ms */ 621203134Sthompsa }, 622203134Sthompsa [RUN_BULK_TX_PRIO] = { 623203134Sthompsa .type = UE_BULK, 624203134Sthompsa .endpoint = UE_ADDR_ANY, 625203134Sthompsa .direction = UE_DIR_OUT, 626203134Sthompsa .ep_index = 5, 627203134Sthompsa .bufsize = RUN_MAX_TXSZ, 628203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 629203134Sthompsa .callback = run_bulk_tx_callback5, 630203134Sthompsa .timeout = 5000, /* ms */ 631203134Sthompsa }, 632203134Sthompsa [RUN_BULK_RX] = { 633203134Sthompsa .type = UE_BULK, 634203134Sthompsa .endpoint = UE_ADDR_ANY, 635203134Sthompsa .direction = UE_DIR_IN, 636203134Sthompsa .bufsize = RUN_MAX_RXSZ, 637203134Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 638203134Sthompsa .callback = run_bulk_rx_callback, 639203134Sthompsa } 640203134Sthompsa}; 641203134Sthompsa 642259812Skevlostatic void 643259812Skevlorun_autoinst(void *arg, struct usb_device *udev, 644259812Skevlo struct usb_attach_arg *uaa) 645259812Skevlo{ 646259812Skevlo struct usb_interface *iface; 647259812Skevlo struct usb_interface_descriptor *id; 648259812Skevlo 649259812Skevlo if (uaa->dev_state != UAA_DEV_READY) 650259812Skevlo return; 651259812Skevlo 652259812Skevlo iface = usbd_get_iface(udev, 0); 653259812Skevlo if (iface == NULL) 654259812Skevlo return; 655259812Skevlo id = iface->idesc; 656259812Skevlo if (id == NULL || id->bInterfaceClass != UICLASS_MASS) 657259812Skevlo return; 658259812Skevlo if (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa)) 659259812Skevlo return; 660259812Skevlo 661259812Skevlo if (usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT) == 0) 662259812Skevlo uaa->dev_state = UAA_DEV_EJECTING; 663259812Skevlo} 664259812Skevlo 665220235Skevlostatic int 666259812Skevlorun_driver_loaded(struct module *mod, int what, void *arg) 667259812Skevlo{ 668259812Skevlo switch (what) { 669259812Skevlo case MOD_LOAD: 670259812Skevlo run_etag = EVENTHANDLER_REGISTER(usb_dev_configured, 671259812Skevlo run_autoinst, NULL, EVENTHANDLER_PRI_ANY); 672259812Skevlo break; 673259812Skevlo case MOD_UNLOAD: 674259812Skevlo EVENTHANDLER_DEREGISTER(usb_dev_configured, run_etag); 675259812Skevlo break; 676259812Skevlo default: 677259812Skevlo return (EOPNOTSUPP); 678259812Skevlo } 679259812Skevlo return (0); 680259812Skevlo} 681259812Skevlo 682259812Skevlostatic int 683203134Sthompsarun_match(device_t self) 684203134Sthompsa{ 685203134Sthompsa struct usb_attach_arg *uaa = device_get_ivars(self); 686203134Sthompsa 687203134Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 688203134Sthompsa return (ENXIO); 689203134Sthompsa if (uaa->info.bConfigIndex != 0) 690203134Sthompsa return (ENXIO); 691203134Sthompsa if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX) 692203134Sthompsa return (ENXIO); 693203134Sthompsa 694203134Sthompsa return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa)); 695203134Sthompsa} 696203134Sthompsa 697203134Sthompsastatic int 698203134Sthompsarun_attach(device_t self) 699203134Sthompsa{ 700203134Sthompsa struct run_softc *sc = device_get_softc(self); 701203134Sthompsa struct usb_attach_arg *uaa = device_get_ivars(self); 702287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 703205042Sthompsa uint32_t ver; 704258082Skevlo int ntries, error; 705203134Sthompsa uint8_t iface_index, bands; 706203134Sthompsa 707203134Sthompsa device_set_usb_desc(self); 708203134Sthompsa sc->sc_udev = uaa->device; 709203134Sthompsa sc->sc_dev = self; 710262465Skevlo if (USB_GET_DRIVER_INFO(uaa) != RUN_EJECT) 711262465Skevlo sc->sc_flags |= RUN_FLAG_FWLOAD_NEEDED; 712203134Sthompsa 713203134Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), 714203134Sthompsa MTX_NETWORK_LOCK, MTX_DEF); 715287197Sglebius mbufq_init(&sc->sc_snd, ifqmaxlen); 716203134Sthompsa 717203134Sthompsa iface_index = RT2860_IFACE_INDEX; 718208019Sthompsa 719203134Sthompsa error = usbd_transfer_setup(uaa->device, &iface_index, 720203134Sthompsa sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx); 721203134Sthompsa if (error) { 722205042Sthompsa device_printf(self, "could not allocate USB transfers, " 723203134Sthompsa "err=%s\n", usbd_errstr(error)); 724203134Sthompsa goto detach; 725203134Sthompsa } 726203134Sthompsa 727203134Sthompsa RUN_LOCK(sc); 728203134Sthompsa 729203134Sthompsa /* wait for the chip to settle */ 730203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 731209917Sthompsa if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0) { 732203134Sthompsa RUN_UNLOCK(sc); 733203134Sthompsa goto detach; 734203134Sthompsa } 735205042Sthompsa if (ver != 0 && ver != 0xffffffff) 736203134Sthompsa break; 737203134Sthompsa run_delay(sc, 10); 738203134Sthompsa } 739203134Sthompsa if (ntries == 100) { 740203138Sthompsa device_printf(sc->sc_dev, 741203138Sthompsa "timeout waiting for NIC to initialize\n"); 742203134Sthompsa RUN_UNLOCK(sc); 743203134Sthompsa goto detach; 744203134Sthompsa } 745205042Sthompsa sc->mac_ver = ver >> 16; 746205042Sthompsa sc->mac_rev = ver & 0xffff; 747203134Sthompsa 748203134Sthompsa /* retrieve RF rev. no and various other things from EEPROM */ 749203134Sthompsa run_read_eeprom(sc); 750203134Sthompsa 751203138Sthompsa device_printf(sc->sc_dev, 752203138Sthompsa "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n", 753205042Sthompsa sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev), 754287197Sglebius sc->ntxchains, sc->nrxchains, ether_sprintf(ic->ic_macaddr)); 755203134Sthompsa 756203134Sthompsa RUN_UNLOCK(sc); 757203134Sthompsa 758283537Sglebius ic->ic_softc = sc; 759283527Sglebius ic->ic_name = device_get_nameunit(self); 760203134Sthompsa ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 761203134Sthompsa ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 762208019Sthompsa 763203134Sthompsa /* set device capabilities */ 764203134Sthompsa ic->ic_caps = 765203134Sthompsa IEEE80211_C_STA | /* station mode supported */ 766203134Sthompsa IEEE80211_C_MONITOR | /* monitor mode supported */ 767203134Sthompsa IEEE80211_C_IBSS | 768203134Sthompsa IEEE80211_C_HOSTAP | 769208019Sthompsa IEEE80211_C_WDS | /* 4-address traffic works */ 770208019Sthompsa IEEE80211_C_MBSS | 771203134Sthompsa IEEE80211_C_SHPREAMBLE | /* short preamble supported */ 772203134Sthompsa IEEE80211_C_SHSLOT | /* short slot time supported */ 773203134Sthompsa IEEE80211_C_WME | /* WME */ 774214894Sbschmidt IEEE80211_C_WPA; /* WPA1|WPA2(RSN) */ 775203134Sthompsa 776203134Sthompsa ic->ic_cryptocaps = 777203134Sthompsa IEEE80211_CRYPTO_WEP | 778203134Sthompsa IEEE80211_CRYPTO_AES_CCM | 779203134Sthompsa IEEE80211_CRYPTO_TKIPMIC | 780203134Sthompsa IEEE80211_CRYPTO_TKIP; 781203134Sthompsa 782203134Sthompsa ic->ic_flags |= IEEE80211_F_DATAPAD; 783203134Sthompsa ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; 784203134Sthompsa 785203134Sthompsa bands = 0; 786203134Sthompsa setbit(&bands, IEEE80211_MODE_11B); 787203134Sthompsa setbit(&bands, IEEE80211_MODE_11G); 788258082Skevlo if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850 || 789260219Skevlo sc->rf_rev == RT3070_RF_3052 || sc->rf_rev == RT3593_RF_3053 || 790260219Skevlo sc->rf_rev == RT5592_RF_5592) 791258082Skevlo setbit(&bands, IEEE80211_MODE_11A); 792203134Sthompsa ieee80211_init_channels(ic, NULL, &bands); 793203134Sthompsa 794287197Sglebius ieee80211_ifattach(ic); 795203134Sthompsa 796203134Sthompsa ic->ic_scan_start = run_scan_start; 797203134Sthompsa ic->ic_scan_end = run_scan_end; 798203134Sthompsa ic->ic_set_channel = run_set_channel; 799203134Sthompsa ic->ic_node_alloc = run_node_alloc; 800203134Sthompsa ic->ic_newassoc = run_newassoc; 801218492Sbschmidt ic->ic_updateslot = run_updateslot; 802208019Sthompsa ic->ic_update_mcast = run_update_mcast; 803203134Sthompsa ic->ic_wme.wme_update = run_wme_update; 804203134Sthompsa ic->ic_raw_xmit = run_raw_xmit; 805203134Sthompsa ic->ic_update_promisc = run_update_promisc; 806203134Sthompsa ic->ic_vap_create = run_vap_create; 807203134Sthompsa ic->ic_vap_delete = run_vap_delete; 808287197Sglebius ic->ic_transmit = run_transmit; 809287197Sglebius ic->ic_parent = run_parent; 810203134Sthompsa 811203134Sthompsa ieee80211_radiotap_attach(ic, 812203134Sthompsa &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), 813203134Sthompsa RUN_TX_RADIOTAP_PRESENT, 814203134Sthompsa &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 815203134Sthompsa RUN_RX_RADIOTAP_PRESENT); 816203134Sthompsa 817208019Sthompsa TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc); 818208019Sthompsa TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc); 819257712Shselasky usb_callout_init_mtx(&sc->ratectl_ch, &sc->sc_mtx, 0); 820208019Sthompsa 821203134Sthompsa if (bootverbose) 822203134Sthompsa ieee80211_announce(ic); 823203134Sthompsa 824209917Sthompsa return (0); 825203134Sthompsa 826203134Sthompsadetach: 827203134Sthompsa run_detach(self); 828209917Sthompsa return (ENXIO); 829203134Sthompsa} 830203134Sthompsa 831203134Sthompsastatic int 832203134Sthompsarun_detach(device_t self) 833203134Sthompsa{ 834203134Sthompsa struct run_softc *sc = device_get_softc(self); 835287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 836203134Sthompsa int i; 837203134Sthompsa 838246614Shselasky RUN_LOCK(sc); 839246614Shselasky sc->sc_detached = 1; 840246614Shselasky RUN_UNLOCK(sc); 841246614Shselasky 842203134Sthompsa /* stop all USB transfers */ 843203134Sthompsa usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER); 844203134Sthompsa 845203134Sthompsa RUN_LOCK(sc); 846209144Sthompsa sc->ratectl_run = RUN_RATECTL_OFF; 847209144Sthompsa sc->cmdq_run = sc->cmdq_key_set = RUN_CMDQ_ABORT; 848209144Sthompsa 849203134Sthompsa /* free TX list, if any */ 850203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 851203134Sthompsa run_unsetup_tx_list(sc, &sc->sc_epq[i]); 852203134Sthompsa RUN_UNLOCK(sc); 853203134Sthompsa 854287197Sglebius if (sc->sc_ic.ic_softc == sc) { 855208019Sthompsa /* drain tasks */ 856208019Sthompsa usb_callout_drain(&sc->ratectl_ch); 857208019Sthompsa ieee80211_draintask(ic, &sc->cmdq_task); 858208019Sthompsa ieee80211_draintask(ic, &sc->ratectl_task); 859203134Sthompsa ieee80211_ifdetach(ic); 860203134Sthompsa } 861203134Sthompsa 862287197Sglebius mbufq_drain(&sc->sc_snd); 863203134Sthompsa mtx_destroy(&sc->sc_mtx); 864203134Sthompsa 865203134Sthompsa return (0); 866203134Sthompsa} 867203134Sthompsa 868203134Sthompsastatic struct ieee80211vap * 869228621Sbschmidtrun_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, 870228621Sbschmidt enum ieee80211_opmode opmode, int flags, 871203134Sthompsa const uint8_t bssid[IEEE80211_ADDR_LEN], 872203134Sthompsa const uint8_t mac[IEEE80211_ADDR_LEN]) 873203134Sthompsa{ 874286950Sadrian struct run_softc *sc = ic->ic_softc; 875203134Sthompsa struct run_vap *rvp; 876203134Sthompsa struct ieee80211vap *vap; 877208019Sthompsa int i; 878203134Sthompsa 879209917Sthompsa if (sc->rvp_cnt >= RUN_VAP_MAX) { 880287197Sglebius device_printf(sc->sc_dev, "number of VAPs maxed out\n"); 881209917Sthompsa return (NULL); 882208019Sthompsa } 883208019Sthompsa 884208019Sthompsa switch (opmode) { 885208019Sthompsa case IEEE80211_M_STA: 886208019Sthompsa /* enable s/w bmiss handling for sta mode */ 887208019Sthompsa flags |= IEEE80211_CLONE_NOBEACONS; 888208019Sthompsa /* fall though */ 889208019Sthompsa case IEEE80211_M_IBSS: 890208019Sthompsa case IEEE80211_M_MONITOR: 891208019Sthompsa case IEEE80211_M_HOSTAP: 892208019Sthompsa case IEEE80211_M_MBSS: 893208019Sthompsa /* other than WDS vaps, only one at a time */ 894208019Sthompsa if (!TAILQ_EMPTY(&ic->ic_vaps)) 895209917Sthompsa return (NULL); 896208019Sthompsa break; 897208019Sthompsa case IEEE80211_M_WDS: 898208019Sthompsa TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next){ 899208019Sthompsa if(vap->iv_opmode != IEEE80211_M_HOSTAP) 900208019Sthompsa continue; 901208019Sthompsa /* WDS vap's always share the local mac address. */ 902208019Sthompsa flags &= ~IEEE80211_CLONE_BSSID; 903208019Sthompsa break; 904208019Sthompsa } 905209917Sthompsa if (vap == NULL) { 906287197Sglebius device_printf(sc->sc_dev, 907287197Sglebius "wds only supported in ap mode\n"); 908209917Sthompsa return (NULL); 909208019Sthompsa } 910208019Sthompsa break; 911208019Sthompsa default: 912287197Sglebius device_printf(sc->sc_dev, "unknown opmode %d\n", opmode); 913209917Sthompsa return (NULL); 914208019Sthompsa } 915208019Sthompsa 916287197Sglebius rvp = malloc(sizeof(struct run_vap), M_80211_VAP, M_WAITOK | M_ZERO); 917203134Sthompsa vap = &rvp->vap; 918203134Sthompsa 919287197Sglebius if (ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, 920287197Sglebius bssid) != 0) { 921257743Shselasky /* out of memory */ 922257743Shselasky free(rvp, M_80211_VAP); 923257743Shselasky return (NULL); 924257743Shselasky } 925257743Shselasky 926203134Sthompsa vap->iv_update_beacon = run_update_beacon; 927208019Sthompsa vap->iv_max_aid = RT2870_WCID_MAX; 928208019Sthompsa /* 929208019Sthompsa * To delete the right key from h/w, we need wcid. 930208019Sthompsa * Luckily, there is unused space in ieee80211_key{}, wk_pad, 931208019Sthompsa * and matching wcid will be written into there. So, cast 932208019Sthompsa * some spells to remove 'const' from ieee80211_key{} 933208019Sthompsa */ 934208019Sthompsa vap->iv_key_delete = (void *)run_key_delete; 935208019Sthompsa vap->iv_key_set = (void *)run_key_set; 936203134Sthompsa 937203134Sthompsa /* override state transition machine */ 938203134Sthompsa rvp->newstate = vap->iv_newstate; 939203134Sthompsa vap->iv_newstate = run_newstate; 940203134Sthompsa 941206358Srpaulo ieee80211_ratectl_init(vap); 942206358Srpaulo ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */); 943203134Sthompsa 944203134Sthompsa /* complete setup */ 945287197Sglebius ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status, 946287197Sglebius mac); 947208019Sthompsa 948208019Sthompsa /* make sure id is always unique */ 949209917Sthompsa for (i = 0; i < RUN_VAP_MAX; i++) { 950208019Sthompsa if((sc->rvp_bmap & 1 << i) == 0){ 951208019Sthompsa sc->rvp_bmap |= 1 << i; 952208019Sthompsa rvp->rvp_id = i; 953208019Sthompsa break; 954208019Sthompsa } 955208019Sthompsa } 956209917Sthompsa if (sc->rvp_cnt++ == 0) 957208019Sthompsa ic->ic_opmode = opmode; 958208019Sthompsa 959209917Sthompsa if (opmode == IEEE80211_M_HOSTAP) 960209144Sthompsa sc->cmdq_run = RUN_CMDQ_GO; 961209144Sthompsa 962208019Sthompsa DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n", 963208019Sthompsa rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt); 964208019Sthompsa 965209917Sthompsa return (vap); 966203134Sthompsa} 967203134Sthompsa 968203134Sthompsastatic void 969203134Sthompsarun_vap_delete(struct ieee80211vap *vap) 970203134Sthompsa{ 971203134Sthompsa struct run_vap *rvp = RUN_VAP(vap); 972203134Sthompsa struct ieee80211com *ic; 973203134Sthompsa struct run_softc *sc; 974208019Sthompsa uint8_t rvp_id; 975203134Sthompsa 976209917Sthompsa if (vap == NULL) 977203134Sthompsa return; 978203134Sthompsa 979203134Sthompsa ic = vap->iv_ic; 980286950Sadrian sc = ic->ic_softc; 981203134Sthompsa 982205042Sthompsa RUN_LOCK(sc); 983208019Sthompsa 984218492Sbschmidt m_freem(rvp->beacon_mbuf); 985218492Sbschmidt rvp->beacon_mbuf = NULL; 986218492Sbschmidt 987208019Sthompsa rvp_id = rvp->rvp_id; 988208019Sthompsa sc->ratectl_run &= ~(1 << rvp_id); 989208019Sthompsa sc->rvp_bmap &= ~(1 << rvp_id); 990208019Sthompsa run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128); 991208019Sthompsa run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512); 992208019Sthompsa --sc->rvp_cnt; 993208019Sthompsa 994208019Sthompsa DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n", 995208019Sthompsa vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt); 996208019Sthompsa 997205042Sthompsa RUN_UNLOCK(sc); 998203134Sthompsa 999206358Srpaulo ieee80211_ratectl_deinit(vap); 1000203134Sthompsa ieee80211_vap_detach(vap); 1001203134Sthompsa free(rvp, M_80211_VAP); 1002203134Sthompsa} 1003203134Sthompsa 1004208019Sthompsa/* 1005208019Sthompsa * There are numbers of functions need to be called in context thread. 1006208019Sthompsa * Rather than creating taskqueue event for each of those functions, 1007208019Sthompsa * here is all-for-one taskqueue callback function. This function 1008208019Sthompsa * gurantees deferred functions are executed in the same order they 1009208019Sthompsa * were enqueued. 1010208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[]. 1011208019Sthompsa */ 1012203134Sthompsastatic void 1013208019Sthompsarun_cmdq_cb(void *arg, int pending) 1014208019Sthompsa{ 1015208019Sthompsa struct run_softc *sc = arg; 1016208019Sthompsa uint8_t i; 1017208019Sthompsa 1018208019Sthompsa /* call cmdq[].func locked */ 1019208019Sthompsa RUN_LOCK(sc); 1020209917Sthompsa for (i = sc->cmdq_exec; sc->cmdq[i].func && pending; 1021209917Sthompsa i = sc->cmdq_exec, pending--) { 1022208019Sthompsa DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending); 1023209917Sthompsa if (sc->cmdq_run == RUN_CMDQ_GO) { 1024208019Sthompsa /* 1025208019Sthompsa * If arg0 is NULL, callback func needs more 1026208019Sthompsa * than one arg. So, pass ptr to cmdq struct. 1027208019Sthompsa */ 1028209917Sthompsa if (sc->cmdq[i].arg0) 1029208019Sthompsa sc->cmdq[i].func(sc->cmdq[i].arg0); 1030208019Sthompsa else 1031208019Sthompsa sc->cmdq[i].func(&sc->cmdq[i]); 1032208019Sthompsa } 1033208019Sthompsa sc->cmdq[i].arg0 = NULL; 1034208019Sthompsa sc->cmdq[i].func = NULL; 1035208019Sthompsa sc->cmdq_exec++; 1036208019Sthompsa sc->cmdq_exec &= RUN_CMDQ_MASQ; 1037208019Sthompsa } 1038208019Sthompsa RUN_UNLOCK(sc); 1039208019Sthompsa} 1040208019Sthompsa 1041208019Sthompsastatic void 1042203134Sthompsarun_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq) 1043203134Sthompsa{ 1044203134Sthompsa struct run_tx_data *data; 1045203134Sthompsa 1046203134Sthompsa memset(pq, 0, sizeof(*pq)); 1047203134Sthompsa 1048203134Sthompsa STAILQ_INIT(&pq->tx_qh); 1049203134Sthompsa STAILQ_INIT(&pq->tx_fh); 1050203134Sthompsa 1051203134Sthompsa for (data = &pq->tx_data[0]; 1052203134Sthompsa data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) { 1053203134Sthompsa data->sc = sc; 1054203134Sthompsa STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); 1055203134Sthompsa } 1056203134Sthompsa pq->tx_nfree = RUN_TX_RING_COUNT; 1057203134Sthompsa} 1058203134Sthompsa 1059203134Sthompsastatic void 1060203134Sthompsarun_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq) 1061203134Sthompsa{ 1062203134Sthompsa struct run_tx_data *data; 1063203134Sthompsa 1064203134Sthompsa /* make sure any subsequent use of the queues will fail */ 1065203134Sthompsa pq->tx_nfree = 0; 1066203134Sthompsa STAILQ_INIT(&pq->tx_fh); 1067203134Sthompsa STAILQ_INIT(&pq->tx_qh); 1068203134Sthompsa 1069203134Sthompsa /* free up all node references and mbufs */ 1070203134Sthompsa for (data = &pq->tx_data[0]; 1071209917Sthompsa data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) { 1072203134Sthompsa if (data->m != NULL) { 1073203134Sthompsa m_freem(data->m); 1074203134Sthompsa data->m = NULL; 1075203134Sthompsa } 1076203134Sthompsa if (data->ni != NULL) { 1077203134Sthompsa ieee80211_free_node(data->ni); 1078203134Sthompsa data->ni = NULL; 1079203134Sthompsa } 1080203134Sthompsa } 1081203134Sthompsa} 1082203134Sthompsa 1083220235Skevlostatic int 1084203134Sthompsarun_load_microcode(struct run_softc *sc) 1085203134Sthompsa{ 1086203134Sthompsa usb_device_request_t req; 1087203137Sthompsa const struct firmware *fw; 1088203134Sthompsa const u_char *base; 1089203134Sthompsa uint32_t tmp; 1090203134Sthompsa int ntries, error; 1091203134Sthompsa const uint64_t *temp; 1092203134Sthompsa uint64_t bytes; 1093203134Sthompsa 1094205042Sthompsa RUN_UNLOCK(sc); 1095203137Sthompsa fw = firmware_get("runfw"); 1096205042Sthompsa RUN_LOCK(sc); 1097209917Sthompsa if (fw == NULL) { 1098203138Sthompsa device_printf(sc->sc_dev, 1099203138Sthompsa "failed loadfirmware of file %s\n", "runfw"); 1100203134Sthompsa return ENOENT; 1101203134Sthompsa } 1102203134Sthompsa 1103203137Sthompsa if (fw->datasize != 8192) { 1104203138Sthompsa device_printf(sc->sc_dev, 1105203138Sthompsa "invalid firmware size (should be 8KB)\n"); 1106203137Sthompsa error = EINVAL; 1107203137Sthompsa goto fail; 1108203134Sthompsa } 1109203134Sthompsa 1110203134Sthompsa /* 1111203134Sthompsa * RT3071/RT3072 use a different firmware 1112203134Sthompsa * run-rt2870 (8KB) contains both, 1113203134Sthompsa * first half (4KB) is for rt2870, 1114203134Sthompsa * last half is for rt3071. 1115203134Sthompsa */ 1116203137Sthompsa base = fw->data; 1117205042Sthompsa if ((sc->mac_ver) != 0x2860 && 1118205042Sthompsa (sc->mac_ver) != 0x2872 && 1119209917Sthompsa (sc->mac_ver) != 0x3070) { 1120203134Sthompsa base += 4096; 1121205042Sthompsa } 1122203134Sthompsa 1123203134Sthompsa /* cheap sanity check */ 1124203137Sthompsa temp = fw->data; 1125203134Sthompsa bytes = *temp; 1126257712Shselasky if (bytes != be64toh(0xffffff0210280210ULL)) { 1127203138Sthompsa device_printf(sc->sc_dev, "firmware checksum failed\n"); 1128203137Sthompsa error = EINVAL; 1129203137Sthompsa goto fail; 1130203137Sthompsa } 1131203134Sthompsa 1132203134Sthompsa /* write microcode image */ 1133262465Skevlo if (sc->sc_flags & RUN_FLAG_FWLOAD_NEEDED) { 1134260219Skevlo run_write_region_1(sc, RT2870_FW_BASE, base, 4096); 1135260219Skevlo run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff); 1136260219Skevlo run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff); 1137260219Skevlo } 1138203134Sthompsa 1139203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1140203134Sthompsa req.bRequest = RT2870_RESET; 1141203134Sthompsa USETW(req.wValue, 8); 1142203134Sthompsa USETW(req.wIndex, 0); 1143203134Sthompsa USETW(req.wLength, 0); 1144220235Skevlo if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)) 1145220235Skevlo != 0) { 1146203138Sthompsa device_printf(sc->sc_dev, "firmware reset failed\n"); 1147203137Sthompsa goto fail; 1148203137Sthompsa } 1149203134Sthompsa 1150203134Sthompsa run_delay(sc, 10); 1151203134Sthompsa 1152260219Skevlo run_write(sc, RT2860_H2M_BBPAGENT, 0); 1153203134Sthompsa run_write(sc, RT2860_H2M_MAILBOX, 0); 1154260219Skevlo run_write(sc, RT2860_H2M_INTSRC, 0); 1155205042Sthompsa if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0) 1156203137Sthompsa goto fail; 1157203134Sthompsa 1158203134Sthompsa /* wait until microcontroller is ready */ 1159203134Sthompsa for (ntries = 0; ntries < 1000; ntries++) { 1160260219Skevlo if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0) 1161203137Sthompsa goto fail; 1162203134Sthompsa if (tmp & RT2860_MCU_READY) 1163203134Sthompsa break; 1164203134Sthompsa run_delay(sc, 10); 1165203134Sthompsa } 1166203134Sthompsa if (ntries == 1000) { 1167203138Sthompsa device_printf(sc->sc_dev, 1168203138Sthompsa "timeout waiting for MCU to initialize\n"); 1169203137Sthompsa error = ETIMEDOUT; 1170203137Sthompsa goto fail; 1171203134Sthompsa } 1172233283Sbschmidt device_printf(sc->sc_dev, "firmware %s ver. %u.%u loaded\n", 1173233283Sbschmidt (base == fw->data) ? "RT2870" : "RT3071", 1174233283Sbschmidt *(base + 4092), *(base + 4093)); 1175203134Sthompsa 1176203137Sthompsafail: 1177203137Sthompsa firmware_put(fw, FIRMWARE_UNLOAD); 1178203137Sthompsa return (error); 1179203134Sthompsa} 1180203134Sthompsa 1181258641Shselaskystatic int 1182203134Sthompsarun_reset(struct run_softc *sc) 1183203134Sthompsa{ 1184203134Sthompsa usb_device_request_t req; 1185203134Sthompsa 1186203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1187203134Sthompsa req.bRequest = RT2870_RESET; 1188203134Sthompsa USETW(req.wValue, 1); 1189203134Sthompsa USETW(req.wIndex, 0); 1190203134Sthompsa USETW(req.wLength, 0); 1191209917Sthompsa return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)); 1192203134Sthompsa} 1193203134Sthompsa 1194203134Sthompsastatic usb_error_t 1195203134Sthompsarun_do_request(struct run_softc *sc, 1196203134Sthompsa struct usb_device_request *req, void *data) 1197203134Sthompsa{ 1198203134Sthompsa usb_error_t err; 1199203134Sthompsa int ntries = 10; 1200203134Sthompsa 1201203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 1202203134Sthompsa 1203203134Sthompsa while (ntries--) { 1204203134Sthompsa err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, 1205203134Sthompsa req, data, 0, NULL, 250 /* ms */); 1206203134Sthompsa if (err == 0) 1207203134Sthompsa break; 1208203134Sthompsa DPRINTFN(1, "Control request failed, %s (retrying)\n", 1209203134Sthompsa usbd_errstr(err)); 1210203134Sthompsa run_delay(sc, 10); 1211203134Sthompsa } 1212203134Sthompsa return (err); 1213203134Sthompsa} 1214203134Sthompsa 1215203134Sthompsastatic int 1216203134Sthompsarun_read(struct run_softc *sc, uint16_t reg, uint32_t *val) 1217203134Sthompsa{ 1218203134Sthompsa uint32_t tmp; 1219203134Sthompsa int error; 1220203134Sthompsa 1221203134Sthompsa error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp); 1222203134Sthompsa if (error == 0) 1223203134Sthompsa *val = le32toh(tmp); 1224203134Sthompsa else 1225203134Sthompsa *val = 0xffffffff; 1226209917Sthompsa return (error); 1227203134Sthompsa} 1228203134Sthompsa 1229203134Sthompsastatic int 1230203134Sthompsarun_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len) 1231203134Sthompsa{ 1232203134Sthompsa usb_device_request_t req; 1233203134Sthompsa 1234203134Sthompsa req.bmRequestType = UT_READ_VENDOR_DEVICE; 1235203134Sthompsa req.bRequest = RT2870_READ_REGION_1; 1236203134Sthompsa USETW(req.wValue, 0); 1237203134Sthompsa USETW(req.wIndex, reg); 1238203134Sthompsa USETW(req.wLength, len); 1239203134Sthompsa 1240209917Sthompsa return (run_do_request(sc, &req, buf)); 1241203134Sthompsa} 1242203134Sthompsa 1243203134Sthompsastatic int 1244203134Sthompsarun_write_2(struct run_softc *sc, uint16_t reg, uint16_t val) 1245203134Sthompsa{ 1246203134Sthompsa usb_device_request_t req; 1247203134Sthompsa 1248203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1249203134Sthompsa req.bRequest = RT2870_WRITE_2; 1250203134Sthompsa USETW(req.wValue, val); 1251203134Sthompsa USETW(req.wIndex, reg); 1252203134Sthompsa USETW(req.wLength, 0); 1253203134Sthompsa 1254209917Sthompsa return (run_do_request(sc, &req, NULL)); 1255203134Sthompsa} 1256203134Sthompsa 1257203134Sthompsastatic int 1258203134Sthompsarun_write(struct run_softc *sc, uint16_t reg, uint32_t val) 1259203134Sthompsa{ 1260203134Sthompsa int error; 1261203134Sthompsa 1262203134Sthompsa if ((error = run_write_2(sc, reg, val & 0xffff)) == 0) 1263203134Sthompsa error = run_write_2(sc, reg + 2, val >> 16); 1264209917Sthompsa return (error); 1265203134Sthompsa} 1266203134Sthompsa 1267203134Sthompsastatic int 1268203134Sthompsarun_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf, 1269203134Sthompsa int len) 1270203134Sthompsa{ 1271203134Sthompsa#if 1 1272203134Sthompsa int i, error = 0; 1273203134Sthompsa /* 1274203134Sthompsa * NB: the WRITE_REGION_1 command is not stable on RT2860. 1275203134Sthompsa * We thus issue multiple WRITE_2 commands instead. 1276203134Sthompsa */ 1277203134Sthompsa KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n")); 1278203134Sthompsa for (i = 0; i < len && error == 0; i += 2) 1279203134Sthompsa error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8); 1280209917Sthompsa return (error); 1281203134Sthompsa#else 1282203134Sthompsa usb_device_request_t req; 1283257958Skevlo int error = 0; 1284203134Sthompsa 1285257958Skevlo /* 1286257958Skevlo * NOTE: It appears the WRITE_REGION_1 command cannot be 1287257958Skevlo * passed a huge amount of data, which will crash the 1288257958Skevlo * firmware. Limit amount of data passed to 64-bytes at a 1289257958Skevlo * time. 1290257958Skevlo */ 1291257958Skevlo while (len > 0) { 1292257958Skevlo int delta = 64; 1293257958Skevlo if (delta > len) 1294257958Skevlo delta = len; 1295257958Skevlo 1296257958Skevlo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1297257958Skevlo req.bRequest = RT2870_WRITE_REGION_1; 1298257958Skevlo USETW(req.wValue, 0); 1299257958Skevlo USETW(req.wIndex, reg); 1300257958Skevlo USETW(req.wLength, delta); 1301257958Skevlo error = run_do_request(sc, &req, __DECONST(uint8_t *, buf)); 1302257958Skevlo if (error != 0) 1303257958Skevlo break; 1304257958Skevlo reg += delta; 1305257958Skevlo buf += delta; 1306257958Skevlo len -= delta; 1307257958Skevlo } 1308257958Skevlo return (error); 1309203134Sthompsa#endif 1310203134Sthompsa} 1311203134Sthompsa 1312203134Sthompsastatic int 1313203134Sthompsarun_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len) 1314203134Sthompsa{ 1315203134Sthompsa int i, error = 0; 1316203134Sthompsa 1317203134Sthompsa KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n")); 1318203134Sthompsa for (i = 0; i < len && error == 0; i += 4) 1319203134Sthompsa error = run_write(sc, reg + i, val); 1320209917Sthompsa return (error); 1321203134Sthompsa} 1322203134Sthompsa 1323203134Sthompsastatic int 1324259544Skevlorun_efuse_read(struct run_softc *sc, uint16_t addr, uint16_t *val, int count) 1325203134Sthompsa{ 1326203134Sthompsa uint32_t tmp; 1327203134Sthompsa uint16_t reg; 1328203134Sthompsa int error, ntries; 1329203134Sthompsa 1330203134Sthompsa if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0) 1331209917Sthompsa return (error); 1332203134Sthompsa 1333261076Shselasky if (count == 2) 1334261076Shselasky addr *= 2; 1335203134Sthompsa /*- 1336203134Sthompsa * Read one 16-byte block into registers EFUSE_DATA[0-3]: 1337203134Sthompsa * DATA0: F E D C 1338203134Sthompsa * DATA1: B A 9 8 1339203134Sthompsa * DATA2: 7 6 5 4 1340203134Sthompsa * DATA3: 3 2 1 0 1341203134Sthompsa */ 1342203134Sthompsa tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK); 1343203134Sthompsa tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK; 1344203134Sthompsa run_write(sc, RT3070_EFUSE_CTRL, tmp); 1345203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1346203134Sthompsa if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0) 1347209917Sthompsa return (error); 1348203134Sthompsa if (!(tmp & RT3070_EFSROM_KICK)) 1349203134Sthompsa break; 1350203134Sthompsa run_delay(sc, 2); 1351203134Sthompsa } 1352203134Sthompsa if (ntries == 100) 1353209917Sthompsa return (ETIMEDOUT); 1354203134Sthompsa 1355261076Shselasky if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) { 1356261076Shselasky *val = 0xffff; /* address not found */ 1357209917Sthompsa return (0); 1358261076Shselasky } 1359203134Sthompsa /* determine to which 32-bit register our 16-bit word belongs */ 1360203134Sthompsa reg = RT3070_EFUSE_DATA3 - (addr & 0xc); 1361203134Sthompsa if ((error = run_read(sc, reg, &tmp)) != 0) 1362209917Sthompsa return (error); 1363203134Sthompsa 1364261118Skevlo tmp >>= (8 * (addr & 0x3)); 1365261118Skevlo *val = (addr & 1) ? tmp >> 16 : tmp & 0xffff; 1366261118Skevlo 1367209917Sthompsa return (0); 1368203134Sthompsa} 1369203134Sthompsa 1370261124Skevlo/* Read 16-bit from eFUSE ROM for RT3xxx. */ 1371203134Sthompsastatic int 1372259544Skevlorun_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val) 1373259544Skevlo{ 1374259544Skevlo return (run_efuse_read(sc, addr, val, 2)); 1375259544Skevlo} 1376259544Skevlo 1377259544Skevlostatic int 1378203134Sthompsarun_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val) 1379203134Sthompsa{ 1380203134Sthompsa usb_device_request_t req; 1381203134Sthompsa uint16_t tmp; 1382203134Sthompsa int error; 1383203134Sthompsa 1384203134Sthompsa addr *= 2; 1385203134Sthompsa req.bmRequestType = UT_READ_VENDOR_DEVICE; 1386203134Sthompsa req.bRequest = RT2870_EEPROM_READ; 1387203134Sthompsa USETW(req.wValue, 0); 1388203134Sthompsa USETW(req.wIndex, addr); 1389260219Skevlo USETW(req.wLength, sizeof(tmp)); 1390203134Sthompsa 1391203134Sthompsa error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp); 1392203134Sthompsa if (error == 0) 1393203134Sthompsa *val = le16toh(tmp); 1394203134Sthompsa else 1395203134Sthompsa *val = 0xffff; 1396209917Sthompsa return (error); 1397203134Sthompsa} 1398203134Sthompsa 1399203134Sthompsastatic __inline int 1400203134Sthompsarun_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val) 1401203134Sthompsa{ 1402203134Sthompsa /* either eFUSE ROM or EEPROM */ 1403203134Sthompsa return sc->sc_srom_read(sc, addr, val); 1404203134Sthompsa} 1405203134Sthompsa 1406203134Sthompsastatic int 1407258733Skevlorun_rt2870_rf_write(struct run_softc *sc, uint32_t val) 1408203134Sthompsa{ 1409203134Sthompsa uint32_t tmp; 1410203134Sthompsa int error, ntries; 1411203134Sthompsa 1412203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1413203134Sthompsa if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0) 1414209917Sthompsa return (error); 1415203134Sthompsa if (!(tmp & RT2860_RF_REG_CTRL)) 1416203134Sthompsa break; 1417203134Sthompsa } 1418203134Sthompsa if (ntries == 10) 1419209917Sthompsa return (ETIMEDOUT); 1420203134Sthompsa 1421258732Skevlo return (run_write(sc, RT2860_RF_CSR_CFG0, val)); 1422203134Sthompsa} 1423203134Sthompsa 1424203134Sthompsastatic int 1425203134Sthompsarun_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val) 1426203134Sthompsa{ 1427203134Sthompsa uint32_t tmp; 1428203134Sthompsa int error, ntries; 1429203134Sthompsa 1430203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1431203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1432209917Sthompsa return (error); 1433203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1434203134Sthompsa break; 1435203134Sthompsa } 1436203134Sthompsa if (ntries == 100) 1437209917Sthompsa return (ETIMEDOUT); 1438203134Sthompsa 1439203134Sthompsa tmp = RT3070_RF_KICK | reg << 8; 1440203134Sthompsa if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0) 1441209917Sthompsa return (error); 1442203134Sthompsa 1443203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1444203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1445209917Sthompsa return (error); 1446203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1447203134Sthompsa break; 1448203134Sthompsa } 1449203134Sthompsa if (ntries == 100) 1450209917Sthompsa return (ETIMEDOUT); 1451203134Sthompsa 1452203134Sthompsa *val = tmp & 0xff; 1453209917Sthompsa return (0); 1454203134Sthompsa} 1455203134Sthompsa 1456203134Sthompsastatic int 1457203134Sthompsarun_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val) 1458203134Sthompsa{ 1459203134Sthompsa uint32_t tmp; 1460203134Sthompsa int error, ntries; 1461203134Sthompsa 1462203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1463203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1464209917Sthompsa return (error); 1465203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1466203134Sthompsa break; 1467203134Sthompsa } 1468203134Sthompsa if (ntries == 10) 1469209917Sthompsa return (ETIMEDOUT); 1470203134Sthompsa 1471203134Sthompsa tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val; 1472209917Sthompsa return (run_write(sc, RT3070_RF_CSR_CFG, tmp)); 1473203134Sthompsa} 1474203134Sthompsa 1475203134Sthompsastatic int 1476203134Sthompsarun_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val) 1477203134Sthompsa{ 1478203134Sthompsa uint32_t tmp; 1479203134Sthompsa int ntries, error; 1480203134Sthompsa 1481203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1482203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1483209917Sthompsa return (error); 1484203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1485203134Sthompsa break; 1486203134Sthompsa } 1487203134Sthompsa if (ntries == 10) 1488209917Sthompsa return (ETIMEDOUT); 1489203134Sthompsa 1490203134Sthompsa tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8; 1491203134Sthompsa if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0) 1492209917Sthompsa return (error); 1493203134Sthompsa 1494203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1495203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1496209917Sthompsa return (error); 1497203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1498203134Sthompsa break; 1499203134Sthompsa } 1500203134Sthompsa if (ntries == 10) 1501209917Sthompsa return (ETIMEDOUT); 1502203134Sthompsa 1503203134Sthompsa *val = tmp & 0xff; 1504209917Sthompsa return (0); 1505203134Sthompsa} 1506203134Sthompsa 1507203134Sthompsastatic int 1508203134Sthompsarun_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val) 1509203134Sthompsa{ 1510203134Sthompsa uint32_t tmp; 1511203134Sthompsa int ntries, error; 1512203134Sthompsa 1513203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1514203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1515209917Sthompsa return (error); 1516203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1517203134Sthompsa break; 1518203134Sthompsa } 1519203134Sthompsa if (ntries == 10) 1520209917Sthompsa return (ETIMEDOUT); 1521203134Sthompsa 1522203134Sthompsa tmp = RT2860_BBP_CSR_KICK | reg << 8 | val; 1523209917Sthompsa return (run_write(sc, RT2860_BBP_CSR_CFG, tmp)); 1524203134Sthompsa} 1525203134Sthompsa 1526203134Sthompsa/* 1527203134Sthompsa * Send a command to the 8051 microcontroller unit. 1528203134Sthompsa */ 1529203134Sthompsastatic int 1530203134Sthompsarun_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg) 1531203134Sthompsa{ 1532203134Sthompsa uint32_t tmp; 1533203134Sthompsa int error, ntries; 1534203134Sthompsa 1535203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1536203134Sthompsa if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0) 1537203134Sthompsa return error; 1538203134Sthompsa if (!(tmp & RT2860_H2M_BUSY)) 1539203134Sthompsa break; 1540203134Sthompsa } 1541203134Sthompsa if (ntries == 100) 1542203134Sthompsa return ETIMEDOUT; 1543203134Sthompsa 1544203134Sthompsa tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg; 1545203134Sthompsa if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0) 1546203134Sthompsa error = run_write(sc, RT2860_HOST_CMD, cmd); 1547209917Sthompsa return (error); 1548203134Sthompsa} 1549203134Sthompsa 1550203134Sthompsa/* 1551203134Sthompsa * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word. 1552203134Sthompsa * Used to adjust per-rate Tx power registers. 1553203134Sthompsa */ 1554203134Sthompsastatic __inline uint32_t 1555203134Sthompsab4inc(uint32_t b32, int8_t delta) 1556203134Sthompsa{ 1557203134Sthompsa int8_t i, b4; 1558203134Sthompsa 1559203134Sthompsa for (i = 0; i < 8; i++) { 1560203134Sthompsa b4 = b32 & 0xf; 1561203134Sthompsa b4 += delta; 1562203134Sthompsa if (b4 < 0) 1563203134Sthompsa b4 = 0; 1564203134Sthompsa else if (b4 > 0xf) 1565203134Sthompsa b4 = 0xf; 1566203134Sthompsa b32 = b32 >> 4 | b4 << 28; 1567203134Sthompsa } 1568209917Sthompsa return (b32); 1569203134Sthompsa} 1570203134Sthompsa 1571203134Sthompsastatic const char * 1572257955Skevlorun_get_rf(uint16_t rev) 1573203134Sthompsa{ 1574203134Sthompsa switch (rev) { 1575203134Sthompsa case RT2860_RF_2820: return "RT2820"; 1576203134Sthompsa case RT2860_RF_2850: return "RT2850"; 1577203134Sthompsa case RT2860_RF_2720: return "RT2720"; 1578203134Sthompsa case RT2860_RF_2750: return "RT2750"; 1579203134Sthompsa case RT3070_RF_3020: return "RT3020"; 1580203134Sthompsa case RT3070_RF_2020: return "RT2020"; 1581203134Sthompsa case RT3070_RF_3021: return "RT3021"; 1582203134Sthompsa case RT3070_RF_3022: return "RT3022"; 1583203134Sthompsa case RT3070_RF_3052: return "RT3052"; 1584260219Skevlo case RT3593_RF_3053: return "RT3053"; 1585259032Skevlo case RT5592_RF_5592: return "RT5592"; 1586257955Skevlo case RT5390_RF_5370: return "RT5370"; 1587257955Skevlo case RT5390_RF_5372: return "RT5372"; 1588203134Sthompsa } 1589209917Sthompsa return ("unknown"); 1590203134Sthompsa} 1591203134Sthompsa 1592260219Skevlostatic void 1593260219Skevlorun_rt3593_get_txpower(struct run_softc *sc) 1594260219Skevlo{ 1595260219Skevlo uint16_t addr, val; 1596260219Skevlo int i; 1597260219Skevlo 1598260219Skevlo /* Read power settings for 2GHz channels. */ 1599260219Skevlo for (i = 0; i < 14; i += 2) { 1600260219Skevlo addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE1 : 1601260219Skevlo RT2860_EEPROM_PWR2GHZ_BASE1; 1602260219Skevlo run_srom_read(sc, addr + i / 2, &val); 1603260219Skevlo sc->txpow1[i + 0] = (int8_t)(val & 0xff); 1604260219Skevlo sc->txpow1[i + 1] = (int8_t)(val >> 8); 1605260219Skevlo 1606260219Skevlo addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE2 : 1607260219Skevlo RT2860_EEPROM_PWR2GHZ_BASE2; 1608260219Skevlo run_srom_read(sc, addr + i / 2, &val); 1609260219Skevlo sc->txpow2[i + 0] = (int8_t)(val & 0xff); 1610260219Skevlo sc->txpow2[i + 1] = (int8_t)(val >> 8); 1611260219Skevlo 1612260219Skevlo if (sc->ntxchains == 3) { 1613260219Skevlo run_srom_read(sc, RT3593_EEPROM_PWR2GHZ_BASE3 + i / 2, 1614260219Skevlo &val); 1615260219Skevlo sc->txpow3[i + 0] = (int8_t)(val & 0xff); 1616260219Skevlo sc->txpow3[i + 1] = (int8_t)(val >> 8); 1617260219Skevlo } 1618260219Skevlo } 1619260219Skevlo /* Fix broken Tx power entries. */ 1620260219Skevlo for (i = 0; i < 14; i++) { 1621260542Skevlo if (sc->txpow1[i] > 31) 1622260219Skevlo sc->txpow1[i] = 5; 1623260542Skevlo if (sc->txpow2[i] > 31) 1624260219Skevlo sc->txpow2[i] = 5; 1625260219Skevlo if (sc->ntxchains == 3) { 1626260542Skevlo if (sc->txpow3[i] > 31) 1627260219Skevlo sc->txpow3[i] = 5; 1628260219Skevlo } 1629260219Skevlo } 1630260219Skevlo /* Read power settings for 5GHz channels. */ 1631260219Skevlo for (i = 0; i < 40; i += 2) { 1632260219Skevlo run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE1 + i / 2, &val); 1633260219Skevlo sc->txpow1[i + 14] = (int8_t)(val & 0xff); 1634260219Skevlo sc->txpow1[i + 15] = (int8_t)(val >> 8); 1635260219Skevlo 1636260219Skevlo run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE2 + i / 2, &val); 1637260219Skevlo sc->txpow2[i + 14] = (int8_t)(val & 0xff); 1638260219Skevlo sc->txpow2[i + 15] = (int8_t)(val >> 8); 1639260219Skevlo 1640260219Skevlo if (sc->ntxchains == 3) { 1641260219Skevlo run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE3 + i / 2, 1642260219Skevlo &val); 1643260219Skevlo sc->txpow3[i + 14] = (int8_t)(val & 0xff); 1644260219Skevlo sc->txpow3[i + 15] = (int8_t)(val >> 8); 1645260219Skevlo } 1646260219Skevlo } 1647260219Skevlo} 1648260219Skevlo 1649260219Skevlostatic void 1650260219Skevlorun_get_txpower(struct run_softc *sc) 1651260219Skevlo{ 1652260219Skevlo uint16_t val; 1653260219Skevlo int i; 1654260219Skevlo 1655260219Skevlo /* Read power settings for 2GHz channels. */ 1656260219Skevlo for (i = 0; i < 14; i += 2) { 1657260219Skevlo run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val); 1658260219Skevlo sc->txpow1[i + 0] = (int8_t)(val & 0xff); 1659260219Skevlo sc->txpow1[i + 1] = (int8_t)(val >> 8); 1660260219Skevlo 1661260219Skevlo if (sc->mac_ver != 0x5390) { 1662260219Skevlo run_srom_read(sc, 1663260219Skevlo RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val); 1664260219Skevlo sc->txpow2[i + 0] = (int8_t)(val & 0xff); 1665260219Skevlo sc->txpow2[i + 1] = (int8_t)(val >> 8); 1666260219Skevlo } 1667260219Skevlo } 1668260219Skevlo /* Fix broken Tx power entries. */ 1669260219Skevlo for (i = 0; i < 14; i++) { 1670260219Skevlo if (sc->mac_ver >= 0x5390) { 1671260219Skevlo if (sc->txpow1[i] < 0 || sc->txpow1[i] > 27) 1672260219Skevlo sc->txpow1[i] = 5; 1673260219Skevlo } else { 1674260219Skevlo if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31) 1675260219Skevlo sc->txpow1[i] = 5; 1676260219Skevlo } 1677260219Skevlo if (sc->mac_ver > 0x5390) { 1678260219Skevlo if (sc->txpow2[i] < 0 || sc->txpow2[i] > 27) 1679260219Skevlo sc->txpow2[i] = 5; 1680260219Skevlo } else if (sc->mac_ver < 0x5390) { 1681260219Skevlo if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31) 1682260219Skevlo sc->txpow2[i] = 5; 1683260219Skevlo } 1684260219Skevlo DPRINTF("chan %d: power1=%d, power2=%d\n", 1685260219Skevlo rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]); 1686260219Skevlo } 1687260219Skevlo /* Read power settings for 5GHz channels. */ 1688260219Skevlo for (i = 0; i < 40; i += 2) { 1689260219Skevlo run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val); 1690260219Skevlo sc->txpow1[i + 14] = (int8_t)(val & 0xff); 1691260219Skevlo sc->txpow1[i + 15] = (int8_t)(val >> 8); 1692260219Skevlo 1693260219Skevlo run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val); 1694260219Skevlo sc->txpow2[i + 14] = (int8_t)(val & 0xff); 1695260219Skevlo sc->txpow2[i + 15] = (int8_t)(val >> 8); 1696260219Skevlo } 1697260219Skevlo /* Fix broken Tx power entries. */ 1698260219Skevlo for (i = 0; i < 40; i++ ) { 1699260219Skevlo if (sc->mac_ver != 0x5592) { 1700260219Skevlo if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15) 1701260219Skevlo sc->txpow1[14 + i] = 5; 1702260219Skevlo if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15) 1703260219Skevlo sc->txpow2[14 + i] = 5; 1704260219Skevlo } 1705260219Skevlo DPRINTF("chan %d: power1=%d, power2=%d\n", 1706260219Skevlo rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i], 1707260219Skevlo sc->txpow2[14 + i]); 1708260219Skevlo } 1709260219Skevlo} 1710260219Skevlo 1711258641Shselaskystatic int 1712203134Sthompsarun_read_eeprom(struct run_softc *sc) 1713203134Sthompsa{ 1714287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 1715203134Sthompsa int8_t delta_2ghz, delta_5ghz; 1716203134Sthompsa uint32_t tmp; 1717203134Sthompsa uint16_t val; 1718203134Sthompsa int ridx, ant, i; 1719203134Sthompsa 1720203134Sthompsa /* check whether the ROM is eFUSE ROM or EEPROM */ 1721203134Sthompsa sc->sc_srom_read = run_eeprom_read_2; 1722205042Sthompsa if (sc->mac_ver >= 0x3070) { 1723203134Sthompsa run_read(sc, RT3070_EFUSE_CTRL, &tmp); 1724203134Sthompsa DPRINTF("EFUSE_CTRL=0x%08x\n", tmp); 1725261118Skevlo if ((tmp & RT3070_SEL_EFUSE) || sc->mac_ver == 0x3593) 1726203134Sthompsa sc->sc_srom_read = run_efuse_read_2; 1727203134Sthompsa } 1728203134Sthompsa 1729203134Sthompsa /* read ROM version */ 1730203134Sthompsa run_srom_read(sc, RT2860_EEPROM_VERSION, &val); 1731203134Sthompsa DPRINTF("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8); 1732203134Sthompsa 1733203134Sthompsa /* read MAC address */ 1734203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC01, &val); 1735287197Sglebius ic->ic_macaddr[0] = val & 0xff; 1736287197Sglebius ic->ic_macaddr[1] = val >> 8; 1737203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC23, &val); 1738287197Sglebius ic->ic_macaddr[2] = val & 0xff; 1739287197Sglebius ic->ic_macaddr[3] = val >> 8; 1740203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC45, &val); 1741287197Sglebius ic->ic_macaddr[4] = val & 0xff; 1742287197Sglebius ic->ic_macaddr[5] = val >> 8; 1743203134Sthompsa 1744260219Skevlo if (sc->mac_ver < 0x3593) { 1745257955Skevlo /* read vender BBP settings */ 1746205042Sthompsa for (i = 0; i < 10; i++) { 1747257955Skevlo run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val); 1748257955Skevlo sc->bbp[i].val = val & 0xff; 1749257955Skevlo sc->bbp[i].reg = val >> 8; 1750257955Skevlo DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg, 1751257955Skevlo sc->bbp[i].val); 1752205042Sthompsa } 1753257955Skevlo if (sc->mac_ver >= 0x3071) { 1754257955Skevlo /* read vendor RF settings */ 1755257955Skevlo for (i = 0; i < 10; i++) { 1756257955Skevlo run_srom_read(sc, RT3071_EEPROM_RF_BASE + i, 1757257955Skevlo &val); 1758257955Skevlo sc->rf[i].val = val & 0xff; 1759257955Skevlo sc->rf[i].reg = val >> 8; 1760257955Skevlo DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg, 1761257955Skevlo sc->rf[i].val); 1762257955Skevlo } 1763257955Skevlo } 1764205042Sthompsa } 1765203134Sthompsa 1766203134Sthompsa /* read RF frequency offset from EEPROM */ 1767260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS : 1768260219Skevlo RT3593_EEPROM_FREQ, &val); 1769203134Sthompsa sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0; 1770203134Sthompsa DPRINTF("EEPROM freq offset %d\n", sc->freq & 0xff); 1771203134Sthompsa 1772260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS : 1773260219Skevlo RT3593_EEPROM_FREQ_LEDS, &val); 1774205042Sthompsa if (val >> 8 != 0xff) { 1775203134Sthompsa /* read LEDs operating mode */ 1776205042Sthompsa sc->leds = val >> 8; 1777260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED1 : 1778260219Skevlo RT3593_EEPROM_LED1, &sc->led[0]); 1779260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED2 : 1780260219Skevlo RT3593_EEPROM_LED2, &sc->led[1]); 1781260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED3 : 1782260219Skevlo RT3593_EEPROM_LED3, &sc->led[2]); 1783203134Sthompsa } else { 1784203134Sthompsa /* broken EEPROM, use default settings */ 1785203134Sthompsa sc->leds = 0x01; 1786203134Sthompsa sc->led[0] = 0x5555; 1787203134Sthompsa sc->led[1] = 0x2221; 1788203134Sthompsa sc->led[2] = 0x5627; /* differs from RT2860 */ 1789203134Sthompsa } 1790203134Sthompsa DPRINTF("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n", 1791203134Sthompsa sc->leds, sc->led[0], sc->led[1], sc->led[2]); 1792203134Sthompsa 1793203134Sthompsa /* read RF information */ 1794259032Skevlo if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) 1795257955Skevlo run_srom_read(sc, 0x00, &val); 1796257955Skevlo else 1797257955Skevlo run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val); 1798257955Skevlo 1799203134Sthompsa if (val == 0xffff) { 1800260219Skevlo device_printf(sc->sc_dev, 1801260219Skevlo "invalid EEPROM antenna info, using default\n"); 1802203134Sthompsa DPRINTF("invalid EEPROM antenna info, using default\n"); 1803205042Sthompsa if (sc->mac_ver == 0x3572) { 1804205042Sthompsa /* default to RF3052 2T2R */ 1805205042Sthompsa sc->rf_rev = RT3070_RF_3052; 1806205042Sthompsa sc->ntxchains = 2; 1807205042Sthompsa sc->nrxchains = 2; 1808205042Sthompsa } else if (sc->mac_ver >= 0x3070) { 1809203134Sthompsa /* default to RF3020 1T1R */ 1810203134Sthompsa sc->rf_rev = RT3070_RF_3020; 1811203134Sthompsa sc->ntxchains = 1; 1812203134Sthompsa sc->nrxchains = 1; 1813203134Sthompsa } else { 1814203134Sthompsa /* default to RF2820 1T2R */ 1815203134Sthompsa sc->rf_rev = RT2860_RF_2820; 1816203134Sthompsa sc->ntxchains = 1; 1817203134Sthompsa sc->nrxchains = 2; 1818203134Sthompsa } 1819203134Sthompsa } else { 1820259032Skevlo if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) { 1821257955Skevlo sc->rf_rev = val; 1822257955Skevlo run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val); 1823257955Skevlo } else 1824257955Skevlo sc->rf_rev = (val >> 8) & 0xf; 1825203134Sthompsa sc->ntxchains = (val >> 4) & 0xf; 1826203134Sthompsa sc->nrxchains = val & 0xf; 1827203134Sthompsa } 1828257955Skevlo DPRINTF("EEPROM RF rev=0x%04x chains=%dT%dR\n", 1829203134Sthompsa sc->rf_rev, sc->ntxchains, sc->nrxchains); 1830203134Sthompsa 1831208019Sthompsa /* check if RF supports automatic Tx access gain control */ 1832203134Sthompsa run_srom_read(sc, RT2860_EEPROM_CONFIG, &val); 1833203134Sthompsa DPRINTF("EEPROM CFG 0x%04x\n", val); 1834205042Sthompsa /* check if driver should patch the DAC issue */ 1835205042Sthompsa if ((val >> 8) != 0xff) 1836205042Sthompsa sc->patch_dac = (val >> 15) & 1; 1837203134Sthompsa if ((val & 0xff) != 0xff) { 1838203134Sthompsa sc->ext_5ghz_lna = (val >> 3) & 1; 1839203134Sthompsa sc->ext_2ghz_lna = (val >> 2) & 1; 1840205042Sthompsa /* check if RF supports automatic Tx access gain control */ 1841203134Sthompsa sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1; 1842205042Sthompsa /* check if we have a hardware radio switch */ 1843205042Sthompsa sc->rfswitch = val & 1; 1844203134Sthompsa } 1845203134Sthompsa 1846260219Skevlo /* Read Tx power settings. */ 1847260219Skevlo if (sc->mac_ver == 0x3593) 1848260219Skevlo run_rt3593_get_txpower(sc); 1849260219Skevlo else 1850260219Skevlo run_get_txpower(sc); 1851203134Sthompsa 1852203134Sthompsa /* read Tx power compensation for each Tx rate */ 1853203134Sthompsa run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val); 1854203134Sthompsa delta_2ghz = delta_5ghz = 0; 1855203134Sthompsa if ((val & 0xff) != 0xff && (val & 0x80)) { 1856203134Sthompsa delta_2ghz = val & 0xf; 1857203134Sthompsa if (!(val & 0x40)) /* negative number */ 1858203134Sthompsa delta_2ghz = -delta_2ghz; 1859203134Sthompsa } 1860203134Sthompsa val >>= 8; 1861203134Sthompsa if ((val & 0xff) != 0xff && (val & 0x80)) { 1862203134Sthompsa delta_5ghz = val & 0xf; 1863203134Sthompsa if (!(val & 0x40)) /* negative number */ 1864203134Sthompsa delta_5ghz = -delta_5ghz; 1865203134Sthompsa } 1866203134Sthompsa DPRINTF("power compensation=%d (2GHz), %d (5GHz)\n", 1867203134Sthompsa delta_2ghz, delta_5ghz); 1868203134Sthompsa 1869203134Sthompsa for (ridx = 0; ridx < 5; ridx++) { 1870203134Sthompsa uint32_t reg; 1871203134Sthompsa 1872208019Sthompsa run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val); 1873208019Sthompsa reg = val; 1874208019Sthompsa run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val); 1875208019Sthompsa reg |= (uint32_t)val << 16; 1876203134Sthompsa 1877203134Sthompsa sc->txpow20mhz[ridx] = reg; 1878203134Sthompsa sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz); 1879203134Sthompsa sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz); 1880203134Sthompsa 1881203134Sthompsa DPRINTF("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, " 1882203134Sthompsa "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx], 1883203134Sthompsa sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]); 1884203134Sthompsa } 1885203134Sthompsa 1886260219Skevlo /* Read RSSI offsets and LNA gains from EEPROM. */ 1887260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_2GHZ : 1888260219Skevlo RT3593_EEPROM_RSSI1_2GHZ, &val); 1889203134Sthompsa sc->rssi_2ghz[0] = val & 0xff; /* Ant A */ 1890203134Sthompsa sc->rssi_2ghz[1] = val >> 8; /* Ant B */ 1891260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_2GHZ : 1892260219Skevlo RT3593_EEPROM_RSSI2_2GHZ, &val); 1893205042Sthompsa if (sc->mac_ver >= 0x3070) { 1894260219Skevlo if (sc->mac_ver == 0x3593) { 1895260219Skevlo sc->txmixgain_2ghz = 0; 1896260219Skevlo sc->rssi_2ghz[2] = val & 0xff; /* Ant C */ 1897260219Skevlo } else { 1898260219Skevlo /* 1899260219Skevlo * On RT3070 chips (limited to 2 Rx chains), this ROM 1900260219Skevlo * field contains the Tx mixer gain for the 2GHz band. 1901260219Skevlo */ 1902260219Skevlo if ((val & 0xff) != 0xff) 1903260219Skevlo sc->txmixgain_2ghz = val & 0x7; 1904260219Skevlo } 1905205042Sthompsa DPRINTF("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz); 1906205042Sthompsa } else 1907205042Sthompsa sc->rssi_2ghz[2] = val & 0xff; /* Ant C */ 1908260219Skevlo if (sc->mac_ver == 0x3593) 1909260219Skevlo run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val); 1910203134Sthompsa sc->lna[2] = val >> 8; /* channel group 2 */ 1911203134Sthompsa 1912260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_5GHZ : 1913260219Skevlo RT3593_EEPROM_RSSI1_5GHZ, &val); 1914203134Sthompsa sc->rssi_5ghz[0] = val & 0xff; /* Ant A */ 1915203134Sthompsa sc->rssi_5ghz[1] = val >> 8; /* Ant B */ 1916260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_5GHZ : 1917260219Skevlo RT3593_EEPROM_RSSI2_5GHZ, &val); 1918205042Sthompsa if (sc->mac_ver == 0x3572) { 1919205042Sthompsa /* 1920205042Sthompsa * On RT3572 chips (limited to 2 Rx chains), this ROM 1921205042Sthompsa * field contains the Tx mixer gain for the 5GHz band. 1922205042Sthompsa */ 1923205042Sthompsa if ((val & 0xff) != 0xff) 1924205042Sthompsa sc->txmixgain_5ghz = val & 0x7; 1925205042Sthompsa DPRINTF("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz); 1926205042Sthompsa } else 1927205042Sthompsa sc->rssi_5ghz[2] = val & 0xff; /* Ant C */ 1928260219Skevlo if (sc->mac_ver == 0x3593) { 1929260219Skevlo sc->txmixgain_5ghz = 0; 1930260219Skevlo run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val); 1931260219Skevlo } 1932203134Sthompsa sc->lna[3] = val >> 8; /* channel group 3 */ 1933203134Sthompsa 1934260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LNA : 1935260219Skevlo RT3593_EEPROM_LNA, &val); 1936203134Sthompsa sc->lna[0] = val & 0xff; /* channel group 0 */ 1937203134Sthompsa sc->lna[1] = val >> 8; /* channel group 1 */ 1938203134Sthompsa 1939203134Sthompsa /* fix broken 5GHz LNA entries */ 1940203134Sthompsa if (sc->lna[2] == 0 || sc->lna[2] == 0xff) { 1941203134Sthompsa DPRINTF("invalid LNA for channel group %d\n", 2); 1942203134Sthompsa sc->lna[2] = sc->lna[1]; 1943203134Sthompsa } 1944203134Sthompsa if (sc->lna[3] == 0 || sc->lna[3] == 0xff) { 1945203134Sthompsa DPRINTF("invalid LNA for channel group %d\n", 3); 1946203134Sthompsa sc->lna[3] = sc->lna[1]; 1947203134Sthompsa } 1948203134Sthompsa 1949203134Sthompsa /* fix broken RSSI offset entries */ 1950203134Sthompsa for (ant = 0; ant < 3; ant++) { 1951203134Sthompsa if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) { 1952203134Sthompsa DPRINTF("invalid RSSI%d offset: %d (2GHz)\n", 1953203134Sthompsa ant + 1, sc->rssi_2ghz[ant]); 1954203134Sthompsa sc->rssi_2ghz[ant] = 0; 1955203134Sthompsa } 1956203134Sthompsa if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) { 1957203134Sthompsa DPRINTF("invalid RSSI%d offset: %d (5GHz)\n", 1958203134Sthompsa ant + 1, sc->rssi_5ghz[ant]); 1959203134Sthompsa sc->rssi_5ghz[ant] = 0; 1960203134Sthompsa } 1961203134Sthompsa } 1962209917Sthompsa return (0); 1963203134Sthompsa} 1964203134Sthompsa 1965218676Shselaskystatic struct ieee80211_node * 1966203134Sthompsarun_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) 1967203134Sthompsa{ 1968203134Sthompsa return malloc(sizeof (struct run_node), M_DEVBUF, M_NOWAIT | M_ZERO); 1969203134Sthompsa} 1970203134Sthompsa 1971203134Sthompsastatic int 1972203134Sthompsarun_media_change(struct ifnet *ifp) 1973203134Sthompsa{ 1974208019Sthompsa struct ieee80211vap *vap = ifp->if_softc; 1975208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 1976203134Sthompsa const struct ieee80211_txparam *tp; 1977286950Sadrian struct run_softc *sc = ic->ic_softc; 1978203134Sthompsa uint8_t rate, ridx; 1979203134Sthompsa int error; 1980203134Sthompsa 1981203134Sthompsa RUN_LOCK(sc); 1982203134Sthompsa 1983203134Sthompsa error = ieee80211_media_change(ifp); 1984209917Sthompsa if (error != ENETRESET) { 1985203134Sthompsa RUN_UNLOCK(sc); 1986209917Sthompsa return (error); 1987208019Sthompsa } 1988203134Sthompsa 1989203134Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 1990203134Sthompsa if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 1991212127Sthompsa struct ieee80211_node *ni; 1992212127Sthompsa struct run_node *rn; 1993212127Sthompsa 1994203134Sthompsa rate = ic->ic_sup_rates[ic->ic_curmode]. 1995203134Sthompsa rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL; 1996203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 1997203134Sthompsa if (rt2860_rates[ridx].rate == rate) 1998203134Sthompsa break; 1999212127Sthompsa ni = ieee80211_ref_node(vap->iv_bss); 2000287552Skevlo rn = RUN_NODE(ni); 2001208019Sthompsa rn->fix_ridx = ridx; 2002208019Sthompsa DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx); 2003212127Sthompsa ieee80211_free_node(ni); 2004203134Sthompsa } 2005203134Sthompsa 2006208019Sthompsa#if 0 2007203134Sthompsa if ((ifp->if_flags & IFF_UP) && 2008287197Sglebius (ifp->if_drv_flags & RUN_RUNNING)){ 2009203134Sthompsa run_init_locked(sc); 2010203134Sthompsa } 2011208019Sthompsa#endif 2012203134Sthompsa 2013203134Sthompsa RUN_UNLOCK(sc); 2014203134Sthompsa 2015209917Sthompsa return (0); 2016203134Sthompsa} 2017203134Sthompsa 2018203134Sthompsastatic int 2019203134Sthompsarun_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 2020203134Sthompsa{ 2021203134Sthompsa const struct ieee80211_txparam *tp; 2022203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2023286950Sadrian struct run_softc *sc = ic->ic_softc; 2024203134Sthompsa struct run_vap *rvp = RUN_VAP(vap); 2025203134Sthompsa enum ieee80211_state ostate; 2026208019Sthompsa uint32_t sta[3]; 2027203134Sthompsa uint32_t tmp; 2028208019Sthompsa uint8_t ratectl; 2029208019Sthompsa uint8_t restart_ratectl = 0; 2030208019Sthompsa uint8_t bid = 1 << rvp->rvp_id; 2031203134Sthompsa 2032203134Sthompsa ostate = vap->iv_state; 2033203134Sthompsa DPRINTF("%s -> %s\n", 2034203134Sthompsa ieee80211_state_name[ostate], 2035203134Sthompsa ieee80211_state_name[nstate]); 2036203134Sthompsa 2037203134Sthompsa IEEE80211_UNLOCK(ic); 2038203134Sthompsa RUN_LOCK(sc); 2039203134Sthompsa 2040208019Sthompsa ratectl = sc->ratectl_run; /* remember current state */ 2041208019Sthompsa sc->ratectl_run = RUN_RATECTL_OFF; 2042208019Sthompsa usb_callout_stop(&sc->ratectl_ch); 2043203134Sthompsa 2044203134Sthompsa if (ostate == IEEE80211_S_RUN) { 2045203134Sthompsa /* turn link LED off */ 2046203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO); 2047203134Sthompsa } 2048203134Sthompsa 2049203134Sthompsa switch (nstate) { 2050203134Sthompsa case IEEE80211_S_INIT: 2051208019Sthompsa restart_ratectl = 1; 2052208019Sthompsa 2053208019Sthompsa if (ostate != IEEE80211_S_RUN) 2054208019Sthompsa break; 2055208019Sthompsa 2056208019Sthompsa ratectl &= ~bid; 2057208019Sthompsa sc->runbmap &= ~bid; 2058208019Sthompsa 2059208019Sthompsa /* abort TSF synchronization if there is no vap running */ 2060209917Sthompsa if (--sc->running == 0) { 2061203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 2062203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, 2063203134Sthompsa tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 2064203134Sthompsa RT2860_TBTT_TIMER_EN)); 2065203134Sthompsa } 2066203134Sthompsa break; 2067203134Sthompsa 2068203134Sthompsa case IEEE80211_S_RUN: 2069209917Sthompsa if (!(sc->runbmap & bid)) { 2070208019Sthompsa if(sc->running++) 2071208019Sthompsa restart_ratectl = 1; 2072208019Sthompsa sc->runbmap |= bid; 2073208019Sthompsa } 2074203134Sthompsa 2075218492Sbschmidt m_freem(rvp->beacon_mbuf); 2076218492Sbschmidt rvp->beacon_mbuf = NULL; 2077218492Sbschmidt 2078209917Sthompsa switch (vap->iv_opmode) { 2079208019Sthompsa case IEEE80211_M_HOSTAP: 2080208019Sthompsa case IEEE80211_M_MBSS: 2081208019Sthompsa sc->ap_running |= bid; 2082208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2083208019Sthompsa run_update_beacon_cb(vap); 2084208019Sthompsa break; 2085208019Sthompsa case IEEE80211_M_IBSS: 2086208019Sthompsa sc->adhoc_running |= bid; 2087209917Sthompsa if (!sc->ap_running) 2088208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2089208019Sthompsa run_update_beacon_cb(vap); 2090208019Sthompsa break; 2091208019Sthompsa case IEEE80211_M_STA: 2092208019Sthompsa sc->sta_running |= bid; 2093209917Sthompsa if (!sc->ap_running && !sc->adhoc_running) 2094208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2095208019Sthompsa 2096208019Sthompsa /* read statistic counters (clear on read) */ 2097208019Sthompsa run_read_region_1(sc, RT2860_TX_STA_CNT0, 2098208019Sthompsa (uint8_t *)sta, sizeof sta); 2099208019Sthompsa 2100208019Sthompsa break; 2101208019Sthompsa default: 2102208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2103208019Sthompsa break; 2104208019Sthompsa } 2105208019Sthompsa 2106203134Sthompsa if (vap->iv_opmode != IEEE80211_M_MONITOR) { 2107212127Sthompsa struct ieee80211_node *ni; 2108212127Sthompsa 2109236439Shselasky if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) { 2110236439Shselasky RUN_UNLOCK(sc); 2111236439Shselasky IEEE80211_LOCK(ic); 2112236439Shselasky return (-1); 2113236439Shselasky } 2114283540Sglebius run_updateslot(ic); 2115203134Sthompsa run_enable_mrr(sc); 2116203134Sthompsa run_set_txpreamble(sc); 2117203134Sthompsa run_set_basicrates(sc); 2118212127Sthompsa ni = ieee80211_ref_node(vap->iv_bss); 2119287197Sglebius IEEE80211_ADDR_COPY(ic->ic_macaddr, ni->ni_bssid); 2120203134Sthompsa run_set_bssid(sc, ni->ni_bssid); 2121212127Sthompsa ieee80211_free_node(ni); 2122208019Sthompsa run_enable_tsf_sync(sc); 2123203134Sthompsa 2124208019Sthompsa /* enable automatic rate adaptation */ 2125208019Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 2126208019Sthompsa if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) 2127208019Sthompsa ratectl |= bid; 2128203134Sthompsa } 2129203134Sthompsa 2130203134Sthompsa /* turn link LED on */ 2131203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO | 2132208019Sthompsa (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 2133203134Sthompsa RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ)); 2134203134Sthompsa 2135203134Sthompsa break; 2136203134Sthompsa default: 2137203134Sthompsa DPRINTFN(6, "undefined case\n"); 2138203134Sthompsa break; 2139203134Sthompsa } 2140203134Sthompsa 2141208019Sthompsa /* restart amrr for running VAPs */ 2142209917Sthompsa if ((sc->ratectl_run = ratectl) && restart_ratectl) 2143208019Sthompsa usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2144208019Sthompsa 2145203134Sthompsa RUN_UNLOCK(sc); 2146203134Sthompsa IEEE80211_LOCK(ic); 2147203134Sthompsa 2148203134Sthompsa return(rvp->newstate(vap, nstate, arg)); 2149203134Sthompsa} 2150203134Sthompsa 2151203134Sthompsa/* ARGSUSED */ 2152203134Sthompsastatic void 2153208019Sthompsarun_wme_update_cb(void *arg) 2154203134Sthompsa{ 2155203134Sthompsa struct ieee80211com *ic = arg; 2156286950Sadrian struct run_softc *sc = ic->ic_softc; 2157203134Sthompsa struct ieee80211_wme_state *wmesp = &ic->ic_wme; 2158203134Sthompsa int aci, error = 0; 2159203134Sthompsa 2160208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2161203134Sthompsa 2162203134Sthompsa /* update MAC TX configuration registers */ 2163203134Sthompsa for (aci = 0; aci < WME_NUM_AC; aci++) { 2164203134Sthompsa error = run_write(sc, RT2860_EDCA_AC_CFG(aci), 2165203134Sthompsa wmesp->wme_params[aci].wmep_logcwmax << 16 | 2166203134Sthompsa wmesp->wme_params[aci].wmep_logcwmin << 12 | 2167203134Sthompsa wmesp->wme_params[aci].wmep_aifsn << 8 | 2168203134Sthompsa wmesp->wme_params[aci].wmep_txopLimit); 2169209917Sthompsa if (error) goto err; 2170203134Sthompsa } 2171203134Sthompsa 2172203134Sthompsa /* update SCH/DMA registers too */ 2173203134Sthompsa error = run_write(sc, RT2860_WMM_AIFSN_CFG, 2174203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_aifsn << 12 | 2175203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_aifsn << 8 | 2176203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_aifsn << 4 | 2177203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_aifsn); 2178209917Sthompsa if (error) goto err; 2179203134Sthompsa error = run_write(sc, RT2860_WMM_CWMIN_CFG, 2180203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_logcwmin << 12 | 2181203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_logcwmin << 8 | 2182203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_logcwmin << 4 | 2183203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_logcwmin); 2184209917Sthompsa if (error) goto err; 2185203134Sthompsa error = run_write(sc, RT2860_WMM_CWMAX_CFG, 2186203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_logcwmax << 12 | 2187203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_logcwmax << 8 | 2188203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_logcwmax << 4 | 2189203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_logcwmax); 2190209917Sthompsa if (error) goto err; 2191203134Sthompsa error = run_write(sc, RT2860_WMM_TXOP0_CFG, 2192203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_txopLimit << 16 | 2193203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_txopLimit); 2194209917Sthompsa if (error) goto err; 2195203134Sthompsa error = run_write(sc, RT2860_WMM_TXOP1_CFG, 2196203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_txopLimit << 16 | 2197203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_txopLimit); 2198203134Sthompsa 2199203134Sthompsaerr: 2200209917Sthompsa if (error) 2201203134Sthompsa DPRINTF("WME update failed\n"); 2202203134Sthompsa 2203203134Sthompsa return; 2204203134Sthompsa} 2205203134Sthompsa 2206208019Sthompsastatic int 2207208019Sthompsarun_wme_update(struct ieee80211com *ic) 2208208019Sthompsa{ 2209286950Sadrian struct run_softc *sc = ic->ic_softc; 2210208019Sthompsa 2211208019Sthompsa /* sometime called wothout lock */ 2212209917Sthompsa if (mtx_owned(&ic->ic_comlock.mtx)) { 2213208019Sthompsa uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 2214208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 2215208019Sthompsa sc->cmdq[i].func = run_wme_update_cb; 2216208019Sthompsa sc->cmdq[i].arg0 = ic; 2217208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2218209918Sthompsa return (0); 2219208019Sthompsa } 2220208019Sthompsa 2221208019Sthompsa RUN_LOCK(sc); 2222208019Sthompsa run_wme_update_cb(ic); 2223208019Sthompsa RUN_UNLOCK(sc); 2224208019Sthompsa 2225287552Skevlo /* return whatever, upper layer doesn't care anyway */ 2226208019Sthompsa return (0); 2227208019Sthompsa} 2228208019Sthompsa 2229203134Sthompsastatic void 2230208019Sthompsarun_key_set_cb(void *arg) 2231203134Sthompsa{ 2232208019Sthompsa struct run_cmdq *cmdq = arg; 2233208019Sthompsa struct ieee80211vap *vap = cmdq->arg1; 2234208019Sthompsa struct ieee80211_key *k = cmdq->k; 2235203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2236286950Sadrian struct run_softc *sc = ic->ic_softc; 2237203134Sthompsa struct ieee80211_node *ni; 2238287553Skevlo u_int cipher = k->wk_cipher->ic_cipher; 2239203134Sthompsa uint32_t attr; 2240203134Sthompsa uint16_t base, associd; 2241209144Sthompsa uint8_t mode, wcid, iv[8]; 2242203134Sthompsa 2243208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2244203134Sthompsa 2245209917Sthompsa if (vap->iv_opmode == IEEE80211_M_HOSTAP) 2246208019Sthompsa ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac); 2247209144Sthompsa else 2248203134Sthompsa ni = vap->iv_bss; 2249208019Sthompsa associd = (ni != NULL) ? ni->ni_associd : 0; 2250203134Sthompsa 2251203134Sthompsa /* map net80211 cipher to RT2860 security mode */ 2252287553Skevlo switch (cipher) { 2253203134Sthompsa case IEEE80211_CIPHER_WEP: 2254203134Sthompsa if(k->wk_keylen < 8) 2255203134Sthompsa mode = RT2860_MODE_WEP40; 2256203134Sthompsa else 2257203134Sthompsa mode = RT2860_MODE_WEP104; 2258203134Sthompsa break; 2259203134Sthompsa case IEEE80211_CIPHER_TKIP: 2260203134Sthompsa mode = RT2860_MODE_TKIP; 2261203134Sthompsa break; 2262203134Sthompsa case IEEE80211_CIPHER_AES_CCM: 2263203134Sthompsa mode = RT2860_MODE_AES_CCMP; 2264203134Sthompsa break; 2265203134Sthompsa default: 2266203134Sthompsa DPRINTF("undefined case\n"); 2267208019Sthompsa return; 2268203134Sthompsa } 2269203134Sthompsa 2270208019Sthompsa DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n", 2271203134Sthompsa associd, k->wk_keyix, mode, 2272208019Sthompsa (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise", 2273208019Sthompsa (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off", 2274208019Sthompsa (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off"); 2275203134Sthompsa 2276203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 2277203134Sthompsa wcid = 0; /* NB: update WCID0 for group keys */ 2278208019Sthompsa base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix); 2279203134Sthompsa } else { 2280245047Shselasky wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 2281245047Shselasky 1 : RUN_AID2WCID(associd); 2282203134Sthompsa base = RT2860_PKEY(wcid); 2283203134Sthompsa } 2284203134Sthompsa 2285287553Skevlo if (cipher == IEEE80211_CIPHER_TKIP) { 2286203134Sthompsa if(run_write_region_1(sc, base, k->wk_key, 16)) 2287208019Sthompsa return; 2288209144Sthompsa if(run_write_region_1(sc, base + 16, &k->wk_key[16], 8)) /* wk_txmic */ 2289208019Sthompsa return; 2290209144Sthompsa if(run_write_region_1(sc, base + 24, &k->wk_key[24], 8)) /* wk_rxmic */ 2291208019Sthompsa return; 2292203134Sthompsa } else { 2293203134Sthompsa /* roundup len to 16-bit: XXX fix write_region_1() instead */ 2294203134Sthompsa if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1)) 2295208019Sthompsa return; 2296203134Sthompsa } 2297203134Sthompsa 2298203134Sthompsa if (!(k->wk_flags & IEEE80211_KEY_GROUP) || 2299203134Sthompsa (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) { 2300203134Sthompsa /* set initial packet number in IV+EIV */ 2301287553Skevlo if (cipher == IEEE80211_CIPHER_WEP) { 2302203134Sthompsa memset(iv, 0, sizeof iv); 2303208019Sthompsa iv[3] = vap->iv_def_txkey << 6; 2304203134Sthompsa } else { 2305287553Skevlo if (cipher == IEEE80211_CIPHER_TKIP) { 2306203134Sthompsa iv[0] = k->wk_keytsc >> 8; 2307203134Sthompsa iv[1] = (iv[0] | 0x20) & 0x7f; 2308203134Sthompsa iv[2] = k->wk_keytsc; 2309203134Sthompsa } else /* CCMP */ { 2310203134Sthompsa iv[0] = k->wk_keytsc; 2311203134Sthompsa iv[1] = k->wk_keytsc >> 8; 2312203134Sthompsa iv[2] = 0; 2313203134Sthompsa } 2314203134Sthompsa iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV; 2315203134Sthompsa iv[4] = k->wk_keytsc >> 16; 2316203134Sthompsa iv[5] = k->wk_keytsc >> 24; 2317203134Sthompsa iv[6] = k->wk_keytsc >> 32; 2318203134Sthompsa iv[7] = k->wk_keytsc >> 40; 2319203134Sthompsa } 2320209917Sthompsa if (run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8)) 2321208019Sthompsa return; 2322203134Sthompsa } 2323203134Sthompsa 2324203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 2325203134Sthompsa /* install group key */ 2326209917Sthompsa if (run_read(sc, RT2860_SKEY_MODE_0_7, &attr)) 2327208019Sthompsa return; 2328203134Sthompsa attr &= ~(0xf << (k->wk_keyix * 4)); 2329203134Sthompsa attr |= mode << (k->wk_keyix * 4); 2330209917Sthompsa if (run_write(sc, RT2860_SKEY_MODE_0_7, attr)) 2331208019Sthompsa return; 2332203134Sthompsa } else { 2333203134Sthompsa /* install pairwise key */ 2334209917Sthompsa if (run_read(sc, RT2860_WCID_ATTR(wcid), &attr)) 2335208019Sthompsa return; 2336203134Sthompsa attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN; 2337209917Sthompsa if (run_write(sc, RT2860_WCID_ATTR(wcid), attr)) 2338208019Sthompsa return; 2339203134Sthompsa } 2340203134Sthompsa 2341203134Sthompsa /* TODO create a pass-thru key entry? */ 2342203134Sthompsa 2343208019Sthompsa /* need wcid to delete the right key later */ 2344208019Sthompsa k->wk_pad = wcid; 2345203134Sthompsa} 2346203134Sthompsa 2347203134Sthompsa/* 2348208019Sthompsa * Don't have to be deferred, but in order to keep order of 2349208019Sthompsa * execution, i.e. with run_key_delete(), defer this and let 2350208019Sthompsa * run_cmdq_cb() maintain the order. 2351208019Sthompsa * 2352203134Sthompsa * return 0 on error 2353203134Sthompsa */ 2354203134Sthompsastatic int 2355208019Sthompsarun_key_set(struct ieee80211vap *vap, struct ieee80211_key *k, 2356208019Sthompsa const uint8_t mac[IEEE80211_ADDR_LEN]) 2357203134Sthompsa{ 2358203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2359286950Sadrian struct run_softc *sc = ic->ic_softc; 2360208019Sthompsa uint32_t i; 2361208019Sthompsa 2362208019Sthompsa i = RUN_CMDQ_GET(&sc->cmdq_store); 2363208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 2364208019Sthompsa sc->cmdq[i].func = run_key_set_cb; 2365208019Sthompsa sc->cmdq[i].arg0 = NULL; 2366208019Sthompsa sc->cmdq[i].arg1 = vap; 2367208019Sthompsa sc->cmdq[i].k = k; 2368208019Sthompsa IEEE80211_ADDR_COPY(sc->cmdq[i].mac, mac); 2369208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2370208019Sthompsa 2371209144Sthompsa /* 2372209144Sthompsa * To make sure key will be set when hostapd 2373209144Sthompsa * calls iv_key_set() before if_init(). 2374209144Sthompsa */ 2375209917Sthompsa if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 2376209144Sthompsa RUN_LOCK(sc); 2377209144Sthompsa sc->cmdq_key_set = RUN_CMDQ_GO; 2378209144Sthompsa RUN_UNLOCK(sc); 2379209144Sthompsa } 2380209144Sthompsa 2381209917Sthompsa return (1); 2382208019Sthompsa} 2383208019Sthompsa 2384208019Sthompsa/* 2385208019Sthompsa * If wlan is destroyed without being brought down i.e. without 2386208019Sthompsa * wlan down or wpa_cli terminate, this function is called after 2387208019Sthompsa * vap is gone. Don't refer it. 2388208019Sthompsa */ 2389208019Sthompsastatic void 2390208019Sthompsarun_key_delete_cb(void *arg) 2391208019Sthompsa{ 2392208019Sthompsa struct run_cmdq *cmdq = arg; 2393208019Sthompsa struct run_softc *sc = cmdq->arg1; 2394208019Sthompsa struct ieee80211_key *k = &cmdq->key; 2395203134Sthompsa uint32_t attr; 2396203134Sthompsa uint8_t wcid; 2397203134Sthompsa 2398208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2399203134Sthompsa 2400203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 2401203134Sthompsa /* remove group key */ 2402208019Sthompsa DPRINTF("removing group key\n"); 2403208019Sthompsa run_read(sc, RT2860_SKEY_MODE_0_7, &attr); 2404203134Sthompsa attr &= ~(0xf << (k->wk_keyix * 4)); 2405208019Sthompsa run_write(sc, RT2860_SKEY_MODE_0_7, attr); 2406203134Sthompsa } else { 2407203134Sthompsa /* remove pairwise key */ 2408208019Sthompsa DPRINTF("removing key for wcid %x\n", k->wk_pad); 2409208019Sthompsa /* matching wcid was written to wk_pad in run_key_set() */ 2410208019Sthompsa wcid = k->wk_pad; 2411208019Sthompsa run_read(sc, RT2860_WCID_ATTR(wcid), &attr); 2412203134Sthompsa attr &= ~0xf; 2413208019Sthompsa run_write(sc, RT2860_WCID_ATTR(wcid), attr); 2414208019Sthompsa run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8); 2415203134Sthompsa } 2416203134Sthompsa 2417208019Sthompsa k->wk_pad = 0; 2418203134Sthompsa} 2419203134Sthompsa 2420208019Sthompsa/* 2421208019Sthompsa * return 0 on error 2422208019Sthompsa */ 2423208019Sthompsastatic int 2424208019Sthompsarun_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k) 2425203134Sthompsa{ 2426208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 2427286950Sadrian struct run_softc *sc = ic->ic_softc; 2428208019Sthompsa struct ieee80211_key *k0; 2429208019Sthompsa uint32_t i; 2430203134Sthompsa 2431208019Sthompsa /* 2432208019Sthompsa * When called back, key might be gone. So, make a copy 2433208019Sthompsa * of some values need to delete keys before deferring. 2434208019Sthompsa * But, because of LOR with node lock, cannot use lock here. 2435208019Sthompsa * So, use atomic instead. 2436208019Sthompsa */ 2437208019Sthompsa i = RUN_CMDQ_GET(&sc->cmdq_store); 2438208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 2439208019Sthompsa sc->cmdq[i].func = run_key_delete_cb; 2440208019Sthompsa sc->cmdq[i].arg0 = NULL; 2441208019Sthompsa sc->cmdq[i].arg1 = sc; 2442208019Sthompsa k0 = &sc->cmdq[i].key; 2443208019Sthompsa k0->wk_flags = k->wk_flags; 2444208019Sthompsa k0->wk_keyix = k->wk_keyix; 2445208019Sthompsa /* matching wcid was written to wk_pad in run_key_set() */ 2446208019Sthompsa k0->wk_pad = k->wk_pad; 2447208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2448208019Sthompsa return (1); /* return fake success */ 2449203134Sthompsa 2450203134Sthompsa} 2451203134Sthompsa 2452203134Sthompsastatic void 2453206358Srpaulorun_ratectl_to(void *arg) 2454203134Sthompsa{ 2455208019Sthompsa struct run_softc *sc = arg; 2456203134Sthompsa 2457203134Sthompsa /* do it in a process context, so it can go sleep */ 2458287197Sglebius ieee80211_runtask(&sc->sc_ic, &sc->ratectl_task); 2459203134Sthompsa /* next timeout will be rescheduled in the callback task */ 2460203134Sthompsa} 2461203134Sthompsa 2462203134Sthompsa/* ARGSUSED */ 2463203134Sthompsastatic void 2464206358Srpaulorun_ratectl_cb(void *arg, int pending) 2465203134Sthompsa{ 2466208019Sthompsa struct run_softc *sc = arg; 2467287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2468208019Sthompsa struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2469203134Sthompsa 2470209917Sthompsa if (vap == NULL) 2471208019Sthompsa return; 2472208019Sthompsa 2473262795Shselasky if (sc->rvp_cnt > 1 || vap->iv_opmode != IEEE80211_M_STA) { 2474203134Sthompsa /* 2475203134Sthompsa * run_reset_livelock() doesn't do anything with AMRR, 2476203134Sthompsa * but Ralink wants us to call it every 1 sec. So, we 2477203134Sthompsa * piggyback here rather than creating another callout. 2478203134Sthompsa * Livelock may occur only in HOSTAP or IBSS mode 2479203134Sthompsa * (when h/w is sending beacons). 2480203134Sthompsa */ 2481203134Sthompsa RUN_LOCK(sc); 2482203134Sthompsa run_reset_livelock(sc); 2483208019Sthompsa /* just in case, there are some stats to drain */ 2484208019Sthompsa run_drain_fifo(sc); 2485203134Sthompsa RUN_UNLOCK(sc); 2486203134Sthompsa } 2487203134Sthompsa 2488262795Shselasky ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc); 2489262795Shselasky 2490257712Shselasky RUN_LOCK(sc); 2491208019Sthompsa if(sc->ratectl_run != RUN_RATECTL_OFF) 2492208019Sthompsa usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2493257712Shselasky RUN_UNLOCK(sc); 2494203134Sthompsa} 2495203134Sthompsa 2496203134Sthompsastatic void 2497208019Sthompsarun_drain_fifo(void *arg) 2498203134Sthompsa{ 2499208019Sthompsa struct run_softc *sc = arg; 2500208019Sthompsa uint32_t stat; 2501218676Shselasky uint16_t (*wstat)[3]; 2502203134Sthompsa uint8_t wcid, mcs, pid; 2503218676Shselasky int8_t retry; 2504203134Sthompsa 2505208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2506203134Sthompsa 2507208019Sthompsa for (;;) { 2508203134Sthompsa /* drain Tx status FIFO (maxsize = 16) */ 2509203134Sthompsa run_read(sc, RT2860_TX_STAT_FIFO, &stat); 2510208019Sthompsa DPRINTFN(4, "tx stat 0x%08x\n", stat); 2511209917Sthompsa if (!(stat & RT2860_TXQ_VLD)) 2512208019Sthompsa break; 2513203134Sthompsa 2514208019Sthompsa wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff; 2515203134Sthompsa 2516208019Sthompsa /* if no ACK was requested, no feedback is available */ 2517208019Sthompsa if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX || 2518208019Sthompsa wcid == 0) 2519208019Sthompsa continue; 2520203134Sthompsa 2521218676Shselasky /* 2522218676Shselasky * Even though each stat is Tx-complete-status like format, 2523218676Shselasky * the device can poll stats. Because there is no guarantee 2524218676Shselasky * that the referring node is still around when read the stats. 2525218676Shselasky * So that, if we use ieee80211_ratectl_tx_update(), we will 2526218676Shselasky * have hard time not to refer already freed node. 2527218676Shselasky * 2528218676Shselasky * To eliminate such page faults, we poll stats in softc. 2529218676Shselasky * Then, update the rates later with ieee80211_ratectl_tx_update(). 2530218676Shselasky */ 2531218676Shselasky wstat = &(sc->wcid_stats[wcid]); 2532218676Shselasky (*wstat)[RUN_TXCNT]++; 2533218676Shselasky if (stat & RT2860_TXQ_OK) 2534218676Shselasky (*wstat)[RUN_SUCCESS]++; 2535218676Shselasky else 2536287197Sglebius counter_u64_add(sc->sc_ic.ic_oerrors, 1); 2537218676Shselasky /* 2538218676Shselasky * Check if there were retries, ie if the Tx success rate is 2539218676Shselasky * different from the requested rate. Note that it works only 2540218676Shselasky * because we do not allow rate fallback from OFDM to CCK. 2541218676Shselasky */ 2542218676Shselasky mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f; 2543218676Shselasky pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf; 2544218676Shselasky if ((retry = pid -1 - mcs) > 0) { 2545218676Shselasky (*wstat)[RUN_TXCNT] += retry; 2546218676Shselasky (*wstat)[RUN_RETRY] += retry; 2547203134Sthompsa } 2548208019Sthompsa } 2549208019Sthompsa DPRINTFN(3, "count=%d\n", sc->fifo_cnt); 2550208019Sthompsa 2551208019Sthompsa sc->fifo_cnt = 0; 2552208019Sthompsa} 2553208019Sthompsa 2554208019Sthompsastatic void 2555208019Sthompsarun_iter_func(void *arg, struct ieee80211_node *ni) 2556208019Sthompsa{ 2557208019Sthompsa struct run_softc *sc = arg; 2558208019Sthompsa struct ieee80211vap *vap = ni->ni_vap; 2559287552Skevlo struct run_node *rn = RUN_NODE(ni); 2560218676Shselasky union run_stats sta[2]; 2561218676Shselasky uint16_t (*wstat)[3]; 2562218676Shselasky int txcnt, success, retrycnt, error; 2563208019Sthompsa 2564218676Shselasky RUN_LOCK(sc); 2565218676Shselasky 2566262795Shselasky /* Check for special case */ 2567262795Shselasky if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA && 2568262795Shselasky ni != vap->iv_bss) 2569262795Shselasky goto fail; 2570262795Shselasky 2571209917Sthompsa if (sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS || 2572209917Sthompsa vap->iv_opmode == IEEE80211_M_STA)) { 2573203134Sthompsa /* read statistic counters (clear on read) and update AMRR state */ 2574203134Sthompsa error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta, 2575203134Sthompsa sizeof sta); 2576203134Sthompsa if (error != 0) 2577218676Shselasky goto fail; 2578203134Sthompsa 2579203134Sthompsa /* count failed TX as errors */ 2580287197Sglebius if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS, 2581287197Sglebius le16toh(sta[0].error.fail)); 2582203134Sthompsa 2583218676Shselasky retrycnt = le16toh(sta[1].tx.retry); 2584218676Shselasky success = le16toh(sta[1].tx.success); 2585218676Shselasky txcnt = retrycnt + success + le16toh(sta[0].error.fail); 2586203134Sthompsa 2587218676Shselasky DPRINTFN(3, "retrycnt=%d success=%d failcnt=%d\n", 2588218676Shselasky retrycnt, success, le16toh(sta[0].error.fail)); 2589218676Shselasky } else { 2590218676Shselasky wstat = &(sc->wcid_stats[RUN_AID2WCID(ni->ni_associd)]); 2591203134Sthompsa 2592218676Shselasky if (wstat == &(sc->wcid_stats[0]) || 2593218676Shselasky wstat > &(sc->wcid_stats[RT2870_WCID_MAX])) 2594218676Shselasky goto fail; 2595208019Sthompsa 2596218676Shselasky txcnt = (*wstat)[RUN_TXCNT]; 2597218676Shselasky success = (*wstat)[RUN_SUCCESS]; 2598218676Shselasky retrycnt = (*wstat)[RUN_RETRY]; 2599218676Shselasky DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n", 2600218676Shselasky retrycnt, txcnt, success); 2601208019Sthompsa 2602218676Shselasky memset(wstat, 0, sizeof(*wstat)); 2603203134Sthompsa } 2604203134Sthompsa 2605218676Shselasky ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt); 2606208019Sthompsa rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0); 2607218676Shselasky 2608218676Shselaskyfail: 2609218676Shselasky RUN_UNLOCK(sc); 2610218676Shselasky 2611208019Sthompsa DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx); 2612208019Sthompsa} 2613203134Sthompsa 2614208019Sthompsastatic void 2615208019Sthompsarun_newassoc_cb(void *arg) 2616208019Sthompsa{ 2617208019Sthompsa struct run_cmdq *cmdq = arg; 2618208019Sthompsa struct ieee80211_node *ni = cmdq->arg1; 2619286950Sadrian struct run_softc *sc = ni->ni_vap->iv_ic->ic_softc; 2620208019Sthompsa uint8_t wcid = cmdq->wcid; 2621203134Sthompsa 2622208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2623208019Sthompsa 2624208019Sthompsa run_write_region_1(sc, RT2860_WCID_ENTRY(wcid), 2625208019Sthompsa ni->ni_macaddr, IEEE80211_ADDR_LEN); 2626218676Shselasky 2627218676Shselasky memset(&(sc->wcid_stats[wcid]), 0, sizeof(sc->wcid_stats[wcid])); 2628203134Sthompsa} 2629203134Sthompsa 2630203134Sthompsastatic void 2631203134Sthompsarun_newassoc(struct ieee80211_node *ni, int isnew) 2632203134Sthompsa{ 2633287552Skevlo struct run_node *rn = RUN_NODE(ni); 2634203134Sthompsa struct ieee80211_rateset *rs = &ni->ni_rates; 2635208019Sthompsa struct ieee80211vap *vap = ni->ni_vap; 2636208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 2637286950Sadrian struct run_softc *sc = ic->ic_softc; 2638203134Sthompsa uint8_t rate; 2639208019Sthompsa uint8_t ridx; 2640245047Shselasky uint8_t wcid; 2641208019Sthompsa int i, j; 2642203134Sthompsa 2643245047Shselasky wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 2644245047Shselasky 1 : RUN_AID2WCID(ni->ni_associd); 2645245047Shselasky 2646209917Sthompsa if (wcid > RT2870_WCID_MAX) { 2647208019Sthompsa device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid); 2648208019Sthompsa return; 2649208019Sthompsa } 2650203134Sthompsa 2651208019Sthompsa /* only interested in true associations */ 2652209917Sthompsa if (isnew && ni->ni_associd != 0) { 2653208019Sthompsa 2654208019Sthompsa /* 2655208019Sthompsa * This function could is called though timeout function. 2656208019Sthompsa * Need to defer. 2657208019Sthompsa */ 2658208019Sthompsa uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store); 2659208019Sthompsa DPRINTF("cmdq_store=%d\n", cnt); 2660208019Sthompsa sc->cmdq[cnt].func = run_newassoc_cb; 2661208019Sthompsa sc->cmdq[cnt].arg0 = NULL; 2662208019Sthompsa sc->cmdq[cnt].arg1 = ni; 2663208019Sthompsa sc->cmdq[cnt].wcid = wcid; 2664208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2665208019Sthompsa } 2666208019Sthompsa 2667208019Sthompsa DPRINTF("new assoc isnew=%d associd=%x addr=%s\n", 2668208019Sthompsa isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr)); 2669208019Sthompsa 2670203134Sthompsa for (i = 0; i < rs->rs_nrates; i++) { 2671203134Sthompsa rate = rs->rs_rates[i] & IEEE80211_RATE_VAL; 2672203134Sthompsa /* convert 802.11 rate to hardware rate index */ 2673203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2674203134Sthompsa if (rt2860_rates[ridx].rate == rate) 2675203134Sthompsa break; 2676203134Sthompsa rn->ridx[i] = ridx; 2677203134Sthompsa /* determine rate of control response frames */ 2678203134Sthompsa for (j = i; j >= 0; j--) { 2679203134Sthompsa if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) && 2680203134Sthompsa rt2860_rates[rn->ridx[i]].phy == 2681203134Sthompsa rt2860_rates[rn->ridx[j]].phy) 2682203134Sthompsa break; 2683203134Sthompsa } 2684203134Sthompsa if (j >= 0) { 2685203134Sthompsa rn->ctl_ridx[i] = rn->ridx[j]; 2686203134Sthompsa } else { 2687203134Sthompsa /* no basic rate found, use mandatory one */ 2688203134Sthompsa rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx; 2689203134Sthompsa } 2690203134Sthompsa DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n", 2691203134Sthompsa rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]); 2692203134Sthompsa } 2693208019Sthompsa rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate; 2694208019Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2695208019Sthompsa if (rt2860_rates[ridx].rate == rate) 2696208019Sthompsa break; 2697208019Sthompsa rn->mgt_ridx = ridx; 2698208019Sthompsa DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx); 2699208019Sthompsa 2700262795Shselasky RUN_LOCK(sc); 2701262795Shselasky if(sc->ratectl_run != RUN_RATECTL_OFF) 2702262795Shselasky usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2703262795Shselasky RUN_UNLOCK(sc); 2704203134Sthompsa} 2705203134Sthompsa 2706203134Sthompsa/* 2707203134Sthompsa * Return the Rx chain with the highest RSSI for a given frame. 2708203134Sthompsa */ 2709203134Sthompsastatic __inline uint8_t 2710203134Sthompsarun_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi) 2711203134Sthompsa{ 2712203134Sthompsa uint8_t rxchain = 0; 2713203134Sthompsa 2714203134Sthompsa if (sc->nrxchains > 1) { 2715203134Sthompsa if (rxwi->rssi[1] > rxwi->rssi[rxchain]) 2716203134Sthompsa rxchain = 1; 2717203134Sthompsa if (sc->nrxchains > 2) 2718203134Sthompsa if (rxwi->rssi[2] > rxwi->rssi[rxchain]) 2719203134Sthompsa rxchain = 2; 2720203134Sthompsa } 2721209917Sthompsa return (rxchain); 2722203134Sthompsa} 2723203134Sthompsa 2724203134Sthompsastatic void 2725203134Sthompsarun_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) 2726203134Sthompsa{ 2727287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2728203134Sthompsa struct ieee80211_frame *wh; 2729203134Sthompsa struct ieee80211_node *ni; 2730203134Sthompsa struct rt2870_rxd *rxd; 2731203134Sthompsa struct rt2860_rxwi *rxwi; 2732203134Sthompsa uint32_t flags; 2733259032Skevlo uint16_t len, rxwisize; 2734203134Sthompsa uint8_t ant, rssi; 2735203134Sthompsa int8_t nf; 2736203134Sthompsa 2737203134Sthompsa rxwi = mtod(m, struct rt2860_rxwi *); 2738203134Sthompsa len = le16toh(rxwi->len) & 0xfff; 2739260219Skevlo rxwisize = sizeof(struct rt2860_rxwi); 2740260219Skevlo if (sc->mac_ver == 0x5592) 2741260219Skevlo rxwisize += sizeof(uint64_t); 2742260219Skevlo else if (sc->mac_ver == 0x3593) 2743260219Skevlo rxwisize += sizeof(uint32_t); 2744203134Sthompsa if (__predict_false(len > dmalen)) { 2745203134Sthompsa m_freem(m); 2746287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 2747203134Sthompsa DPRINTF("bad RXWI length %u > %u\n", len, dmalen); 2748203134Sthompsa return; 2749203134Sthompsa } 2750203134Sthompsa /* Rx descriptor is located at the end */ 2751203134Sthompsa rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen); 2752203134Sthompsa flags = le32toh(rxd->flags); 2753203134Sthompsa 2754203134Sthompsa if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) { 2755203134Sthompsa m_freem(m); 2756287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 2757203134Sthompsa DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV"); 2758203134Sthompsa return; 2759203134Sthompsa } 2760203134Sthompsa 2761259032Skevlo m->m_data += rxwisize; 2762259032Skevlo m->m_pkthdr.len = m->m_len -= rxwisize; 2763203134Sthompsa 2764203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 2765203134Sthompsa 2766260444Skevlo if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 2767260444Skevlo wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; 2768203134Sthompsa m->m_flags |= M_WEP; 2769203134Sthompsa } 2770203134Sthompsa 2771209917Sthompsa if (flags & RT2860_RX_L2PAD) { 2772203134Sthompsa DPRINTFN(8, "received RT2860_RX_L2PAD frame\n"); 2773203134Sthompsa len += 2; 2774203134Sthompsa } 2775203134Sthompsa 2776208019Sthompsa ni = ieee80211_find_rxnode(ic, 2777208019Sthompsa mtod(m, struct ieee80211_frame_min *)); 2778208019Sthompsa 2779203134Sthompsa if (__predict_false(flags & RT2860_RX_MICERR)) { 2780203134Sthompsa /* report MIC failures to net80211 for TKIP */ 2781209917Sthompsa if (ni != NULL) 2782259032Skevlo ieee80211_notify_michael_failure(ni->ni_vap, wh, 2783259032Skevlo rxwi->keyidx); 2784203134Sthompsa m_freem(m); 2785287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 2786203134Sthompsa DPRINTF("MIC error. Someone is lying.\n"); 2787203134Sthompsa return; 2788203134Sthompsa } 2789203134Sthompsa 2790203134Sthompsa ant = run_maxrssi_chain(sc, rxwi); 2791203134Sthompsa rssi = rxwi->rssi[ant]; 2792203134Sthompsa nf = run_rssi2dbm(sc, rssi, ant); 2793203134Sthompsa 2794203134Sthompsa m->m_pkthdr.len = m->m_len = len; 2795203134Sthompsa 2796203134Sthompsa if (ni != NULL) { 2797203134Sthompsa (void)ieee80211_input(ni, m, rssi, nf); 2798203134Sthompsa ieee80211_free_node(ni); 2799203134Sthompsa } else { 2800203134Sthompsa (void)ieee80211_input_all(ic, m, rssi, nf); 2801203134Sthompsa } 2802203134Sthompsa 2803209917Sthompsa if (__predict_false(ieee80211_radiotap_active(ic))) { 2804203134Sthompsa struct run_rx_radiotap_header *tap = &sc->sc_rxtap; 2805258643Shselasky uint16_t phy; 2806203134Sthompsa 2807203134Sthompsa tap->wr_flags = 0; 2808236439Shselasky tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); 2809236439Shselasky tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); 2810203134Sthompsa tap->wr_antsignal = rssi; 2811203134Sthompsa tap->wr_antenna = ant; 2812203134Sthompsa tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant); 2813203134Sthompsa tap->wr_rate = 2; /* in case it can't be found below */ 2814203134Sthompsa phy = le16toh(rxwi->phy); 2815203134Sthompsa switch (phy & RT2860_PHY_MODE) { 2816203134Sthompsa case RT2860_PHY_CCK: 2817203134Sthompsa switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) { 2818203134Sthompsa case 0: tap->wr_rate = 2; break; 2819203134Sthompsa case 1: tap->wr_rate = 4; break; 2820203134Sthompsa case 2: tap->wr_rate = 11; break; 2821203134Sthompsa case 3: tap->wr_rate = 22; break; 2822203134Sthompsa } 2823203134Sthompsa if (phy & RT2860_PHY_SHPRE) 2824203134Sthompsa tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 2825203134Sthompsa break; 2826203134Sthompsa case RT2860_PHY_OFDM: 2827203134Sthompsa switch (phy & RT2860_PHY_MCS) { 2828203134Sthompsa case 0: tap->wr_rate = 12; break; 2829203134Sthompsa case 1: tap->wr_rate = 18; break; 2830203134Sthompsa case 2: tap->wr_rate = 24; break; 2831203134Sthompsa case 3: tap->wr_rate = 36; break; 2832203134Sthompsa case 4: tap->wr_rate = 48; break; 2833203134Sthompsa case 5: tap->wr_rate = 72; break; 2834203134Sthompsa case 6: tap->wr_rate = 96; break; 2835203134Sthompsa case 7: tap->wr_rate = 108; break; 2836203134Sthompsa } 2837203134Sthompsa break; 2838203134Sthompsa } 2839203134Sthompsa } 2840203134Sthompsa} 2841203134Sthompsa 2842203134Sthompsastatic void 2843203134Sthompsarun_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) 2844203134Sthompsa{ 2845203134Sthompsa struct run_softc *sc = usbd_xfer_softc(xfer); 2846287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2847203134Sthompsa struct mbuf *m = NULL; 2848203134Sthompsa struct mbuf *m0; 2849203134Sthompsa uint32_t dmalen; 2850259032Skevlo uint16_t rxwisize; 2851203134Sthompsa int xferlen; 2852203134Sthompsa 2853260219Skevlo rxwisize = sizeof(struct rt2860_rxwi); 2854260219Skevlo if (sc->mac_ver == 0x5592) 2855260219Skevlo rxwisize += sizeof(uint64_t); 2856260219Skevlo else if (sc->mac_ver == 0x3593) 2857260219Skevlo rxwisize += sizeof(uint32_t); 2858259032Skevlo 2859203134Sthompsa usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL); 2860203134Sthompsa 2861203134Sthompsa switch (USB_GET_STATE(xfer)) { 2862203134Sthompsa case USB_ST_TRANSFERRED: 2863203134Sthompsa 2864203134Sthompsa DPRINTFN(15, "rx done, actlen=%d\n", xferlen); 2865203134Sthompsa 2866259032Skevlo if (xferlen < (int)(sizeof(uint32_t) + rxwisize + 2867259032Skevlo sizeof(struct rt2870_rxd))) { 2868203134Sthompsa DPRINTF("xfer too short %d\n", xferlen); 2869203134Sthompsa goto tr_setup; 2870203134Sthompsa } 2871203134Sthompsa 2872203134Sthompsa m = sc->rx_m; 2873203134Sthompsa sc->rx_m = NULL; 2874203134Sthompsa 2875203134Sthompsa /* FALLTHROUGH */ 2876203134Sthompsa case USB_ST_SETUP: 2877203134Sthompsatr_setup: 2878203134Sthompsa if (sc->rx_m == NULL) { 2879243857Sglebius sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, 2880203134Sthompsa MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */); 2881203134Sthompsa } 2882203134Sthompsa if (sc->rx_m == NULL) { 2883203134Sthompsa DPRINTF("could not allocate mbuf - idle with stall\n"); 2884287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 2885203134Sthompsa usbd_xfer_set_stall(xfer); 2886203134Sthompsa usbd_xfer_set_frames(xfer, 0); 2887203134Sthompsa } else { 2888203134Sthompsa /* 2889203134Sthompsa * Directly loading a mbuf cluster into DMA to 2890203134Sthompsa * save some data copying. This works because 2891203134Sthompsa * there is only one cluster. 2892203134Sthompsa */ 2893203134Sthompsa usbd_xfer_set_frame_data(xfer, 0, 2894203134Sthompsa mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ); 2895203134Sthompsa usbd_xfer_set_frames(xfer, 1); 2896203134Sthompsa } 2897203134Sthompsa usbd_transfer_submit(xfer); 2898203134Sthompsa break; 2899203134Sthompsa 2900203134Sthompsa default: /* Error */ 2901203134Sthompsa if (error != USB_ERR_CANCELLED) { 2902203134Sthompsa /* try to clear stall first */ 2903203134Sthompsa usbd_xfer_set_stall(xfer); 2904203134Sthompsa if (error == USB_ERR_TIMEOUT) 2905203134Sthompsa device_printf(sc->sc_dev, "device timeout\n"); 2906287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 2907203134Sthompsa goto tr_setup; 2908203134Sthompsa } 2909209917Sthompsa if (sc->rx_m != NULL) { 2910203134Sthompsa m_freem(sc->rx_m); 2911203134Sthompsa sc->rx_m = NULL; 2912203134Sthompsa } 2913203134Sthompsa break; 2914203134Sthompsa } 2915203134Sthompsa 2916203134Sthompsa if (m == NULL) 2917203134Sthompsa return; 2918203134Sthompsa 2919203134Sthompsa /* inputting all the frames must be last */ 2920203134Sthompsa 2921203134Sthompsa RUN_UNLOCK(sc); 2922203134Sthompsa 2923203134Sthompsa m->m_pkthdr.len = m->m_len = xferlen; 2924203134Sthompsa 2925203134Sthompsa /* HW can aggregate multiple 802.11 frames in a single USB xfer */ 2926203134Sthompsa for(;;) { 2927203134Sthompsa dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff; 2928203134Sthompsa 2929233774Shselasky if ((dmalen >= (uint32_t)-8) || (dmalen == 0) || 2930233774Shselasky ((dmalen & 3) != 0)) { 2931203134Sthompsa DPRINTF("bad DMA length %u\n", dmalen); 2932203134Sthompsa break; 2933203134Sthompsa } 2934233774Shselasky if ((dmalen + 8) > (uint32_t)xferlen) { 2935203134Sthompsa DPRINTF("bad DMA length %u > %d\n", 2936203134Sthompsa dmalen + 8, xferlen); 2937203134Sthompsa break; 2938203134Sthompsa } 2939203134Sthompsa 2940203134Sthompsa /* If it is the last one or a single frame, we won't copy. */ 2941209917Sthompsa if ((xferlen -= dmalen + 8) <= 8) { 2942203134Sthompsa /* trim 32-bit DMA-len header */ 2943203134Sthompsa m->m_data += 4; 2944203134Sthompsa m->m_pkthdr.len = m->m_len -= 4; 2945203134Sthompsa run_rx_frame(sc, m, dmalen); 2946257435Shselasky m = NULL; /* don't free source buffer */ 2947203134Sthompsa break; 2948203134Sthompsa } 2949203134Sthompsa 2950203134Sthompsa /* copy aggregated frames to another mbuf */ 2951243857Sglebius m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 2952203134Sthompsa if (__predict_false(m0 == NULL)) { 2953203134Sthompsa DPRINTF("could not allocate mbuf\n"); 2954287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 2955203134Sthompsa break; 2956203134Sthompsa } 2957203134Sthompsa m_copydata(m, 4 /* skip 32-bit DMA-len header */, 2958203134Sthompsa dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t)); 2959203134Sthompsa m0->m_pkthdr.len = m0->m_len = 2960203134Sthompsa dmalen + sizeof(struct rt2870_rxd); 2961203134Sthompsa run_rx_frame(sc, m0, dmalen); 2962203134Sthompsa 2963203134Sthompsa /* update data ptr */ 2964203134Sthompsa m->m_data += dmalen + 8; 2965203134Sthompsa m->m_pkthdr.len = m->m_len -= dmalen + 8; 2966203134Sthompsa } 2967203134Sthompsa 2968257435Shselasky /* make sure we free the source buffer, if any */ 2969257435Shselasky m_freem(m); 2970257435Shselasky 2971203134Sthompsa RUN_LOCK(sc); 2972203134Sthompsa} 2973203134Sthompsa 2974203134Sthompsastatic void 2975203134Sthompsarun_tx_free(struct run_endpoint_queue *pq, 2976203134Sthompsa struct run_tx_data *data, int txerr) 2977203134Sthompsa{ 2978203134Sthompsa if (data->m != NULL) { 2979203134Sthompsa if (data->m->m_flags & M_TXCB) 2980203134Sthompsa ieee80211_process_callback(data->ni, data->m, 2981203134Sthompsa txerr ? ETIMEDOUT : 0); 2982203134Sthompsa m_freem(data->m); 2983203134Sthompsa data->m = NULL; 2984203134Sthompsa 2985209917Sthompsa if (data->ni == NULL) { 2986203134Sthompsa DPRINTF("no node\n"); 2987203134Sthompsa } else { 2988203134Sthompsa ieee80211_free_node(data->ni); 2989203134Sthompsa data->ni = NULL; 2990203134Sthompsa } 2991203134Sthompsa } 2992203134Sthompsa 2993203134Sthompsa STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); 2994203134Sthompsa pq->tx_nfree++; 2995203134Sthompsa} 2996203134Sthompsa 2997203134Sthompsastatic void 2998257429Shselaskyrun_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index) 2999203134Sthompsa{ 3000203134Sthompsa struct run_softc *sc = usbd_xfer_softc(xfer); 3001287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3002203134Sthompsa struct run_tx_data *data; 3003203134Sthompsa struct ieee80211vap *vap = NULL; 3004203134Sthompsa struct usb_page_cache *pc; 3005203134Sthompsa struct run_endpoint_queue *pq = &sc->sc_epq[index]; 3006203134Sthompsa struct mbuf *m; 3007203134Sthompsa usb_frlength_t size; 3008203134Sthompsa int actlen; 3009203134Sthompsa int sumlen; 3010203134Sthompsa 3011203134Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 3012203134Sthompsa 3013209917Sthompsa switch (USB_GET_STATE(xfer)) { 3014203134Sthompsa case USB_ST_TRANSFERRED: 3015203134Sthompsa DPRINTFN(11, "transfer complete: %d " 3016203134Sthompsa "bytes @ index %d\n", actlen, index); 3017203134Sthompsa 3018203134Sthompsa data = usbd_xfer_get_priv(xfer); 3019203134Sthompsa run_tx_free(pq, data, 0); 3020203134Sthompsa usbd_xfer_set_priv(xfer, NULL); 3021203134Sthompsa 3022203134Sthompsa /* FALLTHROUGH */ 3023203134Sthompsa case USB_ST_SETUP: 3024203134Sthompsatr_setup: 3025203134Sthompsa data = STAILQ_FIRST(&pq->tx_qh); 3026209917Sthompsa if (data == NULL) 3027203134Sthompsa break; 3028203134Sthompsa 3029203134Sthompsa STAILQ_REMOVE_HEAD(&pq->tx_qh, next); 3030203134Sthompsa 3031203134Sthompsa m = data->m; 3032261330Shselasky size = (sc->mac_ver == 0x5592) ? 3033261330Shselasky sizeof(data->desc) + sizeof(uint32_t) : sizeof(data->desc); 3034261076Shselasky if ((m->m_pkthdr.len + 3035261330Shselasky size + 3 + 8) > RUN_MAX_TXSZ) { 3036203134Sthompsa DPRINTF("data overflow, %u bytes\n", 3037203134Sthompsa m->m_pkthdr.len); 3038203134Sthompsa run_tx_free(pq, data, 1); 3039203134Sthompsa goto tr_setup; 3040203134Sthompsa } 3041203134Sthompsa 3042203134Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 3043203134Sthompsa usbd_copy_in(pc, 0, &data->desc, size); 3044203134Sthompsa usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len); 3045228508Shselasky size += m->m_pkthdr.len; 3046228508Shselasky /* 3047228508Shselasky * Align end on a 4-byte boundary, pad 8 bytes (CRC + 3048228508Shselasky * 4-byte padding), and be sure to zero those trailing 3049228508Shselasky * bytes: 3050228508Shselasky */ 3051228508Shselasky usbd_frame_zero(pc, size, ((-size) & 3) + 8); 3052228508Shselasky size += ((-size) & 3) + 8; 3053203134Sthompsa 3054203134Sthompsa vap = data->ni->ni_vap; 3055203134Sthompsa if (ieee80211_radiotap_active_vap(vap)) { 3056203134Sthompsa struct run_tx_radiotap_header *tap = &sc->sc_txtap; 3057259032Skevlo struct rt2860_txwi *txwi = 3058208019Sthompsa (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd)); 3059203134Sthompsa tap->wt_flags = 0; 3060203134Sthompsa tap->wt_rate = rt2860_rates[data->ridx].rate; 3061236439Shselasky tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 3062236439Shselasky tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 3063203134Sthompsa tap->wt_hwqueue = index; 3064208019Sthompsa if (le16toh(txwi->phy) & RT2860_PHY_SHPRE) 3065203134Sthompsa tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 3066203134Sthompsa 3067203134Sthompsa ieee80211_radiotap_tx(vap, m); 3068203134Sthompsa } 3069203134Sthompsa 3070228508Shselasky DPRINTFN(11, "sending frame len=%u/%u @ index %d\n", 3071228508Shselasky m->m_pkthdr.len, size, index); 3072203134Sthompsa 3073228508Shselasky usbd_xfer_set_frame_len(xfer, 0, size); 3074203134Sthompsa usbd_xfer_set_priv(xfer, data); 3075203134Sthompsa usbd_transfer_submit(xfer); 3076287197Sglebius run_start(sc); 3077203134Sthompsa 3078203134Sthompsa break; 3079203134Sthompsa 3080203134Sthompsa default: 3081203134Sthompsa DPRINTF("USB transfer error, %s\n", 3082203134Sthompsa usbd_errstr(error)); 3083203134Sthompsa 3084203134Sthompsa data = usbd_xfer_get_priv(xfer); 3085203134Sthompsa 3086203134Sthompsa if (data != NULL) { 3087208019Sthompsa if(data->ni != NULL) 3088208019Sthompsa vap = data->ni->ni_vap; 3089203134Sthompsa run_tx_free(pq, data, error); 3090203134Sthompsa usbd_xfer_set_priv(xfer, NULL); 3091203134Sthompsa } 3092287197Sglebius 3093209917Sthompsa if (vap == NULL) 3094208019Sthompsa vap = TAILQ_FIRST(&ic->ic_vaps); 3095203134Sthompsa 3096203134Sthompsa if (error != USB_ERR_CANCELLED) { 3097203134Sthompsa if (error == USB_ERR_TIMEOUT) { 3098203134Sthompsa device_printf(sc->sc_dev, "device timeout\n"); 3099208019Sthompsa uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 3100208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 3101208019Sthompsa sc->cmdq[i].func = run_usb_timeout_cb; 3102208019Sthompsa sc->cmdq[i].arg0 = vap; 3103208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 3104203134Sthompsa } 3105203134Sthompsa 3106203134Sthompsa /* 3107203134Sthompsa * Try to clear stall first, also if other 3108203134Sthompsa * errors occur, hence clearing stall 3109203134Sthompsa * introduces a 50 ms delay: 3110203134Sthompsa */ 3111203134Sthompsa usbd_xfer_set_stall(xfer); 3112203134Sthompsa goto tr_setup; 3113203134Sthompsa } 3114203134Sthompsa break; 3115203134Sthompsa } 3116203134Sthompsa} 3117203134Sthompsa 3118203134Sthompsastatic void 3119203134Sthompsarun_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error) 3120203134Sthompsa{ 3121203134Sthompsa run_bulk_tx_callbackN(xfer, error, 0); 3122203134Sthompsa} 3123203134Sthompsa 3124203134Sthompsastatic void 3125203134Sthompsarun_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error) 3126203134Sthompsa{ 3127203134Sthompsa run_bulk_tx_callbackN(xfer, error, 1); 3128203134Sthompsa} 3129203134Sthompsa 3130203134Sthompsastatic void 3131203134Sthompsarun_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error) 3132203134Sthompsa{ 3133203134Sthompsa run_bulk_tx_callbackN(xfer, error, 2); 3134203134Sthompsa} 3135203134Sthompsa 3136203134Sthompsastatic void 3137203134Sthompsarun_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error) 3138203134Sthompsa{ 3139203134Sthompsa run_bulk_tx_callbackN(xfer, error, 3); 3140203134Sthompsa} 3141203134Sthompsa 3142203134Sthompsastatic void 3143203134Sthompsarun_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error) 3144203134Sthompsa{ 3145203134Sthompsa run_bulk_tx_callbackN(xfer, error, 4); 3146203134Sthompsa} 3147203134Sthompsa 3148203134Sthompsastatic void 3149203134Sthompsarun_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error) 3150203134Sthompsa{ 3151203134Sthompsa run_bulk_tx_callbackN(xfer, error, 5); 3152203134Sthompsa} 3153203134Sthompsa 3154203134Sthompsastatic void 3155208019Sthompsarun_set_tx_desc(struct run_softc *sc, struct run_tx_data *data) 3156203134Sthompsa{ 3157203134Sthompsa struct mbuf *m = data->m; 3158287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3159208019Sthompsa struct ieee80211vap *vap = data->ni->ni_vap; 3160203134Sthompsa struct ieee80211_frame *wh; 3161203134Sthompsa struct rt2870_txd *txd; 3162203134Sthompsa struct rt2860_txwi *txwi; 3163259032Skevlo uint16_t xferlen, txwisize; 3164208019Sthompsa uint16_t mcs; 3165203134Sthompsa uint8_t ridx = data->ridx; 3166208019Sthompsa uint8_t pad; 3167203134Sthompsa 3168203134Sthompsa /* get MCS code from rate index */ 3169208019Sthompsa mcs = rt2860_rates[ridx].mcs; 3170203134Sthompsa 3171259032Skevlo txwisize = (sc->mac_ver == 0x5592) ? 3172259032Skevlo sizeof(*txwi) + sizeof(uint32_t) : sizeof(*txwi); 3173259032Skevlo xferlen = txwisize + m->m_pkthdr.len; 3174203134Sthompsa 3175203134Sthompsa /* roundup to 32-bit alignment */ 3176203134Sthompsa xferlen = (xferlen + 3) & ~3; 3177203134Sthompsa 3178203134Sthompsa txd = (struct rt2870_txd *)&data->desc; 3179203134Sthompsa txd->len = htole16(xferlen); 3180203134Sthompsa 3181208019Sthompsa wh = mtod(m, struct ieee80211_frame *); 3182208019Sthompsa 3183208019Sthompsa /* 3184208019Sthompsa * Ether both are true or both are false, the header 3185208019Sthompsa * are nicely aligned to 32-bit. So, no L2 padding. 3186208019Sthompsa */ 3187208019Sthompsa if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh)) 3188208019Sthompsa pad = 0; 3189208019Sthompsa else 3190208019Sthompsa pad = 2; 3191208019Sthompsa 3192203134Sthompsa /* setup TX Wireless Information */ 3193203134Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3194203134Sthompsa txwi->len = htole16(m->m_pkthdr.len - pad); 3195203134Sthompsa if (rt2860_rates[ridx].phy == IEEE80211_T_DS) { 3196270192Skevlo mcs |= RT2860_PHY_CCK; 3197203134Sthompsa if (ridx != RT2860_RIDX_CCK1 && 3198203134Sthompsa (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 3199203134Sthompsa mcs |= RT2860_PHY_SHPRE; 3200203134Sthompsa } else 3201270192Skevlo mcs |= RT2860_PHY_OFDM; 3202270192Skevlo txwi->phy = htole16(mcs); 3203203134Sthompsa 3204203134Sthompsa /* check if RTS/CTS or CTS-to-self protection is required */ 3205203134Sthompsa if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 3206203134Sthompsa (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold || 3207203134Sthompsa ((ic->ic_flags & IEEE80211_F_USEPROT) && 3208203134Sthompsa rt2860_rates[ridx].phy == IEEE80211_T_OFDM))) 3209208019Sthompsa txwi->txop |= RT2860_TX_TXOP_HT; 3210203134Sthompsa else 3211208019Sthompsa txwi->txop |= RT2860_TX_TXOP_BACKOFF; 3212209144Sthompsa 3213209917Sthompsa if (vap->iv_opmode != IEEE80211_M_STA && !IEEE80211_QOS_HAS_SEQ(wh)) 3214209144Sthompsa txwi->xflags |= RT2860_TX_NSEQ; 3215203134Sthompsa} 3216203134Sthompsa 3217203134Sthompsa/* This function must be called locked */ 3218203134Sthompsastatic int 3219203134Sthompsarun_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) 3220203134Sthompsa{ 3221287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3222208019Sthompsa struct ieee80211vap *vap = ni->ni_vap; 3223203134Sthompsa struct ieee80211_frame *wh; 3224208019Sthompsa struct ieee80211_channel *chan; 3225203134Sthompsa const struct ieee80211_txparam *tp; 3226287552Skevlo struct run_node *rn = RUN_NODE(ni); 3227203134Sthompsa struct run_tx_data *data; 3228208019Sthompsa struct rt2870_txd *txd; 3229208019Sthompsa struct rt2860_txwi *txwi; 3230203134Sthompsa uint16_t qos; 3231203134Sthompsa uint16_t dur; 3232208019Sthompsa uint16_t qid; 3233203134Sthompsa uint8_t type; 3234203134Sthompsa uint8_t tid; 3235208019Sthompsa uint8_t ridx; 3236208019Sthompsa uint8_t ctl_ridx; 3237203134Sthompsa uint8_t qflags; 3238203134Sthompsa uint8_t xflags = 0; 3239203134Sthompsa int hasqos; 3240203134Sthompsa 3241203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3242203134Sthompsa 3243203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3244203134Sthompsa 3245203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3246203134Sthompsa 3247203134Sthompsa /* 3248203134Sthompsa * There are 7 bulk endpoints: 1 for RX 3249203134Sthompsa * and 6 for TX (4 EDCAs + HCCA + Prio). 3250203134Sthompsa * Update 03-14-2009: some devices like the Planex GW-US300MiniS 3251203134Sthompsa * seem to have only 4 TX bulk endpoints (Fukaumi Naoki). 3252203134Sthompsa */ 3253203134Sthompsa if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) { 3254203134Sthompsa uint8_t *frm; 3255203134Sthompsa 3256203134Sthompsa if(IEEE80211_HAS_ADDR4(wh)) 3257203134Sthompsa frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos; 3258203134Sthompsa else 3259203134Sthompsa frm =((struct ieee80211_qosframe *)wh)->i_qos; 3260203134Sthompsa 3261203134Sthompsa qos = le16toh(*(const uint16_t *)frm); 3262203134Sthompsa tid = qos & IEEE80211_QOS_TID; 3263203134Sthompsa qid = TID_TO_WME_AC(tid); 3264203134Sthompsa } else { 3265203134Sthompsa qos = 0; 3266203134Sthompsa tid = 0; 3267203134Sthompsa qid = WME_AC_BE; 3268203134Sthompsa } 3269203134Sthompsa qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA; 3270203134Sthompsa 3271203134Sthompsa DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n", 3272203134Sthompsa qos, qid, tid, qflags); 3273203134Sthompsa 3274208019Sthompsa chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan; 3275208019Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(chan)]; 3276203134Sthompsa 3277203134Sthompsa /* pickup a rate index */ 3278203134Sthompsa if (IEEE80211_IS_MULTICAST(wh->i_addr1) || 3279270192Skevlo type != IEEE80211_FC0_TYPE_DATA || m->m_flags & M_EAPOL) { 3280203134Sthompsa ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? 3281203134Sthompsa RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; 3282203134Sthompsa ctl_ridx = rt2860_rates[ridx].ctl_ridx; 3283203134Sthompsa } else { 3284208019Sthompsa if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) 3285208019Sthompsa ridx = rn->fix_ridx; 3286208019Sthompsa else 3287208019Sthompsa ridx = rn->amrr_ridx; 3288203134Sthompsa ctl_ridx = rt2860_rates[ridx].ctl_ridx; 3289203134Sthompsa } 3290203134Sthompsa 3291203134Sthompsa if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 3292203134Sthompsa (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) != 3293203134Sthompsa IEEE80211_QOS_ACKPOLICY_NOACK)) { 3294209144Sthompsa xflags |= RT2860_TX_ACK; 3295203134Sthompsa if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 3296208019Sthompsa dur = rt2860_rates[ctl_ridx].sp_ack_dur; 3297203134Sthompsa else 3298208019Sthompsa dur = rt2860_rates[ctl_ridx].lp_ack_dur; 3299258919Shselasky USETW(wh->i_dur, dur); 3300203134Sthompsa } 3301203134Sthompsa 3302203134Sthompsa /* reserve slots for mgmt packets, just in case */ 3303203134Sthompsa if (sc->sc_epq[qid].tx_nfree < 3) { 3304203134Sthompsa DPRINTFN(10, "tx ring %d is full\n", qid); 3305203134Sthompsa return (-1); 3306203134Sthompsa } 3307203134Sthompsa 3308203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh); 3309203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next); 3310203134Sthompsa sc->sc_epq[qid].tx_nfree--; 3311203134Sthompsa 3312208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3313208019Sthompsa txd->flags = qflags; 3314208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3315208019Sthompsa txwi->xflags = xflags; 3316259032Skevlo if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 3317245047Shselasky txwi->wcid = 0; 3318259032Skevlo else 3319245047Shselasky txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 3320245047Shselasky 1 : RUN_AID2WCID(ni->ni_associd); 3321259032Skevlo 3322208019Sthompsa /* clear leftover garbage bits */ 3323208019Sthompsa txwi->flags = 0; 3324208019Sthompsa txwi->txop = 0; 3325208019Sthompsa 3326203134Sthompsa data->m = m; 3327203134Sthompsa data->ni = ni; 3328203134Sthompsa data->ridx = ridx; 3329203134Sthompsa 3330208019Sthompsa run_set_tx_desc(sc, data); 3331203134Sthompsa 3332208019Sthompsa /* 3333208019Sthompsa * The chip keeps track of 2 kind of Tx stats, 3334208019Sthompsa * * TX_STAT_FIFO, for per WCID stats, and 3335208019Sthompsa * * TX_STA_CNT0 for all-TX-in-one stats. 3336208019Sthompsa * 3337208019Sthompsa * To use FIFO stats, we need to store MCS into the driver-private 3338208019Sthompsa * PacketID field. So that, we can tell whose stats when we read them. 3339208019Sthompsa * We add 1 to the MCS because setting the PacketID field to 0 means 3340208019Sthompsa * that we don't want feedback in TX_STAT_FIFO. 3341208019Sthompsa * And, that's what we want for STA mode, since TX_STA_CNT0 does the job. 3342208019Sthompsa * 3343208019Sthompsa * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx(). 3344208019Sthompsa */ 3345209917Sthompsa if (sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP || 3346209917Sthompsa vap->iv_opmode == IEEE80211_M_MBSS) { 3347208019Sthompsa uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf; 3348208019Sthompsa txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT); 3349208019Sthompsa 3350208019Sthompsa /* 3351208019Sthompsa * Unlike PCI based devices, we don't get any interrupt from 3352208019Sthompsa * USB devices, so we simulate FIFO-is-full interrupt here. 3353208019Sthompsa * Ralink recomends to drain FIFO stats every 100 ms, but 16 slots 3354208019Sthompsa * quickly get fulled. To prevent overflow, increment a counter on 3355208019Sthompsa * every FIFO stat request, so we know how many slots are left. 3356208019Sthompsa * We do this only in HOSTAP or multiple vap mode since FIFO stats 3357208019Sthompsa * are used only in those modes. 3358208019Sthompsa * We just drain stats. AMRR gets updated every 1 sec by 3359208019Sthompsa * run_ratectl_cb() via callout. 3360208019Sthompsa * Call it early. Otherwise overflow. 3361208019Sthompsa */ 3362209917Sthompsa if (sc->fifo_cnt++ == 10) { 3363208019Sthompsa /* 3364208019Sthompsa * With multiple vaps or if_bridge, if_start() is called 3365208019Sthompsa * with a non-sleepable lock, tcpinp. So, need to defer. 3366208019Sthompsa */ 3367208019Sthompsa uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 3368208019Sthompsa DPRINTFN(6, "cmdq_store=%d\n", i); 3369208019Sthompsa sc->cmdq[i].func = run_drain_fifo; 3370208019Sthompsa sc->cmdq[i].arg0 = sc; 3371208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 3372208019Sthompsa } 3373208019Sthompsa } 3374208019Sthompsa 3375203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next); 3376203134Sthompsa 3377203134Sthompsa usbd_transfer_start(sc->sc_xfer[qid]); 3378203134Sthompsa 3379258840Skevlo DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n", 3380259032Skevlo m->m_pkthdr.len + (int)(sizeof(struct rt2870_txd) + 3381259046Shselasky sizeof(struct rt2860_txwi)), rt2860_rates[ridx].rate, qid); 3382203134Sthompsa 3383203134Sthompsa return (0); 3384203134Sthompsa} 3385203134Sthompsa 3386203134Sthompsastatic int 3387203134Sthompsarun_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) 3388203134Sthompsa{ 3389287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3390287552Skevlo struct run_node *rn = RUN_NODE(ni); 3391203134Sthompsa struct run_tx_data *data; 3392203134Sthompsa struct ieee80211_frame *wh; 3393208019Sthompsa struct rt2870_txd *txd; 3394208019Sthompsa struct rt2860_txwi *txwi; 3395203134Sthompsa uint16_t dur; 3396208019Sthompsa uint8_t ridx = rn->mgt_ridx; 3397203134Sthompsa uint8_t type; 3398203134Sthompsa uint8_t xflags = 0; 3399208019Sthompsa uint8_t wflags = 0; 3400203134Sthompsa 3401203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3402203134Sthompsa 3403203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3404203134Sthompsa 3405203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3406203134Sthompsa 3407208019Sthompsa /* tell hardware to add timestamp for probe responses */ 3408208019Sthompsa if ((wh->i_fc[0] & 3409208019Sthompsa (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == 3410208019Sthompsa (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) 3411208019Sthompsa wflags |= RT2860_TX_TS; 3412208019Sthompsa else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 3413203134Sthompsa xflags |= RT2860_TX_ACK; 3414203134Sthompsa 3415208019Sthompsa dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate, 3416203134Sthompsa ic->ic_flags & IEEE80211_F_SHPREAMBLE); 3417258919Shselasky USETW(wh->i_dur, dur); 3418203134Sthompsa } 3419203134Sthompsa 3420287197Sglebius if (sc->sc_epq[0].tx_nfree == 0) 3421203134Sthompsa /* let caller free mbuf */ 3422203134Sthompsa return (EIO); 3423203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3424203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3425203134Sthompsa sc->sc_epq[0].tx_nfree--; 3426203134Sthompsa 3427208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3428208019Sthompsa txd->flags = RT2860_TX_QSEL_EDCA; 3429208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3430208019Sthompsa txwi->wcid = 0xff; 3431208019Sthompsa txwi->flags = wflags; 3432208019Sthompsa txwi->xflags = xflags; 3433208019Sthompsa txwi->txop = 0; /* clear leftover garbage bits */ 3434208019Sthompsa 3435203134Sthompsa data->m = m; 3436203134Sthompsa data->ni = ni; 3437203134Sthompsa data->ridx = ridx; 3438203134Sthompsa 3439208019Sthompsa run_set_tx_desc(sc, data); 3440203134Sthompsa 3441203134Sthompsa DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len + 3442258840Skevlo (int)(sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi)), 3443208019Sthompsa rt2860_rates[ridx].rate); 3444203134Sthompsa 3445203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3446203134Sthompsa 3447203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 3448203134Sthompsa 3449203134Sthompsa return (0); 3450203134Sthompsa} 3451203134Sthompsa 3452203134Sthompsastatic int 3453203134Sthompsarun_sendprot(struct run_softc *sc, 3454203134Sthompsa const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) 3455203134Sthompsa{ 3456203134Sthompsa struct ieee80211com *ic = ni->ni_ic; 3457203134Sthompsa struct ieee80211_frame *wh; 3458203134Sthompsa struct run_tx_data *data; 3459208019Sthompsa struct rt2870_txd *txd; 3460208019Sthompsa struct rt2860_txwi *txwi; 3461203134Sthompsa struct mbuf *mprot; 3462203134Sthompsa int ridx; 3463203134Sthompsa int protrate; 3464203134Sthompsa int ackrate; 3465203134Sthompsa int pktlen; 3466203134Sthompsa int isshort; 3467203134Sthompsa uint16_t dur; 3468203134Sthompsa uint8_t type; 3469208019Sthompsa uint8_t wflags = 0; 3470208019Sthompsa uint8_t xflags = 0; 3471203134Sthompsa 3472203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3473203134Sthompsa 3474203134Sthompsa KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, 3475203134Sthompsa ("protection %d", prot)); 3476203134Sthompsa 3477203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3478203134Sthompsa pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; 3479203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3480203134Sthompsa 3481203134Sthompsa protrate = ieee80211_ctl_rate(ic->ic_rt, rate); 3482203134Sthompsa ackrate = ieee80211_ack_rate(ic->ic_rt, rate); 3483203134Sthompsa 3484203134Sthompsa isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; 3485209189Sjkim dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort) 3486203134Sthompsa + ieee80211_ack_duration(ic->ic_rt, rate, isshort); 3487203134Sthompsa wflags = RT2860_TX_FRAG; 3488203134Sthompsa 3489203134Sthompsa /* check that there are free slots before allocating the mbuf */ 3490287197Sglebius if (sc->sc_epq[0].tx_nfree == 0) 3491203134Sthompsa /* let caller free mbuf */ 3492203134Sthompsa return (ENOBUFS); 3493203134Sthompsa 3494203134Sthompsa if (prot == IEEE80211_PROT_RTSCTS) { 3495203134Sthompsa /* NB: CTS is the same size as an ACK */ 3496203134Sthompsa dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); 3497208019Sthompsa xflags |= RT2860_TX_ACK; 3498203134Sthompsa mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); 3499203134Sthompsa } else { 3500203134Sthompsa mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); 3501203134Sthompsa } 3502203134Sthompsa if (mprot == NULL) { 3503287197Sglebius if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); 3504203134Sthompsa DPRINTF("could not allocate mbuf\n"); 3505203134Sthompsa return (ENOBUFS); 3506203134Sthompsa } 3507203134Sthompsa 3508203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3509203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3510203134Sthompsa sc->sc_epq[0].tx_nfree--; 3511203134Sthompsa 3512208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3513208019Sthompsa txd->flags = RT2860_TX_QSEL_EDCA; 3514208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3515208019Sthompsa txwi->wcid = 0xff; 3516208019Sthompsa txwi->flags = wflags; 3517208019Sthompsa txwi->xflags = xflags; 3518208019Sthompsa txwi->txop = 0; /* clear leftover garbage bits */ 3519208019Sthompsa 3520203134Sthompsa data->m = mprot; 3521203134Sthompsa data->ni = ieee80211_ref_node(ni); 3522203134Sthompsa 3523203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 3524203134Sthompsa if (rt2860_rates[ridx].rate == protrate) 3525203134Sthompsa break; 3526203134Sthompsa data->ridx = ridx; 3527203134Sthompsa 3528208019Sthompsa run_set_tx_desc(sc, data); 3529203134Sthompsa 3530203134Sthompsa DPRINTFN(1, "sending prot len=%u rate=%u\n", 3531203134Sthompsa m->m_pkthdr.len, rate); 3532203134Sthompsa 3533203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3534203134Sthompsa 3535203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 3536203134Sthompsa 3537203134Sthompsa return (0); 3538203134Sthompsa} 3539203134Sthompsa 3540203134Sthompsastatic int 3541203134Sthompsarun_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, 3542203134Sthompsa const struct ieee80211_bpf_params *params) 3543203134Sthompsa{ 3544203134Sthompsa struct ieee80211com *ic = ni->ni_ic; 3545203134Sthompsa struct ieee80211_frame *wh; 3546203134Sthompsa struct run_tx_data *data; 3547208019Sthompsa struct rt2870_txd *txd; 3548208019Sthompsa struct rt2860_txwi *txwi; 3549203134Sthompsa uint8_t type; 3550208019Sthompsa uint8_t ridx; 3551208019Sthompsa uint8_t rate; 3552208019Sthompsa uint8_t opflags = 0; 3553208019Sthompsa uint8_t xflags = 0; 3554203134Sthompsa int error; 3555203134Sthompsa 3556203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3557203134Sthompsa 3558203134Sthompsa KASSERT(params != NULL, ("no raw xmit params")); 3559203134Sthompsa 3560203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3561203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3562203134Sthompsa 3563203134Sthompsa rate = params->ibp_rate0; 3564203134Sthompsa if (!ieee80211_isratevalid(ic->ic_rt, rate)) { 3565203134Sthompsa /* let caller free mbuf */ 3566203134Sthompsa return (EINVAL); 3567203134Sthompsa } 3568203134Sthompsa 3569203134Sthompsa if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) 3570208019Sthompsa xflags |= RT2860_TX_ACK; 3571203134Sthompsa if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { 3572203134Sthompsa error = run_sendprot(sc, m, ni, 3573203134Sthompsa params->ibp_flags & IEEE80211_BPF_RTS ? 3574203134Sthompsa IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, 3575203134Sthompsa rate); 3576203134Sthompsa if (error) { 3577203134Sthompsa /* let caller free mbuf */ 3578209917Sthompsa return error; 3579203134Sthompsa } 3580203134Sthompsa opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS; 3581203134Sthompsa } 3582203134Sthompsa 3583203134Sthompsa if (sc->sc_epq[0].tx_nfree == 0) { 3584203134Sthompsa /* let caller free mbuf */ 3585203134Sthompsa DPRINTF("sending raw frame, but tx ring is full\n"); 3586203134Sthompsa return (EIO); 3587203134Sthompsa } 3588203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3589203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3590203134Sthompsa sc->sc_epq[0].tx_nfree--; 3591203134Sthompsa 3592208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3593208019Sthompsa txd->flags = RT2860_TX_QSEL_EDCA; 3594208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3595208019Sthompsa txwi->wcid = 0xff; 3596208019Sthompsa txwi->xflags = xflags; 3597208019Sthompsa txwi->txop = opflags; 3598208019Sthompsa txwi->flags = 0; /* clear leftover garbage bits */ 3599208019Sthompsa 3600203134Sthompsa data->m = m; 3601203134Sthompsa data->ni = ni; 3602203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 3603203134Sthompsa if (rt2860_rates[ridx].rate == rate) 3604203134Sthompsa break; 3605203134Sthompsa data->ridx = ridx; 3606203134Sthompsa 3607208019Sthompsa run_set_tx_desc(sc, data); 3608203134Sthompsa 3609203134Sthompsa DPRINTFN(10, "sending raw frame len=%u rate=%u\n", 3610203134Sthompsa m->m_pkthdr.len, rate); 3611203134Sthompsa 3612203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3613203134Sthompsa 3614203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 3615203134Sthompsa 3616209917Sthompsa return (0); 3617203134Sthompsa} 3618203134Sthompsa 3619203134Sthompsastatic int 3620203134Sthompsarun_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 3621203134Sthompsa const struct ieee80211_bpf_params *params) 3622203134Sthompsa{ 3623286950Sadrian struct run_softc *sc = ni->ni_ic->ic_softc; 3624208019Sthompsa int error = 0; 3625208019Sthompsa 3626203134Sthompsa RUN_LOCK(sc); 3627203134Sthompsa 3628203134Sthompsa /* prevent management frames from being sent if we're not ready */ 3629287197Sglebius if (!(sc->sc_flags & RUN_RUNNING)) { 3630287197Sglebius error = ENETDOWN; 3631208019Sthompsa goto done; 3632203134Sthompsa } 3633203134Sthompsa 3634203134Sthompsa if (params == NULL) { 3635203134Sthompsa /* tx mgt packet */ 3636209917Sthompsa if ((error = run_tx_mgt(sc, m, ni)) != 0) { 3637203134Sthompsa DPRINTF("mgt tx failed\n"); 3638208019Sthompsa goto done; 3639203134Sthompsa } 3640203134Sthompsa } else { 3641203134Sthompsa /* tx raw packet with param */ 3642209917Sthompsa if ((error = run_tx_param(sc, m, ni, params)) != 0) { 3643203134Sthompsa DPRINTF("tx with param failed\n"); 3644208019Sthompsa goto done; 3645203134Sthompsa } 3646203134Sthompsa } 3647203134Sthompsa 3648208019Sthompsadone: 3649203134Sthompsa RUN_UNLOCK(sc); 3650203134Sthompsa 3651209917Sthompsa if (error != 0) { 3652208019Sthompsa if(m != NULL) 3653208019Sthompsa m_freem(m); 3654208019Sthompsa ieee80211_free_node(ni); 3655208019Sthompsa } 3656203134Sthompsa 3657203134Sthompsa return (error); 3658203134Sthompsa} 3659203134Sthompsa 3660287197Sglebiusstatic int 3661287197Sglebiusrun_transmit(struct ieee80211com *ic, struct mbuf *m) 3662287197Sglebius{ 3663287197Sglebius struct run_softc *sc = ic->ic_softc; 3664287197Sglebius int error; 3665287197Sglebius 3666287197Sglebius RUN_LOCK(sc); 3667287197Sglebius if ((sc->sc_flags & RUN_RUNNING) == 0) { 3668287197Sglebius RUN_UNLOCK(sc); 3669287197Sglebius return (ENXIO); 3670287197Sglebius } 3671287197Sglebius error = mbufq_enqueue(&sc->sc_snd, m); 3672287197Sglebius if (error) { 3673287197Sglebius RUN_UNLOCK(sc); 3674287197Sglebius return (error); 3675287197Sglebius } 3676287197Sglebius run_start(sc); 3677287197Sglebius RUN_UNLOCK(sc); 3678287197Sglebius 3679287197Sglebius return (0); 3680287197Sglebius} 3681287197Sglebius 3682203134Sthompsastatic void 3683287197Sglebiusrun_start(struct run_softc *sc) 3684203134Sthompsa{ 3685203134Sthompsa struct ieee80211_node *ni; 3686203134Sthompsa struct mbuf *m; 3687203134Sthompsa 3688287197Sglebius RUN_LOCK_ASSERT(sc, MA_OWNED); 3689203134Sthompsa 3690287197Sglebius if ((sc->sc_flags & RUN_RUNNING) == 0) 3691203134Sthompsa return; 3692203134Sthompsa 3693287197Sglebius while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { 3694203134Sthompsa ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 3695203134Sthompsa if (run_tx(sc, m, ni) != 0) { 3696287197Sglebius mbufq_prepend(&sc->sc_snd, m); 3697203134Sthompsa break; 3698203134Sthompsa } 3699203134Sthompsa } 3700203134Sthompsa} 3701203134Sthompsa 3702287197Sglebiusstatic void 3703287197Sglebiusrun_parent(struct ieee80211com *ic) 3704203134Sthompsa{ 3705286950Sadrian struct run_softc *sc = ic->ic_softc; 3706208019Sthompsa int startall = 0; 3707203134Sthompsa 3708246614Shselasky RUN_LOCK(sc); 3709287197Sglebius if (sc->sc_detached) { 3710203134Sthompsa RUN_UNLOCK(sc); 3711287197Sglebius return; 3712203134Sthompsa } 3713203134Sthompsa 3714287197Sglebius if (ic->ic_nrunning > 0) { 3715287197Sglebius if (!(sc->sc_flags & RUN_RUNNING)) { 3716287197Sglebius startall = 1; 3717287197Sglebius run_init_locked(sc); 3718287197Sglebius } else 3719287197Sglebius run_update_promisc_locked(sc); 3720287197Sglebius } else if ((sc->sc_flags & RUN_RUNNING) && sc->rvp_cnt <= 1) 3721287197Sglebius run_stop(sc); 3722287197Sglebius RUN_UNLOCK(sc); 3723287197Sglebius if (startall) 3724287197Sglebius ieee80211_start_all(ic); 3725203134Sthompsa} 3726203134Sthompsa 3727203134Sthompsastatic void 3728259544Skevlorun_iq_calib(struct run_softc *sc, u_int chan) 3729259544Skevlo{ 3730259544Skevlo uint16_t val; 3731259544Skevlo 3732259544Skevlo /* Tx0 IQ gain. */ 3733259544Skevlo run_bbp_write(sc, 158, 0x2c); 3734259544Skevlo if (chan <= 14) 3735259544Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX0_2GHZ, &val, 1); 3736259544Skevlo else if (chan <= 64) { 3737259544Skevlo run_efuse_read(sc, 3738259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5GHZ, 3739259544Skevlo &val, 1); 3740259544Skevlo } else if (chan <= 138) { 3741259544Skevlo run_efuse_read(sc, 3742259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5GHZ, 3743259544Skevlo &val, 1); 3744259544Skevlo } else if (chan <= 165) { 3745259544Skevlo run_efuse_read(sc, 3746259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5GHZ, 3747259544Skevlo &val, 1); 3748259544Skevlo } else 3749259544Skevlo val = 0; 3750259547Skevlo run_bbp_write(sc, 159, val); 3751259544Skevlo 3752259544Skevlo /* Tx0 IQ phase. */ 3753259544Skevlo run_bbp_write(sc, 158, 0x2d); 3754259544Skevlo if (chan <= 14) { 3755259544Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX0_2GHZ, 3756259544Skevlo &val, 1); 3757259544Skevlo } else if (chan <= 64) { 3758259544Skevlo run_efuse_read(sc, 3759259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5GHZ, 3760259544Skevlo &val, 1); 3761259544Skevlo } else if (chan <= 138) { 3762259544Skevlo run_efuse_read(sc, 3763259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5GHZ, 3764259544Skevlo &val, 1); 3765259544Skevlo } else if (chan <= 165) { 3766259544Skevlo run_efuse_read(sc, 3767259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5GHZ, 3768259544Skevlo &val, 1); 3769259544Skevlo } else 3770259544Skevlo val = 0; 3771259547Skevlo run_bbp_write(sc, 159, val); 3772259544Skevlo 3773259544Skevlo /* Tx1 IQ gain. */ 3774259544Skevlo run_bbp_write(sc, 158, 0x4a); 3775259544Skevlo if (chan <= 14) { 3776259544Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX1_2GHZ, 3777259544Skevlo &val, 1); 3778259544Skevlo } else if (chan <= 64) { 3779259544Skevlo run_efuse_read(sc, 3780259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5GHZ, 3781259544Skevlo &val, 1); 3782259544Skevlo } else if (chan <= 138) { 3783259544Skevlo run_efuse_read(sc, 3784259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5GHZ, 3785259544Skevlo &val, 1); 3786259544Skevlo } else if (chan <= 165) { 3787259544Skevlo run_efuse_read(sc, 3788259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5GHZ, 3789259544Skevlo &val, 1); 3790259544Skevlo } else 3791259544Skevlo val = 0; 3792259547Skevlo run_bbp_write(sc, 159, val); 3793259544Skevlo 3794259544Skevlo /* Tx1 IQ phase. */ 3795259544Skevlo run_bbp_write(sc, 158, 0x4b); 3796259544Skevlo if (chan <= 14) { 3797259544Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX1_2GHZ, 3798259544Skevlo &val, 1); 3799259544Skevlo } else if (chan <= 64) { 3800259544Skevlo run_efuse_read(sc, 3801259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5GHZ, 3802259544Skevlo &val, 1); 3803259544Skevlo } else if (chan <= 138) { 3804259544Skevlo run_efuse_read(sc, 3805259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5GHZ, 3806259544Skevlo &val, 1); 3807259544Skevlo } else if (chan <= 165) { 3808259544Skevlo run_efuse_read(sc, 3809259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5GHZ, 3810259544Skevlo &val, 1); 3811259544Skevlo } else 3812259544Skevlo val = 0; 3813259547Skevlo run_bbp_write(sc, 159, val); 3814259544Skevlo 3815259544Skevlo /* RF IQ compensation control. */ 3816259544Skevlo run_bbp_write(sc, 158, 0x04); 3817259544Skevlo run_efuse_read(sc, RT5390_EEPROM_RF_IQ_COMPENSATION_CTL, 3818259544Skevlo &val, 1); 3819259547Skevlo run_bbp_write(sc, 159, val); 3820259544Skevlo 3821259544Skevlo /* RF IQ imbalance compensation control. */ 3822259544Skevlo run_bbp_write(sc, 158, 0x03); 3823259544Skevlo run_efuse_read(sc, 3824259544Skevlo RT5390_EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CTL, &val, 1); 3825259547Skevlo run_bbp_write(sc, 159, val); 3826259544Skevlo} 3827259544Skevlo 3828259544Skevlostatic void 3829205042Sthompsarun_set_agc(struct run_softc *sc, uint8_t agc) 3830205042Sthompsa{ 3831205042Sthompsa uint8_t bbp; 3832205042Sthompsa 3833205042Sthompsa if (sc->mac_ver == 0x3572) { 3834205042Sthompsa run_bbp_read(sc, 27, &bbp); 3835205042Sthompsa bbp &= ~(0x3 << 5); 3836205042Sthompsa run_bbp_write(sc, 27, bbp | 0 << 5); /* select Rx0 */ 3837205042Sthompsa run_bbp_write(sc, 66, agc); 3838205042Sthompsa run_bbp_write(sc, 27, bbp | 1 << 5); /* select Rx1 */ 3839205042Sthompsa run_bbp_write(sc, 66, agc); 3840205042Sthompsa } else 3841205042Sthompsa run_bbp_write(sc, 66, agc); 3842205042Sthompsa} 3843205042Sthompsa 3844205042Sthompsastatic void 3845203134Sthompsarun_select_chan_group(struct run_softc *sc, int group) 3846203134Sthompsa{ 3847203134Sthompsa uint32_t tmp; 3848205042Sthompsa uint8_t agc; 3849203134Sthompsa 3850203134Sthompsa run_bbp_write(sc, 62, 0x37 - sc->lna[group]); 3851203134Sthompsa run_bbp_write(sc, 63, 0x37 - sc->lna[group]); 3852203134Sthompsa run_bbp_write(sc, 64, 0x37 - sc->lna[group]); 3853258082Skevlo if (sc->mac_ver < 0x3572) 3854257955Skevlo run_bbp_write(sc, 86, 0x00); 3855203134Sthompsa 3856260219Skevlo if (sc->mac_ver == 0x3593) { 3857260219Skevlo run_bbp_write(sc, 77, 0x98); 3858260219Skevlo run_bbp_write(sc, 83, (group == 0) ? 0x8a : 0x9a); 3859260219Skevlo } 3860260219Skevlo 3861203134Sthompsa if (group == 0) { 3862203134Sthompsa if (sc->ext_2ghz_lna) { 3863257955Skevlo if (sc->mac_ver >= 0x5390) 3864257955Skevlo run_bbp_write(sc, 75, 0x52); 3865257955Skevlo else { 3866257955Skevlo run_bbp_write(sc, 82, 0x62); 3867257955Skevlo run_bbp_write(sc, 75, 0x46); 3868257955Skevlo } 3869203134Sthompsa } else { 3870259032Skevlo if (sc->mac_ver == 0x5592) { 3871259032Skevlo run_bbp_write(sc, 79, 0x1c); 3872259032Skevlo run_bbp_write(sc, 80, 0x0e); 3873259032Skevlo run_bbp_write(sc, 81, 0x3a); 3874259032Skevlo run_bbp_write(sc, 82, 0x62); 3875259032Skevlo 3876259032Skevlo run_bbp_write(sc, 195, 0x80); 3877259032Skevlo run_bbp_write(sc, 196, 0xe0); 3878259032Skevlo run_bbp_write(sc, 195, 0x81); 3879259032Skevlo run_bbp_write(sc, 196, 0x1f); 3880259032Skevlo run_bbp_write(sc, 195, 0x82); 3881259032Skevlo run_bbp_write(sc, 196, 0x38); 3882259032Skevlo run_bbp_write(sc, 195, 0x83); 3883259032Skevlo run_bbp_write(sc, 196, 0x32); 3884259032Skevlo run_bbp_write(sc, 195, 0x85); 3885259032Skevlo run_bbp_write(sc, 196, 0x28); 3886259032Skevlo run_bbp_write(sc, 195, 0x86); 3887259032Skevlo run_bbp_write(sc, 196, 0x19); 3888259032Skevlo } else if (sc->mac_ver >= 0x5390) 3889257955Skevlo run_bbp_write(sc, 75, 0x50); 3890257955Skevlo else { 3891260219Skevlo run_bbp_write(sc, 82, 3892260219Skevlo (sc->mac_ver == 0x3593) ? 0x62 : 0x84); 3893257955Skevlo run_bbp_write(sc, 75, 0x50); 3894257955Skevlo } 3895203134Sthompsa } 3896203134Sthompsa } else { 3897259032Skevlo if (sc->mac_ver == 0x5592) { 3898259032Skevlo run_bbp_write(sc, 79, 0x18); 3899259032Skevlo run_bbp_write(sc, 80, 0x08); 3900259032Skevlo run_bbp_write(sc, 81, 0x38); 3901259032Skevlo run_bbp_write(sc, 82, 0x92); 3902259032Skevlo 3903259032Skevlo run_bbp_write(sc, 195, 0x80); 3904259032Skevlo run_bbp_write(sc, 196, 0xf0); 3905259032Skevlo run_bbp_write(sc, 195, 0x81); 3906259032Skevlo run_bbp_write(sc, 196, 0x1e); 3907259032Skevlo run_bbp_write(sc, 195, 0x82); 3908259032Skevlo run_bbp_write(sc, 196, 0x28); 3909259032Skevlo run_bbp_write(sc, 195, 0x83); 3910259032Skevlo run_bbp_write(sc, 196, 0x20); 3911259032Skevlo run_bbp_write(sc, 195, 0x85); 3912259032Skevlo run_bbp_write(sc, 196, 0x7f); 3913259032Skevlo run_bbp_write(sc, 195, 0x86); 3914259032Skevlo run_bbp_write(sc, 196, 0x7f); 3915259032Skevlo } else if (sc->mac_ver == 0x3572) 3916205042Sthompsa run_bbp_write(sc, 82, 0x94); 3917205042Sthompsa else 3918260219Skevlo run_bbp_write(sc, 82, 3919260219Skevlo (sc->mac_ver == 0x3593) ? 0x82 : 0xf2); 3920205042Sthompsa if (sc->ext_5ghz_lna) 3921203134Sthompsa run_bbp_write(sc, 75, 0x46); 3922205042Sthompsa else 3923203134Sthompsa run_bbp_write(sc, 75, 0x50); 3924203134Sthompsa } 3925203134Sthompsa 3926203134Sthompsa run_read(sc, RT2860_TX_BAND_CFG, &tmp); 3927203134Sthompsa tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P); 3928203134Sthompsa tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P; 3929203134Sthompsa run_write(sc, RT2860_TX_BAND_CFG, tmp); 3930203134Sthompsa 3931203134Sthompsa /* enable appropriate Power Amplifiers and Low Noise Amplifiers */ 3932208019Sthompsa tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN; 3933260219Skevlo if (sc->mac_ver == 0x3593) 3934260219Skevlo tmp |= 1 << 29 | 1 << 28; 3935208019Sthompsa if (sc->nrxchains > 1) 3936208019Sthompsa tmp |= RT2860_LNA_PE1_EN; 3937203134Sthompsa if (group == 0) { /* 2GHz */ 3938208019Sthompsa tmp |= RT2860_PA_PE_G0_EN; 3939203134Sthompsa if (sc->ntxchains > 1) 3940203134Sthompsa tmp |= RT2860_PA_PE_G1_EN; 3941260219Skevlo if (sc->mac_ver == 0x3593) { 3942260219Skevlo if (sc->ntxchains > 2) 3943260219Skevlo tmp |= 1 << 25; 3944260219Skevlo } 3945203134Sthompsa } else { /* 5GHz */ 3946208019Sthompsa tmp |= RT2860_PA_PE_A0_EN; 3947203134Sthompsa if (sc->ntxchains > 1) 3948203134Sthompsa tmp |= RT2860_PA_PE_A1_EN; 3949203134Sthompsa } 3950205042Sthompsa if (sc->mac_ver == 0x3572) { 3951205042Sthompsa run_rt3070_rf_write(sc, 8, 0x00); 3952205042Sthompsa run_write(sc, RT2860_TX_PIN_CFG, tmp); 3953205042Sthompsa run_rt3070_rf_write(sc, 8, 0x80); 3954205042Sthompsa } else 3955205042Sthompsa run_write(sc, RT2860_TX_PIN_CFG, tmp); 3956203134Sthompsa 3957259032Skevlo if (sc->mac_ver == 0x5592) { 3958259032Skevlo run_bbp_write(sc, 195, 0x8d); 3959259032Skevlo run_bbp_write(sc, 196, 0x1a); 3960259032Skevlo } 3961259032Skevlo 3962260219Skevlo if (sc->mac_ver == 0x3593) { 3963260219Skevlo run_read(sc, RT2860_GPIO_CTRL, &tmp); 3964260219Skevlo tmp &= ~0x01010000; 3965260219Skevlo if (group == 0) 3966260219Skevlo tmp |= 0x00010000; 3967260219Skevlo tmp = (tmp & ~0x00009090) | 0x00000090; 3968260219Skevlo run_write(sc, RT2860_GPIO_CTRL, tmp); 3969260219Skevlo } 3970260219Skevlo 3971203134Sthompsa /* set initial AGC value */ 3972205042Sthompsa if (group == 0) { /* 2GHz band */ 3973205042Sthompsa if (sc->mac_ver >= 0x3070) 3974205042Sthompsa agc = 0x1c + sc->lna[0] * 2; 3975205042Sthompsa else 3976205042Sthompsa agc = 0x2e + sc->lna[0]; 3977205042Sthompsa } else { /* 5GHz band */ 3978259032Skevlo if (sc->mac_ver == 0x5592) 3979259032Skevlo agc = 0x24 + sc->lna[group] * 2; 3980260219Skevlo else if (sc->mac_ver == 0x3572 || sc->mac_ver == 0x3593) 3981205042Sthompsa agc = 0x22 + (sc->lna[group] * 5) / 3; 3982205042Sthompsa else 3983205042Sthompsa agc = 0x32 + (sc->lna[group] * 5) / 3; 3984205042Sthompsa } 3985205042Sthompsa run_set_agc(sc, agc); 3986203134Sthompsa} 3987203134Sthompsa 3988203134Sthompsastatic void 3989257429Shselaskyrun_rt2870_set_chan(struct run_softc *sc, u_int chan) 3990203134Sthompsa{ 3991203134Sthompsa const struct rfprog *rfprog = rt2860_rf2850; 3992203134Sthompsa uint32_t r2, r3, r4; 3993203134Sthompsa int8_t txpow1, txpow2; 3994203134Sthompsa int i; 3995203134Sthompsa 3996203134Sthompsa /* find the settings for this channel (we know it exists) */ 3997203134Sthompsa for (i = 0; rfprog[i].chan != chan; i++); 3998203134Sthompsa 3999203134Sthompsa r2 = rfprog[i].r2; 4000203134Sthompsa if (sc->ntxchains == 1) 4001258732Skevlo r2 |= 1 << 14; /* 1T: disable Tx chain 2 */ 4002203134Sthompsa if (sc->nrxchains == 1) 4003258732Skevlo r2 |= 1 << 17 | 1 << 6; /* 1R: disable Rx chains 2 & 3 */ 4004203134Sthompsa else if (sc->nrxchains == 2) 4005258732Skevlo r2 |= 1 << 6; /* 2R: disable Rx chain 3 */ 4006203134Sthompsa 4007203134Sthompsa /* use Tx power values from EEPROM */ 4008203134Sthompsa txpow1 = sc->txpow1[i]; 4009203134Sthompsa txpow2 = sc->txpow2[i]; 4010258732Skevlo 4011258732Skevlo /* Initialize RF R3 and R4. */ 4012258732Skevlo r3 = rfprog[i].r3 & 0xffffc1ff; 4013258732Skevlo r4 = (rfprog[i].r4 & ~(0x001f87c0)) | (sc->freq << 15); 4014203134Sthompsa if (chan > 14) { 4015258732Skevlo if (txpow1 >= 0) { 4016258732Skevlo txpow1 = (txpow1 > 0xf) ? (0xf) : (txpow1); 4017258732Skevlo r3 |= (txpow1 << 10) | (1 << 9); 4018258732Skevlo } else { 4019258732Skevlo txpow1 += 7; 4020258732Skevlo 4021258732Skevlo /* txpow1 is not possible larger than 15. */ 4022258732Skevlo r3 |= (txpow1 << 10); 4023258732Skevlo } 4024258732Skevlo if (txpow2 >= 0) { 4025258732Skevlo txpow2 = (txpow2 > 0xf) ? (0xf) : (txpow2); 4026258921Shselasky r4 |= (txpow2 << 7) | (1 << 6); 4027258732Skevlo } else { 4028258732Skevlo txpow2 += 7; 4029258732Skevlo r4 |= (txpow2 << 7); 4030258732Skevlo } 4031258732Skevlo } else { 4032258732Skevlo /* Set Tx0 power. */ 4033258732Skevlo r3 |= (txpow1 << 9); 4034258732Skevlo 4035258732Skevlo /* Set frequency offset and Tx1 power. */ 4036258732Skevlo r4 |= (txpow2 << 6); 4037203134Sthompsa } 4038203134Sthompsa 4039258733Skevlo run_rt2870_rf_write(sc, rfprog[i].r1); 4040258733Skevlo run_rt2870_rf_write(sc, r2); 4041258733Skevlo run_rt2870_rf_write(sc, r3 & ~(1 << 2)); 4042258733Skevlo run_rt2870_rf_write(sc, r4); 4043203134Sthompsa 4044203134Sthompsa run_delay(sc, 10); 4045203134Sthompsa 4046258733Skevlo run_rt2870_rf_write(sc, rfprog[i].r1); 4047258733Skevlo run_rt2870_rf_write(sc, r2); 4048258733Skevlo run_rt2870_rf_write(sc, r3 | (1 << 2)); 4049258733Skevlo run_rt2870_rf_write(sc, r4); 4050203134Sthompsa 4051203134Sthompsa run_delay(sc, 10); 4052203134Sthompsa 4053258733Skevlo run_rt2870_rf_write(sc, rfprog[i].r1); 4054258733Skevlo run_rt2870_rf_write(sc, r2); 4055258733Skevlo run_rt2870_rf_write(sc, r3 & ~(1 << 2)); 4056258733Skevlo run_rt2870_rf_write(sc, r4); 4057203134Sthompsa} 4058203134Sthompsa 4059203134Sthompsastatic void 4060257429Shselaskyrun_rt3070_set_chan(struct run_softc *sc, u_int chan) 4061203134Sthompsa{ 4062203134Sthompsa int8_t txpow1, txpow2; 4063203134Sthompsa uint8_t rf; 4064205042Sthompsa int i; 4065203134Sthompsa 4066205042Sthompsa /* find the settings for this channel (we know it exists) */ 4067205042Sthompsa for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4068205042Sthompsa 4069203134Sthompsa /* use Tx power values from EEPROM */ 4070205042Sthompsa txpow1 = sc->txpow1[i]; 4071205042Sthompsa txpow2 = sc->txpow2[i]; 4072203134Sthompsa 4073205042Sthompsa run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n); 4074256720Skevlo 4075256720Skevlo /* RT3370/RT3390: RF R3 [7:4] is not reserved bits. */ 4076256720Skevlo run_rt3070_rf_read(sc, 3, &rf); 4077256720Skevlo rf = (rf & ~0x0f) | rt3070_freqs[i].k; 4078256720Skevlo run_rt3070_rf_write(sc, 3, rf); 4079256720Skevlo 4080203134Sthompsa run_rt3070_rf_read(sc, 6, &rf); 4081205042Sthompsa rf = (rf & ~0x03) | rt3070_freqs[i].r; 4082203134Sthompsa run_rt3070_rf_write(sc, 6, rf); 4083203134Sthompsa 4084203134Sthompsa /* set Tx0 power */ 4085203134Sthompsa run_rt3070_rf_read(sc, 12, &rf); 4086203134Sthompsa rf = (rf & ~0x1f) | txpow1; 4087203134Sthompsa run_rt3070_rf_write(sc, 12, rf); 4088203134Sthompsa 4089203134Sthompsa /* set Tx1 power */ 4090203134Sthompsa run_rt3070_rf_read(sc, 13, &rf); 4091203134Sthompsa rf = (rf & ~0x1f) | txpow2; 4092203134Sthompsa run_rt3070_rf_write(sc, 13, rf); 4093203134Sthompsa 4094203134Sthompsa run_rt3070_rf_read(sc, 1, &rf); 4095203134Sthompsa rf &= ~0xfc; 4096203134Sthompsa if (sc->ntxchains == 1) 4097203134Sthompsa rf |= 1 << 7 | 1 << 5; /* 1T: disable Tx chains 2 & 3 */ 4098203134Sthompsa else if (sc->ntxchains == 2) 4099203134Sthompsa rf |= 1 << 7; /* 2T: disable Tx chain 3 */ 4100203134Sthompsa if (sc->nrxchains == 1) 4101203134Sthompsa rf |= 1 << 6 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 4102203134Sthompsa else if (sc->nrxchains == 2) 4103203134Sthompsa rf |= 1 << 6; /* 2R: disable Rx chain 3 */ 4104203134Sthompsa run_rt3070_rf_write(sc, 1, rf); 4105203134Sthompsa 4106203134Sthompsa /* set RF offset */ 4107203134Sthompsa run_rt3070_rf_read(sc, 23, &rf); 4108203134Sthompsa rf = (rf & ~0x7f) | sc->freq; 4109203134Sthompsa run_rt3070_rf_write(sc, 23, rf); 4110203134Sthompsa 4111203134Sthompsa /* program RF filter */ 4112205042Sthompsa run_rt3070_rf_read(sc, 24, &rf); /* Tx */ 4113205042Sthompsa rf = (rf & ~0x3f) | sc->rf24_20mhz; 4114205042Sthompsa run_rt3070_rf_write(sc, 24, rf); 4115205042Sthompsa run_rt3070_rf_read(sc, 31, &rf); /* Rx */ 4116205042Sthompsa rf = (rf & ~0x3f) | sc->rf24_20mhz; 4117205042Sthompsa run_rt3070_rf_write(sc, 31, rf); 4118203134Sthompsa 4119203134Sthompsa /* enable RF tuning */ 4120203134Sthompsa run_rt3070_rf_read(sc, 7, &rf); 4121203134Sthompsa run_rt3070_rf_write(sc, 7, rf | 0x01); 4122203134Sthompsa} 4123203134Sthompsa 4124203134Sthompsastatic void 4125205042Sthompsarun_rt3572_set_chan(struct run_softc *sc, u_int chan) 4126205042Sthompsa{ 4127205042Sthompsa int8_t txpow1, txpow2; 4128205042Sthompsa uint32_t tmp; 4129205042Sthompsa uint8_t rf; 4130205042Sthompsa int i; 4131205042Sthompsa 4132205042Sthompsa /* find the settings for this channel (we know it exists) */ 4133205042Sthompsa for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4134205042Sthompsa 4135205042Sthompsa /* use Tx power values from EEPROM */ 4136205042Sthompsa txpow1 = sc->txpow1[i]; 4137205042Sthompsa txpow2 = sc->txpow2[i]; 4138205042Sthompsa 4139205042Sthompsa if (chan <= 14) { 4140205042Sthompsa run_bbp_write(sc, 25, sc->bbp25); 4141205042Sthompsa run_bbp_write(sc, 26, sc->bbp26); 4142205042Sthompsa } else { 4143205042Sthompsa /* enable IQ phase correction */ 4144205042Sthompsa run_bbp_write(sc, 25, 0x09); 4145205042Sthompsa run_bbp_write(sc, 26, 0xff); 4146205042Sthompsa } 4147205042Sthompsa 4148205042Sthompsa run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n); 4149205042Sthompsa run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k); 4150205042Sthompsa run_rt3070_rf_read(sc, 6, &rf); 4151205042Sthompsa rf = (rf & ~0x0f) | rt3070_freqs[i].r; 4152205042Sthompsa rf |= (chan <= 14) ? 0x08 : 0x04; 4153205042Sthompsa run_rt3070_rf_write(sc, 6, rf); 4154205042Sthompsa 4155205042Sthompsa /* set PLL mode */ 4156205042Sthompsa run_rt3070_rf_read(sc, 5, &rf); 4157205042Sthompsa rf &= ~(0x08 | 0x04); 4158205042Sthompsa rf |= (chan <= 14) ? 0x04 : 0x08; 4159205042Sthompsa run_rt3070_rf_write(sc, 5, rf); 4160205042Sthompsa 4161205042Sthompsa /* set Tx power for chain 0 */ 4162205042Sthompsa if (chan <= 14) 4163205042Sthompsa rf = 0x60 | txpow1; 4164205042Sthompsa else 4165205042Sthompsa rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3); 4166205042Sthompsa run_rt3070_rf_write(sc, 12, rf); 4167205042Sthompsa 4168205042Sthompsa /* set Tx power for chain 1 */ 4169205042Sthompsa if (chan <= 14) 4170205042Sthompsa rf = 0x60 | txpow2; 4171205042Sthompsa else 4172205042Sthompsa rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3); 4173205042Sthompsa run_rt3070_rf_write(sc, 13, rf); 4174205042Sthompsa 4175205042Sthompsa /* set Tx/Rx streams */ 4176205042Sthompsa run_rt3070_rf_read(sc, 1, &rf); 4177205042Sthompsa rf &= ~0xfc; 4178205042Sthompsa if (sc->ntxchains == 1) 4179205042Sthompsa rf |= 1 << 7 | 1 << 5; /* 1T: disable Tx chains 2 & 3 */ 4180205042Sthompsa else if (sc->ntxchains == 2) 4181205042Sthompsa rf |= 1 << 7; /* 2T: disable Tx chain 3 */ 4182205042Sthompsa if (sc->nrxchains == 1) 4183205042Sthompsa rf |= 1 << 6 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 4184205042Sthompsa else if (sc->nrxchains == 2) 4185205042Sthompsa rf |= 1 << 6; /* 2R: disable Rx chain 3 */ 4186205042Sthompsa run_rt3070_rf_write(sc, 1, rf); 4187205042Sthompsa 4188205042Sthompsa /* set RF offset */ 4189205042Sthompsa run_rt3070_rf_read(sc, 23, &rf); 4190205042Sthompsa rf = (rf & ~0x7f) | sc->freq; 4191205042Sthompsa run_rt3070_rf_write(sc, 23, rf); 4192205042Sthompsa 4193205042Sthompsa /* program RF filter */ 4194205042Sthompsa rf = sc->rf24_20mhz; 4195205042Sthompsa run_rt3070_rf_write(sc, 24, rf); /* Tx */ 4196205042Sthompsa run_rt3070_rf_write(sc, 31, rf); /* Rx */ 4197205042Sthompsa 4198205042Sthompsa /* enable RF tuning */ 4199205042Sthompsa run_rt3070_rf_read(sc, 7, &rf); 4200205042Sthompsa rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14); 4201205042Sthompsa run_rt3070_rf_write(sc, 7, rf); 4202205042Sthompsa 4203205042Sthompsa /* TSSI */ 4204205042Sthompsa rf = (chan <= 14) ? 0xc3 : 0xc0; 4205205042Sthompsa run_rt3070_rf_write(sc, 9, rf); 4206205042Sthompsa 4207205042Sthompsa /* set loop filter 1 */ 4208205042Sthompsa run_rt3070_rf_write(sc, 10, 0xf1); 4209205042Sthompsa /* set loop filter 2 */ 4210205042Sthompsa run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00); 4211205042Sthompsa 4212205042Sthompsa /* set tx_mx2_ic */ 4213205042Sthompsa run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43); 4214205042Sthompsa /* set tx_mx1_ic */ 4215205042Sthompsa if (chan <= 14) 4216205042Sthompsa rf = 0x48 | sc->txmixgain_2ghz; 4217205042Sthompsa else 4218205042Sthompsa rf = 0x78 | sc->txmixgain_5ghz; 4219205042Sthompsa run_rt3070_rf_write(sc, 16, rf); 4220205042Sthompsa 4221205042Sthompsa /* set tx_lo1 */ 4222205042Sthompsa run_rt3070_rf_write(sc, 17, 0x23); 4223205042Sthompsa /* set tx_lo2 */ 4224205042Sthompsa if (chan <= 14) 4225205042Sthompsa rf = 0x93; 4226205042Sthompsa else if (chan <= 64) 4227205042Sthompsa rf = 0xb7; 4228205042Sthompsa else if (chan <= 128) 4229205042Sthompsa rf = 0x74; 4230205042Sthompsa else 4231205042Sthompsa rf = 0x72; 4232205042Sthompsa run_rt3070_rf_write(sc, 19, rf); 4233205042Sthompsa 4234205042Sthompsa /* set rx_lo1 */ 4235205042Sthompsa if (chan <= 14) 4236205042Sthompsa rf = 0xb3; 4237205042Sthompsa else if (chan <= 64) 4238205042Sthompsa rf = 0xf6; 4239205042Sthompsa else if (chan <= 128) 4240205042Sthompsa rf = 0xf4; 4241205042Sthompsa else 4242205042Sthompsa rf = 0xf3; 4243205042Sthompsa run_rt3070_rf_write(sc, 20, rf); 4244205042Sthompsa 4245205042Sthompsa /* set pfd_delay */ 4246205042Sthompsa if (chan <= 14) 4247205042Sthompsa rf = 0x15; 4248205042Sthompsa else if (chan <= 64) 4249205042Sthompsa rf = 0x3d; 4250205042Sthompsa else 4251205042Sthompsa rf = 0x01; 4252205042Sthompsa run_rt3070_rf_write(sc, 25, rf); 4253205042Sthompsa 4254205042Sthompsa /* set rx_lo2 */ 4255205042Sthompsa run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87); 4256205042Sthompsa /* set ldo_rf_vc */ 4257205042Sthompsa run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01); 4258205042Sthompsa /* set drv_cc */ 4259205042Sthompsa run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f); 4260205042Sthompsa 4261205042Sthompsa run_read(sc, RT2860_GPIO_CTRL, &tmp); 4262205042Sthompsa tmp &= ~0x8080; 4263205042Sthompsa if (chan <= 14) 4264205042Sthompsa tmp |= 0x80; 4265205042Sthompsa run_write(sc, RT2860_GPIO_CTRL, tmp); 4266205042Sthompsa 4267205042Sthompsa /* enable RF tuning */ 4268205042Sthompsa run_rt3070_rf_read(sc, 7, &rf); 4269205042Sthompsa run_rt3070_rf_write(sc, 7, rf | 0x01); 4270205042Sthompsa 4271205042Sthompsa run_delay(sc, 2); 4272205042Sthompsa} 4273205042Sthompsa 4274205042Sthompsastatic void 4275260219Skevlorun_rt3593_set_chan(struct run_softc *sc, u_int chan) 4276260219Skevlo{ 4277260219Skevlo int8_t txpow1, txpow2, txpow3; 4278260219Skevlo uint8_t h20mhz, rf; 4279260219Skevlo int i; 4280260219Skevlo 4281260219Skevlo /* find the settings for this channel (we know it exists) */ 4282260219Skevlo for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4283260219Skevlo 4284260219Skevlo /* use Tx power values from EEPROM */ 4285260219Skevlo txpow1 = sc->txpow1[i]; 4286260219Skevlo txpow2 = sc->txpow2[i]; 4287260219Skevlo txpow3 = (sc->ntxchains == 3) ? sc->txpow3[i] : 0; 4288260219Skevlo 4289260219Skevlo if (chan <= 14) { 4290260219Skevlo run_bbp_write(sc, 25, sc->bbp25); 4291260219Skevlo run_bbp_write(sc, 26, sc->bbp26); 4292260219Skevlo } else { 4293260219Skevlo /* Enable IQ phase correction. */ 4294260219Skevlo run_bbp_write(sc, 25, 0x09); 4295260219Skevlo run_bbp_write(sc, 26, 0xff); 4296260219Skevlo } 4297260219Skevlo 4298260219Skevlo run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n); 4299260219Skevlo run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f); 4300260219Skevlo run_rt3070_rf_read(sc, 11, &rf); 4301260219Skevlo rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03); 4302260219Skevlo run_rt3070_rf_write(sc, 11, rf); 4303260219Skevlo 4304260219Skevlo /* Set pll_idoh. */ 4305260219Skevlo run_rt3070_rf_read(sc, 11, &rf); 4306260219Skevlo rf &= ~0x4c; 4307260219Skevlo rf |= (chan <= 14) ? 0x44 : 0x48; 4308260219Skevlo run_rt3070_rf_write(sc, 11, rf); 4309260219Skevlo 4310260219Skevlo if (chan <= 14) 4311260219Skevlo rf = txpow1 & 0x1f; 4312260219Skevlo else 4313260219Skevlo rf = 0x40 | ((txpow1 & 0x18) << 1) | (txpow1 & 0x07); 4314260219Skevlo run_rt3070_rf_write(sc, 53, rf); 4315260219Skevlo 4316260219Skevlo if (chan <= 14) 4317260219Skevlo rf = txpow2 & 0x1f; 4318260219Skevlo else 4319260219Skevlo rf = 0x40 | ((txpow2 & 0x18) << 1) | (txpow2 & 0x07); 4320260219Skevlo run_rt3070_rf_write(sc, 55, rf); 4321260219Skevlo 4322260219Skevlo if (chan <= 14) 4323260219Skevlo rf = txpow3 & 0x1f; 4324260219Skevlo else 4325260219Skevlo rf = 0x40 | ((txpow3 & 0x18) << 1) | (txpow3 & 0x07); 4326260219Skevlo run_rt3070_rf_write(sc, 54, rf); 4327260219Skevlo 4328260219Skevlo rf = RT3070_RF_BLOCK | RT3070_PLL_PD; 4329260219Skevlo if (sc->ntxchains == 3) 4330260219Skevlo rf |= RT3070_TX0_PD | RT3070_TX1_PD | RT3070_TX2_PD; 4331260219Skevlo else 4332260219Skevlo rf |= RT3070_TX0_PD | RT3070_TX1_PD; 4333260219Skevlo rf |= RT3070_RX0_PD | RT3070_RX1_PD | RT3070_RX2_PD; 4334260219Skevlo run_rt3070_rf_write(sc, 1, rf); 4335260219Skevlo 4336260219Skevlo run_adjust_freq_offset(sc); 4337260219Skevlo 4338260219Skevlo run_rt3070_rf_write(sc, 31, (chan <= 14) ? 0xa0 : 0x80); 4339260219Skevlo 4340260219Skevlo h20mhz = (sc->rf24_20mhz & 0x20) >> 5; 4341260219Skevlo run_rt3070_rf_read(sc, 30, &rf); 4342260219Skevlo rf = (rf & ~0x06) | (h20mhz << 1) | (h20mhz << 2); 4343260219Skevlo run_rt3070_rf_write(sc, 30, rf); 4344260219Skevlo 4345260219Skevlo run_rt3070_rf_read(sc, 36, &rf); 4346260219Skevlo if (chan <= 14) 4347260219Skevlo rf |= 0x80; 4348260219Skevlo else 4349260219Skevlo rf &= ~0x80; 4350260219Skevlo run_rt3070_rf_write(sc, 36, rf); 4351260219Skevlo 4352260219Skevlo /* Set vcolo_bs. */ 4353260219Skevlo run_rt3070_rf_write(sc, 34, (chan <= 14) ? 0x3c : 0x20); 4354260219Skevlo /* Set pfd_delay. */ 4355260219Skevlo run_rt3070_rf_write(sc, 12, (chan <= 14) ? 0x1a : 0x12); 4356260219Skevlo 4357260219Skevlo /* Set vco bias current control. */ 4358260219Skevlo run_rt3070_rf_read(sc, 6, &rf); 4359260219Skevlo rf &= ~0xc0; 4360260219Skevlo if (chan <= 14) 4361260219Skevlo rf |= 0x40; 4362260219Skevlo else if (chan <= 128) 4363260219Skevlo rf |= 0x80; 4364260219Skevlo else 4365260219Skevlo rf |= 0x40; 4366260219Skevlo run_rt3070_rf_write(sc, 6, rf); 4367260219Skevlo 4368260219Skevlo run_rt3070_rf_read(sc, 30, &rf); 4369260219Skevlo rf = (rf & ~0x18) | 0x10; 4370260219Skevlo run_rt3070_rf_write(sc, 30, rf); 4371260219Skevlo 4372260219Skevlo run_rt3070_rf_write(sc, 10, (chan <= 14) ? 0xd3 : 0xd8); 4373260219Skevlo run_rt3070_rf_write(sc, 13, (chan <= 14) ? 0x12 : 0x23); 4374260219Skevlo 4375260219Skevlo run_rt3070_rf_read(sc, 51, &rf); 4376260219Skevlo rf = (rf & ~0x03) | 0x01; 4377260219Skevlo run_rt3070_rf_write(sc, 51, rf); 4378260219Skevlo /* Set tx_mx1_cc. */ 4379260219Skevlo run_rt3070_rf_read(sc, 51, &rf); 4380260219Skevlo rf &= ~0x1c; 4381260219Skevlo rf |= (chan <= 14) ? 0x14 : 0x10; 4382260219Skevlo run_rt3070_rf_write(sc, 51, rf); 4383260219Skevlo /* Set tx_mx1_ic. */ 4384260219Skevlo run_rt3070_rf_read(sc, 51, &rf); 4385260219Skevlo rf &= ~0xe0; 4386260219Skevlo rf |= (chan <= 14) ? 0x60 : 0x40; 4387260219Skevlo run_rt3070_rf_write(sc, 51, rf); 4388260219Skevlo /* Set tx_lo1_ic. */ 4389260219Skevlo run_rt3070_rf_read(sc, 49, &rf); 4390260219Skevlo rf &= ~0x1c; 4391260219Skevlo rf |= (chan <= 14) ? 0x0c : 0x08; 4392260219Skevlo run_rt3070_rf_write(sc, 49, rf); 4393260219Skevlo /* Set tx_lo1_en. */ 4394260219Skevlo run_rt3070_rf_read(sc, 50, &rf); 4395260219Skevlo run_rt3070_rf_write(sc, 50, rf & ~0x20); 4396260219Skevlo /* Set drv_cc. */ 4397260219Skevlo run_rt3070_rf_read(sc, 57, &rf); 4398260219Skevlo rf &= ~0xfc; 4399260219Skevlo rf |= (chan <= 14) ? 0x6c : 0x3c; 4400260219Skevlo run_rt3070_rf_write(sc, 57, rf); 4401260219Skevlo /* Set rx_mix1_ic, rxa_lnactr, lna_vc, lna_inbias_en and lna_en. */ 4402260219Skevlo run_rt3070_rf_write(sc, 44, (chan <= 14) ? 0x93 : 0x9b); 4403260219Skevlo /* Set drv_gnd_a, tx_vga_cc_a and tx_mx2_gain. */ 4404260219Skevlo run_rt3070_rf_write(sc, 52, (chan <= 14) ? 0x45 : 0x05); 4405260219Skevlo /* Enable VCO calibration. */ 4406260219Skevlo run_rt3070_rf_read(sc, 3, &rf); 4407260219Skevlo rf &= ~RT5390_VCOCAL; 4408260219Skevlo rf |= (chan <= 14) ? RT5390_VCOCAL : 0xbe; 4409260219Skevlo run_rt3070_rf_write(sc, 3, rf); 4410260219Skevlo 4411260219Skevlo if (chan <= 14) 4412260219Skevlo rf = 0x23; 4413260219Skevlo else if (chan <= 64) 4414260219Skevlo rf = 0x36; 4415260219Skevlo else if (chan <= 128) 4416260219Skevlo rf = 0x32; 4417260219Skevlo else 4418260219Skevlo rf = 0x30; 4419260219Skevlo run_rt3070_rf_write(sc, 39, rf); 4420260219Skevlo if (chan <= 14) 4421260219Skevlo rf = 0xbb; 4422260219Skevlo else if (chan <= 64) 4423260219Skevlo rf = 0xeb; 4424260219Skevlo else if (chan <= 128) 4425260219Skevlo rf = 0xb3; 4426260219Skevlo else 4427260219Skevlo rf = 0x9b; 4428260219Skevlo run_rt3070_rf_write(sc, 45, rf); 4429260219Skevlo 4430260219Skevlo /* Set FEQ/AEQ control. */ 4431260219Skevlo run_bbp_write(sc, 105, 0x34); 4432260219Skevlo} 4433260219Skevlo 4434260219Skevlostatic void 4435257955Skevlorun_rt5390_set_chan(struct run_softc *sc, u_int chan) 4436257955Skevlo{ 4437257955Skevlo int8_t txpow1, txpow2; 4438257955Skevlo uint8_t rf; 4439257955Skevlo int i; 4440257955Skevlo 4441257955Skevlo /* find the settings for this channel (we know it exists) */ 4442257955Skevlo for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4443257955Skevlo 4444257955Skevlo /* use Tx power values from EEPROM */ 4445257955Skevlo txpow1 = sc->txpow1[i]; 4446257955Skevlo txpow2 = sc->txpow2[i]; 4447257955Skevlo 4448257955Skevlo run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n); 4449257955Skevlo run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f); 4450257955Skevlo run_rt3070_rf_read(sc, 11, &rf); 4451257955Skevlo rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03); 4452257955Skevlo run_rt3070_rf_write(sc, 11, rf); 4453257955Skevlo 4454257955Skevlo run_rt3070_rf_read(sc, 49, &rf); 4455257955Skevlo rf = (rf & ~0x3f) | (txpow1 & 0x3f); 4456257955Skevlo /* The valid range of the RF R49 is 0x00 to 0x27. */ 4457257955Skevlo if ((rf & 0x3f) > 0x27) 4458257955Skevlo rf = (rf & ~0x3f) | 0x27; 4459257955Skevlo run_rt3070_rf_write(sc, 49, rf); 4460257955Skevlo 4461257955Skevlo if (sc->mac_ver == 0x5392) { 4462257955Skevlo run_rt3070_rf_read(sc, 50, &rf); 4463257955Skevlo rf = (rf & ~0x3f) | (txpow2 & 0x3f); 4464257955Skevlo /* The valid range of the RF R50 is 0x00 to 0x27. */ 4465257955Skevlo if ((rf & 0x3f) > 0x27) 4466257955Skevlo rf = (rf & ~0x3f) | 0x27; 4467257955Skevlo run_rt3070_rf_write(sc, 50, rf); 4468257955Skevlo } 4469257955Skevlo 4470257955Skevlo run_rt3070_rf_read(sc, 1, &rf); 4471257955Skevlo rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD; 4472257955Skevlo if (sc->mac_ver == 0x5392) 4473257955Skevlo rf |= RT3070_RX1_PD | RT3070_TX1_PD; 4474257955Skevlo run_rt3070_rf_write(sc, 1, rf); 4475257955Skevlo 4476257955Skevlo if (sc->mac_ver != 0x5392) { 4477257955Skevlo run_rt3070_rf_read(sc, 2, &rf); 4478257955Skevlo rf |= 0x80; 4479257955Skevlo run_rt3070_rf_write(sc, 2, rf); 4480257955Skevlo run_delay(sc, 10); 4481257955Skevlo rf &= 0x7f; 4482257955Skevlo run_rt3070_rf_write(sc, 2, rf); 4483257955Skevlo } 4484257955Skevlo 4485257955Skevlo run_adjust_freq_offset(sc); 4486257955Skevlo 4487257955Skevlo if (sc->mac_ver == 0x5392) { 4488257955Skevlo /* Fix for RT5392C. */ 4489257955Skevlo if (sc->mac_rev >= 0x0223) { 4490259030Skevlo if (chan <= 4) 4491257955Skevlo rf = 0x0f; 4492259030Skevlo else if (chan >= 5 && chan <= 7) 4493257955Skevlo rf = 0x0e; 4494259030Skevlo else 4495257955Skevlo rf = 0x0d; 4496257955Skevlo run_rt3070_rf_write(sc, 23, rf); 4497257955Skevlo 4498259030Skevlo if (chan <= 4) 4499257955Skevlo rf = 0x0c; 4500257955Skevlo else if (chan == 5) 4501257955Skevlo rf = 0x0b; 4502259030Skevlo else if (chan >= 6 && chan <= 7) 4503257955Skevlo rf = 0x0a; 4504259030Skevlo else if (chan >= 8 && chan <= 10) 4505257955Skevlo rf = 0x09; 4506259030Skevlo else 4507257955Skevlo rf = 0x08; 4508257955Skevlo run_rt3070_rf_write(sc, 59, rf); 4509257955Skevlo } else { 4510259030Skevlo if (chan <= 11) 4511257955Skevlo rf = 0x0f; 4512259030Skevlo else 4513257955Skevlo rf = 0x0b; 4514257955Skevlo run_rt3070_rf_write(sc, 59, rf); 4515257955Skevlo } 4516257955Skevlo } else { 4517257955Skevlo /* Fix for RT5390F. */ 4518257955Skevlo if (sc->mac_rev >= 0x0502) { 4519259030Skevlo if (chan <= 11) 4520257955Skevlo rf = 0x43; 4521259030Skevlo else 4522257955Skevlo rf = 0x23; 4523257955Skevlo run_rt3070_rf_write(sc, 55, rf); 4524257955Skevlo 4525259030Skevlo if (chan <= 11) 4526257955Skevlo rf = 0x0f; 4527257955Skevlo else if (chan == 12) 4528257955Skevlo rf = 0x0d; 4529259030Skevlo else 4530257955Skevlo rf = 0x0b; 4531257955Skevlo run_rt3070_rf_write(sc, 59, rf); 4532257955Skevlo } else { 4533257955Skevlo run_rt3070_rf_write(sc, 55, 0x44); 4534257955Skevlo run_rt3070_rf_write(sc, 59, 0x8f); 4535257955Skevlo } 4536257955Skevlo } 4537257955Skevlo 4538257955Skevlo /* Enable VCO calibration. */ 4539257955Skevlo run_rt3070_rf_read(sc, 3, &rf); 4540257955Skevlo rf |= RT5390_VCOCAL; 4541257955Skevlo run_rt3070_rf_write(sc, 3, rf); 4542257955Skevlo} 4543257955Skevlo 4544257955Skevlostatic void 4545259032Skevlorun_rt5592_set_chan(struct run_softc *sc, u_int chan) 4546259032Skevlo{ 4547259032Skevlo const struct rt5592_freqs *freqs; 4548259032Skevlo uint32_t tmp; 4549259032Skevlo uint8_t reg, rf, txpow_bound; 4550259032Skevlo int8_t txpow1, txpow2; 4551259032Skevlo int i; 4552259032Skevlo 4553259032Skevlo run_read(sc, RT5592_DEBUG_INDEX, &tmp); 4554259032Skevlo freqs = (tmp & RT5592_SEL_XTAL) ? 4555259032Skevlo rt5592_freqs_40mhz : rt5592_freqs_20mhz; 4556259032Skevlo 4557259032Skevlo /* find the settings for this channel (we know it exists) */ 4558259032Skevlo for (i = 0; rt2860_rf2850[i].chan != chan; i++, freqs++); 4559259032Skevlo 4560259032Skevlo /* use Tx power values from EEPROM */ 4561259032Skevlo txpow1 = sc->txpow1[i]; 4562259032Skevlo txpow2 = sc->txpow2[i]; 4563259032Skevlo 4564259032Skevlo run_read(sc, RT3070_LDO_CFG0, &tmp); 4565259032Skevlo tmp &= ~0x1c000000; 4566259032Skevlo if (chan > 14) 4567259032Skevlo tmp |= 0x14000000; 4568259032Skevlo run_write(sc, RT3070_LDO_CFG0, tmp); 4569259032Skevlo 4570259032Skevlo /* N setting. */ 4571259032Skevlo run_rt3070_rf_write(sc, 8, freqs->n & 0xff); 4572259032Skevlo run_rt3070_rf_read(sc, 9, &rf); 4573259032Skevlo rf &= ~(1 << 4); 4574259032Skevlo rf |= ((freqs->n & 0x0100) >> 8) << 4; 4575259032Skevlo run_rt3070_rf_write(sc, 9, rf); 4576259032Skevlo 4577259032Skevlo /* K setting. */ 4578259032Skevlo run_rt3070_rf_read(sc, 9, &rf); 4579259032Skevlo rf &= ~0x0f; 4580259032Skevlo rf |= (freqs->k & 0x0f); 4581259032Skevlo run_rt3070_rf_write(sc, 9, rf); 4582259032Skevlo 4583259032Skevlo /* Mode setting. */ 4584259032Skevlo run_rt3070_rf_read(sc, 11, &rf); 4585259032Skevlo rf &= ~0x0c; 4586259032Skevlo rf |= ((freqs->m - 0x8) & 0x3) << 2; 4587259032Skevlo run_rt3070_rf_write(sc, 11, rf); 4588259032Skevlo run_rt3070_rf_read(sc, 9, &rf); 4589259032Skevlo rf &= ~(1 << 7); 4590259032Skevlo rf |= (((freqs->m - 0x8) & 0x4) >> 2) << 7; 4591259032Skevlo run_rt3070_rf_write(sc, 9, rf); 4592259032Skevlo 4593259032Skevlo /* R setting. */ 4594259032Skevlo run_rt3070_rf_read(sc, 11, &rf); 4595259032Skevlo rf &= ~0x03; 4596259032Skevlo rf |= (freqs->r - 0x1); 4597259032Skevlo run_rt3070_rf_write(sc, 11, rf); 4598259032Skevlo 4599259032Skevlo if (chan <= 14) { 4600259032Skevlo /* Initialize RF registers for 2GHZ. */ 4601259032Skevlo for (i = 0; i < nitems(rt5592_2ghz_def_rf); i++) { 4602259032Skevlo run_rt3070_rf_write(sc, rt5592_2ghz_def_rf[i].reg, 4603259032Skevlo rt5592_2ghz_def_rf[i].val); 4604259032Skevlo } 4605259032Skevlo 4606259032Skevlo rf = (chan <= 10) ? 0x07 : 0x06; 4607259032Skevlo run_rt3070_rf_write(sc, 23, rf); 4608259032Skevlo run_rt3070_rf_write(sc, 59, rf); 4609259032Skevlo 4610259032Skevlo run_rt3070_rf_write(sc, 55, 0x43); 4611259032Skevlo 4612259032Skevlo /* 4613259032Skevlo * RF R49/R50 Tx power ALC code. 4614259032Skevlo * G-band bit<7:6>=1:0, bit<5:0> range from 0x0 ~ 0x27. 4615259032Skevlo */ 4616259032Skevlo reg = 2; 4617259032Skevlo txpow_bound = 0x27; 4618259032Skevlo } else { 4619259032Skevlo /* Initialize RF registers for 5GHZ. */ 4620259032Skevlo for (i = 0; i < nitems(rt5592_5ghz_def_rf); i++) { 4621259032Skevlo run_rt3070_rf_write(sc, rt5592_5ghz_def_rf[i].reg, 4622259032Skevlo rt5592_5ghz_def_rf[i].val); 4623259032Skevlo } 4624259032Skevlo for (i = 0; i < nitems(rt5592_chan_5ghz); i++) { 4625259032Skevlo if (chan >= rt5592_chan_5ghz[i].firstchan && 4626259032Skevlo chan <= rt5592_chan_5ghz[i].lastchan) { 4627259032Skevlo run_rt3070_rf_write(sc, rt5592_chan_5ghz[i].reg, 4628259032Skevlo rt5592_chan_5ghz[i].val); 4629259032Skevlo } 4630259032Skevlo } 4631259032Skevlo 4632259032Skevlo /* 4633259032Skevlo * RF R49/R50 Tx power ALC code. 4634259032Skevlo * A-band bit<7:6>=1:1, bit<5:0> range from 0x0 ~ 0x2b. 4635259032Skevlo */ 4636259032Skevlo reg = 3; 4637259032Skevlo txpow_bound = 0x2b; 4638259032Skevlo } 4639259032Skevlo 4640259032Skevlo /* RF R49 ch0 Tx power ALC code. */ 4641259032Skevlo run_rt3070_rf_read(sc, 49, &rf); 4642259032Skevlo rf &= ~0xc0; 4643259032Skevlo rf |= (reg << 6); 4644259032Skevlo rf = (rf & ~0x3f) | (txpow1 & 0x3f); 4645259032Skevlo if ((rf & 0x3f) > txpow_bound) 4646259032Skevlo rf = (rf & ~0x3f) | txpow_bound; 4647259032Skevlo run_rt3070_rf_write(sc, 49, rf); 4648259032Skevlo 4649259032Skevlo /* RF R50 ch1 Tx power ALC code. */ 4650259032Skevlo run_rt3070_rf_read(sc, 50, &rf); 4651259032Skevlo rf &= ~(1 << 7 | 1 << 6); 4652259032Skevlo rf |= (reg << 6); 4653259032Skevlo rf = (rf & ~0x3f) | (txpow2 & 0x3f); 4654259032Skevlo if ((rf & 0x3f) > txpow_bound) 4655259032Skevlo rf = (rf & ~0x3f) | txpow_bound; 4656259032Skevlo run_rt3070_rf_write(sc, 50, rf); 4657259032Skevlo 4658259032Skevlo /* Enable RF_BLOCK, PLL_PD, RX0_PD, and TX0_PD. */ 4659259032Skevlo run_rt3070_rf_read(sc, 1, &rf); 4660259032Skevlo rf |= (RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD); 4661259032Skevlo if (sc->ntxchains > 1) 4662259032Skevlo rf |= RT3070_TX1_PD; 4663259032Skevlo if (sc->nrxchains > 1) 4664259032Skevlo rf |= RT3070_RX1_PD; 4665259032Skevlo run_rt3070_rf_write(sc, 1, rf); 4666259032Skevlo 4667259032Skevlo run_rt3070_rf_write(sc, 6, 0xe4); 4668259032Skevlo 4669259032Skevlo run_rt3070_rf_write(sc, 30, 0x10); 4670259032Skevlo run_rt3070_rf_write(sc, 31, 0x80); 4671259032Skevlo run_rt3070_rf_write(sc, 32, 0x80); 4672259032Skevlo 4673259032Skevlo run_adjust_freq_offset(sc); 4674259032Skevlo 4675259032Skevlo /* Enable VCO calibration. */ 4676259032Skevlo run_rt3070_rf_read(sc, 3, &rf); 4677259032Skevlo rf |= RT5390_VCOCAL; 4678259032Skevlo run_rt3070_rf_write(sc, 3, rf); 4679259032Skevlo} 4680259032Skevlo 4681259032Skevlostatic void 4682203134Sthompsarun_set_rx_antenna(struct run_softc *sc, int aux) 4683203134Sthompsa{ 4684203134Sthompsa uint32_t tmp; 4685257955Skevlo uint8_t bbp152; 4686203134Sthompsa 4687203134Sthompsa if (aux) { 4688257955Skevlo if (sc->rf_rev == RT5390_RF_5370) { 4689257955Skevlo run_bbp_read(sc, 152, &bbp152); 4690257955Skevlo run_bbp_write(sc, 152, bbp152 & ~0x80); 4691259030Skevlo } else { 4692257955Skevlo run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0); 4693257955Skevlo run_read(sc, RT2860_GPIO_CTRL, &tmp); 4694257955Skevlo run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08); 4695257955Skevlo } 4696203134Sthompsa } else { 4697257955Skevlo if (sc->rf_rev == RT5390_RF_5370) { 4698257955Skevlo run_bbp_read(sc, 152, &bbp152); 4699257955Skevlo run_bbp_write(sc, 152, bbp152 | 0x80); 4700259030Skevlo } else { 4701257955Skevlo run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1); 4702257955Skevlo run_read(sc, RT2860_GPIO_CTRL, &tmp); 4703257955Skevlo run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808); 4704257955Skevlo } 4705203134Sthompsa } 4706203134Sthompsa} 4707203134Sthompsa 4708203134Sthompsastatic int 4709203134Sthompsarun_set_chan(struct run_softc *sc, struct ieee80211_channel *c) 4710203134Sthompsa{ 4711287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 4712257429Shselasky u_int chan, group; 4713203134Sthompsa 4714203134Sthompsa chan = ieee80211_chan2ieee(ic, c); 4715203134Sthompsa if (chan == 0 || chan == IEEE80211_CHAN_ANY) 4716209917Sthompsa return (EINVAL); 4717203134Sthompsa 4718259032Skevlo if (sc->mac_ver == 0x5592) 4719259032Skevlo run_rt5592_set_chan(sc, chan); 4720259032Skevlo else if (sc->mac_ver >= 0x5390) 4721257955Skevlo run_rt5390_set_chan(sc, chan); 4722260219Skevlo else if (sc->mac_ver == 0x3593) 4723260219Skevlo run_rt3593_set_chan(sc, chan); 4724257955Skevlo else if (sc->mac_ver == 0x3572) 4725205042Sthompsa run_rt3572_set_chan(sc, chan); 4726205042Sthompsa else if (sc->mac_ver >= 0x3070) 4727203134Sthompsa run_rt3070_set_chan(sc, chan); 4728203134Sthompsa else 4729203134Sthompsa run_rt2870_set_chan(sc, chan); 4730203134Sthompsa 4731203134Sthompsa /* determine channel group */ 4732203134Sthompsa if (chan <= 14) 4733203134Sthompsa group = 0; 4734203134Sthompsa else if (chan <= 64) 4735203134Sthompsa group = 1; 4736203134Sthompsa else if (chan <= 128) 4737203134Sthompsa group = 2; 4738203134Sthompsa else 4739203134Sthompsa group = 3; 4740203134Sthompsa 4741203134Sthompsa /* XXX necessary only when group has changed! */ 4742203134Sthompsa run_select_chan_group(sc, group); 4743203134Sthompsa 4744203134Sthompsa run_delay(sc, 10); 4745203134Sthompsa 4746259545Skevlo /* Perform IQ calibration. */ 4747259544Skevlo if (sc->mac_ver >= 0x5392) 4748259544Skevlo run_iq_calib(sc, chan); 4749259544Skevlo 4750209917Sthompsa return (0); 4751203134Sthompsa} 4752203134Sthompsa 4753203134Sthompsastatic void 4754203134Sthompsarun_set_channel(struct ieee80211com *ic) 4755203134Sthompsa{ 4756286950Sadrian struct run_softc *sc = ic->ic_softc; 4757203134Sthompsa 4758203134Sthompsa RUN_LOCK(sc); 4759203134Sthompsa run_set_chan(sc, ic->ic_curchan); 4760203134Sthompsa RUN_UNLOCK(sc); 4761203134Sthompsa 4762203134Sthompsa return; 4763203134Sthompsa} 4764203134Sthompsa 4765203134Sthompsastatic void 4766203134Sthompsarun_scan_start(struct ieee80211com *ic) 4767203134Sthompsa{ 4768286950Sadrian struct run_softc *sc = ic->ic_softc; 4769203134Sthompsa uint32_t tmp; 4770203134Sthompsa 4771203134Sthompsa RUN_LOCK(sc); 4772203134Sthompsa 4773203134Sthompsa /* abort TSF synchronization */ 4774203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 4775203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, 4776203134Sthompsa tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 4777203134Sthompsa RT2860_TBTT_TIMER_EN)); 4778287197Sglebius run_set_bssid(sc, ieee80211broadcastaddr); 4779203134Sthompsa 4780203134Sthompsa RUN_UNLOCK(sc); 4781203134Sthompsa 4782203134Sthompsa return; 4783203134Sthompsa} 4784203134Sthompsa 4785203134Sthompsastatic void 4786203134Sthompsarun_scan_end(struct ieee80211com *ic) 4787203134Sthompsa{ 4788286950Sadrian struct run_softc *sc = ic->ic_softc; 4789203134Sthompsa 4790203134Sthompsa RUN_LOCK(sc); 4791203134Sthompsa 4792203134Sthompsa run_enable_tsf_sync(sc); 4793203134Sthompsa /* XXX keep local copy */ 4794287197Sglebius run_set_bssid(sc, ic->ic_macaddr); 4795203134Sthompsa 4796203134Sthompsa RUN_UNLOCK(sc); 4797203134Sthompsa 4798203134Sthompsa return; 4799203134Sthompsa} 4800203134Sthompsa 4801208019Sthompsa/* 4802208019Sthompsa * Could be called from ieee80211_node_timeout() 4803208019Sthompsa * (non-sleepable thread) 4804208019Sthompsa */ 4805208019Sthompsastatic void 4806208019Sthompsarun_update_beacon(struct ieee80211vap *vap, int item) 4807203134Sthompsa{ 4808208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 4809286950Sadrian struct run_softc *sc = ic->ic_softc; 4810218492Sbschmidt struct run_vap *rvp = RUN_VAP(vap); 4811218492Sbschmidt int mcast = 0; 4812208019Sthompsa uint32_t i; 4813208019Sthompsa 4814218492Sbschmidt KASSERT(vap != NULL, ("no beacon")); 4815218492Sbschmidt 4816218492Sbschmidt switch (item) { 4817218492Sbschmidt case IEEE80211_BEACON_ERP: 4818283540Sglebius run_updateslot(ic); 4819218492Sbschmidt break; 4820218492Sbschmidt case IEEE80211_BEACON_HTINFO: 4821218492Sbschmidt run_updateprot(ic); 4822218492Sbschmidt break; 4823218492Sbschmidt case IEEE80211_BEACON_TIM: 4824218492Sbschmidt mcast = 1; /*TODO*/ 4825218492Sbschmidt break; 4826218492Sbschmidt default: 4827218492Sbschmidt break; 4828218492Sbschmidt } 4829218492Sbschmidt 4830218492Sbschmidt setbit(rvp->bo.bo_flags, item); 4831273448Skevlo if (rvp->beacon_mbuf == NULL) { 4832273448Skevlo rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss, 4833273448Skevlo &rvp->bo); 4834273448Skevlo if (rvp->beacon_mbuf == NULL) 4835273448Skevlo return; 4836273448Skevlo } 4837218492Sbschmidt ieee80211_beacon_update(vap->iv_bss, &rvp->bo, rvp->beacon_mbuf, mcast); 4838218492Sbschmidt 4839208019Sthompsa i = RUN_CMDQ_GET(&sc->cmdq_store); 4840208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 4841208019Sthompsa sc->cmdq[i].func = run_update_beacon_cb; 4842208019Sthompsa sc->cmdq[i].arg0 = vap; 4843208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 4844208019Sthompsa 4845208019Sthompsa return; 4846203134Sthompsa} 4847203134Sthompsa 4848203134Sthompsastatic void 4849208019Sthompsarun_update_beacon_cb(void *arg) 4850203134Sthompsa{ 4851208019Sthompsa struct ieee80211vap *vap = arg; 4852218492Sbschmidt struct run_vap *rvp = RUN_VAP(vap); 4853203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 4854286950Sadrian struct run_softc *sc = ic->ic_softc; 4855203134Sthompsa struct rt2860_txwi txwi; 4856203134Sthompsa struct mbuf *m; 4857259032Skevlo uint16_t txwisize; 4858208019Sthompsa uint8_t ridx; 4859203134Sthompsa 4860209917Sthompsa if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC) 4861208019Sthompsa return; 4862236439Shselasky if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) 4863236439Shselasky return; 4864208019Sthompsa 4865218492Sbschmidt /* 4866218492Sbschmidt * No need to call ieee80211_beacon_update(), run_update_beacon() 4867218492Sbschmidt * is taking care of apropriate calls. 4868218492Sbschmidt */ 4869218492Sbschmidt if (rvp->beacon_mbuf == NULL) { 4870218492Sbschmidt rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss, 4871218492Sbschmidt &rvp->bo); 4872218492Sbschmidt if (rvp->beacon_mbuf == NULL) 4873218492Sbschmidt return; 4874218492Sbschmidt } 4875218492Sbschmidt m = rvp->beacon_mbuf; 4876203134Sthompsa 4877259032Skevlo memset(&txwi, 0, sizeof(txwi)); 4878203134Sthompsa txwi.wcid = 0xff; 4879203134Sthompsa txwi.len = htole16(m->m_pkthdr.len); 4880259032Skevlo 4881203134Sthompsa /* send beacons at the lowest available rate */ 4882208019Sthompsa ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? 4883208019Sthompsa RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; 4884208019Sthompsa txwi.phy = htole16(rt2860_rates[ridx].mcs); 4885208019Sthompsa if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM) 4886259032Skevlo txwi.phy |= htole16(RT2860_PHY_OFDM); 4887203134Sthompsa txwi.txop = RT2860_TX_TXOP_HT; 4888203134Sthompsa txwi.flags = RT2860_TX_TS; 4889209144Sthompsa txwi.xflags = RT2860_TX_NSEQ; 4890203134Sthompsa 4891259032Skevlo txwisize = (sc->mac_ver == 0x5592) ? 4892259032Skevlo sizeof(txwi) + sizeof(uint32_t) : sizeof(txwi); 4893259032Skevlo run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id), (uint8_t *)&txwi, 4894259032Skevlo txwisize); 4895259032Skevlo run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id) + txwisize, 4896259032Skevlo mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1); 4897203134Sthompsa} 4898203134Sthompsa 4899203134Sthompsastatic void 4900203134Sthompsarun_updateprot(struct ieee80211com *ic) 4901203134Sthompsa{ 4902286950Sadrian struct run_softc *sc = ic->ic_softc; 4903218492Sbschmidt uint32_t i; 4904218492Sbschmidt 4905218492Sbschmidt i = RUN_CMDQ_GET(&sc->cmdq_store); 4906218492Sbschmidt DPRINTF("cmdq_store=%d\n", i); 4907218492Sbschmidt sc->cmdq[i].func = run_updateprot_cb; 4908218492Sbschmidt sc->cmdq[i].arg0 = ic; 4909218492Sbschmidt ieee80211_runtask(ic, &sc->cmdq_task); 4910218492Sbschmidt} 4911218492Sbschmidt 4912218492Sbschmidtstatic void 4913218492Sbschmidtrun_updateprot_cb(void *arg) 4914218492Sbschmidt{ 4915218492Sbschmidt struct ieee80211com *ic = arg; 4916286950Sadrian struct run_softc *sc = ic->ic_softc; 4917203134Sthompsa uint32_t tmp; 4918203134Sthompsa 4919203134Sthompsa tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL; 4920203134Sthompsa /* setup protection frame rate (MCS code) */ 4921203134Sthompsa tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ? 4922270192Skevlo rt2860_rates[RT2860_RIDX_OFDM6].mcs | RT2860_PHY_OFDM : 4923203134Sthompsa rt2860_rates[RT2860_RIDX_CCK11].mcs; 4924203134Sthompsa 4925203134Sthompsa /* CCK frames don't require protection */ 4926203134Sthompsa run_write(sc, RT2860_CCK_PROT_CFG, tmp); 4927203134Sthompsa if (ic->ic_flags & IEEE80211_F_USEPROT) { 4928203134Sthompsa if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) 4929203134Sthompsa tmp |= RT2860_PROT_CTRL_RTS_CTS; 4930203134Sthompsa else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) 4931203134Sthompsa tmp |= RT2860_PROT_CTRL_CTS; 4932203134Sthompsa } 4933203134Sthompsa run_write(sc, RT2860_OFDM_PROT_CFG, tmp); 4934203134Sthompsa} 4935203134Sthompsa 4936203134Sthompsastatic void 4937208019Sthompsarun_usb_timeout_cb(void *arg) 4938203134Sthompsa{ 4939208019Sthompsa struct ieee80211vap *vap = arg; 4940286950Sadrian struct run_softc *sc = vap->iv_ic->ic_softc; 4941203134Sthompsa 4942208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 4943203134Sthompsa 4944203134Sthompsa if(vap->iv_state == IEEE80211_S_RUN && 4945203134Sthompsa vap->iv_opmode != IEEE80211_M_STA) 4946203134Sthompsa run_reset_livelock(sc); 4947209917Sthompsa else if (vap->iv_state == IEEE80211_S_SCAN) { 4948203134Sthompsa DPRINTF("timeout caused by scan\n"); 4949203134Sthompsa /* cancel bgscan */ 4950203134Sthompsa ieee80211_cancel_scan(vap); 4951203134Sthompsa } else 4952203134Sthompsa DPRINTF("timeout by unknown cause\n"); 4953203134Sthompsa} 4954203134Sthompsa 4955203134Sthompsastatic void 4956203134Sthompsarun_reset_livelock(struct run_softc *sc) 4957203134Sthompsa{ 4958203134Sthompsa uint32_t tmp; 4959203134Sthompsa 4960208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 4961208019Sthompsa 4962203134Sthompsa /* 4963203134Sthompsa * In IBSS or HostAP modes (when the hardware sends beacons), the MAC 4964203134Sthompsa * can run into a livelock and start sending CTS-to-self frames like 4965203134Sthompsa * crazy if protection is enabled. Reset MAC/BBP for a while 4966203134Sthompsa */ 4967203134Sthompsa run_read(sc, RT2860_DEBUG, &tmp); 4968208019Sthompsa DPRINTFN(3, "debug reg %08x\n", tmp); 4969209917Sthompsa if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) { 4970203134Sthompsa DPRINTF("CTS-to-self livelock detected\n"); 4971203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST); 4972203134Sthompsa run_delay(sc, 1); 4973203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 4974203134Sthompsa RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 4975203134Sthompsa } 4976203134Sthompsa} 4977203134Sthompsa 4978203134Sthompsastatic void 4979283540Sglebiusrun_update_promisc_locked(struct run_softc *sc) 4980203134Sthompsa{ 4981203134Sthompsa uint32_t tmp; 4982203134Sthompsa 4983203134Sthompsa run_read(sc, RT2860_RX_FILTR_CFG, &tmp); 4984203134Sthompsa 4985203134Sthompsa tmp |= RT2860_DROP_UC_NOME; 4986287197Sglebius if (sc->sc_ic.ic_promisc > 0) 4987203134Sthompsa tmp &= ~RT2860_DROP_UC_NOME; 4988203134Sthompsa 4989203134Sthompsa run_write(sc, RT2860_RX_FILTR_CFG, tmp); 4990203134Sthompsa 4991287197Sglebius DPRINTF("%s promiscuous mode\n", (sc->sc_ic.ic_promisc > 0) ? 4992203134Sthompsa "entering" : "leaving"); 4993203134Sthompsa} 4994203134Sthompsa 4995203134Sthompsastatic void 4996283540Sglebiusrun_update_promisc(struct ieee80211com *ic) 4997203134Sthompsa{ 4998283540Sglebius struct run_softc *sc = ic->ic_softc; 4999203134Sthompsa 5000287197Sglebius if ((sc->sc_flags & RUN_RUNNING) == 0) 5001203134Sthompsa return; 5002203134Sthompsa 5003203134Sthompsa RUN_LOCK(sc); 5004283540Sglebius run_update_promisc_locked(sc); 5005203134Sthompsa RUN_UNLOCK(sc); 5006203134Sthompsa} 5007203134Sthompsa 5008203134Sthompsastatic void 5009203134Sthompsarun_enable_tsf_sync(struct run_softc *sc) 5010203134Sthompsa{ 5011287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 5012203134Sthompsa struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 5013203134Sthompsa uint32_t tmp; 5014203134Sthompsa 5015257955Skevlo DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id, 5016257955Skevlo ic->ic_opmode); 5017208019Sthompsa 5018203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 5019203134Sthompsa tmp &= ~0x1fffff; 5020203134Sthompsa tmp |= vap->iv_bss->ni_intval * 16; 5021203134Sthompsa tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN; 5022203134Sthompsa 5023208019Sthompsa if (ic->ic_opmode == IEEE80211_M_STA) { 5024203134Sthompsa /* 5025203134Sthompsa * Local TSF is always updated with remote TSF on beacon 5026203134Sthompsa * reception. 5027203134Sthompsa */ 5028203134Sthompsa tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT; 5029208019Sthompsa } else if (ic->ic_opmode == IEEE80211_M_IBSS) { 5030203134Sthompsa tmp |= RT2860_BCN_TX_EN; 5031203134Sthompsa /* 5032203134Sthompsa * Local TSF is updated with remote TSF on beacon reception 5033203134Sthompsa * only if the remote TSF is greater than local TSF. 5034203134Sthompsa */ 5035203134Sthompsa tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT; 5036208019Sthompsa } else if (ic->ic_opmode == IEEE80211_M_HOSTAP || 5037208019Sthompsa ic->ic_opmode == IEEE80211_M_MBSS) { 5038203134Sthompsa tmp |= RT2860_BCN_TX_EN; 5039203134Sthompsa /* SYNC with nobody */ 5040203134Sthompsa tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT; 5041208019Sthompsa } else { 5042203134Sthompsa DPRINTF("Enabling TSF failed. undefined opmode\n"); 5043208019Sthompsa return; 5044208019Sthompsa } 5045203134Sthompsa 5046203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, tmp); 5047203134Sthompsa} 5048203134Sthompsa 5049203134Sthompsastatic void 5050203134Sthompsarun_enable_mrr(struct run_softc *sc) 5051203134Sthompsa{ 5052259546Skevlo#define CCK(mcs) (mcs) 5053259546Skevlo#define OFDM(mcs) (1 << 3 | (mcs)) 5054203134Sthompsa run_write(sc, RT2860_LG_FBK_CFG0, 5055203134Sthompsa OFDM(6) << 28 | /* 54->48 */ 5056203134Sthompsa OFDM(5) << 24 | /* 48->36 */ 5057203134Sthompsa OFDM(4) << 20 | /* 36->24 */ 5058203134Sthompsa OFDM(3) << 16 | /* 24->18 */ 5059203134Sthompsa OFDM(2) << 12 | /* 18->12 */ 5060203134Sthompsa OFDM(1) << 8 | /* 12-> 9 */ 5061203134Sthompsa OFDM(0) << 4 | /* 9-> 6 */ 5062203134Sthompsa OFDM(0)); /* 6-> 6 */ 5063203134Sthompsa 5064203134Sthompsa run_write(sc, RT2860_LG_FBK_CFG1, 5065203134Sthompsa CCK(2) << 12 | /* 11->5.5 */ 5066203134Sthompsa CCK(1) << 8 | /* 5.5-> 2 */ 5067203134Sthompsa CCK(0) << 4 | /* 2-> 1 */ 5068203134Sthompsa CCK(0)); /* 1-> 1 */ 5069203134Sthompsa#undef OFDM 5070203134Sthompsa#undef CCK 5071203134Sthompsa} 5072203134Sthompsa 5073203134Sthompsastatic void 5074203134Sthompsarun_set_txpreamble(struct run_softc *sc) 5075203134Sthompsa{ 5076287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 5077203134Sthompsa uint32_t tmp; 5078203134Sthompsa 5079203134Sthompsa run_read(sc, RT2860_AUTO_RSP_CFG, &tmp); 5080203134Sthompsa if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 5081203134Sthompsa tmp |= RT2860_CCK_SHORT_EN; 5082203134Sthompsa else 5083203134Sthompsa tmp &= ~RT2860_CCK_SHORT_EN; 5084203134Sthompsa run_write(sc, RT2860_AUTO_RSP_CFG, tmp); 5085203134Sthompsa} 5086203134Sthompsa 5087203134Sthompsastatic void 5088203134Sthompsarun_set_basicrates(struct run_softc *sc) 5089203134Sthompsa{ 5090287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 5091203134Sthompsa 5092203134Sthompsa /* set basic rates mask */ 5093203134Sthompsa if (ic->ic_curmode == IEEE80211_MODE_11B) 5094203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003); 5095203134Sthompsa else if (ic->ic_curmode == IEEE80211_MODE_11A) 5096203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150); 5097203134Sthompsa else /* 11g */ 5098203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f); 5099203134Sthompsa} 5100203134Sthompsa 5101203134Sthompsastatic void 5102203134Sthompsarun_set_leds(struct run_softc *sc, uint16_t which) 5103203134Sthompsa{ 5104203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS, 5105203134Sthompsa which | (sc->leds & 0x7f)); 5106203134Sthompsa} 5107203134Sthompsa 5108203134Sthompsastatic void 5109203134Sthompsarun_set_bssid(struct run_softc *sc, const uint8_t *bssid) 5110203134Sthompsa{ 5111203134Sthompsa run_write(sc, RT2860_MAC_BSSID_DW0, 5112203134Sthompsa bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24); 5113203134Sthompsa run_write(sc, RT2860_MAC_BSSID_DW1, 5114203134Sthompsa bssid[4] | bssid[5] << 8); 5115203134Sthompsa} 5116203134Sthompsa 5117203134Sthompsastatic void 5118203134Sthompsarun_set_macaddr(struct run_softc *sc, const uint8_t *addr) 5119203134Sthompsa{ 5120203134Sthompsa run_write(sc, RT2860_MAC_ADDR_DW0, 5121203134Sthompsa addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24); 5122203134Sthompsa run_write(sc, RT2860_MAC_ADDR_DW1, 5123203134Sthompsa addr[4] | addr[5] << 8 | 0xff << 16); 5124203134Sthompsa} 5125203134Sthompsa 5126203134Sthompsastatic void 5127283540Sglebiusrun_updateslot(struct ieee80211com *ic) 5128203134Sthompsa{ 5129283540Sglebius struct run_softc *sc = ic->ic_softc; 5130218492Sbschmidt uint32_t i; 5131218492Sbschmidt 5132218492Sbschmidt i = RUN_CMDQ_GET(&sc->cmdq_store); 5133218492Sbschmidt DPRINTF("cmdq_store=%d\n", i); 5134218492Sbschmidt sc->cmdq[i].func = run_updateslot_cb; 5135287197Sglebius sc->cmdq[i].arg0 = ic; 5136218492Sbschmidt ieee80211_runtask(ic, &sc->cmdq_task); 5137218492Sbschmidt 5138218492Sbschmidt return; 5139218492Sbschmidt} 5140218492Sbschmidt 5141218492Sbschmidt/* ARGSUSED */ 5142218492Sbschmidtstatic void 5143218492Sbschmidtrun_updateslot_cb(void *arg) 5144218492Sbschmidt{ 5145287197Sglebius struct ieee80211com *ic = arg; 5146286950Sadrian struct run_softc *sc = ic->ic_softc; 5147203134Sthompsa uint32_t tmp; 5148203134Sthompsa 5149203134Sthompsa run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp); 5150203134Sthompsa tmp &= ~0xff; 5151203134Sthompsa tmp |= (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; 5152203134Sthompsa run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp); 5153203134Sthompsa} 5154203134Sthompsa 5155208019Sthompsastatic void 5156283540Sglebiusrun_update_mcast(struct ieee80211com *ic) 5157208019Sthompsa{ 5158208019Sthompsa} 5159208019Sthompsa 5160203134Sthompsastatic int8_t 5161203134Sthompsarun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain) 5162203134Sthompsa{ 5163287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 5164203134Sthompsa struct ieee80211_channel *c = ic->ic_curchan; 5165203134Sthompsa int delta; 5166203134Sthompsa 5167203134Sthompsa if (IEEE80211_IS_CHAN_5GHZ(c)) { 5168257429Shselasky u_int chan = ieee80211_chan2ieee(ic, c); 5169203134Sthompsa delta = sc->rssi_5ghz[rxchain]; 5170203134Sthompsa 5171203134Sthompsa /* determine channel group */ 5172203134Sthompsa if (chan <= 64) 5173203134Sthompsa delta -= sc->lna[1]; 5174203134Sthompsa else if (chan <= 128) 5175203134Sthompsa delta -= sc->lna[2]; 5176203134Sthompsa else 5177203134Sthompsa delta -= sc->lna[3]; 5178203134Sthompsa } else 5179203134Sthompsa delta = sc->rssi_2ghz[rxchain] - sc->lna[0]; 5180203134Sthompsa 5181209917Sthompsa return (-12 - delta - rssi); 5182203134Sthompsa} 5183203134Sthompsa 5184257955Skevlostatic void 5185257955Skevlorun_rt5390_bbp_init(struct run_softc *sc) 5186257955Skevlo{ 5187257955Skevlo int i; 5188259032Skevlo uint8_t bbp; 5189257955Skevlo 5190259032Skevlo /* Apply maximum likelihood detection for 2 stream case. */ 5191259032Skevlo run_bbp_read(sc, 105, &bbp); 5192259032Skevlo if (sc->nrxchains > 1) 5193259032Skevlo run_bbp_write(sc, 105, bbp | RT5390_MLD); 5194259032Skevlo 5195257955Skevlo /* Avoid data lost and CRC error. */ 5196259032Skevlo run_bbp_read(sc, 4, &bbp); 5197259031Skevlo run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 5198257955Skevlo 5199259032Skevlo if (sc->mac_ver == 0x5592) { 5200259032Skevlo for (i = 0; i < nitems(rt5592_def_bbp); i++) { 5201259032Skevlo run_bbp_write(sc, rt5592_def_bbp[i].reg, 5202259032Skevlo rt5592_def_bbp[i].val); 5203259032Skevlo } 5204259032Skevlo for (i = 0; i < nitems(rt5592_bbp_r196); i++) { 5205259032Skevlo run_bbp_write(sc, 195, i + 0x80); 5206259032Skevlo run_bbp_write(sc, 196, rt5592_bbp_r196[i]); 5207259032Skevlo } 5208259032Skevlo } else { 5209259032Skevlo for (i = 0; i < nitems(rt5390_def_bbp); i++) { 5210259032Skevlo run_bbp_write(sc, rt5390_def_bbp[i].reg, 5211259032Skevlo rt5390_def_bbp[i].val); 5212259032Skevlo } 5213257955Skevlo } 5214257955Skevlo if (sc->mac_ver == 0x5392) { 5215257955Skevlo run_bbp_write(sc, 88, 0x90); 5216257955Skevlo run_bbp_write(sc, 95, 0x9a); 5217257955Skevlo run_bbp_write(sc, 98, 0x12); 5218257955Skevlo run_bbp_write(sc, 106, 0x12); 5219257955Skevlo run_bbp_write(sc, 134, 0xd0); 5220257955Skevlo run_bbp_write(sc, 135, 0xf6); 5221257955Skevlo run_bbp_write(sc, 148, 0x84); 5222257955Skevlo } 5223257955Skevlo 5224259032Skevlo run_bbp_read(sc, 152, &bbp); 5225259032Skevlo run_bbp_write(sc, 152, bbp | 0x80); 5226259032Skevlo 5227259032Skevlo /* Fix BBP254 for RT5592C. */ 5228259032Skevlo if (sc->mac_ver == 0x5592 && sc->mac_rev >= 0x0221) { 5229259032Skevlo run_bbp_read(sc, 254, &bbp); 5230259032Skevlo run_bbp_write(sc, 254, bbp | 0x80); 5231259032Skevlo } 5232259032Skevlo 5233257955Skevlo /* Disable hardware antenna diversity. */ 5234257955Skevlo if (sc->mac_ver == 0x5390) 5235257955Skevlo run_bbp_write(sc, 154, 0); 5236259032Skevlo 5237259032Skevlo /* Initialize Rx CCK/OFDM frequency offset report. */ 5238259032Skevlo run_bbp_write(sc, 142, 1); 5239259032Skevlo run_bbp_write(sc, 143, 57); 5240257955Skevlo} 5241257955Skevlo 5242203134Sthompsastatic int 5243203134Sthompsarun_bbp_init(struct run_softc *sc) 5244203134Sthompsa{ 5245203134Sthompsa int i, error, ntries; 5246203134Sthompsa uint8_t bbp0; 5247203134Sthompsa 5248203134Sthompsa /* wait for BBP to wake up */ 5249203134Sthompsa for (ntries = 0; ntries < 20; ntries++) { 5250203134Sthompsa if ((error = run_bbp_read(sc, 0, &bbp0)) != 0) 5251203134Sthompsa return error; 5252203134Sthompsa if (bbp0 != 0 && bbp0 != 0xff) 5253203134Sthompsa break; 5254203134Sthompsa } 5255203134Sthompsa if (ntries == 20) 5256209917Sthompsa return (ETIMEDOUT); 5257203134Sthompsa 5258203134Sthompsa /* initialize BBP registers to default values */ 5259257955Skevlo if (sc->mac_ver >= 0x5390) 5260257955Skevlo run_rt5390_bbp_init(sc); 5261257955Skevlo else { 5262257955Skevlo for (i = 0; i < nitems(rt2860_def_bbp); i++) { 5263257955Skevlo run_bbp_write(sc, rt2860_def_bbp[i].reg, 5264257955Skevlo rt2860_def_bbp[i].val); 5265257955Skevlo } 5266203134Sthompsa } 5267203134Sthompsa 5268260219Skevlo if (sc->mac_ver == 0x3593) { 5269260219Skevlo run_bbp_write(sc, 79, 0x13); 5270260219Skevlo run_bbp_write(sc, 80, 0x05); 5271260219Skevlo run_bbp_write(sc, 81, 0x33); 5272260219Skevlo run_bbp_write(sc, 86, 0x46); 5273260219Skevlo run_bbp_write(sc, 137, 0x0f); 5274260219Skevlo } 5275260219Skevlo 5276203134Sthompsa /* fix BBP84 for RT2860E */ 5277205042Sthompsa if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101) 5278205042Sthompsa run_bbp_write(sc, 84, 0x19); 5279203134Sthompsa 5280260219Skevlo if (sc->mac_ver >= 0x3070 && (sc->mac_ver != 0x3593 && 5281260219Skevlo sc->mac_ver != 0x5592)) { 5282203134Sthompsa run_bbp_write(sc, 79, 0x13); 5283203134Sthompsa run_bbp_write(sc, 80, 0x05); 5284203134Sthompsa run_bbp_write(sc, 81, 0x33); 5285205042Sthompsa } else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) { 5286203134Sthompsa run_bbp_write(sc, 69, 0x16); 5287203134Sthompsa run_bbp_write(sc, 73, 0x12); 5288203134Sthompsa } 5289209917Sthompsa return (0); 5290203134Sthompsa} 5291203134Sthompsa 5292203134Sthompsastatic int 5293203134Sthompsarun_rt3070_rf_init(struct run_softc *sc) 5294203134Sthompsa{ 5295203134Sthompsa uint32_t tmp; 5296256722Skevlo uint8_t bbp4, mingain, rf, target; 5297203134Sthompsa int i; 5298203134Sthompsa 5299203134Sthompsa run_rt3070_rf_read(sc, 30, &rf); 5300203134Sthompsa /* toggle RF R30 bit 7 */ 5301203134Sthompsa run_rt3070_rf_write(sc, 30, rf | 0x80); 5302203134Sthompsa run_delay(sc, 10); 5303203134Sthompsa run_rt3070_rf_write(sc, 30, rf & ~0x80); 5304203134Sthompsa 5305203134Sthompsa /* initialize RF registers to default value */ 5306205042Sthompsa if (sc->mac_ver == 0x3572) { 5307257955Skevlo for (i = 0; i < nitems(rt3572_def_rf); i++) { 5308205042Sthompsa run_rt3070_rf_write(sc, rt3572_def_rf[i].reg, 5309205042Sthompsa rt3572_def_rf[i].val); 5310205042Sthompsa } 5311205042Sthompsa } else { 5312257955Skevlo for (i = 0; i < nitems(rt3070_def_rf); i++) { 5313205042Sthompsa run_rt3070_rf_write(sc, rt3070_def_rf[i].reg, 5314205042Sthompsa rt3070_def_rf[i].val); 5315205042Sthompsa } 5316203134Sthompsa } 5317205042Sthompsa 5318256721Skevlo if (sc->mac_ver == 0x3070 && sc->mac_rev < 0x0201) { 5319256721Skevlo /* 5320256721Skevlo * Change voltage from 1.2V to 1.35V for RT3070. 5321256721Skevlo * The DAC issue (RT3070_LDO_CFG0) has been fixed 5322256721Skevlo * in RT3070(F). 5323256721Skevlo */ 5324203134Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 5325203134Sthompsa tmp = (tmp & ~0x0f000000) | 0x0d000000; 5326203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5327203134Sthompsa 5328205042Sthompsa } else if (sc->mac_ver == 0x3071) { 5329203134Sthompsa run_rt3070_rf_read(sc, 6, &rf); 5330203134Sthompsa run_rt3070_rf_write(sc, 6, rf | 0x40); 5331203134Sthompsa run_rt3070_rf_write(sc, 31, 0x14); 5332203134Sthompsa 5333203134Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 5334203134Sthompsa tmp &= ~0x1f000000; 5335205042Sthompsa if (sc->mac_rev < 0x0211) 5336205042Sthompsa tmp |= 0x0d000000; /* 1.3V */ 5337203134Sthompsa else 5338205042Sthompsa tmp |= 0x01000000; /* 1.2V */ 5339203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5340203134Sthompsa 5341203134Sthompsa /* patch LNA_PE_G1 */ 5342203134Sthompsa run_read(sc, RT3070_GPIO_SWITCH, &tmp); 5343203134Sthompsa run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20); 5344208019Sthompsa 5345209917Sthompsa } else if (sc->mac_ver == 0x3572) { 5346205042Sthompsa run_rt3070_rf_read(sc, 6, &rf); 5347205042Sthompsa run_rt3070_rf_write(sc, 6, rf | 0x40); 5348205042Sthompsa 5349208019Sthompsa /* increase voltage from 1.2V to 1.35V */ 5350208019Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 5351208019Sthompsa tmp = (tmp & ~0x1f000000) | 0x0d000000; 5352208019Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5353203134Sthompsa 5354209917Sthompsa if (sc->mac_rev < 0x0211 || !sc->patch_dac) { 5355203134Sthompsa run_delay(sc, 1); /* wait for 1msec */ 5356205042Sthompsa /* decrease voltage back to 1.2V */ 5357203134Sthompsa tmp = (tmp & ~0x1f000000) | 0x01000000; 5358203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5359203134Sthompsa } 5360203134Sthompsa } 5361203134Sthompsa 5362203134Sthompsa /* select 20MHz bandwidth */ 5363203134Sthompsa run_rt3070_rf_read(sc, 31, &rf); 5364203134Sthompsa run_rt3070_rf_write(sc, 31, rf & ~0x20); 5365203134Sthompsa 5366203134Sthompsa /* calibrate filter for 20MHz bandwidth */ 5367203134Sthompsa sc->rf24_20mhz = 0x1f; /* default value */ 5368205042Sthompsa target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13; 5369205042Sthompsa run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz); 5370203134Sthompsa 5371203134Sthompsa /* select 40MHz bandwidth */ 5372203134Sthompsa run_bbp_read(sc, 4, &bbp4); 5373256721Skevlo run_bbp_write(sc, 4, (bbp4 & ~0x18) | 0x10); 5374205042Sthompsa run_rt3070_rf_read(sc, 31, &rf); 5375205042Sthompsa run_rt3070_rf_write(sc, 31, rf | 0x20); 5376203134Sthompsa 5377203134Sthompsa /* calibrate filter for 40MHz bandwidth */ 5378203134Sthompsa sc->rf24_40mhz = 0x2f; /* default value */ 5379205042Sthompsa target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15; 5380205042Sthompsa run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz); 5381203134Sthompsa 5382203134Sthompsa /* go back to 20MHz bandwidth */ 5383203134Sthompsa run_bbp_read(sc, 4, &bbp4); 5384203134Sthompsa run_bbp_write(sc, 4, bbp4 & ~0x18); 5385203134Sthompsa 5386205042Sthompsa if (sc->mac_ver == 0x3572) { 5387205042Sthompsa /* save default BBP registers 25 and 26 values */ 5388205042Sthompsa run_bbp_read(sc, 25, &sc->bbp25); 5389205042Sthompsa run_bbp_read(sc, 26, &sc->bbp26); 5390256721Skevlo } else if (sc->mac_rev < 0x0201 || sc->mac_rev < 0x0211) 5391203134Sthompsa run_rt3070_rf_write(sc, 27, 0x03); 5392203134Sthompsa 5393203134Sthompsa run_read(sc, RT3070_OPT_14, &tmp); 5394203134Sthompsa run_write(sc, RT3070_OPT_14, tmp | 1); 5395203134Sthompsa 5396205042Sthompsa if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) { 5397205042Sthompsa run_rt3070_rf_read(sc, 17, &rf); 5398205042Sthompsa rf &= ~RT3070_TX_LO1; 5399205042Sthompsa if ((sc->mac_ver == 0x3070 || 5400205042Sthompsa (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) && 5401205042Sthompsa !sc->ext_2ghz_lna) 5402205042Sthompsa rf |= 0x20; /* fix for long range Rx issue */ 5403256722Skevlo mingain = (sc->mac_ver == 0x3070) ? 1 : 2; 5404256722Skevlo if (sc->txmixgain_2ghz >= mingain) 5405205042Sthompsa rf = (rf & ~0x7) | sc->txmixgain_2ghz; 5406205042Sthompsa run_rt3070_rf_write(sc, 17, rf); 5407205042Sthompsa } 5408205042Sthompsa 5409270643Skevlo if (sc->mac_ver == 0x3071) { 5410203134Sthompsa run_rt3070_rf_read(sc, 1, &rf); 5411203134Sthompsa rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD); 5412203134Sthompsa rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD; 5413203134Sthompsa run_rt3070_rf_write(sc, 1, rf); 5414203134Sthompsa 5415203134Sthompsa run_rt3070_rf_read(sc, 15, &rf); 5416203134Sthompsa run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2); 5417203134Sthompsa 5418203134Sthompsa run_rt3070_rf_read(sc, 20, &rf); 5419203134Sthompsa run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1); 5420203134Sthompsa 5421203134Sthompsa run_rt3070_rf_read(sc, 21, &rf); 5422203134Sthompsa run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2); 5423205042Sthompsa } 5424203134Sthompsa 5425205042Sthompsa if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) { 5426205042Sthompsa /* fix Tx to Rx IQ glitch by raising RF voltage */ 5427203134Sthompsa run_rt3070_rf_read(sc, 27, &rf); 5428203134Sthompsa rf &= ~0x77; 5429205042Sthompsa if (sc->mac_rev < 0x0211) 5430203134Sthompsa rf |= 0x03; 5431203134Sthompsa run_rt3070_rf_write(sc, 27, rf); 5432203134Sthompsa } 5433209917Sthompsa return (0); 5434203134Sthompsa} 5435203134Sthompsa 5436257955Skevlostatic void 5437260219Skevlorun_rt3593_rf_init(struct run_softc *sc) 5438260219Skevlo{ 5439260219Skevlo uint32_t tmp; 5440260219Skevlo uint8_t rf; 5441260219Skevlo int i; 5442260219Skevlo 5443260219Skevlo /* Disable the GPIO bits 4 and 7 for LNA PE control. */ 5444260219Skevlo run_read(sc, RT3070_GPIO_SWITCH, &tmp); 5445260219Skevlo tmp &= ~(1 << 4 | 1 << 7); 5446260219Skevlo run_write(sc, RT3070_GPIO_SWITCH, tmp); 5447260219Skevlo 5448260219Skevlo /* Initialize RF registers to default value. */ 5449260219Skevlo for (i = 0; i < nitems(rt3593_def_rf); i++) { 5450260219Skevlo run_rt3070_rf_write(sc, rt3593_def_rf[i].reg, 5451260219Skevlo rt3593_def_rf[i].val); 5452260219Skevlo } 5453260219Skevlo 5454260219Skevlo /* Toggle RF R2 to initiate calibration. */ 5455260219Skevlo run_rt3070_rf_write(sc, 2, RT5390_RESCAL); 5456260219Skevlo 5457260219Skevlo /* Initialize RF frequency offset. */ 5458260219Skevlo run_adjust_freq_offset(sc); 5459260219Skevlo 5460260219Skevlo run_rt3070_rf_read(sc, 18, &rf); 5461260219Skevlo run_rt3070_rf_write(sc, 18, rf | RT3593_AUTOTUNE_BYPASS); 5462260219Skevlo 5463260219Skevlo /* 5464260219Skevlo * Increase voltage from 1.2V to 1.35V, wait for 1 msec to 5465260219Skevlo * decrease voltage back to 1.2V. 5466260219Skevlo */ 5467260219Skevlo run_read(sc, RT3070_LDO_CFG0, &tmp); 5468260219Skevlo tmp = (tmp & ~0x1f000000) | 0x0d000000; 5469260219Skevlo run_write(sc, RT3070_LDO_CFG0, tmp); 5470260219Skevlo run_delay(sc, 1); 5471260219Skevlo tmp = (tmp & ~0x1f000000) | 0x01000000; 5472260219Skevlo run_write(sc, RT3070_LDO_CFG0, tmp); 5473260219Skevlo 5474260219Skevlo sc->rf24_20mhz = 0x1f; 5475260219Skevlo sc->rf24_40mhz = 0x2f; 5476260219Skevlo 5477260219Skevlo /* Save default BBP registers 25 and 26 values. */ 5478260219Skevlo run_bbp_read(sc, 25, &sc->bbp25); 5479260219Skevlo run_bbp_read(sc, 26, &sc->bbp26); 5480260219Skevlo 5481260219Skevlo run_read(sc, RT3070_OPT_14, &tmp); 5482260219Skevlo run_write(sc, RT3070_OPT_14, tmp | 1); 5483260219Skevlo} 5484260219Skevlo 5485260219Skevlostatic void 5486257955Skevlorun_rt5390_rf_init(struct run_softc *sc) 5487257955Skevlo{ 5488257955Skevlo uint32_t tmp; 5489257955Skevlo uint8_t rf; 5490257955Skevlo int i; 5491257955Skevlo 5492259030Skevlo /* Toggle RF R2 to initiate calibration. */ 5493259030Skevlo if (sc->mac_ver == 0x5390) { 5494257955Skevlo run_rt3070_rf_read(sc, 2, &rf); 5495259031Skevlo run_rt3070_rf_write(sc, 2, rf | RT5390_RESCAL); 5496257955Skevlo run_delay(sc, 10); 5497259031Skevlo run_rt3070_rf_write(sc, 2, rf & ~RT5390_RESCAL); 5498259030Skevlo } else { 5499259031Skevlo run_rt3070_rf_write(sc, 2, RT5390_RESCAL); 5500259030Skevlo run_delay(sc, 10); 5501257955Skevlo } 5502257955Skevlo 5503257955Skevlo /* Initialize RF registers to default value. */ 5504259032Skevlo if (sc->mac_ver == 0x5592) { 5505259032Skevlo for (i = 0; i < nitems(rt5592_def_rf); i++) { 5506259032Skevlo run_rt3070_rf_write(sc, rt5592_def_rf[i].reg, 5507259032Skevlo rt5592_def_rf[i].val); 5508259032Skevlo } 5509259032Skevlo /* Initialize RF frequency offset. */ 5510259032Skevlo run_adjust_freq_offset(sc); 5511259032Skevlo } else if (sc->mac_ver == 0x5392) { 5512257955Skevlo for (i = 0; i < nitems(rt5392_def_rf); i++) { 5513257955Skevlo run_rt3070_rf_write(sc, rt5392_def_rf[i].reg, 5514257955Skevlo rt5392_def_rf[i].val); 5515257955Skevlo } 5516257955Skevlo if (sc->mac_rev >= 0x0223) { 5517257955Skevlo run_rt3070_rf_write(sc, 23, 0x0f); 5518257955Skevlo run_rt3070_rf_write(sc, 24, 0x3e); 5519257955Skevlo run_rt3070_rf_write(sc, 51, 0x32); 5520257955Skevlo run_rt3070_rf_write(sc, 53, 0x22); 5521257955Skevlo run_rt3070_rf_write(sc, 56, 0xc1); 5522257955Skevlo run_rt3070_rf_write(sc, 59, 0x0f); 5523257955Skevlo } 5524257955Skevlo } else { 5525257955Skevlo for (i = 0; i < nitems(rt5390_def_rf); i++) { 5526257955Skevlo run_rt3070_rf_write(sc, rt5390_def_rf[i].reg, 5527257955Skevlo rt5390_def_rf[i].val); 5528257955Skevlo } 5529257955Skevlo if (sc->mac_rev >= 0x0502) { 5530257955Skevlo run_rt3070_rf_write(sc, 6, 0xe0); 5531257955Skevlo run_rt3070_rf_write(sc, 25, 0x80); 5532257955Skevlo run_rt3070_rf_write(sc, 46, 0x73); 5533257955Skevlo run_rt3070_rf_write(sc, 53, 0x00); 5534257955Skevlo run_rt3070_rf_write(sc, 56, 0x42); 5535257955Skevlo run_rt3070_rf_write(sc, 61, 0xd1); 5536257955Skevlo } 5537257955Skevlo } 5538257955Skevlo 5539257955Skevlo sc->rf24_20mhz = 0x1f; /* default value */ 5540259032Skevlo sc->rf24_40mhz = (sc->mac_ver == 0x5592) ? 0 : 0x2f; 5541257955Skevlo 5542257955Skevlo if (sc->mac_rev < 0x0211) 5543257955Skevlo run_rt3070_rf_write(sc, 27, 0x3); 5544257955Skevlo 5545257955Skevlo run_read(sc, RT3070_OPT_14, &tmp); 5546257955Skevlo run_write(sc, RT3070_OPT_14, tmp | 1); 5547257955Skevlo} 5548257955Skevlo 5549203134Sthompsastatic int 5550203134Sthompsarun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target, 5551203134Sthompsa uint8_t *val) 5552203134Sthompsa{ 5553203134Sthompsa uint8_t rf22, rf24; 5554203134Sthompsa uint8_t bbp55_pb, bbp55_sb, delta; 5555203134Sthompsa int ntries; 5556203134Sthompsa 5557203134Sthompsa /* program filter */ 5558205042Sthompsa run_rt3070_rf_read(sc, 24, &rf24); 5559205042Sthompsa rf24 = (rf24 & 0xc0) | init; /* initial filter value */ 5560203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 5561203134Sthompsa 5562203134Sthompsa /* enable baseband loopback mode */ 5563203134Sthompsa run_rt3070_rf_read(sc, 22, &rf22); 5564203134Sthompsa run_rt3070_rf_write(sc, 22, rf22 | 0x01); 5565203134Sthompsa 5566203134Sthompsa /* set power and frequency of passband test tone */ 5567203134Sthompsa run_bbp_write(sc, 24, 0x00); 5568203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5569203134Sthompsa /* transmit test tone */ 5570203134Sthompsa run_bbp_write(sc, 25, 0x90); 5571203134Sthompsa run_delay(sc, 10); 5572203134Sthompsa /* read received power */ 5573203134Sthompsa run_bbp_read(sc, 55, &bbp55_pb); 5574203134Sthompsa if (bbp55_pb != 0) 5575203134Sthompsa break; 5576203134Sthompsa } 5577203134Sthompsa if (ntries == 100) 5578257955Skevlo return (ETIMEDOUT); 5579203134Sthompsa 5580203134Sthompsa /* set power and frequency of stopband test tone */ 5581203134Sthompsa run_bbp_write(sc, 24, 0x06); 5582203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5583203134Sthompsa /* transmit test tone */ 5584203134Sthompsa run_bbp_write(sc, 25, 0x90); 5585203134Sthompsa run_delay(sc, 10); 5586203134Sthompsa /* read received power */ 5587203134Sthompsa run_bbp_read(sc, 55, &bbp55_sb); 5588203134Sthompsa 5589203134Sthompsa delta = bbp55_pb - bbp55_sb; 5590203134Sthompsa if (delta > target) 5591203134Sthompsa break; 5592203134Sthompsa 5593203134Sthompsa /* reprogram filter */ 5594203134Sthompsa rf24++; 5595203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 5596203134Sthompsa } 5597203134Sthompsa if (ntries < 100) { 5598203134Sthompsa if (rf24 != init) 5599203134Sthompsa rf24--; /* backtrack */ 5600203134Sthompsa *val = rf24; 5601203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 5602203134Sthompsa } 5603203134Sthompsa 5604203134Sthompsa /* restore initial state */ 5605203134Sthompsa run_bbp_write(sc, 24, 0x00); 5606203134Sthompsa 5607203134Sthompsa /* disable baseband loopback mode */ 5608203134Sthompsa run_rt3070_rf_read(sc, 22, &rf22); 5609203134Sthompsa run_rt3070_rf_write(sc, 22, rf22 & ~0x01); 5610203134Sthompsa 5611209917Sthompsa return (0); 5612203134Sthompsa} 5613203134Sthompsa 5614205042Sthompsastatic void 5615205042Sthompsarun_rt3070_rf_setup(struct run_softc *sc) 5616205042Sthompsa{ 5617205042Sthompsa uint8_t bbp, rf; 5618205042Sthompsa int i; 5619205042Sthompsa 5620260219Skevlo if (sc->mac_ver == 0x3572) { 5621205042Sthompsa /* enable DC filter */ 5622205042Sthompsa if (sc->mac_rev >= 0x0201) 5623205042Sthompsa run_bbp_write(sc, 103, 0xc0); 5624205042Sthompsa 5625205042Sthompsa run_bbp_read(sc, 138, &bbp); 5626205042Sthompsa if (sc->ntxchains == 1) 5627205042Sthompsa bbp |= 0x20; /* turn off DAC1 */ 5628205042Sthompsa if (sc->nrxchains == 1) 5629205042Sthompsa bbp &= ~0x02; /* turn off ADC1 */ 5630205042Sthompsa run_bbp_write(sc, 138, bbp); 5631205042Sthompsa 5632205042Sthompsa if (sc->mac_rev >= 0x0211) { 5633205042Sthompsa /* improve power consumption */ 5634205042Sthompsa run_bbp_read(sc, 31, &bbp); 5635205042Sthompsa run_bbp_write(sc, 31, bbp & ~0x03); 5636205042Sthompsa } 5637205042Sthompsa 5638205042Sthompsa run_rt3070_rf_read(sc, 16, &rf); 5639205042Sthompsa rf = (rf & ~0x07) | sc->txmixgain_2ghz; 5640205042Sthompsa run_rt3070_rf_write(sc, 16, rf); 5641205042Sthompsa 5642205042Sthompsa } else if (sc->mac_ver == 0x3071) { 5643257409Skevlo if (sc->mac_rev >= 0x0211) { 5644257409Skevlo /* enable DC filter */ 5645205042Sthompsa run_bbp_write(sc, 103, 0xc0); 5646205042Sthompsa 5647257409Skevlo /* improve power consumption */ 5648257409Skevlo run_bbp_read(sc, 31, &bbp); 5649257409Skevlo run_bbp_write(sc, 31, bbp & ~0x03); 5650257409Skevlo } 5651257409Skevlo 5652205042Sthompsa run_bbp_read(sc, 138, &bbp); 5653205042Sthompsa if (sc->ntxchains == 1) 5654205042Sthompsa bbp |= 0x20; /* turn off DAC1 */ 5655205042Sthompsa if (sc->nrxchains == 1) 5656205042Sthompsa bbp &= ~0x02; /* turn off ADC1 */ 5657205042Sthompsa run_bbp_write(sc, 138, bbp); 5658205042Sthompsa 5659205042Sthompsa run_write(sc, RT2860_TX_SW_CFG1, 0); 5660205042Sthompsa if (sc->mac_rev < 0x0211) { 5661205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 5662205042Sthompsa sc->patch_dac ? 0x2c : 0x0f); 5663205042Sthompsa } else 5664205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0); 5665205042Sthompsa 5666205042Sthompsa } else if (sc->mac_ver == 0x3070) { 5667205042Sthompsa if (sc->mac_rev >= 0x0201) { 5668205042Sthompsa /* enable DC filter */ 5669205042Sthompsa run_bbp_write(sc, 103, 0xc0); 5670205042Sthompsa 5671205042Sthompsa /* improve power consumption */ 5672205042Sthompsa run_bbp_read(sc, 31, &bbp); 5673205042Sthompsa run_bbp_write(sc, 31, bbp & ~0x03); 5674205042Sthompsa } 5675205042Sthompsa 5676256955Skevlo if (sc->mac_rev < 0x0201) { 5677205042Sthompsa run_write(sc, RT2860_TX_SW_CFG1, 0); 5678205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0x2c); 5679205042Sthompsa } else 5680205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0); 5681205042Sthompsa } 5682205042Sthompsa 5683205042Sthompsa /* initialize RF registers from ROM for >=RT3071*/ 5684260219Skevlo if (sc->mac_ver >= 0x3071) { 5685205042Sthompsa for (i = 0; i < 10; i++) { 5686205042Sthompsa if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff) 5687205042Sthompsa continue; 5688205042Sthompsa run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val); 5689205042Sthompsa } 5690205042Sthompsa } 5691205042Sthompsa} 5692205042Sthompsa 5693260219Skevlostatic void 5694260219Skevlorun_rt3593_rf_setup(struct run_softc *sc) 5695260219Skevlo{ 5696260219Skevlo uint8_t bbp, rf; 5697260219Skevlo 5698260219Skevlo if (sc->mac_rev >= 0x0211) { 5699260219Skevlo /* Enable DC filter. */ 5700260219Skevlo run_bbp_write(sc, 103, 0xc0); 5701260219Skevlo } 5702260219Skevlo run_write(sc, RT2860_TX_SW_CFG1, 0); 5703260219Skevlo if (sc->mac_rev < 0x0211) { 5704260219Skevlo run_write(sc, RT2860_TX_SW_CFG2, 5705260219Skevlo sc->patch_dac ? 0x2c : 0x0f); 5706260219Skevlo } else 5707260219Skevlo run_write(sc, RT2860_TX_SW_CFG2, 0); 5708260219Skevlo 5709260219Skevlo run_rt3070_rf_read(sc, 50, &rf); 5710260219Skevlo run_rt3070_rf_write(sc, 50, rf & ~RT3593_TX_LO2); 5711260219Skevlo 5712260219Skevlo run_rt3070_rf_read(sc, 51, &rf); 5713260219Skevlo rf = (rf & ~(RT3593_TX_LO1 | 0x0c)) | 5714260219Skevlo ((sc->txmixgain_2ghz & 0x07) << 2); 5715260219Skevlo run_rt3070_rf_write(sc, 51, rf); 5716260219Skevlo 5717260219Skevlo run_rt3070_rf_read(sc, 38, &rf); 5718260219Skevlo run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1); 5719260219Skevlo 5720260219Skevlo run_rt3070_rf_read(sc, 39, &rf); 5721260219Skevlo run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2); 5722260219Skevlo 5723260219Skevlo run_rt3070_rf_read(sc, 1, &rf); 5724260219Skevlo run_rt3070_rf_write(sc, 1, rf & ~(RT3070_RF_BLOCK | RT3070_PLL_PD)); 5725260219Skevlo 5726260219Skevlo run_rt3070_rf_read(sc, 30, &rf); 5727260219Skevlo rf = (rf & ~0x18) | 0x10; 5728260219Skevlo run_rt3070_rf_write(sc, 30, rf); 5729260219Skevlo 5730260219Skevlo /* Apply maximum likelihood detection for 2 stream case. */ 5731260219Skevlo run_bbp_read(sc, 105, &bbp); 5732260219Skevlo if (sc->nrxchains > 1) 5733260219Skevlo run_bbp_write(sc, 105, bbp | RT5390_MLD); 5734260219Skevlo 5735260219Skevlo /* Avoid data lost and CRC error. */ 5736260219Skevlo run_bbp_read(sc, 4, &bbp); 5737260219Skevlo run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 5738260219Skevlo 5739260219Skevlo run_bbp_write(sc, 92, 0x02); 5740260219Skevlo run_bbp_write(sc, 82, 0x82); 5741260219Skevlo run_bbp_write(sc, 106, 0x05); 5742260219Skevlo run_bbp_write(sc, 104, 0x92); 5743260219Skevlo run_bbp_write(sc, 88, 0x90); 5744260219Skevlo run_bbp_write(sc, 148, 0xc8); 5745260219Skevlo run_bbp_write(sc, 47, 0x48); 5746260219Skevlo run_bbp_write(sc, 120, 0x50); 5747260219Skevlo 5748260219Skevlo run_bbp_write(sc, 163, 0x9d); 5749260219Skevlo 5750260219Skevlo /* SNR mapping. */ 5751260219Skevlo run_bbp_write(sc, 142, 0x06); 5752260219Skevlo run_bbp_write(sc, 143, 0xa0); 5753260219Skevlo run_bbp_write(sc, 142, 0x07); 5754260219Skevlo run_bbp_write(sc, 143, 0xa1); 5755260219Skevlo run_bbp_write(sc, 142, 0x08); 5756260219Skevlo run_bbp_write(sc, 143, 0xa2); 5757260219Skevlo 5758260219Skevlo run_bbp_write(sc, 31, 0x08); 5759260219Skevlo run_bbp_write(sc, 68, 0x0b); 5760260219Skevlo run_bbp_write(sc, 105, 0x04); 5761260219Skevlo} 5762260219Skevlo 5763260219Skevlostatic void 5764260219Skevlorun_rt5390_rf_setup(struct run_softc *sc) 5765260219Skevlo{ 5766260219Skevlo uint8_t bbp, rf; 5767260219Skevlo 5768260219Skevlo if (sc->mac_rev >= 0x0211) { 5769260219Skevlo /* Enable DC filter. */ 5770260219Skevlo run_bbp_write(sc, 103, 0xc0); 5771260219Skevlo 5772260219Skevlo if (sc->mac_ver != 0x5592) { 5773260219Skevlo /* Improve power consumption. */ 5774260219Skevlo run_bbp_read(sc, 31, &bbp); 5775260219Skevlo run_bbp_write(sc, 31, bbp & ~0x03); 5776260219Skevlo } 5777260219Skevlo } 5778260219Skevlo 5779260219Skevlo run_bbp_read(sc, 138, &bbp); 5780260219Skevlo if (sc->ntxchains == 1) 5781260219Skevlo bbp |= 0x20; /* turn off DAC1 */ 5782260219Skevlo if (sc->nrxchains == 1) 5783260219Skevlo bbp &= ~0x02; /* turn off ADC1 */ 5784260219Skevlo run_bbp_write(sc, 138, bbp); 5785260219Skevlo 5786260219Skevlo run_rt3070_rf_read(sc, 38, &rf); 5787260219Skevlo run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1); 5788260219Skevlo 5789260219Skevlo run_rt3070_rf_read(sc, 39, &rf); 5790260219Skevlo run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2); 5791260219Skevlo 5792260219Skevlo /* Avoid data lost and CRC error. */ 5793260219Skevlo run_bbp_read(sc, 4, &bbp); 5794260219Skevlo run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 5795260219Skevlo 5796260219Skevlo run_rt3070_rf_read(sc, 30, &rf); 5797260219Skevlo rf = (rf & ~0x18) | 0x10; 5798260219Skevlo run_rt3070_rf_write(sc, 30, rf); 5799260219Skevlo 5800260219Skevlo if (sc->mac_ver != 0x5592) { 5801260219Skevlo run_write(sc, RT2860_TX_SW_CFG1, 0); 5802260219Skevlo if (sc->mac_rev < 0x0211) { 5803260219Skevlo run_write(sc, RT2860_TX_SW_CFG2, 5804260219Skevlo sc->patch_dac ? 0x2c : 0x0f); 5805260219Skevlo } else 5806260219Skevlo run_write(sc, RT2860_TX_SW_CFG2, 0); 5807260219Skevlo } 5808260219Skevlo} 5809260219Skevlo 5810203134Sthompsastatic int 5811203134Sthompsarun_txrx_enable(struct run_softc *sc) 5812203134Sthompsa{ 5813287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 5814203134Sthompsa uint32_t tmp; 5815203134Sthompsa int error, ntries; 5816203134Sthompsa 5817203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN); 5818203134Sthompsa for (ntries = 0; ntries < 200; ntries++) { 5819203134Sthompsa if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0) 5820257955Skevlo return (error); 5821203134Sthompsa if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 5822203134Sthompsa break; 5823203134Sthompsa run_delay(sc, 50); 5824203134Sthompsa } 5825203134Sthompsa if (ntries == 200) 5826257955Skevlo return (ETIMEDOUT); 5827203134Sthompsa 5828203134Sthompsa run_delay(sc, 50); 5829203134Sthompsa 5830203134Sthompsa tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE; 5831203134Sthompsa run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 5832203134Sthompsa 5833203134Sthompsa /* enable Rx bulk aggregation (set timeout and limit) */ 5834203134Sthompsa tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN | 5835203134Sthompsa RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2); 5836203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, tmp); 5837203134Sthompsa 5838203134Sthompsa /* set Rx filter */ 5839203134Sthompsa tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR; 5840203134Sthompsa if (ic->ic_opmode != IEEE80211_M_MONITOR) { 5841203134Sthompsa tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL | 5842203134Sthompsa RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK | 5843203134Sthompsa RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV | 5844203134Sthompsa RT2860_DROP_CFACK | RT2860_DROP_CFEND; 5845203134Sthompsa if (ic->ic_opmode == IEEE80211_M_STA) 5846203134Sthompsa tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL; 5847203134Sthompsa } 5848203134Sthompsa run_write(sc, RT2860_RX_FILTR_CFG, tmp); 5849203134Sthompsa 5850203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 5851203134Sthompsa RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 5852203134Sthompsa 5853209917Sthompsa return (0); 5854203134Sthompsa} 5855203134Sthompsa 5856203134Sthompsastatic void 5857259030Skevlorun_adjust_freq_offset(struct run_softc *sc) 5858257955Skevlo{ 5859257955Skevlo uint8_t rf, tmp; 5860257955Skevlo 5861257955Skevlo run_rt3070_rf_read(sc, 17, &rf); 5862257955Skevlo tmp = rf; 5863257955Skevlo rf = (rf & ~0x7f) | (sc->freq & 0x7f); 5864257955Skevlo rf = MIN(rf, 0x5f); 5865257955Skevlo 5866257955Skevlo if (tmp != rf) 5867257955Skevlo run_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf); 5868257955Skevlo} 5869257955Skevlo 5870257955Skevlostatic void 5871203134Sthompsarun_init_locked(struct run_softc *sc) 5872203134Sthompsa{ 5873287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 5874287197Sglebius struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 5875203134Sthompsa uint32_t tmp; 5876203134Sthompsa uint8_t bbp1, bbp3; 5877203134Sthompsa int i; 5878203134Sthompsa int ridx; 5879203134Sthompsa int ntries; 5880203134Sthompsa 5881209917Sthompsa if (ic->ic_nrunning > 1) 5882208019Sthompsa return; 5883208019Sthompsa 5884203134Sthompsa run_stop(sc); 5885203134Sthompsa 5886233283Sbschmidt if (run_load_microcode(sc) != 0) { 5887233283Sbschmidt device_printf(sc->sc_dev, "could not load 8051 microcode\n"); 5888233283Sbschmidt goto fail; 5889233283Sbschmidt } 5890233283Sbschmidt 5891203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5892203134Sthompsa if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0) 5893203134Sthompsa goto fail; 5894203134Sthompsa if (tmp != 0 && tmp != 0xffffffff) 5895203134Sthompsa break; 5896203134Sthompsa run_delay(sc, 10); 5897203134Sthompsa } 5898203134Sthompsa if (ntries == 100) 5899203134Sthompsa goto fail; 5900203134Sthompsa 5901203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 5902203134Sthompsa run_setup_tx_list(sc, &sc->sc_epq[i]); 5903203134Sthompsa 5904287197Sglebius run_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); 5905203134Sthompsa 5906203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5907203134Sthompsa if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 5908203134Sthompsa goto fail; 5909203134Sthompsa if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 5910203134Sthompsa break; 5911203134Sthompsa run_delay(sc, 10); 5912203134Sthompsa } 5913203134Sthompsa if (ntries == 100) { 5914203138Sthompsa device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); 5915203134Sthompsa goto fail; 5916203134Sthompsa } 5917203134Sthompsa tmp &= 0xff0; 5918203134Sthompsa tmp |= RT2860_TX_WB_DDONE; 5919203134Sthompsa run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 5920203134Sthompsa 5921203134Sthompsa /* turn off PME_OEN to solve high-current issue */ 5922203134Sthompsa run_read(sc, RT2860_SYS_CTRL, &tmp); 5923203134Sthompsa run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN); 5924203134Sthompsa 5925203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 5926203134Sthompsa RT2860_BBP_HRST | RT2860_MAC_SRST); 5927203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, 0); 5928203134Sthompsa 5929203134Sthompsa if (run_reset(sc) != 0) { 5930203138Sthompsa device_printf(sc->sc_dev, "could not reset chipset\n"); 5931203134Sthompsa goto fail; 5932203134Sthompsa } 5933203134Sthompsa 5934203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 0); 5935203134Sthompsa 5936203134Sthompsa /* init Tx power for all Tx rates (from EEPROM) */ 5937203134Sthompsa for (ridx = 0; ridx < 5; ridx++) { 5938203134Sthompsa if (sc->txpow20mhz[ridx] == 0xffffffff) 5939203134Sthompsa continue; 5940203134Sthompsa run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]); 5941203134Sthompsa } 5942203134Sthompsa 5943257955Skevlo for (i = 0; i < nitems(rt2870_def_mac); i++) 5944203134Sthompsa run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val); 5945203134Sthompsa run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273); 5946203134Sthompsa run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344); 5947203134Sthompsa run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa); 5948203134Sthompsa 5949259030Skevlo if (sc->mac_ver >= 0x5390) { 5950259030Skevlo run_write(sc, RT2860_TX_SW_CFG0, 5951259030Skevlo 4 << RT2860_DLY_PAPE_EN_SHIFT | 4); 5952259030Skevlo if (sc->mac_ver >= 0x5392) { 5953259030Skevlo run_write(sc, RT2860_MAX_LEN_CFG, 0x00002fff); 5954259032Skevlo if (sc->mac_ver == 0x5592) { 5955259032Skevlo run_write(sc, RT2860_HT_FBK_CFG1, 0xedcba980); 5956259032Skevlo run_write(sc, RT2860_TXOP_HLDR_ET, 0x00000082); 5957259032Skevlo } else { 5958259032Skevlo run_write(sc, RT2860_HT_FBK_CFG1, 0xedcb4980); 5959259032Skevlo run_write(sc, RT2860_LG_FBK_CFG0, 0xedcba322); 5960259032Skevlo } 5961259030Skevlo } 5962260219Skevlo } else if (sc->mac_ver == 0x3593) { 5963260219Skevlo run_write(sc, RT2860_TX_SW_CFG0, 5964260219Skevlo 4 << RT2860_DLY_PAPE_EN_SHIFT | 2); 5965257955Skevlo } else if (sc->mac_ver >= 0x3070) { 5966203134Sthompsa /* set delay of PA_PE assertion to 1us (unit of 0.25us) */ 5967203134Sthompsa run_write(sc, RT2860_TX_SW_CFG0, 5968203134Sthompsa 4 << RT2860_DLY_PAPE_EN_SHIFT); 5969203134Sthompsa } 5970203134Sthompsa 5971203134Sthompsa /* wait while MAC is busy */ 5972203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5973203134Sthompsa if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0) 5974203134Sthompsa goto fail; 5975203134Sthompsa if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY))) 5976203134Sthompsa break; 5977203134Sthompsa run_delay(sc, 10); 5978203134Sthompsa } 5979203134Sthompsa if (ntries == 100) 5980203134Sthompsa goto fail; 5981203134Sthompsa 5982203134Sthompsa /* clear Host to MCU mailbox */ 5983203134Sthompsa run_write(sc, RT2860_H2M_BBPAGENT, 0); 5984203134Sthompsa run_write(sc, RT2860_H2M_MAILBOX, 0); 5985203134Sthompsa run_delay(sc, 10); 5986203134Sthompsa 5987203134Sthompsa if (run_bbp_init(sc) != 0) { 5988203138Sthompsa device_printf(sc->sc_dev, "could not initialize BBP\n"); 5989203134Sthompsa goto fail; 5990203134Sthompsa } 5991203134Sthompsa 5992203134Sthompsa /* abort TSF synchronization */ 5993203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 5994203134Sthompsa tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 5995203134Sthompsa RT2860_TBTT_TIMER_EN); 5996203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, tmp); 5997203134Sthompsa 5998203134Sthompsa /* clear RX WCID search table */ 5999203134Sthompsa run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512); 6000203134Sthompsa /* clear WCID attribute table */ 6001203134Sthompsa run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32); 6002203134Sthompsa 6003209144Sthompsa /* hostapd sets a key before init. So, don't clear it. */ 6004209917Sthompsa if (sc->cmdq_key_set != RUN_CMDQ_GO) { 6005209144Sthompsa /* clear shared key table */ 6006209144Sthompsa run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32); 6007209144Sthompsa /* clear shared key mode */ 6008209144Sthompsa run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4); 6009209144Sthompsa } 6010209144Sthompsa 6011203134Sthompsa run_read(sc, RT2860_US_CYC_CNT, &tmp); 6012203134Sthompsa tmp = (tmp & ~0xff) | 0x1e; 6013203134Sthompsa run_write(sc, RT2860_US_CYC_CNT, tmp); 6014203134Sthompsa 6015205042Sthompsa if (sc->mac_rev != 0x0101) 6016203134Sthompsa run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f); 6017203134Sthompsa 6018203134Sthompsa run_write(sc, RT2860_WMM_TXOP0_CFG, 0); 6019203134Sthompsa run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96); 6020203134Sthompsa 6021203134Sthompsa /* write vendor-specific BBP values (from EEPROM) */ 6022260219Skevlo if (sc->mac_ver < 0x3593) { 6023257955Skevlo for (i = 0; i < 10; i++) { 6024257955Skevlo if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff) 6025257955Skevlo continue; 6026257955Skevlo run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val); 6027257955Skevlo } 6028203134Sthompsa } 6029203134Sthompsa 6030203134Sthompsa /* select Main antenna for 1T1R devices */ 6031257955Skevlo if (sc->rf_rev == RT3070_RF_3020 || sc->rf_rev == RT5390_RF_5370) 6032203134Sthompsa run_set_rx_antenna(sc, 0); 6033203134Sthompsa 6034203134Sthompsa /* send LEDs operating mode to microcontroller */ 6035203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]); 6036203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]); 6037203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]); 6038203134Sthompsa 6039257955Skevlo if (sc->mac_ver >= 0x5390) 6040257955Skevlo run_rt5390_rf_init(sc); 6041260219Skevlo else if (sc->mac_ver == 0x3593) 6042260219Skevlo run_rt3593_rf_init(sc); 6043257955Skevlo else if (sc->mac_ver >= 0x3070) 6044205042Sthompsa run_rt3070_rf_init(sc); 6045205042Sthompsa 6046203134Sthompsa /* disable non-existing Rx chains */ 6047203134Sthompsa run_bbp_read(sc, 3, &bbp3); 6048203134Sthompsa bbp3 &= ~(1 << 3 | 1 << 4); 6049203134Sthompsa if (sc->nrxchains == 2) 6050203134Sthompsa bbp3 |= 1 << 3; 6051203134Sthompsa else if (sc->nrxchains == 3) 6052203134Sthompsa bbp3 |= 1 << 4; 6053203134Sthompsa run_bbp_write(sc, 3, bbp3); 6054203134Sthompsa 6055203134Sthompsa /* disable non-existing Tx chains */ 6056203134Sthompsa run_bbp_read(sc, 1, &bbp1); 6057203134Sthompsa if (sc->ntxchains == 1) 6058203134Sthompsa bbp1 &= ~(1 << 3 | 1 << 4); 6059203134Sthompsa run_bbp_write(sc, 1, bbp1); 6060203134Sthompsa 6061260219Skevlo if (sc->mac_ver >= 0x5390) 6062260219Skevlo run_rt5390_rf_setup(sc); 6063260219Skevlo else if (sc->mac_ver == 0x3593) 6064260219Skevlo run_rt3593_rf_setup(sc); 6065260219Skevlo else if (sc->mac_ver >= 0x3070) 6066205042Sthompsa run_rt3070_rf_setup(sc); 6067203134Sthompsa 6068203134Sthompsa /* select default channel */ 6069203134Sthompsa run_set_chan(sc, ic->ic_curchan); 6070203134Sthompsa 6071203134Sthompsa /* setup initial protection mode */ 6072218492Sbschmidt run_updateprot_cb(ic); 6073203134Sthompsa 6074203134Sthompsa /* turn radio LED on */ 6075203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO); 6076203134Sthompsa 6077287197Sglebius sc->sc_flags |= RUN_RUNNING; 6078208019Sthompsa sc->cmdq_run = RUN_CMDQ_GO; 6079203134Sthompsa 6080209917Sthompsa for (i = 0; i != RUN_N_XFER; i++) 6081203134Sthompsa usbd_xfer_set_stall(sc->sc_xfer[i]); 6082203134Sthompsa 6083203134Sthompsa usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]); 6084203134Sthompsa 6085203134Sthompsa if (run_txrx_enable(sc) != 0) 6086203134Sthompsa goto fail; 6087203134Sthompsa 6088203134Sthompsa return; 6089203134Sthompsa 6090203134Sthompsafail: 6091203134Sthompsa run_stop(sc); 6092203134Sthompsa} 6093203134Sthompsa 6094203134Sthompsastatic void 6095203134Sthompsarun_stop(void *arg) 6096203134Sthompsa{ 6097203134Sthompsa struct run_softc *sc = (struct run_softc *)arg; 6098203134Sthompsa uint32_t tmp; 6099203134Sthompsa int i; 6100203134Sthompsa int ntries; 6101203134Sthompsa 6102203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 6103203134Sthompsa 6104287197Sglebius if (sc->sc_flags & RUN_RUNNING) 6105203134Sthompsa run_set_leds(sc, 0); /* turn all LEDs off */ 6106203134Sthompsa 6107287197Sglebius sc->sc_flags &= ~RUN_RUNNING; 6108203134Sthompsa 6109208019Sthompsa sc->ratectl_run = RUN_RATECTL_OFF; 6110209144Sthompsa sc->cmdq_run = sc->cmdq_key_set; 6111208019Sthompsa 6112203134Sthompsa RUN_UNLOCK(sc); 6113203134Sthompsa 6114203134Sthompsa for(i = 0; i < RUN_N_XFER; i++) 6115203134Sthompsa usbd_transfer_drain(sc->sc_xfer[i]); 6116203134Sthompsa 6117203134Sthompsa RUN_LOCK(sc); 6118203134Sthompsa 6119209917Sthompsa if (sc->rx_m != NULL) { 6120203134Sthompsa m_free(sc->rx_m); 6121203134Sthompsa sc->rx_m = NULL; 6122203134Sthompsa } 6123203134Sthompsa 6124257955Skevlo /* Disable Tx/Rx DMA. */ 6125257955Skevlo if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 6126257955Skevlo return; 6127257955Skevlo tmp &= ~(RT2860_RX_DMA_EN | RT2860_TX_DMA_EN); 6128257955Skevlo run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 6129257955Skevlo 6130258643Shselasky for (ntries = 0; ntries < 100; ntries++) { 6131257955Skevlo if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 6132257955Skevlo return; 6133257955Skevlo if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 6134257955Skevlo break; 6135257955Skevlo run_delay(sc, 10); 6136257955Skevlo } 6137257955Skevlo if (ntries == 100) { 6138257955Skevlo device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); 6139257955Skevlo return; 6140257955Skevlo } 6141257955Skevlo 6142203134Sthompsa /* disable Tx/Rx */ 6143203134Sthompsa run_read(sc, RT2860_MAC_SYS_CTRL, &tmp); 6144203134Sthompsa tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 6145203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, tmp); 6146203134Sthompsa 6147203134Sthompsa /* wait for pending Tx to complete */ 6148203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 6149209917Sthompsa if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0) { 6150203134Sthompsa DPRINTF("Cannot read Tx queue count\n"); 6151203134Sthompsa break; 6152203134Sthompsa } 6153209917Sthompsa if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0) { 6154203134Sthompsa DPRINTF("All Tx cleared\n"); 6155203134Sthompsa break; 6156203134Sthompsa } 6157203134Sthompsa run_delay(sc, 10); 6158203134Sthompsa } 6159209917Sthompsa if (ntries >= 100) 6160203134Sthompsa DPRINTF("There are still pending Tx\n"); 6161203134Sthompsa run_delay(sc, 10); 6162203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, 0); 6163203134Sthompsa 6164203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST); 6165203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 0); 6166203134Sthompsa 6167203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 6168203134Sthompsa run_unsetup_tx_list(sc, &sc->sc_epq[i]); 6169203134Sthompsa} 6170203134Sthompsa 6171203134Sthompsastatic void 6172257429Shselaskyrun_delay(struct run_softc *sc, u_int ms) 6173203134Sthompsa{ 6174203134Sthompsa usb_pause_mtx(mtx_owned(&sc->sc_mtx) ? 6175203134Sthompsa &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms)); 6176203134Sthompsa} 6177203134Sthompsa 6178203134Sthompsastatic device_method_t run_methods[] = { 6179203134Sthompsa /* Device interface */ 6180203134Sthompsa DEVMETHOD(device_probe, run_match), 6181203134Sthompsa DEVMETHOD(device_attach, run_attach), 6182203134Sthompsa DEVMETHOD(device_detach, run_detach), 6183246614Shselasky DEVMETHOD_END 6184203134Sthompsa}; 6185203134Sthompsa 6186203134Sthompsastatic driver_t run_driver = { 6187233774Shselasky .name = "run", 6188233774Shselasky .methods = run_methods, 6189233774Shselasky .size = sizeof(struct run_softc) 6190203134Sthompsa}; 6191203134Sthompsa 6192203134Sthompsastatic devclass_t run_devclass; 6193203134Sthompsa 6194259812SkevloDRIVER_MODULE(run, uhub, run_driver, run_devclass, run_driver_loaded, NULL); 6195212122SthompsaMODULE_DEPEND(run, wlan, 1, 1, 1); 6196212122SthompsaMODULE_DEPEND(run, usb, 1, 1, 1); 6197212122SthompsaMODULE_DEPEND(run, firmware, 1, 1, 1); 6198212122SthompsaMODULE_VERSION(run, 1); 6199