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> 5261868Skevlo * 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: releng/10.2/sys/dev/usb/wlan/if_run.c 281878 2015-04-23 01:52:07Z kevlo $"); 22203134Sthompsa 23203134Sthompsa/*- 24259453Shselasky * 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> 51203134Sthompsa#include <net/if_arp.h> 52203134Sthompsa#include <net/ethernet.h> 53203134Sthompsa#include <net/if_dl.h> 54203134Sthompsa#include <net/if_media.h> 55203134Sthompsa#include <net/if_types.h> 56203134Sthompsa 57203134Sthompsa#include <netinet/in.h> 58203134Sthompsa#include <netinet/in_systm.h> 59203134Sthompsa#include <netinet/in_var.h> 60203134Sthompsa#include <netinet/if_ether.h> 61203134Sthompsa#include <netinet/ip.h> 62203134Sthompsa 63203134Sthompsa#include <net80211/ieee80211_var.h> 64203134Sthompsa#include <net80211/ieee80211_regdomain.h> 65203134Sthompsa#include <net80211/ieee80211_radiotap.h> 66206358Srpaulo#include <net80211/ieee80211_ratectl.h> 67203134Sthompsa 68203134Sthompsa#include <dev/usb/usb.h> 69203134Sthompsa#include <dev/usb/usbdi.h> 70203134Sthompsa#include "usbdevs.h" 71203134Sthompsa 72261868Skevlo#define USB_DEBUG_VAR run_debug 73203134Sthompsa#include <dev/usb/usb_debug.h> 74261868Skevlo#include <dev/usb/usb_msctest.h> 75203134Sthompsa 76220235Skevlo#include <dev/usb/wlan/if_runreg.h> 77220235Skevlo#include <dev/usb/wlan/if_runvar.h> 78203134Sthompsa 79207077Sthompsa#ifdef USB_DEBUG 80261868Skevlo#define RUN_DEBUG 81203134Sthompsa#endif 82203134Sthompsa 83203134Sthompsa#ifdef RUN_DEBUG 84203134Sthompsaint run_debug = 0; 85227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, run, CTLFLAG_RW, 0, "USB run"); 86203134SthompsaSYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RW, &run_debug, 0, 87203134Sthompsa "run debug level"); 88203134Sthompsa#endif 89203134Sthompsa 90261868Skevlo#define IEEE80211_HAS_ADDR4(wh) \ 91203134Sthompsa (((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) 92203134Sthompsa 93208019Sthompsa/* 94208019Sthompsa * Because of LOR in run_key_delete(), use atomic instead. 95208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[]. 96208019Sthompsa */ 97261868Skevlo#define RUN_CMDQ_GET(c) (atomic_fetchadd_32((c), 1) & RUN_CMDQ_MASQ) 98208019Sthompsa 99223486Shselaskystatic const STRUCT_USB_HOST_ID run_devs[] = { 100261868Skevlo#define RUN_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } 101261868Skevlo#define RUN_DEV_EJECT(v,p) \ 102262604Skevlo { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RUN_EJECT) } 103262604Skevlo#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), 142261868Skevlo 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), 150261868Skevlo RUN_DEV(BELKIN, F9L1103), 151209918Sthompsa RUN_DEV(BELKIN, F5D8053V3), 152209918Sthompsa RUN_DEV(BELKIN, F5D8055), 153226534Shselasky RUN_DEV(BELKIN, F5D8055V2), 154209918Sthompsa RUN_DEV(BELKIN, F6D4050V1), 155257044Shselasky 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), 181259453Shselasky RUN_DEV(DLINK, DWA140B3), 182259453Shselasky RUN_DEV(DLINK, DWA160B2), 183267263Skevlo RUN_DEV(DLINK, DWA140D1), 184261868Skevlo 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), 197261868Skevlo 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), 227281878Skevlo 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), 234281878Skevlo 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), 270261868Skevlo RUN_DEV(RALINK, RT3573), 271259453Shselasky RUN_DEV(RALINK, RT5370), 272259453Shselasky 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), 320262604Skevlo RUN_DEV_EJECT(ZYXEL, NWD2705), 321261868Skevlo RUN_DEV_EJECT(RALINK, RT_STOR), 322261868Skevlo#undef RUN_DEV_EJECT 323209918Sthompsa#undef RUN_DEV 324203134Sthompsa}; 325203134Sthompsa 326203134Sthompsastatic device_probe_t run_match; 327203134Sthompsastatic device_attach_t run_attach; 328203134Sthompsastatic device_detach_t run_detach; 329203134Sthompsa 330203134Sthompsastatic usb_callback_t run_bulk_rx_callback; 331203134Sthompsastatic usb_callback_t run_bulk_tx_callback0; 332203134Sthompsastatic usb_callback_t run_bulk_tx_callback1; 333203134Sthompsastatic usb_callback_t run_bulk_tx_callback2; 334203134Sthompsastatic usb_callback_t run_bulk_tx_callback3; 335203134Sthompsastatic usb_callback_t run_bulk_tx_callback4; 336203134Sthompsastatic usb_callback_t run_bulk_tx_callback5; 337203134Sthompsa 338261868Skevlostatic void run_autoinst(void *, struct usb_device *, 339261868Skevlo struct usb_attach_arg *); 340261868Skevlostatic int run_driver_loaded(struct module *, int, void *); 341203134Sthompsastatic void run_bulk_tx_callbackN(struct usb_xfer *xfer, 342259453Shselasky usb_error_t error, u_int index); 343203134Sthompsastatic struct ieee80211vap *run_vap_create(struct ieee80211com *, 344228621Sbschmidt const char [IFNAMSIZ], int, enum ieee80211_opmode, int, 345228621Sbschmidt const uint8_t [IEEE80211_ADDR_LEN], 346228621Sbschmidt const uint8_t [IEEE80211_ADDR_LEN]); 347203134Sthompsastatic void run_vap_delete(struct ieee80211vap *); 348208019Sthompsastatic void run_cmdq_cb(void *, int); 349203134Sthompsastatic void run_setup_tx_list(struct run_softc *, 350203134Sthompsa struct run_endpoint_queue *); 351203134Sthompsastatic void run_unsetup_tx_list(struct run_softc *, 352203134Sthompsa struct run_endpoint_queue *); 353203134Sthompsastatic int run_load_microcode(struct run_softc *); 354203134Sthompsastatic int run_reset(struct run_softc *); 355203134Sthompsastatic usb_error_t run_do_request(struct run_softc *, 356203134Sthompsa struct usb_device_request *, void *); 357203134Sthompsastatic int run_read(struct run_softc *, uint16_t, uint32_t *); 358203134Sthompsastatic int run_read_region_1(struct run_softc *, uint16_t, uint8_t *, int); 359203134Sthompsastatic int run_write_2(struct run_softc *, uint16_t, uint16_t); 360203134Sthompsastatic int run_write(struct run_softc *, uint16_t, uint32_t); 361203134Sthompsastatic int run_write_region_1(struct run_softc *, uint16_t, 362203134Sthompsa const uint8_t *, int); 363203134Sthompsastatic int run_set_region_4(struct run_softc *, uint16_t, uint32_t, int); 364261868Skevlostatic int run_efuse_read(struct run_softc *, uint16_t, uint16_t *, int); 365203134Sthompsastatic int run_efuse_read_2(struct run_softc *, uint16_t, uint16_t *); 366203134Sthompsastatic int run_eeprom_read_2(struct run_softc *, uint16_t, uint16_t *); 367259453Shselaskystatic int run_rt2870_rf_write(struct run_softc *, uint32_t); 368203134Sthompsastatic int run_rt3070_rf_read(struct run_softc *, uint8_t, uint8_t *); 369203134Sthompsastatic int run_rt3070_rf_write(struct run_softc *, uint8_t, uint8_t); 370203134Sthompsastatic int run_bbp_read(struct run_softc *, uint8_t, uint8_t *); 371203134Sthompsastatic int run_bbp_write(struct run_softc *, uint8_t, uint8_t); 372203134Sthompsastatic int run_mcu_cmd(struct run_softc *, uint8_t, uint16_t); 373259453Shselaskystatic const char *run_get_rf(uint16_t); 374261868Skevlostatic void run_rt3593_get_txpower(struct run_softc *); 375261868Skevlostatic void run_get_txpower(struct run_softc *); 376203134Sthompsastatic int run_read_eeprom(struct run_softc *); 377203134Sthompsastatic struct ieee80211_node *run_node_alloc(struct ieee80211vap *, 378203134Sthompsa const uint8_t mac[IEEE80211_ADDR_LEN]); 379203134Sthompsastatic int run_media_change(struct ifnet *); 380203134Sthompsastatic int run_newstate(struct ieee80211vap *, enum ieee80211_state, int); 381203134Sthompsastatic int run_wme_update(struct ieee80211com *); 382208019Sthompsastatic void run_wme_update_cb(void *); 383203134Sthompsastatic void run_key_update_begin(struct ieee80211vap *); 384203134Sthompsastatic void run_key_update_end(struct ieee80211vap *); 385208019Sthompsastatic void run_key_set_cb(void *); 386208019Sthompsastatic int run_key_set(struct ieee80211vap *, struct ieee80211_key *, 387259453Shselasky const uint8_t mac[IEEE80211_ADDR_LEN]); 388208019Sthompsastatic void run_key_delete_cb(void *); 389208019Sthompsastatic int run_key_delete(struct ieee80211vap *, struct ieee80211_key *); 390206358Srpaulostatic void run_ratectl_to(void *); 391206358Srpaulostatic void run_ratectl_cb(void *, int); 392208019Sthompsastatic void run_drain_fifo(void *); 393203134Sthompsastatic void run_iter_func(void *, struct ieee80211_node *); 394208019Sthompsastatic void run_newassoc_cb(void *); 395203134Sthompsastatic void run_newassoc(struct ieee80211_node *, int); 396203134Sthompsastatic void run_rx_frame(struct run_softc *, struct mbuf *, uint32_t); 397203134Sthompsastatic void run_tx_free(struct run_endpoint_queue *pq, 398203134Sthompsa struct run_tx_data *, int); 399208019Sthompsastatic void run_set_tx_desc(struct run_softc *, struct run_tx_data *); 400203134Sthompsastatic int run_tx(struct run_softc *, struct mbuf *, 401203134Sthompsa struct ieee80211_node *); 402203134Sthompsastatic int run_tx_mgt(struct run_softc *, struct mbuf *, 403203134Sthompsa struct ieee80211_node *); 404203134Sthompsastatic int run_sendprot(struct run_softc *, const struct mbuf *, 405203134Sthompsa struct ieee80211_node *, int, int); 406203134Sthompsastatic int run_tx_param(struct run_softc *, struct mbuf *, 407203134Sthompsa struct ieee80211_node *, 408203134Sthompsa const struct ieee80211_bpf_params *); 409203134Sthompsastatic int run_raw_xmit(struct ieee80211_node *, struct mbuf *, 410203134Sthompsa const struct ieee80211_bpf_params *); 411203134Sthompsastatic void run_start(struct ifnet *); 412203134Sthompsastatic int run_ioctl(struct ifnet *, u_long, caddr_t); 413261868Skevlostatic 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); 420261868Skevlostatic void run_rt3593_set_chan(struct run_softc *, u_int); 421259453Shselaskystatic void run_rt5390_set_chan(struct run_softc *, u_int); 422259453Shselaskystatic 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 *); 440203134Sthompsastatic void run_updateslot(struct ifnet *); 441218492Sbschmidtstatic void run_updateslot_cb(void *); 442208019Sthompsastatic void run_update_mcast(struct ifnet *); 443203134Sthompsastatic int8_t run_rssi2dbm(struct run_softc *, uint8_t, uint8_t); 444203134Sthompsastatic void run_update_promisc_locked(struct ifnet *); 445203134Sthompsastatic void run_update_promisc(struct ifnet *); 446259453Shselaskystatic 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 *); 449261868Skevlostatic void run_rt3593_rf_init(struct run_softc *); 450259453Shselaskystatic 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 *); 454261868Skevlostatic void run_rt3593_rf_setup(struct run_softc *); 455261868Skevlostatic void run_rt5390_rf_setup(struct run_softc *); 456203134Sthompsastatic int run_txrx_enable(struct run_softc *); 457259453Shselaskystatic void run_adjust_freq_offset(struct run_softc *); 458203134Sthompsastatic void run_init(void *); 459203134Sthompsastatic void run_init_locked(struct run_softc *); 460203134Sthompsastatic void run_stop(void *); 461259453Shselaskystatic void run_delay(struct run_softc *, u_int); 462203134Sthompsa 463261868Skevlostatic eventhandler_tag run_etag; 464261868Skevlo 465261868Skevlostatic const struct rt2860_rate { 466261868Skevlo uint8_t rate; 467261868Skevlo uint8_t mcs; 468261868Skevlo enum ieee80211_phytype phy; 469261868Skevlo uint8_t ctl_ridx; 470261868Skevlo uint16_t sp_ack_dur; 471261868Skevlo uint16_t lp_ack_dur; 472261868Skevlo} rt2860_rates[] = { 473261868Skevlo { 2, 0, IEEE80211_T_DS, 0, 314, 314 }, 474261868Skevlo { 4, 1, IEEE80211_T_DS, 1, 258, 162 }, 475261868Skevlo { 11, 2, IEEE80211_T_DS, 2, 223, 127 }, 476261868Skevlo { 22, 3, IEEE80211_T_DS, 3, 213, 117 }, 477261868Skevlo { 12, 0, IEEE80211_T_OFDM, 4, 60, 60 }, 478261868Skevlo { 18, 1, IEEE80211_T_OFDM, 4, 52, 52 }, 479261868Skevlo { 24, 2, IEEE80211_T_OFDM, 6, 48, 48 }, 480261868Skevlo { 36, 3, IEEE80211_T_OFDM, 6, 44, 44 }, 481261868Skevlo { 48, 4, IEEE80211_T_OFDM, 8, 44, 44 }, 482261868Skevlo { 72, 5, IEEE80211_T_OFDM, 8, 40, 40 }, 483261868Skevlo { 96, 6, IEEE80211_T_OFDM, 8, 40, 40 }, 484261868Skevlo { 108, 7, IEEE80211_T_OFDM, 8, 40, 40 } 485261868Skevlo}; 486261868Skevlo 487203134Sthompsastatic const struct { 488208019Sthompsa uint16_t reg; 489203134Sthompsa uint32_t val; 490203134Sthompsa} rt2870_def_mac[] = { 491203134Sthompsa RT2870_DEF_MAC 492203134Sthompsa}; 493203134Sthompsa 494203134Sthompsastatic const struct { 495203134Sthompsa uint8_t reg; 496203134Sthompsa uint8_t val; 497203134Sthompsa} rt2860_def_bbp[] = { 498203134Sthompsa RT2860_DEF_BBP 499259453Shselasky},rt5390_def_bbp[] = { 500259453Shselasky RT5390_DEF_BBP 501259453Shselasky},rt5592_def_bbp[] = { 502259453Shselasky RT5592_DEF_BBP 503203134Sthompsa}; 504203134Sthompsa 505259453Shselasky/* 506259453Shselasky * Default values for BBP register R196 for RT5592. 507259453Shselasky */ 508259453Shselaskystatic const uint8_t rt5592_bbp_r196[] = { 509259453Shselasky 0xe0, 0x1f, 0x38, 0x32, 0x08, 0x28, 0x19, 0x0a, 0xff, 0x00, 510259453Shselasky 0x16, 0x10, 0x10, 0x0b, 0x36, 0x2c, 0x26, 0x24, 0x42, 0x36, 511259453Shselasky 0x30, 0x2d, 0x4c, 0x46, 0x3d, 0x40, 0x3e, 0x42, 0x3d, 0x40, 512259453Shselasky 0x3c, 0x34, 0x2c, 0x2f, 0x3c, 0x35, 0x2e, 0x2a, 0x49, 0x41, 513259453Shselasky 0x36, 0x31, 0x30, 0x30, 0x0e, 0x0d, 0x28, 0x21, 0x1c, 0x16, 514259453Shselasky 0x50, 0x4a, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 515259453Shselasky 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 516259453Shselasky 0x00, 0x00, 0x7d, 0x14, 0x32, 0x2c, 0x36, 0x4c, 0x43, 0x2c, 517259453Shselasky 0x2e, 0x36, 0x30, 0x6e 518259453Shselasky}; 519259453Shselasky 520203134Sthompsastatic const struct rfprog { 521203134Sthompsa uint8_t chan; 522203134Sthompsa uint32_t r1, r2, r3, r4; 523203134Sthompsa} rt2860_rf2850[] = { 524203134Sthompsa RT2860_RF2850 525203134Sthompsa}; 526203134Sthompsa 527203134Sthompsastruct { 528203134Sthompsa uint8_t n, r, k; 529205042Sthompsa} rt3070_freqs[] = { 530205042Sthompsa RT3070_RF3052 531203134Sthompsa}; 532203134Sthompsa 533259453Shselaskystatic const struct rt5592_freqs { 534259453Shselasky uint16_t n; 535259453Shselasky uint8_t k, m, r; 536259453Shselasky} rt5592_freqs_20mhz[] = { 537259453Shselasky RT5592_RF5592_20MHZ 538259453Shselasky},rt5592_freqs_40mhz[] = { 539259453Shselasky RT5592_RF5592_40MHZ 540259453Shselasky}; 541259453Shselasky 542203134Sthompsastatic const struct { 543203134Sthompsa uint8_t reg; 544203134Sthompsa uint8_t val; 545203134Sthompsa} rt3070_def_rf[] = { 546203134Sthompsa RT3070_DEF_RF 547205042Sthompsa},rt3572_def_rf[] = { 548205042Sthompsa RT3572_DEF_RF 549261868Skevlo},rt3593_def_rf[] = { 550261868Skevlo RT3593_DEF_RF 551259453Shselasky},rt5390_def_rf[] = { 552259453Shselasky RT5390_DEF_RF 553259453Shselasky},rt5392_def_rf[] = { 554259453Shselasky RT5392_DEF_RF 555259453Shselasky},rt5592_def_rf[] = { 556259453Shselasky RT5592_DEF_RF 557259453Shselasky},rt5592_2ghz_def_rf[] = { 558259453Shselasky RT5592_2GHZ_DEF_RF 559259453Shselasky},rt5592_5ghz_def_rf[] = { 560259453Shselasky RT5592_5GHZ_DEF_RF 561203134Sthompsa}; 562203134Sthompsa 563259453Shselaskystatic const struct { 564259453Shselasky u_int firstchan; 565259453Shselasky u_int lastchan; 566259453Shselasky uint8_t reg; 567259453Shselasky uint8_t val; 568259453Shselasky} rt5592_chan_5ghz[] = { 569259453Shselasky RT5592_CHAN_5GHZ 570259453Shselasky}; 571259453Shselasky 572203134Sthompsastatic const struct usb_config run_config[RUN_N_XFER] = { 573203134Sthompsa [RUN_BULK_TX_BE] = { 574203134Sthompsa .type = UE_BULK, 575203134Sthompsa .endpoint = UE_ADDR_ANY, 576203134Sthompsa .ep_index = 0, 577203134Sthompsa .direction = UE_DIR_OUT, 578203134Sthompsa .bufsize = RUN_MAX_TXSZ, 579203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 580203134Sthompsa .callback = run_bulk_tx_callback0, 581203134Sthompsa .timeout = 5000, /* ms */ 582203134Sthompsa }, 583203134Sthompsa [RUN_BULK_TX_BK] = { 584203134Sthompsa .type = UE_BULK, 585203134Sthompsa .endpoint = UE_ADDR_ANY, 586203134Sthompsa .direction = UE_DIR_OUT, 587203134Sthompsa .ep_index = 1, 588203134Sthompsa .bufsize = RUN_MAX_TXSZ, 589203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 590203134Sthompsa .callback = run_bulk_tx_callback1, 591203134Sthompsa .timeout = 5000, /* ms */ 592203134Sthompsa }, 593203134Sthompsa [RUN_BULK_TX_VI] = { 594203134Sthompsa .type = UE_BULK, 595203134Sthompsa .endpoint = UE_ADDR_ANY, 596203134Sthompsa .direction = UE_DIR_OUT, 597203134Sthompsa .ep_index = 2, 598203134Sthompsa .bufsize = RUN_MAX_TXSZ, 599203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 600203134Sthompsa .callback = run_bulk_tx_callback2, 601203134Sthompsa .timeout = 5000, /* ms */ 602203134Sthompsa }, 603203134Sthompsa [RUN_BULK_TX_VO] = { 604203134Sthompsa .type = UE_BULK, 605203134Sthompsa .endpoint = UE_ADDR_ANY, 606203134Sthompsa .direction = UE_DIR_OUT, 607203134Sthompsa .ep_index = 3, 608203134Sthompsa .bufsize = RUN_MAX_TXSZ, 609203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 610203134Sthompsa .callback = run_bulk_tx_callback3, 611203134Sthompsa .timeout = 5000, /* ms */ 612203134Sthompsa }, 613203134Sthompsa [RUN_BULK_TX_HCCA] = { 614203134Sthompsa .type = UE_BULK, 615203134Sthompsa .endpoint = UE_ADDR_ANY, 616203134Sthompsa .direction = UE_DIR_OUT, 617203134Sthompsa .ep_index = 4, 618203134Sthompsa .bufsize = RUN_MAX_TXSZ, 619203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 620203134Sthompsa .callback = run_bulk_tx_callback4, 621203134Sthompsa .timeout = 5000, /* ms */ 622203134Sthompsa }, 623203134Sthompsa [RUN_BULK_TX_PRIO] = { 624203134Sthompsa .type = UE_BULK, 625203134Sthompsa .endpoint = UE_ADDR_ANY, 626203134Sthompsa .direction = UE_DIR_OUT, 627203134Sthompsa .ep_index = 5, 628203134Sthompsa .bufsize = RUN_MAX_TXSZ, 629203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 630203134Sthompsa .callback = run_bulk_tx_callback5, 631203134Sthompsa .timeout = 5000, /* ms */ 632203134Sthompsa }, 633203134Sthompsa [RUN_BULK_RX] = { 634203134Sthompsa .type = UE_BULK, 635203134Sthompsa .endpoint = UE_ADDR_ANY, 636203134Sthompsa .direction = UE_DIR_IN, 637203134Sthompsa .bufsize = RUN_MAX_RXSZ, 638203134Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 639203134Sthompsa .callback = run_bulk_rx_callback, 640203134Sthompsa } 641203134Sthompsa}; 642203134Sthompsa 643261868Skevlostatic void 644261868Skevlorun_autoinst(void *arg, struct usb_device *udev, 645261868Skevlo struct usb_attach_arg *uaa) 646261868Skevlo{ 647261868Skevlo struct usb_interface *iface; 648261868Skevlo struct usb_interface_descriptor *id; 649261868Skevlo 650261868Skevlo if (uaa->dev_state != UAA_DEV_READY) 651261868Skevlo return; 652261868Skevlo 653261868Skevlo iface = usbd_get_iface(udev, 0); 654261868Skevlo if (iface == NULL) 655261868Skevlo return; 656261868Skevlo id = iface->idesc; 657261868Skevlo if (id == NULL || id->bInterfaceClass != UICLASS_MASS) 658261868Skevlo return; 659261868Skevlo if (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa)) 660261868Skevlo return; 661261868Skevlo 662261868Skevlo if (usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT) == 0) 663261868Skevlo uaa->dev_state = UAA_DEV_EJECTING; 664261868Skevlo} 665261868Skevlo 666220235Skevlostatic int 667261868Skevlorun_driver_loaded(struct module *mod, int what, void *arg) 668261868Skevlo{ 669261868Skevlo switch (what) { 670261868Skevlo case MOD_LOAD: 671261868Skevlo run_etag = EVENTHANDLER_REGISTER(usb_dev_configured, 672261868Skevlo run_autoinst, NULL, EVENTHANDLER_PRI_ANY); 673261868Skevlo break; 674261868Skevlo case MOD_UNLOAD: 675261868Skevlo EVENTHANDLER_DEREGISTER(usb_dev_configured, run_etag); 676261868Skevlo break; 677261868Skevlo default: 678261868Skevlo return (EOPNOTSUPP); 679261868Skevlo } 680261868Skevlo return (0); 681261868Skevlo} 682261868Skevlo 683261868Skevlostatic int 684203134Sthompsarun_match(device_t self) 685203134Sthompsa{ 686203134Sthompsa struct usb_attach_arg *uaa = device_get_ivars(self); 687203134Sthompsa 688203134Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 689203134Sthompsa return (ENXIO); 690203134Sthompsa if (uaa->info.bConfigIndex != 0) 691203134Sthompsa return (ENXIO); 692203134Sthompsa if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX) 693203134Sthompsa return (ENXIO); 694203134Sthompsa 695203134Sthompsa return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa)); 696203134Sthompsa} 697203134Sthompsa 698203134Sthompsastatic int 699203134Sthompsarun_attach(device_t self) 700203134Sthompsa{ 701203134Sthompsa struct run_softc *sc = device_get_softc(self); 702203134Sthompsa struct usb_attach_arg *uaa = device_get_ivars(self); 703203134Sthompsa struct ieee80211com *ic; 704203134Sthompsa struct ifnet *ifp; 705205042Sthompsa uint32_t ver; 706259453Shselasky int ntries, error; 707203134Sthompsa uint8_t iface_index, bands; 708203134Sthompsa 709203134Sthompsa device_set_usb_desc(self); 710203134Sthompsa sc->sc_udev = uaa->device; 711203134Sthompsa sc->sc_dev = self; 712262604Skevlo if (USB_GET_DRIVER_INFO(uaa) != RUN_EJECT) 713262604Skevlo sc->sc_flags |= RUN_FLAG_FWLOAD_NEEDED; 714203134Sthompsa 715203134Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), 716203134Sthompsa MTX_NETWORK_LOCK, MTX_DEF); 717203134Sthompsa 718203134Sthompsa iface_index = RT2860_IFACE_INDEX; 719208019Sthompsa 720203134Sthompsa error = usbd_transfer_setup(uaa->device, &iface_index, 721203134Sthompsa sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx); 722203134Sthompsa if (error) { 723205042Sthompsa device_printf(self, "could not allocate USB transfers, " 724203134Sthompsa "err=%s\n", usbd_errstr(error)); 725203134Sthompsa goto detach; 726203134Sthompsa } 727203134Sthompsa 728203134Sthompsa RUN_LOCK(sc); 729203134Sthompsa 730203134Sthompsa /* wait for the chip to settle */ 731203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 732209917Sthompsa if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0) { 733203134Sthompsa RUN_UNLOCK(sc); 734203134Sthompsa goto detach; 735203134Sthompsa } 736205042Sthompsa if (ver != 0 && ver != 0xffffffff) 737203134Sthompsa break; 738203134Sthompsa run_delay(sc, 10); 739203134Sthompsa } 740203134Sthompsa if (ntries == 100) { 741203138Sthompsa device_printf(sc->sc_dev, 742203138Sthompsa "timeout waiting for NIC to initialize\n"); 743203134Sthompsa RUN_UNLOCK(sc); 744203134Sthompsa goto detach; 745203134Sthompsa } 746205042Sthompsa sc->mac_ver = ver >> 16; 747205042Sthompsa sc->mac_rev = ver & 0xffff; 748203134Sthompsa 749203134Sthompsa /* retrieve RF rev. no and various other things from EEPROM */ 750203134Sthompsa run_read_eeprom(sc); 751203134Sthompsa 752203138Sthompsa device_printf(sc->sc_dev, 753203138Sthompsa "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n", 754205042Sthompsa sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev), 755203138Sthompsa sc->ntxchains, sc->nrxchains, ether_sprintf(sc->sc_bssid)); 756203134Sthompsa 757203134Sthompsa RUN_UNLOCK(sc); 758203134Sthompsa 759203134Sthompsa ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); 760220235Skevlo if (ifp == NULL) { 761203138Sthompsa device_printf(sc->sc_dev, "can not if_alloc()\n"); 762203134Sthompsa goto detach; 763203134Sthompsa } 764203134Sthompsa ic = ifp->if_l2com; 765203134Sthompsa 766203134Sthompsa ifp->if_softc = sc; 767203134Sthompsa if_initname(ifp, "run", device_get_unit(sc->sc_dev)); 768203134Sthompsa ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 769203134Sthompsa ifp->if_init = run_init; 770203134Sthompsa ifp->if_ioctl = run_ioctl; 771203134Sthompsa ifp->if_start = run_start; 772207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 773207554Ssobomax ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 774203134Sthompsa IFQ_SET_READY(&ifp->if_snd); 775203134Sthompsa 776203134Sthompsa ic->ic_ifp = ifp; 777203134Sthompsa ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 778203134Sthompsa ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 779208019Sthompsa 780203134Sthompsa /* set device capabilities */ 781203134Sthompsa ic->ic_caps = 782203134Sthompsa IEEE80211_C_STA | /* station mode supported */ 783203134Sthompsa IEEE80211_C_MONITOR | /* monitor mode supported */ 784203134Sthompsa IEEE80211_C_IBSS | 785203134Sthompsa IEEE80211_C_HOSTAP | 786208019Sthompsa IEEE80211_C_WDS | /* 4-address traffic works */ 787208019Sthompsa IEEE80211_C_MBSS | 788203134Sthompsa IEEE80211_C_SHPREAMBLE | /* short preamble supported */ 789203134Sthompsa IEEE80211_C_SHSLOT | /* short slot time supported */ 790203134Sthompsa IEEE80211_C_WME | /* WME */ 791214894Sbschmidt IEEE80211_C_WPA; /* WPA1|WPA2(RSN) */ 792203134Sthompsa 793203134Sthompsa ic->ic_cryptocaps = 794203134Sthompsa IEEE80211_CRYPTO_WEP | 795203134Sthompsa IEEE80211_CRYPTO_AES_CCM | 796203134Sthompsa IEEE80211_CRYPTO_TKIPMIC | 797203134Sthompsa IEEE80211_CRYPTO_TKIP; 798203134Sthompsa 799203134Sthompsa ic->ic_flags |= IEEE80211_F_DATAPAD; 800203134Sthompsa ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; 801203134Sthompsa 802203134Sthompsa bands = 0; 803203134Sthompsa setbit(&bands, IEEE80211_MODE_11B); 804203134Sthompsa setbit(&bands, IEEE80211_MODE_11G); 805259453Shselasky if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850 || 806261868Skevlo sc->rf_rev == RT3070_RF_3052 || sc->rf_rev == RT3593_RF_3053 || 807261868Skevlo sc->rf_rev == RT5592_RF_5592) 808259453Shselasky setbit(&bands, IEEE80211_MODE_11A); 809203134Sthompsa ieee80211_init_channels(ic, NULL, &bands); 810203134Sthompsa 811203134Sthompsa ieee80211_ifattach(ic, sc->sc_bssid); 812203134Sthompsa 813203134Sthompsa ic->ic_scan_start = run_scan_start; 814203134Sthompsa ic->ic_scan_end = run_scan_end; 815203134Sthompsa ic->ic_set_channel = run_set_channel; 816203134Sthompsa ic->ic_node_alloc = run_node_alloc; 817203134Sthompsa ic->ic_newassoc = run_newassoc; 818218492Sbschmidt ic->ic_updateslot = run_updateslot; 819208019Sthompsa ic->ic_update_mcast = run_update_mcast; 820203134Sthompsa ic->ic_wme.wme_update = run_wme_update; 821203134Sthompsa ic->ic_raw_xmit = run_raw_xmit; 822203134Sthompsa ic->ic_update_promisc = run_update_promisc; 823203134Sthompsa 824203134Sthompsa ic->ic_vap_create = run_vap_create; 825203134Sthompsa ic->ic_vap_delete = run_vap_delete; 826203134Sthompsa 827203134Sthompsa ieee80211_radiotap_attach(ic, 828203134Sthompsa &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), 829203134Sthompsa RUN_TX_RADIOTAP_PRESENT, 830203134Sthompsa &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 831203134Sthompsa RUN_RX_RADIOTAP_PRESENT); 832203134Sthompsa 833208019Sthompsa TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc); 834208019Sthompsa TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc); 835259453Shselasky usb_callout_init_mtx(&sc->ratectl_ch, &sc->sc_mtx, 0); 836208019Sthompsa 837203134Sthompsa if (bootverbose) 838203134Sthompsa ieee80211_announce(ic); 839203134Sthompsa 840209917Sthompsa return (0); 841203134Sthompsa 842203134Sthompsadetach: 843203134Sthompsa run_detach(self); 844209917Sthompsa return (ENXIO); 845203134Sthompsa} 846203134Sthompsa 847203134Sthompsastatic int 848203134Sthompsarun_detach(device_t self) 849203134Sthompsa{ 850203134Sthompsa struct run_softc *sc = device_get_softc(self); 851203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 852203134Sthompsa struct ieee80211com *ic; 853203134Sthompsa int i; 854203134Sthompsa 855246614Shselasky RUN_LOCK(sc); 856246614Shselasky sc->sc_detached = 1; 857246614Shselasky RUN_UNLOCK(sc); 858246614Shselasky 859203134Sthompsa /* stop all USB transfers */ 860203134Sthompsa usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER); 861203134Sthompsa 862203134Sthompsa RUN_LOCK(sc); 863209144Sthompsa sc->ratectl_run = RUN_RATECTL_OFF; 864209144Sthompsa sc->cmdq_run = sc->cmdq_key_set = RUN_CMDQ_ABORT; 865209144Sthompsa 866203134Sthompsa /* free TX list, if any */ 867203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 868203134Sthompsa run_unsetup_tx_list(sc, &sc->sc_epq[i]); 869203134Sthompsa RUN_UNLOCK(sc); 870203134Sthompsa 871203134Sthompsa if (ifp) { 872203134Sthompsa ic = ifp->if_l2com; 873208019Sthompsa /* drain tasks */ 874208019Sthompsa usb_callout_drain(&sc->ratectl_ch); 875208019Sthompsa ieee80211_draintask(ic, &sc->cmdq_task); 876208019Sthompsa ieee80211_draintask(ic, &sc->ratectl_task); 877203134Sthompsa ieee80211_ifdetach(ic); 878203134Sthompsa if_free(ifp); 879203134Sthompsa } 880203134Sthompsa 881203134Sthompsa mtx_destroy(&sc->sc_mtx); 882203134Sthompsa 883203134Sthompsa return (0); 884203134Sthompsa} 885203134Sthompsa 886203134Sthompsastatic struct ieee80211vap * 887228621Sbschmidtrun_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, 888228621Sbschmidt enum ieee80211_opmode opmode, int flags, 889203134Sthompsa const uint8_t bssid[IEEE80211_ADDR_LEN], 890203134Sthompsa const uint8_t mac[IEEE80211_ADDR_LEN]) 891203134Sthompsa{ 892208019Sthompsa struct ifnet *ifp = ic->ic_ifp; 893208019Sthompsa struct run_softc *sc = ifp->if_softc; 894203134Sthompsa struct run_vap *rvp; 895203134Sthompsa struct ieee80211vap *vap; 896208019Sthompsa int i; 897203134Sthompsa 898209917Sthompsa if (sc->rvp_cnt >= RUN_VAP_MAX) { 899208019Sthompsa if_printf(ifp, "number of VAPs maxed out\n"); 900209917Sthompsa return (NULL); 901208019Sthompsa } 902208019Sthompsa 903208019Sthompsa switch (opmode) { 904208019Sthompsa case IEEE80211_M_STA: 905208019Sthompsa /* enable s/w bmiss handling for sta mode */ 906208019Sthompsa flags |= IEEE80211_CLONE_NOBEACONS; 907208019Sthompsa /* fall though */ 908208019Sthompsa case IEEE80211_M_IBSS: 909208019Sthompsa case IEEE80211_M_MONITOR: 910208019Sthompsa case IEEE80211_M_HOSTAP: 911208019Sthompsa case IEEE80211_M_MBSS: 912208019Sthompsa /* other than WDS vaps, only one at a time */ 913208019Sthompsa if (!TAILQ_EMPTY(&ic->ic_vaps)) 914209917Sthompsa return (NULL); 915208019Sthompsa break; 916208019Sthompsa case IEEE80211_M_WDS: 917208019Sthompsa TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next){ 918208019Sthompsa if(vap->iv_opmode != IEEE80211_M_HOSTAP) 919208019Sthompsa continue; 920208019Sthompsa /* WDS vap's always share the local mac address. */ 921208019Sthompsa flags &= ~IEEE80211_CLONE_BSSID; 922208019Sthompsa break; 923208019Sthompsa } 924209917Sthompsa if (vap == NULL) { 925208019Sthompsa if_printf(ifp, "wds only supported in ap mode\n"); 926209917Sthompsa return (NULL); 927208019Sthompsa } 928208019Sthompsa break; 929208019Sthompsa default: 930208019Sthompsa if_printf(ifp, "unknown opmode %d\n", opmode); 931209917Sthompsa return (NULL); 932208019Sthompsa } 933208019Sthompsa 934208019Sthompsa rvp = (struct run_vap *) malloc(sizeof(struct run_vap), 935203134Sthompsa M_80211_VAP, M_NOWAIT | M_ZERO); 936203134Sthompsa if (rvp == NULL) 937209917Sthompsa return (NULL); 938203134Sthompsa vap = &rvp->vap; 939203134Sthompsa 940259453Shselasky if (ieee80211_vap_setup(ic, vap, name, unit, 941259453Shselasky opmode, flags, bssid, mac) != 0) { 942259453Shselasky /* out of memory */ 943259453Shselasky free(rvp, M_80211_VAP); 944259453Shselasky return (NULL); 945259453Shselasky } 946259453Shselasky 947203134Sthompsa vap->iv_key_update_begin = run_key_update_begin; 948203134Sthompsa vap->iv_key_update_end = run_key_update_end; 949203134Sthompsa vap->iv_update_beacon = run_update_beacon; 950208019Sthompsa vap->iv_max_aid = RT2870_WCID_MAX; 951208019Sthompsa /* 952208019Sthompsa * To delete the right key from h/w, we need wcid. 953208019Sthompsa * Luckily, there is unused space in ieee80211_key{}, wk_pad, 954208019Sthompsa * and matching wcid will be written into there. So, cast 955208019Sthompsa * some spells to remove 'const' from ieee80211_key{} 956208019Sthompsa */ 957208019Sthompsa vap->iv_key_delete = (void *)run_key_delete; 958208019Sthompsa vap->iv_key_set = (void *)run_key_set; 959203134Sthompsa 960203134Sthompsa /* override state transition machine */ 961203134Sthompsa rvp->newstate = vap->iv_newstate; 962203134Sthompsa vap->iv_newstate = run_newstate; 963203134Sthompsa 964206358Srpaulo ieee80211_ratectl_init(vap); 965206358Srpaulo ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */); 966203134Sthompsa 967203134Sthompsa /* complete setup */ 968203134Sthompsa ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status); 969208019Sthompsa 970208019Sthompsa /* make sure id is always unique */ 971209917Sthompsa for (i = 0; i < RUN_VAP_MAX; i++) { 972208019Sthompsa if((sc->rvp_bmap & 1 << i) == 0){ 973208019Sthompsa sc->rvp_bmap |= 1 << i; 974208019Sthompsa rvp->rvp_id = i; 975208019Sthompsa break; 976208019Sthompsa } 977208019Sthompsa } 978209917Sthompsa if (sc->rvp_cnt++ == 0) 979208019Sthompsa ic->ic_opmode = opmode; 980208019Sthompsa 981209917Sthompsa if (opmode == IEEE80211_M_HOSTAP) 982209144Sthompsa sc->cmdq_run = RUN_CMDQ_GO; 983209144Sthompsa 984208019Sthompsa DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n", 985208019Sthompsa rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt); 986208019Sthompsa 987209917Sthompsa return (vap); 988203134Sthompsa} 989203134Sthompsa 990203134Sthompsastatic void 991203134Sthompsarun_vap_delete(struct ieee80211vap *vap) 992203134Sthompsa{ 993203134Sthompsa struct run_vap *rvp = RUN_VAP(vap); 994203134Sthompsa struct ifnet *ifp; 995203134Sthompsa struct ieee80211com *ic; 996203134Sthompsa struct run_softc *sc; 997208019Sthompsa uint8_t rvp_id; 998203134Sthompsa 999209917Sthompsa if (vap == NULL) 1000203134Sthompsa return; 1001203134Sthompsa 1002203134Sthompsa ic = vap->iv_ic; 1003203134Sthompsa ifp = ic->ic_ifp; 1004203134Sthompsa 1005203134Sthompsa sc = ifp->if_softc; 1006203134Sthompsa 1007205042Sthompsa RUN_LOCK(sc); 1008208019Sthompsa 1009218492Sbschmidt m_freem(rvp->beacon_mbuf); 1010218492Sbschmidt rvp->beacon_mbuf = NULL; 1011218492Sbschmidt 1012208019Sthompsa rvp_id = rvp->rvp_id; 1013208019Sthompsa sc->ratectl_run &= ~(1 << rvp_id); 1014208019Sthompsa sc->rvp_bmap &= ~(1 << rvp_id); 1015208019Sthompsa run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128); 1016208019Sthompsa run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512); 1017208019Sthompsa --sc->rvp_cnt; 1018208019Sthompsa 1019208019Sthompsa DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n", 1020208019Sthompsa vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt); 1021208019Sthompsa 1022205042Sthompsa RUN_UNLOCK(sc); 1023203134Sthompsa 1024206358Srpaulo ieee80211_ratectl_deinit(vap); 1025203134Sthompsa ieee80211_vap_detach(vap); 1026203134Sthompsa free(rvp, M_80211_VAP); 1027203134Sthompsa} 1028203134Sthompsa 1029208019Sthompsa/* 1030208019Sthompsa * There are numbers of functions need to be called in context thread. 1031208019Sthompsa * Rather than creating taskqueue event for each of those functions, 1032208019Sthompsa * here is all-for-one taskqueue callback function. This function 1033208019Sthompsa * gurantees deferred functions are executed in the same order they 1034208019Sthompsa * were enqueued. 1035208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[]. 1036208019Sthompsa */ 1037203134Sthompsastatic void 1038208019Sthompsarun_cmdq_cb(void *arg, int pending) 1039208019Sthompsa{ 1040208019Sthompsa struct run_softc *sc = arg; 1041208019Sthompsa uint8_t i; 1042208019Sthompsa 1043208019Sthompsa /* call cmdq[].func locked */ 1044208019Sthompsa RUN_LOCK(sc); 1045209917Sthompsa for (i = sc->cmdq_exec; sc->cmdq[i].func && pending; 1046209917Sthompsa i = sc->cmdq_exec, pending--) { 1047208019Sthompsa DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending); 1048209917Sthompsa if (sc->cmdq_run == RUN_CMDQ_GO) { 1049208019Sthompsa /* 1050208019Sthompsa * If arg0 is NULL, callback func needs more 1051208019Sthompsa * than one arg. So, pass ptr to cmdq struct. 1052208019Sthompsa */ 1053209917Sthompsa if (sc->cmdq[i].arg0) 1054208019Sthompsa sc->cmdq[i].func(sc->cmdq[i].arg0); 1055208019Sthompsa else 1056208019Sthompsa sc->cmdq[i].func(&sc->cmdq[i]); 1057208019Sthompsa } 1058208019Sthompsa sc->cmdq[i].arg0 = NULL; 1059208019Sthompsa sc->cmdq[i].func = NULL; 1060208019Sthompsa sc->cmdq_exec++; 1061208019Sthompsa sc->cmdq_exec &= RUN_CMDQ_MASQ; 1062208019Sthompsa } 1063208019Sthompsa RUN_UNLOCK(sc); 1064208019Sthompsa} 1065208019Sthompsa 1066208019Sthompsastatic void 1067203134Sthompsarun_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq) 1068203134Sthompsa{ 1069203134Sthompsa struct run_tx_data *data; 1070203134Sthompsa 1071203134Sthompsa memset(pq, 0, sizeof(*pq)); 1072203134Sthompsa 1073203134Sthompsa STAILQ_INIT(&pq->tx_qh); 1074203134Sthompsa STAILQ_INIT(&pq->tx_fh); 1075203134Sthompsa 1076203134Sthompsa for (data = &pq->tx_data[0]; 1077203134Sthompsa data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) { 1078203134Sthompsa data->sc = sc; 1079203134Sthompsa STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); 1080203134Sthompsa } 1081203134Sthompsa pq->tx_nfree = RUN_TX_RING_COUNT; 1082203134Sthompsa} 1083203134Sthompsa 1084203134Sthompsastatic void 1085203134Sthompsarun_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq) 1086203134Sthompsa{ 1087203134Sthompsa struct run_tx_data *data; 1088203134Sthompsa 1089203134Sthompsa /* make sure any subsequent use of the queues will fail */ 1090203134Sthompsa pq->tx_nfree = 0; 1091203134Sthompsa STAILQ_INIT(&pq->tx_fh); 1092203134Sthompsa STAILQ_INIT(&pq->tx_qh); 1093203134Sthompsa 1094203134Sthompsa /* free up all node references and mbufs */ 1095203134Sthompsa for (data = &pq->tx_data[0]; 1096209917Sthompsa data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) { 1097203134Sthompsa if (data->m != NULL) { 1098203134Sthompsa m_freem(data->m); 1099203134Sthompsa data->m = NULL; 1100203134Sthompsa } 1101203134Sthompsa if (data->ni != NULL) { 1102203134Sthompsa ieee80211_free_node(data->ni); 1103203134Sthompsa data->ni = NULL; 1104203134Sthompsa } 1105203134Sthompsa } 1106203134Sthompsa} 1107203134Sthompsa 1108220235Skevlostatic int 1109203134Sthompsarun_load_microcode(struct run_softc *sc) 1110203134Sthompsa{ 1111203134Sthompsa usb_device_request_t req; 1112203137Sthompsa const struct firmware *fw; 1113203134Sthompsa const u_char *base; 1114203134Sthompsa uint32_t tmp; 1115203134Sthompsa int ntries, error; 1116203134Sthompsa const uint64_t *temp; 1117203134Sthompsa uint64_t bytes; 1118203134Sthompsa 1119205042Sthompsa RUN_UNLOCK(sc); 1120203137Sthompsa fw = firmware_get("runfw"); 1121205042Sthompsa RUN_LOCK(sc); 1122209917Sthompsa if (fw == NULL) { 1123203138Sthompsa device_printf(sc->sc_dev, 1124203138Sthompsa "failed loadfirmware of file %s\n", "runfw"); 1125203134Sthompsa return ENOENT; 1126203134Sthompsa } 1127203134Sthompsa 1128203137Sthompsa if (fw->datasize != 8192) { 1129203138Sthompsa device_printf(sc->sc_dev, 1130203138Sthompsa "invalid firmware size (should be 8KB)\n"); 1131203137Sthompsa error = EINVAL; 1132203137Sthompsa goto fail; 1133203134Sthompsa } 1134203134Sthompsa 1135203134Sthompsa /* 1136203134Sthompsa * RT3071/RT3072 use a different firmware 1137203134Sthompsa * run-rt2870 (8KB) contains both, 1138203134Sthompsa * first half (4KB) is for rt2870, 1139203134Sthompsa * last half is for rt3071. 1140203134Sthompsa */ 1141203137Sthompsa base = fw->data; 1142205042Sthompsa if ((sc->mac_ver) != 0x2860 && 1143205042Sthompsa (sc->mac_ver) != 0x2872 && 1144209917Sthompsa (sc->mac_ver) != 0x3070) { 1145203134Sthompsa base += 4096; 1146205042Sthompsa } 1147203134Sthompsa 1148203134Sthompsa /* cheap sanity check */ 1149203137Sthompsa temp = fw->data; 1150203134Sthompsa bytes = *temp; 1151259453Shselasky if (bytes != be64toh(0xffffff0210280210ULL)) { 1152203138Sthompsa device_printf(sc->sc_dev, "firmware checksum failed\n"); 1153203137Sthompsa error = EINVAL; 1154203137Sthompsa goto fail; 1155203137Sthompsa } 1156203134Sthompsa 1157203134Sthompsa /* write microcode image */ 1158262604Skevlo if (sc->sc_flags & RUN_FLAG_FWLOAD_NEEDED) { 1159261868Skevlo run_write_region_1(sc, RT2870_FW_BASE, base, 4096); 1160261868Skevlo run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff); 1161261868Skevlo run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff); 1162261868Skevlo } 1163203134Sthompsa 1164203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1165203134Sthompsa req.bRequest = RT2870_RESET; 1166203134Sthompsa USETW(req.wValue, 8); 1167203134Sthompsa USETW(req.wIndex, 0); 1168203134Sthompsa USETW(req.wLength, 0); 1169220235Skevlo if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)) 1170220235Skevlo != 0) { 1171203138Sthompsa device_printf(sc->sc_dev, "firmware reset failed\n"); 1172203137Sthompsa goto fail; 1173203137Sthompsa } 1174203134Sthompsa 1175203134Sthompsa run_delay(sc, 10); 1176203134Sthompsa 1177261868Skevlo run_write(sc, RT2860_H2M_BBPAGENT, 0); 1178203134Sthompsa run_write(sc, RT2860_H2M_MAILBOX, 0); 1179261868Skevlo run_write(sc, RT2860_H2M_INTSRC, 0); 1180205042Sthompsa if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0) 1181203137Sthompsa goto fail; 1182203134Sthompsa 1183203134Sthompsa /* wait until microcontroller is ready */ 1184203134Sthompsa for (ntries = 0; ntries < 1000; ntries++) { 1185261868Skevlo if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0) 1186203137Sthompsa goto fail; 1187203134Sthompsa if (tmp & RT2860_MCU_READY) 1188203134Sthompsa break; 1189203134Sthompsa run_delay(sc, 10); 1190203134Sthompsa } 1191203134Sthompsa if (ntries == 1000) { 1192203138Sthompsa device_printf(sc->sc_dev, 1193203138Sthompsa "timeout waiting for MCU to initialize\n"); 1194203137Sthompsa error = ETIMEDOUT; 1195203137Sthompsa goto fail; 1196203134Sthompsa } 1197233283Sbschmidt device_printf(sc->sc_dev, "firmware %s ver. %u.%u loaded\n", 1198233283Sbschmidt (base == fw->data) ? "RT2870" : "RT3071", 1199233283Sbschmidt *(base + 4092), *(base + 4093)); 1200203134Sthompsa 1201203137Sthompsafail: 1202203137Sthompsa firmware_put(fw, FIRMWARE_UNLOAD); 1203203137Sthompsa return (error); 1204203134Sthompsa} 1205203134Sthompsa 1206259453Shselaskystatic int 1207203134Sthompsarun_reset(struct run_softc *sc) 1208203134Sthompsa{ 1209203134Sthompsa usb_device_request_t req; 1210203134Sthompsa 1211203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1212203134Sthompsa req.bRequest = RT2870_RESET; 1213203134Sthompsa USETW(req.wValue, 1); 1214203134Sthompsa USETW(req.wIndex, 0); 1215203134Sthompsa USETW(req.wLength, 0); 1216209917Sthompsa return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)); 1217203134Sthompsa} 1218203134Sthompsa 1219203134Sthompsastatic usb_error_t 1220203134Sthompsarun_do_request(struct run_softc *sc, 1221203134Sthompsa struct usb_device_request *req, void *data) 1222203134Sthompsa{ 1223203134Sthompsa usb_error_t err; 1224203134Sthompsa int ntries = 10; 1225203134Sthompsa 1226203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 1227203134Sthompsa 1228203134Sthompsa while (ntries--) { 1229203134Sthompsa err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, 1230203134Sthompsa req, data, 0, NULL, 250 /* ms */); 1231203134Sthompsa if (err == 0) 1232203134Sthompsa break; 1233203134Sthompsa DPRINTFN(1, "Control request failed, %s (retrying)\n", 1234203134Sthompsa usbd_errstr(err)); 1235203134Sthompsa run_delay(sc, 10); 1236203134Sthompsa } 1237203134Sthompsa return (err); 1238203134Sthompsa} 1239203134Sthompsa 1240203134Sthompsastatic int 1241203134Sthompsarun_read(struct run_softc *sc, uint16_t reg, uint32_t *val) 1242203134Sthompsa{ 1243203134Sthompsa uint32_t tmp; 1244203134Sthompsa int error; 1245203134Sthompsa 1246203134Sthompsa error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp); 1247203134Sthompsa if (error == 0) 1248203134Sthompsa *val = le32toh(tmp); 1249203134Sthompsa else 1250203134Sthompsa *val = 0xffffffff; 1251209917Sthompsa return (error); 1252203134Sthompsa} 1253203134Sthompsa 1254203134Sthompsastatic int 1255203134Sthompsarun_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len) 1256203134Sthompsa{ 1257203134Sthompsa usb_device_request_t req; 1258203134Sthompsa 1259203134Sthompsa req.bmRequestType = UT_READ_VENDOR_DEVICE; 1260203134Sthompsa req.bRequest = RT2870_READ_REGION_1; 1261203134Sthompsa USETW(req.wValue, 0); 1262203134Sthompsa USETW(req.wIndex, reg); 1263203134Sthompsa USETW(req.wLength, len); 1264203134Sthompsa 1265209917Sthompsa return (run_do_request(sc, &req, buf)); 1266203134Sthompsa} 1267203134Sthompsa 1268203134Sthompsastatic int 1269203134Sthompsarun_write_2(struct run_softc *sc, uint16_t reg, uint16_t val) 1270203134Sthompsa{ 1271203134Sthompsa usb_device_request_t req; 1272203134Sthompsa 1273203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1274203134Sthompsa req.bRequest = RT2870_WRITE_2; 1275203134Sthompsa USETW(req.wValue, val); 1276203134Sthompsa USETW(req.wIndex, reg); 1277203134Sthompsa USETW(req.wLength, 0); 1278203134Sthompsa 1279209917Sthompsa return (run_do_request(sc, &req, NULL)); 1280203134Sthompsa} 1281203134Sthompsa 1282203134Sthompsastatic int 1283203134Sthompsarun_write(struct run_softc *sc, uint16_t reg, uint32_t val) 1284203134Sthompsa{ 1285203134Sthompsa int error; 1286203134Sthompsa 1287203134Sthompsa if ((error = run_write_2(sc, reg, val & 0xffff)) == 0) 1288203134Sthompsa error = run_write_2(sc, reg + 2, val >> 16); 1289209917Sthompsa return (error); 1290203134Sthompsa} 1291203134Sthompsa 1292203134Sthompsastatic int 1293203134Sthompsarun_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf, 1294203134Sthompsa int len) 1295203134Sthompsa{ 1296203134Sthompsa#if 1 1297203134Sthompsa int i, error = 0; 1298203134Sthompsa /* 1299203134Sthompsa * NB: the WRITE_REGION_1 command is not stable on RT2860. 1300203134Sthompsa * We thus issue multiple WRITE_2 commands instead. 1301203134Sthompsa */ 1302203134Sthompsa KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n")); 1303203134Sthompsa for (i = 0; i < len && error == 0; i += 2) 1304203134Sthompsa error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8); 1305209917Sthompsa return (error); 1306203134Sthompsa#else 1307203134Sthompsa usb_device_request_t req; 1308259453Shselasky int error = 0; 1309203134Sthompsa 1310259453Shselasky /* 1311259453Shselasky * NOTE: It appears the WRITE_REGION_1 command cannot be 1312259453Shselasky * passed a huge amount of data, which will crash the 1313259453Shselasky * firmware. Limit amount of data passed to 64-bytes at a 1314259453Shselasky * time. 1315259453Shselasky */ 1316259453Shselasky while (len > 0) { 1317259453Shselasky int delta = 64; 1318259453Shselasky if (delta > len) 1319259453Shselasky delta = len; 1320259453Shselasky 1321259453Shselasky req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1322259453Shselasky req.bRequest = RT2870_WRITE_REGION_1; 1323259453Shselasky USETW(req.wValue, 0); 1324259453Shselasky USETW(req.wIndex, reg); 1325259453Shselasky USETW(req.wLength, delta); 1326259453Shselasky error = run_do_request(sc, &req, __DECONST(uint8_t *, buf)); 1327259453Shselasky if (error != 0) 1328259453Shselasky break; 1329259453Shselasky reg += delta; 1330259453Shselasky buf += delta; 1331259453Shselasky len -= delta; 1332259453Shselasky } 1333259453Shselasky return (error); 1334203134Sthompsa#endif 1335203134Sthompsa} 1336203134Sthompsa 1337203134Sthompsastatic int 1338203134Sthompsarun_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len) 1339203134Sthompsa{ 1340203134Sthompsa int i, error = 0; 1341203134Sthompsa 1342203134Sthompsa KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n")); 1343203134Sthompsa for (i = 0; i < len && error == 0; i += 4) 1344203134Sthompsa error = run_write(sc, reg + i, val); 1345209917Sthompsa return (error); 1346203134Sthompsa} 1347203134Sthompsa 1348203134Sthompsastatic int 1349261868Skevlorun_efuse_read(struct run_softc *sc, uint16_t addr, uint16_t *val, int count) 1350203134Sthompsa{ 1351203134Sthompsa uint32_t tmp; 1352203134Sthompsa uint16_t reg; 1353203134Sthompsa int error, ntries; 1354203134Sthompsa 1355203134Sthompsa if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0) 1356209917Sthompsa return (error); 1357203134Sthompsa 1358261868Skevlo if (count == 2) 1359261868Skevlo addr *= 2; 1360203134Sthompsa /*- 1361203134Sthompsa * Read one 16-byte block into registers EFUSE_DATA[0-3]: 1362203134Sthompsa * DATA0: F E D C 1363203134Sthompsa * DATA1: B A 9 8 1364203134Sthompsa * DATA2: 7 6 5 4 1365203134Sthompsa * DATA3: 3 2 1 0 1366203134Sthompsa */ 1367203134Sthompsa tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK); 1368203134Sthompsa tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK; 1369203134Sthompsa run_write(sc, RT3070_EFUSE_CTRL, tmp); 1370203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1371203134Sthompsa if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0) 1372209917Sthompsa return (error); 1373203134Sthompsa if (!(tmp & RT3070_EFSROM_KICK)) 1374203134Sthompsa break; 1375203134Sthompsa run_delay(sc, 2); 1376203134Sthompsa } 1377203134Sthompsa if (ntries == 100) 1378209917Sthompsa return (ETIMEDOUT); 1379203134Sthompsa 1380203134Sthompsa if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) { 1381203134Sthompsa *val = 0xffff; /* address not found */ 1382209917Sthompsa return (0); 1383203134Sthompsa } 1384203134Sthompsa /* determine to which 32-bit register our 16-bit word belongs */ 1385203134Sthompsa reg = RT3070_EFUSE_DATA3 - (addr & 0xc); 1386203134Sthompsa if ((error = run_read(sc, reg, &tmp)) != 0) 1387209917Sthompsa return (error); 1388203134Sthompsa 1389261868Skevlo tmp >>= (8 * (addr & 0x3)); 1390261868Skevlo *val = (addr & 1) ? tmp >> 16 : tmp & 0xffff; 1391261868Skevlo 1392209917Sthompsa return (0); 1393203134Sthompsa} 1394203134Sthompsa 1395261868Skevlo/* Read 16-bit from eFUSE ROM for RT3xxx. */ 1396203134Sthompsastatic int 1397261868Skevlorun_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val) 1398261868Skevlo{ 1399261868Skevlo return (run_efuse_read(sc, addr, val, 2)); 1400261868Skevlo} 1401261868Skevlo 1402261868Skevlostatic int 1403203134Sthompsarun_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val) 1404203134Sthompsa{ 1405203134Sthompsa usb_device_request_t req; 1406203134Sthompsa uint16_t tmp; 1407203134Sthompsa int error; 1408203134Sthompsa 1409203134Sthompsa addr *= 2; 1410203134Sthompsa req.bmRequestType = UT_READ_VENDOR_DEVICE; 1411203134Sthompsa req.bRequest = RT2870_EEPROM_READ; 1412203134Sthompsa USETW(req.wValue, 0); 1413203134Sthompsa USETW(req.wIndex, addr); 1414261868Skevlo USETW(req.wLength, sizeof(tmp)); 1415203134Sthompsa 1416203134Sthompsa error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp); 1417203134Sthompsa if (error == 0) 1418203134Sthompsa *val = le16toh(tmp); 1419203134Sthompsa else 1420203134Sthompsa *val = 0xffff; 1421209917Sthompsa return (error); 1422203134Sthompsa} 1423203134Sthompsa 1424203134Sthompsastatic __inline int 1425203134Sthompsarun_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val) 1426203134Sthompsa{ 1427203134Sthompsa /* either eFUSE ROM or EEPROM */ 1428203134Sthompsa return sc->sc_srom_read(sc, addr, val); 1429203134Sthompsa} 1430203134Sthompsa 1431203134Sthompsastatic int 1432259453Shselaskyrun_rt2870_rf_write(struct run_softc *sc, uint32_t val) 1433203134Sthompsa{ 1434203134Sthompsa uint32_t tmp; 1435203134Sthompsa int error, ntries; 1436203134Sthompsa 1437203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1438203134Sthompsa if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0) 1439209917Sthompsa return (error); 1440203134Sthompsa if (!(tmp & RT2860_RF_REG_CTRL)) 1441203134Sthompsa break; 1442203134Sthompsa } 1443203134Sthompsa if (ntries == 10) 1444209917Sthompsa return (ETIMEDOUT); 1445203134Sthompsa 1446259453Shselasky return (run_write(sc, RT2860_RF_CSR_CFG0, val)); 1447203134Sthompsa} 1448203134Sthompsa 1449203134Sthompsastatic int 1450203134Sthompsarun_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val) 1451203134Sthompsa{ 1452203134Sthompsa uint32_t tmp; 1453203134Sthompsa int error, ntries; 1454203134Sthompsa 1455203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1456203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1457209917Sthompsa return (error); 1458203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1459203134Sthompsa break; 1460203134Sthompsa } 1461203134Sthompsa if (ntries == 100) 1462209917Sthompsa return (ETIMEDOUT); 1463203134Sthompsa 1464203134Sthompsa tmp = RT3070_RF_KICK | reg << 8; 1465203134Sthompsa if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0) 1466209917Sthompsa return (error); 1467203134Sthompsa 1468203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1469203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1470209917Sthompsa return (error); 1471203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1472203134Sthompsa break; 1473203134Sthompsa } 1474203134Sthompsa if (ntries == 100) 1475209917Sthompsa return (ETIMEDOUT); 1476203134Sthompsa 1477203134Sthompsa *val = tmp & 0xff; 1478209917Sthompsa return (0); 1479203134Sthompsa} 1480203134Sthompsa 1481203134Sthompsastatic int 1482203134Sthompsarun_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val) 1483203134Sthompsa{ 1484203134Sthompsa uint32_t tmp; 1485203134Sthompsa int error, ntries; 1486203134Sthompsa 1487203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1488203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1489209917Sthompsa return (error); 1490203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1491203134Sthompsa break; 1492203134Sthompsa } 1493203134Sthompsa if (ntries == 10) 1494209917Sthompsa return (ETIMEDOUT); 1495203134Sthompsa 1496203134Sthompsa tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val; 1497209917Sthompsa return (run_write(sc, RT3070_RF_CSR_CFG, tmp)); 1498203134Sthompsa} 1499203134Sthompsa 1500203134Sthompsastatic int 1501203134Sthompsarun_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val) 1502203134Sthompsa{ 1503203134Sthompsa uint32_t tmp; 1504203134Sthompsa int ntries, error; 1505203134Sthompsa 1506203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1507203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1508209917Sthompsa return (error); 1509203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1510203134Sthompsa break; 1511203134Sthompsa } 1512203134Sthompsa if (ntries == 10) 1513209917Sthompsa return (ETIMEDOUT); 1514203134Sthompsa 1515203134Sthompsa tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8; 1516203134Sthompsa if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0) 1517209917Sthompsa return (error); 1518203134Sthompsa 1519203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1520203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1521209917Sthompsa return (error); 1522203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1523203134Sthompsa break; 1524203134Sthompsa } 1525203134Sthompsa if (ntries == 10) 1526209917Sthompsa return (ETIMEDOUT); 1527203134Sthompsa 1528203134Sthompsa *val = tmp & 0xff; 1529209917Sthompsa return (0); 1530203134Sthompsa} 1531203134Sthompsa 1532203134Sthompsastatic int 1533203134Sthompsarun_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val) 1534203134Sthompsa{ 1535203134Sthompsa uint32_t tmp; 1536203134Sthompsa int ntries, error; 1537203134Sthompsa 1538203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1539203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1540209917Sthompsa return (error); 1541203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1542203134Sthompsa break; 1543203134Sthompsa } 1544203134Sthompsa if (ntries == 10) 1545209917Sthompsa return (ETIMEDOUT); 1546203134Sthompsa 1547203134Sthompsa tmp = RT2860_BBP_CSR_KICK | reg << 8 | val; 1548209917Sthompsa return (run_write(sc, RT2860_BBP_CSR_CFG, tmp)); 1549203134Sthompsa} 1550203134Sthompsa 1551203134Sthompsa/* 1552203134Sthompsa * Send a command to the 8051 microcontroller unit. 1553203134Sthompsa */ 1554203134Sthompsastatic int 1555203134Sthompsarun_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg) 1556203134Sthompsa{ 1557203134Sthompsa uint32_t tmp; 1558203134Sthompsa int error, ntries; 1559203134Sthompsa 1560203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1561203134Sthompsa if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0) 1562203134Sthompsa return error; 1563203134Sthompsa if (!(tmp & RT2860_H2M_BUSY)) 1564203134Sthompsa break; 1565203134Sthompsa } 1566203134Sthompsa if (ntries == 100) 1567203134Sthompsa return ETIMEDOUT; 1568203134Sthompsa 1569203134Sthompsa tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg; 1570203134Sthompsa if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0) 1571203134Sthompsa error = run_write(sc, RT2860_HOST_CMD, cmd); 1572209917Sthompsa return (error); 1573203134Sthompsa} 1574203134Sthompsa 1575203134Sthompsa/* 1576203134Sthompsa * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word. 1577203134Sthompsa * Used to adjust per-rate Tx power registers. 1578203134Sthompsa */ 1579203134Sthompsastatic __inline uint32_t 1580203134Sthompsab4inc(uint32_t b32, int8_t delta) 1581203134Sthompsa{ 1582203134Sthompsa int8_t i, b4; 1583203134Sthompsa 1584203134Sthompsa for (i = 0; i < 8; i++) { 1585203134Sthompsa b4 = b32 & 0xf; 1586203134Sthompsa b4 += delta; 1587203134Sthompsa if (b4 < 0) 1588203134Sthompsa b4 = 0; 1589203134Sthompsa else if (b4 > 0xf) 1590203134Sthompsa b4 = 0xf; 1591203134Sthompsa b32 = b32 >> 4 | b4 << 28; 1592203134Sthompsa } 1593209917Sthompsa return (b32); 1594203134Sthompsa} 1595203134Sthompsa 1596203134Sthompsastatic const char * 1597259453Shselaskyrun_get_rf(uint16_t rev) 1598203134Sthompsa{ 1599203134Sthompsa switch (rev) { 1600203134Sthompsa case RT2860_RF_2820: return "RT2820"; 1601203134Sthompsa case RT2860_RF_2850: return "RT2850"; 1602203134Sthompsa case RT2860_RF_2720: return "RT2720"; 1603203134Sthompsa case RT2860_RF_2750: return "RT2750"; 1604203134Sthompsa case RT3070_RF_3020: return "RT3020"; 1605203134Sthompsa case RT3070_RF_2020: return "RT2020"; 1606203134Sthompsa case RT3070_RF_3021: return "RT3021"; 1607203134Sthompsa case RT3070_RF_3022: return "RT3022"; 1608203134Sthompsa case RT3070_RF_3052: return "RT3052"; 1609261868Skevlo case RT3593_RF_3053: return "RT3053"; 1610259453Shselasky case RT5592_RF_5592: return "RT5592"; 1611259453Shselasky case RT5390_RF_5370: return "RT5370"; 1612259453Shselasky case RT5390_RF_5372: return "RT5372"; 1613203134Sthompsa } 1614209917Sthompsa return ("unknown"); 1615203134Sthompsa} 1616203134Sthompsa 1617261868Skevlostatic void 1618261868Skevlorun_rt3593_get_txpower(struct run_softc *sc) 1619261868Skevlo{ 1620261868Skevlo uint16_t addr, val; 1621261868Skevlo int i; 1622261868Skevlo 1623261868Skevlo /* Read power settings for 2GHz channels. */ 1624261868Skevlo for (i = 0; i < 14; i += 2) { 1625261868Skevlo addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE1 : 1626261868Skevlo RT2860_EEPROM_PWR2GHZ_BASE1; 1627261868Skevlo run_srom_read(sc, addr + i / 2, &val); 1628261868Skevlo sc->txpow1[i + 0] = (int8_t)(val & 0xff); 1629261868Skevlo sc->txpow1[i + 1] = (int8_t)(val >> 8); 1630261868Skevlo 1631261868Skevlo addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE2 : 1632261868Skevlo RT2860_EEPROM_PWR2GHZ_BASE2; 1633261868Skevlo run_srom_read(sc, addr + i / 2, &val); 1634261868Skevlo sc->txpow2[i + 0] = (int8_t)(val & 0xff); 1635261868Skevlo sc->txpow2[i + 1] = (int8_t)(val >> 8); 1636261868Skevlo 1637261868Skevlo if (sc->ntxchains == 3) { 1638261868Skevlo run_srom_read(sc, RT3593_EEPROM_PWR2GHZ_BASE3 + i / 2, 1639261868Skevlo &val); 1640261868Skevlo sc->txpow3[i + 0] = (int8_t)(val & 0xff); 1641261868Skevlo sc->txpow3[i + 1] = (int8_t)(val >> 8); 1642261868Skevlo } 1643261868Skevlo } 1644261868Skevlo /* Fix broken Tx power entries. */ 1645261868Skevlo for (i = 0; i < 14; i++) { 1646261868Skevlo if (sc->txpow1[i] > 31) 1647261868Skevlo sc->txpow1[i] = 5; 1648261868Skevlo if (sc->txpow2[i] > 31) 1649261868Skevlo sc->txpow2[i] = 5; 1650261868Skevlo if (sc->ntxchains == 3) { 1651261868Skevlo if (sc->txpow3[i] > 31) 1652261868Skevlo sc->txpow3[i] = 5; 1653261868Skevlo } 1654261868Skevlo } 1655261868Skevlo /* Read power settings for 5GHz channels. */ 1656261868Skevlo for (i = 0; i < 40; i += 2) { 1657261868Skevlo run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE1 + i / 2, &val); 1658261868Skevlo sc->txpow1[i + 14] = (int8_t)(val & 0xff); 1659261868Skevlo sc->txpow1[i + 15] = (int8_t)(val >> 8); 1660261868Skevlo 1661261868Skevlo run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE2 + i / 2, &val); 1662261868Skevlo sc->txpow2[i + 14] = (int8_t)(val & 0xff); 1663261868Skevlo sc->txpow2[i + 15] = (int8_t)(val >> 8); 1664261868Skevlo 1665261868Skevlo if (sc->ntxchains == 3) { 1666261868Skevlo run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE3 + i / 2, 1667261868Skevlo &val); 1668261868Skevlo sc->txpow3[i + 14] = (int8_t)(val & 0xff); 1669261868Skevlo sc->txpow3[i + 15] = (int8_t)(val >> 8); 1670261868Skevlo } 1671261868Skevlo } 1672261868Skevlo} 1673261868Skevlo 1674261868Skevlostatic void 1675261868Skevlorun_get_txpower(struct run_softc *sc) 1676261868Skevlo{ 1677261868Skevlo uint16_t val; 1678261868Skevlo int i; 1679261868Skevlo 1680261868Skevlo /* Read power settings for 2GHz channels. */ 1681261868Skevlo for (i = 0; i < 14; i += 2) { 1682261868Skevlo run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val); 1683261868Skevlo sc->txpow1[i + 0] = (int8_t)(val & 0xff); 1684261868Skevlo sc->txpow1[i + 1] = (int8_t)(val >> 8); 1685261868Skevlo 1686261868Skevlo if (sc->mac_ver != 0x5390) { 1687261868Skevlo run_srom_read(sc, 1688261868Skevlo RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val); 1689261868Skevlo sc->txpow2[i + 0] = (int8_t)(val & 0xff); 1690261868Skevlo sc->txpow2[i + 1] = (int8_t)(val >> 8); 1691261868Skevlo } 1692261868Skevlo } 1693261868Skevlo /* Fix broken Tx power entries. */ 1694261868Skevlo for (i = 0; i < 14; i++) { 1695261868Skevlo if (sc->mac_ver >= 0x5390) { 1696261868Skevlo if (sc->txpow1[i] < 0 || sc->txpow1[i] > 27) 1697261868Skevlo sc->txpow1[i] = 5; 1698261868Skevlo } else { 1699261868Skevlo if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31) 1700261868Skevlo sc->txpow1[i] = 5; 1701261868Skevlo } 1702261868Skevlo if (sc->mac_ver > 0x5390) { 1703261868Skevlo if (sc->txpow2[i] < 0 || sc->txpow2[i] > 27) 1704261868Skevlo sc->txpow2[i] = 5; 1705261868Skevlo } else if (sc->mac_ver < 0x5390) { 1706261868Skevlo if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31) 1707261868Skevlo sc->txpow2[i] = 5; 1708261868Skevlo } 1709261868Skevlo DPRINTF("chan %d: power1=%d, power2=%d\n", 1710261868Skevlo rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]); 1711261868Skevlo } 1712261868Skevlo /* Read power settings for 5GHz channels. */ 1713261868Skevlo for (i = 0; i < 40; i += 2) { 1714261868Skevlo run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val); 1715261868Skevlo sc->txpow1[i + 14] = (int8_t)(val & 0xff); 1716261868Skevlo sc->txpow1[i + 15] = (int8_t)(val >> 8); 1717261868Skevlo 1718261868Skevlo run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val); 1719261868Skevlo sc->txpow2[i + 14] = (int8_t)(val & 0xff); 1720261868Skevlo sc->txpow2[i + 15] = (int8_t)(val >> 8); 1721261868Skevlo } 1722261868Skevlo /* Fix broken Tx power entries. */ 1723261868Skevlo for (i = 0; i < 40; i++ ) { 1724261868Skevlo if (sc->mac_ver != 0x5592) { 1725261868Skevlo if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15) 1726261868Skevlo sc->txpow1[14 + i] = 5; 1727261868Skevlo if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15) 1728261868Skevlo sc->txpow2[14 + i] = 5; 1729261868Skevlo } 1730261868Skevlo DPRINTF("chan %d: power1=%d, power2=%d\n", 1731261868Skevlo rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i], 1732261868Skevlo sc->txpow2[14 + i]); 1733261868Skevlo } 1734261868Skevlo} 1735261868Skevlo 1736259453Shselaskystatic int 1737203134Sthompsarun_read_eeprom(struct run_softc *sc) 1738203134Sthompsa{ 1739203134Sthompsa int8_t delta_2ghz, delta_5ghz; 1740203134Sthompsa uint32_t tmp; 1741203134Sthompsa uint16_t val; 1742203134Sthompsa int ridx, ant, i; 1743203134Sthompsa 1744203134Sthompsa /* check whether the ROM is eFUSE ROM or EEPROM */ 1745203134Sthompsa sc->sc_srom_read = run_eeprom_read_2; 1746205042Sthompsa if (sc->mac_ver >= 0x3070) { 1747203134Sthompsa run_read(sc, RT3070_EFUSE_CTRL, &tmp); 1748203134Sthompsa DPRINTF("EFUSE_CTRL=0x%08x\n", tmp); 1749261868Skevlo if ((tmp & RT3070_SEL_EFUSE) || sc->mac_ver == 0x3593) 1750203134Sthompsa sc->sc_srom_read = run_efuse_read_2; 1751203134Sthompsa } 1752203134Sthompsa 1753203134Sthompsa /* read ROM version */ 1754203134Sthompsa run_srom_read(sc, RT2860_EEPROM_VERSION, &val); 1755203134Sthompsa DPRINTF("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8); 1756203134Sthompsa 1757203134Sthompsa /* read MAC address */ 1758203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC01, &val); 1759203134Sthompsa sc->sc_bssid[0] = val & 0xff; 1760203134Sthompsa sc->sc_bssid[1] = val >> 8; 1761203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC23, &val); 1762203134Sthompsa sc->sc_bssid[2] = val & 0xff; 1763203134Sthompsa sc->sc_bssid[3] = val >> 8; 1764203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC45, &val); 1765203134Sthompsa sc->sc_bssid[4] = val & 0xff; 1766203134Sthompsa sc->sc_bssid[5] = val >> 8; 1767203134Sthompsa 1768261868Skevlo if (sc->mac_ver < 0x3593) { 1769259453Shselasky /* read vender BBP settings */ 1770205042Sthompsa for (i = 0; i < 10; i++) { 1771259453Shselasky run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val); 1772259453Shselasky sc->bbp[i].val = val & 0xff; 1773259453Shselasky sc->bbp[i].reg = val >> 8; 1774259453Shselasky DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg, 1775259453Shselasky sc->bbp[i].val); 1776205042Sthompsa } 1777259453Shselasky if (sc->mac_ver >= 0x3071) { 1778259453Shselasky /* read vendor RF settings */ 1779259453Shselasky for (i = 0; i < 10; i++) { 1780259453Shselasky run_srom_read(sc, RT3071_EEPROM_RF_BASE + i, 1781259453Shselasky &val); 1782259453Shselasky sc->rf[i].val = val & 0xff; 1783259453Shselasky sc->rf[i].reg = val >> 8; 1784259453Shselasky DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg, 1785259453Shselasky sc->rf[i].val); 1786259453Shselasky } 1787259453Shselasky } 1788205042Sthompsa } 1789203134Sthompsa 1790203134Sthompsa /* read RF frequency offset from EEPROM */ 1791261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS : 1792261868Skevlo RT3593_EEPROM_FREQ, &val); 1793203134Sthompsa sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0; 1794203134Sthompsa DPRINTF("EEPROM freq offset %d\n", sc->freq & 0xff); 1795203134Sthompsa 1796261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS : 1797261868Skevlo RT3593_EEPROM_FREQ_LEDS, &val); 1798205042Sthompsa if (val >> 8 != 0xff) { 1799203134Sthompsa /* read LEDs operating mode */ 1800205042Sthompsa sc->leds = val >> 8; 1801261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED1 : 1802261868Skevlo RT3593_EEPROM_LED1, &sc->led[0]); 1803261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED2 : 1804261868Skevlo RT3593_EEPROM_LED2, &sc->led[1]); 1805261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED3 : 1806261868Skevlo RT3593_EEPROM_LED3, &sc->led[2]); 1807203134Sthompsa } else { 1808203134Sthompsa /* broken EEPROM, use default settings */ 1809203134Sthompsa sc->leds = 0x01; 1810203134Sthompsa sc->led[0] = 0x5555; 1811203134Sthompsa sc->led[1] = 0x2221; 1812203134Sthompsa sc->led[2] = 0x5627; /* differs from RT2860 */ 1813203134Sthompsa } 1814203134Sthompsa DPRINTF("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n", 1815203134Sthompsa sc->leds, sc->led[0], sc->led[1], sc->led[2]); 1816203134Sthompsa 1817203134Sthompsa /* read RF information */ 1818259453Shselasky if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) 1819259453Shselasky run_srom_read(sc, 0x00, &val); 1820259453Shselasky else 1821259453Shselasky run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val); 1822259453Shselasky 1823203134Sthompsa if (val == 0xffff) { 1824261868Skevlo device_printf(sc->sc_dev, 1825261868Skevlo "invalid EEPROM antenna info, using default\n"); 1826203134Sthompsa DPRINTF("invalid EEPROM antenna info, using default\n"); 1827205042Sthompsa if (sc->mac_ver == 0x3572) { 1828205042Sthompsa /* default to RF3052 2T2R */ 1829205042Sthompsa sc->rf_rev = RT3070_RF_3052; 1830205042Sthompsa sc->ntxchains = 2; 1831205042Sthompsa sc->nrxchains = 2; 1832205042Sthompsa } else if (sc->mac_ver >= 0x3070) { 1833203134Sthompsa /* default to RF3020 1T1R */ 1834203134Sthompsa sc->rf_rev = RT3070_RF_3020; 1835203134Sthompsa sc->ntxchains = 1; 1836203134Sthompsa sc->nrxchains = 1; 1837203134Sthompsa } else { 1838203134Sthompsa /* default to RF2820 1T2R */ 1839203134Sthompsa sc->rf_rev = RT2860_RF_2820; 1840203134Sthompsa sc->ntxchains = 1; 1841203134Sthompsa sc->nrxchains = 2; 1842203134Sthompsa } 1843203134Sthompsa } else { 1844259453Shselasky if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) { 1845259453Shselasky sc->rf_rev = val; 1846259453Shselasky run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val); 1847259453Shselasky } else 1848259453Shselasky sc->rf_rev = (val >> 8) & 0xf; 1849203134Sthompsa sc->ntxchains = (val >> 4) & 0xf; 1850203134Sthompsa sc->nrxchains = val & 0xf; 1851203134Sthompsa } 1852259453Shselasky DPRINTF("EEPROM RF rev=0x%04x chains=%dT%dR\n", 1853203134Sthompsa sc->rf_rev, sc->ntxchains, sc->nrxchains); 1854203134Sthompsa 1855208019Sthompsa /* check if RF supports automatic Tx access gain control */ 1856203134Sthompsa run_srom_read(sc, RT2860_EEPROM_CONFIG, &val); 1857203134Sthompsa DPRINTF("EEPROM CFG 0x%04x\n", val); 1858205042Sthompsa /* check if driver should patch the DAC issue */ 1859205042Sthompsa if ((val >> 8) != 0xff) 1860205042Sthompsa sc->patch_dac = (val >> 15) & 1; 1861203134Sthompsa if ((val & 0xff) != 0xff) { 1862203134Sthompsa sc->ext_5ghz_lna = (val >> 3) & 1; 1863203134Sthompsa sc->ext_2ghz_lna = (val >> 2) & 1; 1864205042Sthompsa /* check if RF supports automatic Tx access gain control */ 1865203134Sthompsa sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1; 1866205042Sthompsa /* check if we have a hardware radio switch */ 1867205042Sthompsa sc->rfswitch = val & 1; 1868203134Sthompsa } 1869203134Sthompsa 1870261868Skevlo /* Read Tx power settings. */ 1871261868Skevlo if (sc->mac_ver == 0x3593) 1872261868Skevlo run_rt3593_get_txpower(sc); 1873261868Skevlo else 1874261868Skevlo run_get_txpower(sc); 1875203134Sthompsa 1876203134Sthompsa /* read Tx power compensation for each Tx rate */ 1877203134Sthompsa run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val); 1878203134Sthompsa delta_2ghz = delta_5ghz = 0; 1879203134Sthompsa if ((val & 0xff) != 0xff && (val & 0x80)) { 1880203134Sthompsa delta_2ghz = val & 0xf; 1881203134Sthompsa if (!(val & 0x40)) /* negative number */ 1882203134Sthompsa delta_2ghz = -delta_2ghz; 1883203134Sthompsa } 1884203134Sthompsa val >>= 8; 1885203134Sthompsa if ((val & 0xff) != 0xff && (val & 0x80)) { 1886203134Sthompsa delta_5ghz = val & 0xf; 1887203134Sthompsa if (!(val & 0x40)) /* negative number */ 1888203134Sthompsa delta_5ghz = -delta_5ghz; 1889203134Sthompsa } 1890203134Sthompsa DPRINTF("power compensation=%d (2GHz), %d (5GHz)\n", 1891203134Sthompsa delta_2ghz, delta_5ghz); 1892203134Sthompsa 1893203134Sthompsa for (ridx = 0; ridx < 5; ridx++) { 1894203134Sthompsa uint32_t reg; 1895203134Sthompsa 1896208019Sthompsa run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val); 1897208019Sthompsa reg = val; 1898208019Sthompsa run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val); 1899208019Sthompsa reg |= (uint32_t)val << 16; 1900203134Sthompsa 1901203134Sthompsa sc->txpow20mhz[ridx] = reg; 1902203134Sthompsa sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz); 1903203134Sthompsa sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz); 1904203134Sthompsa 1905203134Sthompsa DPRINTF("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, " 1906203134Sthompsa "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx], 1907203134Sthompsa sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]); 1908203134Sthompsa } 1909203134Sthompsa 1910261868Skevlo /* Read RSSI offsets and LNA gains from EEPROM. */ 1911261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_2GHZ : 1912261868Skevlo RT3593_EEPROM_RSSI1_2GHZ, &val); 1913203134Sthompsa sc->rssi_2ghz[0] = val & 0xff; /* Ant A */ 1914203134Sthompsa sc->rssi_2ghz[1] = val >> 8; /* Ant B */ 1915261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_2GHZ : 1916261868Skevlo RT3593_EEPROM_RSSI2_2GHZ, &val); 1917205042Sthompsa if (sc->mac_ver >= 0x3070) { 1918261868Skevlo if (sc->mac_ver == 0x3593) { 1919261868Skevlo sc->txmixgain_2ghz = 0; 1920261868Skevlo sc->rssi_2ghz[2] = val & 0xff; /* Ant C */ 1921261868Skevlo } else { 1922261868Skevlo /* 1923261868Skevlo * On RT3070 chips (limited to 2 Rx chains), this ROM 1924261868Skevlo * field contains the Tx mixer gain for the 2GHz band. 1925261868Skevlo */ 1926261868Skevlo if ((val & 0xff) != 0xff) 1927261868Skevlo sc->txmixgain_2ghz = val & 0x7; 1928261868Skevlo } 1929205042Sthompsa DPRINTF("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz); 1930205042Sthompsa } else 1931205042Sthompsa sc->rssi_2ghz[2] = val & 0xff; /* Ant C */ 1932261868Skevlo if (sc->mac_ver == 0x3593) 1933261868Skevlo run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val); 1934203134Sthompsa sc->lna[2] = val >> 8; /* channel group 2 */ 1935203134Sthompsa 1936261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_5GHZ : 1937261868Skevlo RT3593_EEPROM_RSSI1_5GHZ, &val); 1938203134Sthompsa sc->rssi_5ghz[0] = val & 0xff; /* Ant A */ 1939203134Sthompsa sc->rssi_5ghz[1] = val >> 8; /* Ant B */ 1940261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_5GHZ : 1941261868Skevlo RT3593_EEPROM_RSSI2_5GHZ, &val); 1942205042Sthompsa if (sc->mac_ver == 0x3572) { 1943205042Sthompsa /* 1944205042Sthompsa * On RT3572 chips (limited to 2 Rx chains), this ROM 1945205042Sthompsa * field contains the Tx mixer gain for the 5GHz band. 1946205042Sthompsa */ 1947205042Sthompsa if ((val & 0xff) != 0xff) 1948205042Sthompsa sc->txmixgain_5ghz = val & 0x7; 1949205042Sthompsa DPRINTF("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz); 1950205042Sthompsa } else 1951205042Sthompsa sc->rssi_5ghz[2] = val & 0xff; /* Ant C */ 1952261868Skevlo if (sc->mac_ver == 0x3593) { 1953261868Skevlo sc->txmixgain_5ghz = 0; 1954261868Skevlo run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val); 1955261868Skevlo } 1956203134Sthompsa sc->lna[3] = val >> 8; /* channel group 3 */ 1957203134Sthompsa 1958261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LNA : 1959261868Skevlo RT3593_EEPROM_LNA, &val); 1960203134Sthompsa sc->lna[0] = val & 0xff; /* channel group 0 */ 1961203134Sthompsa sc->lna[1] = val >> 8; /* channel group 1 */ 1962203134Sthompsa 1963203134Sthompsa /* fix broken 5GHz LNA entries */ 1964203134Sthompsa if (sc->lna[2] == 0 || sc->lna[2] == 0xff) { 1965203134Sthompsa DPRINTF("invalid LNA for channel group %d\n", 2); 1966203134Sthompsa sc->lna[2] = sc->lna[1]; 1967203134Sthompsa } 1968203134Sthompsa if (sc->lna[3] == 0 || sc->lna[3] == 0xff) { 1969203134Sthompsa DPRINTF("invalid LNA for channel group %d\n", 3); 1970203134Sthompsa sc->lna[3] = sc->lna[1]; 1971203134Sthompsa } 1972203134Sthompsa 1973203134Sthompsa /* fix broken RSSI offset entries */ 1974203134Sthompsa for (ant = 0; ant < 3; ant++) { 1975203134Sthompsa if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) { 1976203134Sthompsa DPRINTF("invalid RSSI%d offset: %d (2GHz)\n", 1977203134Sthompsa ant + 1, sc->rssi_2ghz[ant]); 1978203134Sthompsa sc->rssi_2ghz[ant] = 0; 1979203134Sthompsa } 1980203134Sthompsa if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) { 1981203134Sthompsa DPRINTF("invalid RSSI%d offset: %d (5GHz)\n", 1982203134Sthompsa ant + 1, sc->rssi_5ghz[ant]); 1983203134Sthompsa sc->rssi_5ghz[ant] = 0; 1984203134Sthompsa } 1985203134Sthompsa } 1986209917Sthompsa return (0); 1987203134Sthompsa} 1988203134Sthompsa 1989218676Shselaskystatic struct ieee80211_node * 1990203134Sthompsarun_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) 1991203134Sthompsa{ 1992203134Sthompsa return malloc(sizeof (struct run_node), M_DEVBUF, M_NOWAIT | M_ZERO); 1993203134Sthompsa} 1994203134Sthompsa 1995203134Sthompsastatic int 1996203134Sthompsarun_media_change(struct ifnet *ifp) 1997203134Sthompsa{ 1998208019Sthompsa struct ieee80211vap *vap = ifp->if_softc; 1999208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 2000203134Sthompsa const struct ieee80211_txparam *tp; 2001208019Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2002203134Sthompsa uint8_t rate, ridx; 2003203134Sthompsa int error; 2004203134Sthompsa 2005203134Sthompsa RUN_LOCK(sc); 2006203134Sthompsa 2007203134Sthompsa error = ieee80211_media_change(ifp); 2008209917Sthompsa if (error != ENETRESET) { 2009203134Sthompsa RUN_UNLOCK(sc); 2010209917Sthompsa return (error); 2011208019Sthompsa } 2012203134Sthompsa 2013203134Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 2014203134Sthompsa if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 2015212127Sthompsa struct ieee80211_node *ni; 2016212127Sthompsa struct run_node *rn; 2017212127Sthompsa 2018203134Sthompsa rate = ic->ic_sup_rates[ic->ic_curmode]. 2019203134Sthompsa rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL; 2020203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2021203134Sthompsa if (rt2860_rates[ridx].rate == rate) 2022203134Sthompsa break; 2023212127Sthompsa ni = ieee80211_ref_node(vap->iv_bss); 2024212127Sthompsa rn = (struct run_node *)ni; 2025208019Sthompsa rn->fix_ridx = ridx; 2026208019Sthompsa DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx); 2027212127Sthompsa ieee80211_free_node(ni); 2028203134Sthompsa } 2029203134Sthompsa 2030208019Sthompsa#if 0 2031203134Sthompsa if ((ifp->if_flags & IFF_UP) && 2032203134Sthompsa (ifp->if_drv_flags & IFF_DRV_RUNNING)){ 2033203134Sthompsa run_init_locked(sc); 2034203134Sthompsa } 2035208019Sthompsa#endif 2036203134Sthompsa 2037203134Sthompsa RUN_UNLOCK(sc); 2038203134Sthompsa 2039209917Sthompsa return (0); 2040203134Sthompsa} 2041203134Sthompsa 2042203134Sthompsastatic int 2043203134Sthompsarun_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 2044203134Sthompsa{ 2045203134Sthompsa const struct ieee80211_txparam *tp; 2046203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2047203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2048203134Sthompsa struct run_vap *rvp = RUN_VAP(vap); 2049203134Sthompsa enum ieee80211_state ostate; 2050208019Sthompsa uint32_t sta[3]; 2051203134Sthompsa uint32_t tmp; 2052208019Sthompsa uint8_t ratectl; 2053208019Sthompsa uint8_t restart_ratectl = 0; 2054208019Sthompsa uint8_t bid = 1 << rvp->rvp_id; 2055203134Sthompsa 2056203134Sthompsa ostate = vap->iv_state; 2057203134Sthompsa DPRINTF("%s -> %s\n", 2058203134Sthompsa ieee80211_state_name[ostate], 2059203134Sthompsa ieee80211_state_name[nstate]); 2060203134Sthompsa 2061203134Sthompsa IEEE80211_UNLOCK(ic); 2062203134Sthompsa RUN_LOCK(sc); 2063203134Sthompsa 2064208019Sthompsa ratectl = sc->ratectl_run; /* remember current state */ 2065208019Sthompsa sc->ratectl_run = RUN_RATECTL_OFF; 2066208019Sthompsa usb_callout_stop(&sc->ratectl_ch); 2067203134Sthompsa 2068203134Sthompsa if (ostate == IEEE80211_S_RUN) { 2069203134Sthompsa /* turn link LED off */ 2070203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO); 2071203134Sthompsa } 2072203134Sthompsa 2073203134Sthompsa switch (nstate) { 2074203134Sthompsa case IEEE80211_S_INIT: 2075208019Sthompsa restart_ratectl = 1; 2076208019Sthompsa 2077208019Sthompsa if (ostate != IEEE80211_S_RUN) 2078208019Sthompsa break; 2079208019Sthompsa 2080208019Sthompsa ratectl &= ~bid; 2081208019Sthompsa sc->runbmap &= ~bid; 2082208019Sthompsa 2083208019Sthompsa /* abort TSF synchronization if there is no vap running */ 2084209917Sthompsa if (--sc->running == 0) { 2085203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 2086203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, 2087203134Sthompsa tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 2088203134Sthompsa RT2860_TBTT_TIMER_EN)); 2089203134Sthompsa } 2090203134Sthompsa break; 2091203134Sthompsa 2092203134Sthompsa case IEEE80211_S_RUN: 2093209917Sthompsa if (!(sc->runbmap & bid)) { 2094208019Sthompsa if(sc->running++) 2095208019Sthompsa restart_ratectl = 1; 2096208019Sthompsa sc->runbmap |= bid; 2097208019Sthompsa } 2098203134Sthompsa 2099218492Sbschmidt m_freem(rvp->beacon_mbuf); 2100218492Sbschmidt rvp->beacon_mbuf = NULL; 2101218492Sbschmidt 2102209917Sthompsa switch (vap->iv_opmode) { 2103208019Sthompsa case IEEE80211_M_HOSTAP: 2104208019Sthompsa case IEEE80211_M_MBSS: 2105208019Sthompsa sc->ap_running |= bid; 2106208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2107208019Sthompsa run_update_beacon_cb(vap); 2108208019Sthompsa break; 2109208019Sthompsa case IEEE80211_M_IBSS: 2110208019Sthompsa sc->adhoc_running |= bid; 2111209917Sthompsa if (!sc->ap_running) 2112208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2113208019Sthompsa run_update_beacon_cb(vap); 2114208019Sthompsa break; 2115208019Sthompsa case IEEE80211_M_STA: 2116208019Sthompsa sc->sta_running |= bid; 2117209917Sthompsa if (!sc->ap_running && !sc->adhoc_running) 2118208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2119208019Sthompsa 2120208019Sthompsa /* read statistic counters (clear on read) */ 2121208019Sthompsa run_read_region_1(sc, RT2860_TX_STA_CNT0, 2122208019Sthompsa (uint8_t *)sta, sizeof sta); 2123208019Sthompsa 2124208019Sthompsa break; 2125208019Sthompsa default: 2126208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2127208019Sthompsa break; 2128208019Sthompsa } 2129208019Sthompsa 2130203134Sthompsa if (vap->iv_opmode != IEEE80211_M_MONITOR) { 2131212127Sthompsa struct ieee80211_node *ni; 2132212127Sthompsa 2133236439Shselasky if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) { 2134236439Shselasky RUN_UNLOCK(sc); 2135236439Shselasky IEEE80211_LOCK(ic); 2136236439Shselasky return (-1); 2137236439Shselasky } 2138203134Sthompsa run_updateslot(ic->ic_ifp); 2139203134Sthompsa run_enable_mrr(sc); 2140203134Sthompsa run_set_txpreamble(sc); 2141203134Sthompsa run_set_basicrates(sc); 2142212127Sthompsa ni = ieee80211_ref_node(vap->iv_bss); 2143203134Sthompsa IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); 2144203134Sthompsa run_set_bssid(sc, ni->ni_bssid); 2145212127Sthompsa ieee80211_free_node(ni); 2146208019Sthompsa run_enable_tsf_sync(sc); 2147203134Sthompsa 2148208019Sthompsa /* enable automatic rate adaptation */ 2149208019Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 2150208019Sthompsa if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) 2151208019Sthompsa ratectl |= bid; 2152203134Sthompsa } 2153203134Sthompsa 2154203134Sthompsa /* turn link LED on */ 2155203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO | 2156208019Sthompsa (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 2157203134Sthompsa RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ)); 2158203134Sthompsa 2159203134Sthompsa break; 2160203134Sthompsa default: 2161203134Sthompsa DPRINTFN(6, "undefined case\n"); 2162203134Sthompsa break; 2163203134Sthompsa } 2164203134Sthompsa 2165208019Sthompsa /* restart amrr for running VAPs */ 2166209917Sthompsa if ((sc->ratectl_run = ratectl) && restart_ratectl) 2167208019Sthompsa usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2168208019Sthompsa 2169203134Sthompsa RUN_UNLOCK(sc); 2170203134Sthompsa IEEE80211_LOCK(ic); 2171203134Sthompsa 2172203134Sthompsa return(rvp->newstate(vap, nstate, arg)); 2173203134Sthompsa} 2174203134Sthompsa 2175203134Sthompsa/* ARGSUSED */ 2176203134Sthompsastatic void 2177208019Sthompsarun_wme_update_cb(void *arg) 2178203134Sthompsa{ 2179203134Sthompsa struct ieee80211com *ic = arg; 2180203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2181203134Sthompsa struct ieee80211_wme_state *wmesp = &ic->ic_wme; 2182203134Sthompsa int aci, error = 0; 2183203134Sthompsa 2184208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2185203134Sthompsa 2186203134Sthompsa /* update MAC TX configuration registers */ 2187203134Sthompsa for (aci = 0; aci < WME_NUM_AC; aci++) { 2188203134Sthompsa error = run_write(sc, RT2860_EDCA_AC_CFG(aci), 2189203134Sthompsa wmesp->wme_params[aci].wmep_logcwmax << 16 | 2190203134Sthompsa wmesp->wme_params[aci].wmep_logcwmin << 12 | 2191203134Sthompsa wmesp->wme_params[aci].wmep_aifsn << 8 | 2192203134Sthompsa wmesp->wme_params[aci].wmep_txopLimit); 2193209917Sthompsa if (error) goto err; 2194203134Sthompsa } 2195203134Sthompsa 2196203134Sthompsa /* update SCH/DMA registers too */ 2197203134Sthompsa error = run_write(sc, RT2860_WMM_AIFSN_CFG, 2198203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_aifsn << 12 | 2199203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_aifsn << 8 | 2200203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_aifsn << 4 | 2201203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_aifsn); 2202209917Sthompsa if (error) goto err; 2203203134Sthompsa error = run_write(sc, RT2860_WMM_CWMIN_CFG, 2204203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_logcwmin << 12 | 2205203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_logcwmin << 8 | 2206203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_logcwmin << 4 | 2207203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_logcwmin); 2208209917Sthompsa if (error) goto err; 2209203134Sthompsa error = run_write(sc, RT2860_WMM_CWMAX_CFG, 2210203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_logcwmax << 12 | 2211203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_logcwmax << 8 | 2212203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_logcwmax << 4 | 2213203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_logcwmax); 2214209917Sthompsa if (error) goto err; 2215203134Sthompsa error = run_write(sc, RT2860_WMM_TXOP0_CFG, 2216203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_txopLimit << 16 | 2217203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_txopLimit); 2218209917Sthompsa if (error) goto err; 2219203134Sthompsa error = run_write(sc, RT2860_WMM_TXOP1_CFG, 2220203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_txopLimit << 16 | 2221203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_txopLimit); 2222203134Sthompsa 2223203134Sthompsaerr: 2224209917Sthompsa if (error) 2225203134Sthompsa DPRINTF("WME update failed\n"); 2226203134Sthompsa 2227203134Sthompsa return; 2228203134Sthompsa} 2229203134Sthompsa 2230208019Sthompsastatic int 2231208019Sthompsarun_wme_update(struct ieee80211com *ic) 2232208019Sthompsa{ 2233208019Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2234208019Sthompsa 2235208019Sthompsa /* sometime called wothout lock */ 2236209917Sthompsa if (mtx_owned(&ic->ic_comlock.mtx)) { 2237208019Sthompsa uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 2238208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 2239208019Sthompsa sc->cmdq[i].func = run_wme_update_cb; 2240208019Sthompsa sc->cmdq[i].arg0 = ic; 2241208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2242209918Sthompsa return (0); 2243208019Sthompsa } 2244208019Sthompsa 2245208019Sthompsa RUN_LOCK(sc); 2246208019Sthompsa run_wme_update_cb(ic); 2247208019Sthompsa RUN_UNLOCK(sc); 2248208019Sthompsa 2249208019Sthompsa /* return whatever, upper layer desn't care anyway */ 2250208019Sthompsa return (0); 2251208019Sthompsa} 2252208019Sthompsa 2253203134Sthompsastatic void 2254203134Sthompsarun_key_update_begin(struct ieee80211vap *vap) 2255203134Sthompsa{ 2256203134Sthompsa /* 2257208019Sthompsa * To avoid out-of-order events, both run_key_set() and 2258208019Sthompsa * _delete() are deferred and handled by run_cmdq_cb(). 2259208019Sthompsa * So, there is nothing we need to do here. 2260203134Sthompsa */ 2261203134Sthompsa} 2262203134Sthompsa 2263203134Sthompsastatic void 2264203134Sthompsarun_key_update_end(struct ieee80211vap *vap) 2265203134Sthompsa{ 2266203134Sthompsa /* null */ 2267203134Sthompsa} 2268203134Sthompsa 2269208019Sthompsastatic void 2270208019Sthompsarun_key_set_cb(void *arg) 2271203134Sthompsa{ 2272208019Sthompsa struct run_cmdq *cmdq = arg; 2273208019Sthompsa struct ieee80211vap *vap = cmdq->arg1; 2274208019Sthompsa struct ieee80211_key *k = cmdq->k; 2275203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2276208019Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2277203134Sthompsa struct ieee80211_node *ni; 2278203134Sthompsa uint32_t attr; 2279203134Sthompsa uint16_t base, associd; 2280209144Sthompsa uint8_t mode, wcid, iv[8]; 2281203134Sthompsa 2282208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2283203134Sthompsa 2284209917Sthompsa if (vap->iv_opmode == IEEE80211_M_HOSTAP) 2285208019Sthompsa ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac); 2286209144Sthompsa else 2287203134Sthompsa ni = vap->iv_bss; 2288208019Sthompsa associd = (ni != NULL) ? ni->ni_associd : 0; 2289203134Sthompsa 2290203134Sthompsa /* map net80211 cipher to RT2860 security mode */ 2291203134Sthompsa switch (k->wk_cipher->ic_cipher) { 2292203134Sthompsa case IEEE80211_CIPHER_WEP: 2293203134Sthompsa if(k->wk_keylen < 8) 2294203134Sthompsa mode = RT2860_MODE_WEP40; 2295203134Sthompsa else 2296203134Sthompsa mode = RT2860_MODE_WEP104; 2297203134Sthompsa break; 2298203134Sthompsa case IEEE80211_CIPHER_TKIP: 2299203134Sthompsa mode = RT2860_MODE_TKIP; 2300203134Sthompsa break; 2301203134Sthompsa case IEEE80211_CIPHER_AES_CCM: 2302203134Sthompsa mode = RT2860_MODE_AES_CCMP; 2303203134Sthompsa break; 2304203134Sthompsa default: 2305203134Sthompsa DPRINTF("undefined case\n"); 2306208019Sthompsa return; 2307203134Sthompsa } 2308203134Sthompsa 2309208019Sthompsa DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n", 2310203134Sthompsa associd, k->wk_keyix, mode, 2311208019Sthompsa (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise", 2312208019Sthompsa (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off", 2313208019Sthompsa (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off"); 2314203134Sthompsa 2315203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 2316203134Sthompsa wcid = 0; /* NB: update WCID0 for group keys */ 2317208019Sthompsa base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix); 2318203134Sthompsa } else { 2319245047Shselasky wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 2320245047Shselasky 1 : RUN_AID2WCID(associd); 2321203134Sthompsa base = RT2860_PKEY(wcid); 2322203134Sthompsa } 2323203134Sthompsa 2324203134Sthompsa if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) { 2325203134Sthompsa if(run_write_region_1(sc, base, k->wk_key, 16)) 2326208019Sthompsa return; 2327209144Sthompsa if(run_write_region_1(sc, base + 16, &k->wk_key[16], 8)) /* wk_txmic */ 2328208019Sthompsa return; 2329209144Sthompsa if(run_write_region_1(sc, base + 24, &k->wk_key[24], 8)) /* wk_rxmic */ 2330208019Sthompsa return; 2331203134Sthompsa } else { 2332203134Sthompsa /* roundup len to 16-bit: XXX fix write_region_1() instead */ 2333203134Sthompsa if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1)) 2334208019Sthompsa return; 2335203134Sthompsa } 2336203134Sthompsa 2337203134Sthompsa if (!(k->wk_flags & IEEE80211_KEY_GROUP) || 2338203134Sthompsa (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) { 2339203134Sthompsa /* set initial packet number in IV+EIV */ 2340209917Sthompsa if (k->wk_cipher == IEEE80211_CIPHER_WEP) { 2341203134Sthompsa memset(iv, 0, sizeof iv); 2342208019Sthompsa iv[3] = vap->iv_def_txkey << 6; 2343203134Sthompsa } else { 2344203134Sthompsa if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) { 2345203134Sthompsa iv[0] = k->wk_keytsc >> 8; 2346203134Sthompsa iv[1] = (iv[0] | 0x20) & 0x7f; 2347203134Sthompsa iv[2] = k->wk_keytsc; 2348203134Sthompsa } else /* CCMP */ { 2349203134Sthompsa iv[0] = k->wk_keytsc; 2350203134Sthompsa iv[1] = k->wk_keytsc >> 8; 2351203134Sthompsa iv[2] = 0; 2352203134Sthompsa } 2353203134Sthompsa iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV; 2354203134Sthompsa iv[4] = k->wk_keytsc >> 16; 2355203134Sthompsa iv[5] = k->wk_keytsc >> 24; 2356203134Sthompsa iv[6] = k->wk_keytsc >> 32; 2357203134Sthompsa iv[7] = k->wk_keytsc >> 40; 2358203134Sthompsa } 2359209917Sthompsa if (run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8)) 2360208019Sthompsa return; 2361203134Sthompsa } 2362203134Sthompsa 2363203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 2364203134Sthompsa /* install group key */ 2365209917Sthompsa if (run_read(sc, RT2860_SKEY_MODE_0_7, &attr)) 2366208019Sthompsa return; 2367203134Sthompsa attr &= ~(0xf << (k->wk_keyix * 4)); 2368203134Sthompsa attr |= mode << (k->wk_keyix * 4); 2369209917Sthompsa if (run_write(sc, RT2860_SKEY_MODE_0_7, attr)) 2370208019Sthompsa return; 2371203134Sthompsa } else { 2372203134Sthompsa /* install pairwise key */ 2373209917Sthompsa if (run_read(sc, RT2860_WCID_ATTR(wcid), &attr)) 2374208019Sthompsa return; 2375203134Sthompsa attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN; 2376209917Sthompsa if (run_write(sc, RT2860_WCID_ATTR(wcid), attr)) 2377208019Sthompsa return; 2378203134Sthompsa } 2379203134Sthompsa 2380203134Sthompsa /* TODO create a pass-thru key entry? */ 2381203134Sthompsa 2382208019Sthompsa /* need wcid to delete the right key later */ 2383208019Sthompsa k->wk_pad = wcid; 2384203134Sthompsa} 2385203134Sthompsa 2386203134Sthompsa/* 2387208019Sthompsa * Don't have to be deferred, but in order to keep order of 2388208019Sthompsa * execution, i.e. with run_key_delete(), defer this and let 2389208019Sthompsa * run_cmdq_cb() maintain the order. 2390208019Sthompsa * 2391203134Sthompsa * return 0 on error 2392203134Sthompsa */ 2393203134Sthompsastatic int 2394208019Sthompsarun_key_set(struct ieee80211vap *vap, struct ieee80211_key *k, 2395208019Sthompsa const uint8_t mac[IEEE80211_ADDR_LEN]) 2396203134Sthompsa{ 2397203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2398203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2399208019Sthompsa uint32_t i; 2400208019Sthompsa 2401208019Sthompsa i = RUN_CMDQ_GET(&sc->cmdq_store); 2402208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 2403208019Sthompsa sc->cmdq[i].func = run_key_set_cb; 2404208019Sthompsa sc->cmdq[i].arg0 = NULL; 2405208019Sthompsa sc->cmdq[i].arg1 = vap; 2406208019Sthompsa sc->cmdq[i].k = k; 2407208019Sthompsa IEEE80211_ADDR_COPY(sc->cmdq[i].mac, mac); 2408208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2409208019Sthompsa 2410209144Sthompsa /* 2411209144Sthompsa * To make sure key will be set when hostapd 2412209144Sthompsa * calls iv_key_set() before if_init(). 2413209144Sthompsa */ 2414209917Sthompsa if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 2415209144Sthompsa RUN_LOCK(sc); 2416209144Sthompsa sc->cmdq_key_set = RUN_CMDQ_GO; 2417209144Sthompsa RUN_UNLOCK(sc); 2418209144Sthompsa } 2419209144Sthompsa 2420209917Sthompsa return (1); 2421208019Sthompsa} 2422208019Sthompsa 2423208019Sthompsa/* 2424208019Sthompsa * If wlan is destroyed without being brought down i.e. without 2425208019Sthompsa * wlan down or wpa_cli terminate, this function is called after 2426208019Sthompsa * vap is gone. Don't refer it. 2427208019Sthompsa */ 2428208019Sthompsastatic void 2429208019Sthompsarun_key_delete_cb(void *arg) 2430208019Sthompsa{ 2431208019Sthompsa struct run_cmdq *cmdq = arg; 2432208019Sthompsa struct run_softc *sc = cmdq->arg1; 2433208019Sthompsa struct ieee80211_key *k = &cmdq->key; 2434203134Sthompsa uint32_t attr; 2435203134Sthompsa uint8_t wcid; 2436203134Sthompsa 2437208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2438203134Sthompsa 2439203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 2440203134Sthompsa /* remove group key */ 2441208019Sthompsa DPRINTF("removing group key\n"); 2442208019Sthompsa run_read(sc, RT2860_SKEY_MODE_0_7, &attr); 2443203134Sthompsa attr &= ~(0xf << (k->wk_keyix * 4)); 2444208019Sthompsa run_write(sc, RT2860_SKEY_MODE_0_7, attr); 2445203134Sthompsa } else { 2446203134Sthompsa /* remove pairwise key */ 2447208019Sthompsa DPRINTF("removing key for wcid %x\n", k->wk_pad); 2448208019Sthompsa /* matching wcid was written to wk_pad in run_key_set() */ 2449208019Sthompsa wcid = k->wk_pad; 2450208019Sthompsa run_read(sc, RT2860_WCID_ATTR(wcid), &attr); 2451203134Sthompsa attr &= ~0xf; 2452208019Sthompsa run_write(sc, RT2860_WCID_ATTR(wcid), attr); 2453208019Sthompsa run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8); 2454203134Sthompsa } 2455203134Sthompsa 2456208019Sthompsa k->wk_pad = 0; 2457203134Sthompsa} 2458203134Sthompsa 2459208019Sthompsa/* 2460208019Sthompsa * return 0 on error 2461208019Sthompsa */ 2462208019Sthompsastatic int 2463208019Sthompsarun_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k) 2464203134Sthompsa{ 2465208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 2466208019Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2467208019Sthompsa struct ieee80211_key *k0; 2468208019Sthompsa uint32_t i; 2469203134Sthompsa 2470208019Sthompsa /* 2471208019Sthompsa * When called back, key might be gone. So, make a copy 2472208019Sthompsa * of some values need to delete keys before deferring. 2473208019Sthompsa * But, because of LOR with node lock, cannot use lock here. 2474208019Sthompsa * So, use atomic instead. 2475208019Sthompsa */ 2476208019Sthompsa i = RUN_CMDQ_GET(&sc->cmdq_store); 2477208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 2478208019Sthompsa sc->cmdq[i].func = run_key_delete_cb; 2479208019Sthompsa sc->cmdq[i].arg0 = NULL; 2480208019Sthompsa sc->cmdq[i].arg1 = sc; 2481208019Sthompsa k0 = &sc->cmdq[i].key; 2482208019Sthompsa k0->wk_flags = k->wk_flags; 2483208019Sthompsa k0->wk_keyix = k->wk_keyix; 2484208019Sthompsa /* matching wcid was written to wk_pad in run_key_set() */ 2485208019Sthompsa k0->wk_pad = k->wk_pad; 2486208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2487208019Sthompsa return (1); /* return fake success */ 2488203134Sthompsa 2489203134Sthompsa} 2490203134Sthompsa 2491203134Sthompsastatic void 2492206358Srpaulorun_ratectl_to(void *arg) 2493203134Sthompsa{ 2494208019Sthompsa struct run_softc *sc = arg; 2495203134Sthompsa 2496203134Sthompsa /* do it in a process context, so it can go sleep */ 2497208019Sthompsa ieee80211_runtask(sc->sc_ifp->if_l2com, &sc->ratectl_task); 2498203134Sthompsa /* next timeout will be rescheduled in the callback task */ 2499203134Sthompsa} 2500203134Sthompsa 2501203134Sthompsa/* ARGSUSED */ 2502203134Sthompsastatic void 2503206358Srpaulorun_ratectl_cb(void *arg, int pending) 2504203134Sthompsa{ 2505208019Sthompsa struct run_softc *sc = arg; 2506208019Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 2507208019Sthompsa struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2508203134Sthompsa 2509209917Sthompsa if (vap == NULL) 2510208019Sthompsa return; 2511208019Sthompsa 2512263073Shselasky if (sc->rvp_cnt > 1 || vap->iv_opmode != IEEE80211_M_STA) { 2513203134Sthompsa /* 2514203134Sthompsa * run_reset_livelock() doesn't do anything with AMRR, 2515203134Sthompsa * but Ralink wants us to call it every 1 sec. So, we 2516203134Sthompsa * piggyback here rather than creating another callout. 2517203134Sthompsa * Livelock may occur only in HOSTAP or IBSS mode 2518203134Sthompsa * (when h/w is sending beacons). 2519203134Sthompsa */ 2520203134Sthompsa RUN_LOCK(sc); 2521203134Sthompsa run_reset_livelock(sc); 2522208019Sthompsa /* just in case, there are some stats to drain */ 2523208019Sthompsa run_drain_fifo(sc); 2524203134Sthompsa RUN_UNLOCK(sc); 2525203134Sthompsa } 2526203134Sthompsa 2527263073Shselasky ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc); 2528263073Shselasky 2529259453Shselasky RUN_LOCK(sc); 2530208019Sthompsa if(sc->ratectl_run != RUN_RATECTL_OFF) 2531208019Sthompsa usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2532259453Shselasky RUN_UNLOCK(sc); 2533203134Sthompsa} 2534203134Sthompsa 2535203134Sthompsastatic void 2536208019Sthompsarun_drain_fifo(void *arg) 2537203134Sthompsa{ 2538208019Sthompsa struct run_softc *sc = arg; 2539208019Sthompsa struct ifnet *ifp = sc->sc_ifp; 2540208019Sthompsa uint32_t stat; 2541218676Shselasky uint16_t (*wstat)[3]; 2542203134Sthompsa uint8_t wcid, mcs, pid; 2543218676Shselasky int8_t retry; 2544203134Sthompsa 2545208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2546203134Sthompsa 2547208019Sthompsa for (;;) { 2548203134Sthompsa /* drain Tx status FIFO (maxsize = 16) */ 2549203134Sthompsa run_read(sc, RT2860_TX_STAT_FIFO, &stat); 2550208019Sthompsa DPRINTFN(4, "tx stat 0x%08x\n", stat); 2551209917Sthompsa if (!(stat & RT2860_TXQ_VLD)) 2552208019Sthompsa break; 2553203134Sthompsa 2554208019Sthompsa wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff; 2555203134Sthompsa 2556208019Sthompsa /* if no ACK was requested, no feedback is available */ 2557208019Sthompsa if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX || 2558208019Sthompsa wcid == 0) 2559208019Sthompsa continue; 2560203134Sthompsa 2561218676Shselasky /* 2562218676Shselasky * Even though each stat is Tx-complete-status like format, 2563218676Shselasky * the device can poll stats. Because there is no guarantee 2564218676Shselasky * that the referring node is still around when read the stats. 2565218676Shselasky * So that, if we use ieee80211_ratectl_tx_update(), we will 2566218676Shselasky * have hard time not to refer already freed node. 2567218676Shselasky * 2568218676Shselasky * To eliminate such page faults, we poll stats in softc. 2569218676Shselasky * Then, update the rates later with ieee80211_ratectl_tx_update(). 2570218676Shselasky */ 2571218676Shselasky wstat = &(sc->wcid_stats[wcid]); 2572218676Shselasky (*wstat)[RUN_TXCNT]++; 2573218676Shselasky if (stat & RT2860_TXQ_OK) 2574218676Shselasky (*wstat)[RUN_SUCCESS]++; 2575218676Shselasky else 2576208019Sthompsa ifp->if_oerrors++; 2577218676Shselasky /* 2578218676Shselasky * Check if there were retries, ie if the Tx success rate is 2579218676Shselasky * different from the requested rate. Note that it works only 2580218676Shselasky * because we do not allow rate fallback from OFDM to CCK. 2581218676Shselasky */ 2582218676Shselasky mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f; 2583218676Shselasky pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf; 2584218676Shselasky if ((retry = pid -1 - mcs) > 0) { 2585218676Shselasky (*wstat)[RUN_TXCNT] += retry; 2586218676Shselasky (*wstat)[RUN_RETRY] += retry; 2587203134Sthompsa } 2588208019Sthompsa } 2589208019Sthompsa DPRINTFN(3, "count=%d\n", sc->fifo_cnt); 2590208019Sthompsa 2591208019Sthompsa sc->fifo_cnt = 0; 2592208019Sthompsa} 2593208019Sthompsa 2594208019Sthompsastatic void 2595208019Sthompsarun_iter_func(void *arg, struct ieee80211_node *ni) 2596208019Sthompsa{ 2597208019Sthompsa struct run_softc *sc = arg; 2598208019Sthompsa struct ieee80211vap *vap = ni->ni_vap; 2599208019Sthompsa struct ieee80211com *ic = ni->ni_ic; 2600208019Sthompsa struct ifnet *ifp = ic->ic_ifp; 2601208019Sthompsa struct run_node *rn = (void *)ni; 2602218676Shselasky union run_stats sta[2]; 2603218676Shselasky uint16_t (*wstat)[3]; 2604218676Shselasky int txcnt, success, retrycnt, error; 2605208019Sthompsa 2606218676Shselasky RUN_LOCK(sc); 2607218676Shselasky 2608263073Shselasky /* Check for special case */ 2609263073Shselasky if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA && 2610263073Shselasky ni != vap->iv_bss) 2611263073Shselasky goto fail; 2612263073Shselasky 2613209917Sthompsa if (sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS || 2614209917Sthompsa vap->iv_opmode == IEEE80211_M_STA)) { 2615203134Sthompsa /* read statistic counters (clear on read) and update AMRR state */ 2616203134Sthompsa error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta, 2617203134Sthompsa sizeof sta); 2618203134Sthompsa if (error != 0) 2619218676Shselasky goto fail; 2620203134Sthompsa 2621203134Sthompsa /* count failed TX as errors */ 2622218676Shselasky ifp->if_oerrors += le16toh(sta[0].error.fail); 2623203134Sthompsa 2624218676Shselasky retrycnt = le16toh(sta[1].tx.retry); 2625218676Shselasky success = le16toh(sta[1].tx.success); 2626218676Shselasky txcnt = retrycnt + success + le16toh(sta[0].error.fail); 2627203134Sthompsa 2628218676Shselasky DPRINTFN(3, "retrycnt=%d success=%d failcnt=%d\n", 2629218676Shselasky retrycnt, success, le16toh(sta[0].error.fail)); 2630218676Shselasky } else { 2631218676Shselasky wstat = &(sc->wcid_stats[RUN_AID2WCID(ni->ni_associd)]); 2632203134Sthompsa 2633218676Shselasky if (wstat == &(sc->wcid_stats[0]) || 2634218676Shselasky wstat > &(sc->wcid_stats[RT2870_WCID_MAX])) 2635218676Shselasky goto fail; 2636208019Sthompsa 2637218676Shselasky txcnt = (*wstat)[RUN_TXCNT]; 2638218676Shselasky success = (*wstat)[RUN_SUCCESS]; 2639218676Shselasky retrycnt = (*wstat)[RUN_RETRY]; 2640218676Shselasky DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n", 2641218676Shselasky retrycnt, txcnt, success); 2642208019Sthompsa 2643218676Shselasky memset(wstat, 0, sizeof(*wstat)); 2644203134Sthompsa } 2645203134Sthompsa 2646218676Shselasky ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt); 2647208019Sthompsa rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0); 2648218676Shselasky 2649218676Shselaskyfail: 2650218676Shselasky RUN_UNLOCK(sc); 2651218676Shselasky 2652208019Sthompsa DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx); 2653208019Sthompsa} 2654203134Sthompsa 2655208019Sthompsastatic void 2656208019Sthompsarun_newassoc_cb(void *arg) 2657208019Sthompsa{ 2658208019Sthompsa struct run_cmdq *cmdq = arg; 2659208019Sthompsa struct ieee80211_node *ni = cmdq->arg1; 2660208019Sthompsa struct run_softc *sc = ni->ni_vap->iv_ic->ic_ifp->if_softc; 2661208019Sthompsa uint8_t wcid = cmdq->wcid; 2662203134Sthompsa 2663208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2664208019Sthompsa 2665208019Sthompsa run_write_region_1(sc, RT2860_WCID_ENTRY(wcid), 2666208019Sthompsa ni->ni_macaddr, IEEE80211_ADDR_LEN); 2667218676Shselasky 2668218676Shselasky memset(&(sc->wcid_stats[wcid]), 0, sizeof(sc->wcid_stats[wcid])); 2669203134Sthompsa} 2670203134Sthompsa 2671203134Sthompsastatic void 2672203134Sthompsarun_newassoc(struct ieee80211_node *ni, int isnew) 2673203134Sthompsa{ 2674203134Sthompsa struct run_node *rn = (void *)ni; 2675203134Sthompsa struct ieee80211_rateset *rs = &ni->ni_rates; 2676208019Sthompsa struct ieee80211vap *vap = ni->ni_vap; 2677208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 2678208019Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2679203134Sthompsa uint8_t rate; 2680208019Sthompsa uint8_t ridx; 2681245047Shselasky uint8_t wcid; 2682208019Sthompsa int i, j; 2683203134Sthompsa 2684245047Shselasky wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 2685245047Shselasky 1 : RUN_AID2WCID(ni->ni_associd); 2686245047Shselasky 2687209917Sthompsa if (wcid > RT2870_WCID_MAX) { 2688208019Sthompsa device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid); 2689208019Sthompsa return; 2690208019Sthompsa } 2691203134Sthompsa 2692208019Sthompsa /* only interested in true associations */ 2693209917Sthompsa if (isnew && ni->ni_associd != 0) { 2694208019Sthompsa 2695208019Sthompsa /* 2696208019Sthompsa * This function could is called though timeout function. 2697208019Sthompsa * Need to defer. 2698208019Sthompsa */ 2699208019Sthompsa uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store); 2700208019Sthompsa DPRINTF("cmdq_store=%d\n", cnt); 2701208019Sthompsa sc->cmdq[cnt].func = run_newassoc_cb; 2702208019Sthompsa sc->cmdq[cnt].arg0 = NULL; 2703208019Sthompsa sc->cmdq[cnt].arg1 = ni; 2704208019Sthompsa sc->cmdq[cnt].wcid = wcid; 2705208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2706208019Sthompsa } 2707208019Sthompsa 2708208019Sthompsa DPRINTF("new assoc isnew=%d associd=%x addr=%s\n", 2709208019Sthompsa isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr)); 2710208019Sthompsa 2711203134Sthompsa for (i = 0; i < rs->rs_nrates; i++) { 2712203134Sthompsa rate = rs->rs_rates[i] & IEEE80211_RATE_VAL; 2713203134Sthompsa /* convert 802.11 rate to hardware rate index */ 2714203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2715203134Sthompsa if (rt2860_rates[ridx].rate == rate) 2716203134Sthompsa break; 2717203134Sthompsa rn->ridx[i] = ridx; 2718203134Sthompsa /* determine rate of control response frames */ 2719203134Sthompsa for (j = i; j >= 0; j--) { 2720203134Sthompsa if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) && 2721203134Sthompsa rt2860_rates[rn->ridx[i]].phy == 2722203134Sthompsa rt2860_rates[rn->ridx[j]].phy) 2723203134Sthompsa break; 2724203134Sthompsa } 2725203134Sthompsa if (j >= 0) { 2726203134Sthompsa rn->ctl_ridx[i] = rn->ridx[j]; 2727203134Sthompsa } else { 2728203134Sthompsa /* no basic rate found, use mandatory one */ 2729203134Sthompsa rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx; 2730203134Sthompsa } 2731203134Sthompsa DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n", 2732203134Sthompsa rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]); 2733203134Sthompsa } 2734208019Sthompsa rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate; 2735208019Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2736208019Sthompsa if (rt2860_rates[ridx].rate == rate) 2737208019Sthompsa break; 2738208019Sthompsa rn->mgt_ridx = ridx; 2739208019Sthompsa DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx); 2740208019Sthompsa 2741263073Shselasky RUN_LOCK(sc); 2742263073Shselasky if(sc->ratectl_run != RUN_RATECTL_OFF) 2743263073Shselasky usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2744263073Shselasky RUN_UNLOCK(sc); 2745203134Sthompsa} 2746203134Sthompsa 2747203134Sthompsa/* 2748203134Sthompsa * Return the Rx chain with the highest RSSI for a given frame. 2749203134Sthompsa */ 2750203134Sthompsastatic __inline uint8_t 2751203134Sthompsarun_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi) 2752203134Sthompsa{ 2753203134Sthompsa uint8_t rxchain = 0; 2754203134Sthompsa 2755203134Sthompsa if (sc->nrxchains > 1) { 2756203134Sthompsa if (rxwi->rssi[1] > rxwi->rssi[rxchain]) 2757203134Sthompsa rxchain = 1; 2758203134Sthompsa if (sc->nrxchains > 2) 2759203134Sthompsa if (rxwi->rssi[2] > rxwi->rssi[rxchain]) 2760203134Sthompsa rxchain = 2; 2761203134Sthompsa } 2762209917Sthompsa return (rxchain); 2763203134Sthompsa} 2764203134Sthompsa 2765203134Sthompsastatic void 2766203134Sthompsarun_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) 2767203134Sthompsa{ 2768203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 2769203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 2770203134Sthompsa struct ieee80211_frame *wh; 2771203134Sthompsa struct ieee80211_node *ni; 2772203134Sthompsa struct rt2870_rxd *rxd; 2773203134Sthompsa struct rt2860_rxwi *rxwi; 2774203134Sthompsa uint32_t flags; 2775259453Shselasky uint16_t len, rxwisize; 2776203134Sthompsa uint8_t ant, rssi; 2777203134Sthompsa int8_t nf; 2778203134Sthompsa 2779203134Sthompsa rxwi = mtod(m, struct rt2860_rxwi *); 2780203134Sthompsa len = le16toh(rxwi->len) & 0xfff; 2781261868Skevlo rxwisize = sizeof(struct rt2860_rxwi); 2782261868Skevlo if (sc->mac_ver == 0x5592) 2783261868Skevlo rxwisize += sizeof(uint64_t); 2784261868Skevlo else if (sc->mac_ver == 0x3593) 2785261868Skevlo rxwisize += sizeof(uint32_t); 2786203134Sthompsa if (__predict_false(len > dmalen)) { 2787203134Sthompsa m_freem(m); 2788203134Sthompsa ifp->if_ierrors++; 2789203134Sthompsa DPRINTF("bad RXWI length %u > %u\n", len, dmalen); 2790203134Sthompsa return; 2791203134Sthompsa } 2792203134Sthompsa /* Rx descriptor is located at the end */ 2793203134Sthompsa rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen); 2794203134Sthompsa flags = le32toh(rxd->flags); 2795203134Sthompsa 2796203134Sthompsa if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) { 2797203134Sthompsa m_freem(m); 2798203134Sthompsa ifp->if_ierrors++; 2799203134Sthompsa DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV"); 2800203134Sthompsa return; 2801203134Sthompsa } 2802203134Sthompsa 2803259453Shselasky m->m_data += rxwisize; 2804259453Shselasky m->m_pkthdr.len = m->m_len -= rxwisize; 2805203134Sthompsa 2806203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 2807203134Sthompsa 2808262007Skevlo if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 2809262007Skevlo wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; 2810203134Sthompsa m->m_flags |= M_WEP; 2811203134Sthompsa } 2812203134Sthompsa 2813209917Sthompsa if (flags & RT2860_RX_L2PAD) { 2814203134Sthompsa DPRINTFN(8, "received RT2860_RX_L2PAD frame\n"); 2815203134Sthompsa len += 2; 2816203134Sthompsa } 2817203134Sthompsa 2818208019Sthompsa ni = ieee80211_find_rxnode(ic, 2819208019Sthompsa mtod(m, struct ieee80211_frame_min *)); 2820208019Sthompsa 2821203134Sthompsa if (__predict_false(flags & RT2860_RX_MICERR)) { 2822203134Sthompsa /* report MIC failures to net80211 for TKIP */ 2823209917Sthompsa if (ni != NULL) 2824259453Shselasky ieee80211_notify_michael_failure(ni->ni_vap, wh, 2825259453Shselasky rxwi->keyidx); 2826203134Sthompsa m_freem(m); 2827203134Sthompsa ifp->if_ierrors++; 2828203134Sthompsa DPRINTF("MIC error. Someone is lying.\n"); 2829203134Sthompsa return; 2830203134Sthompsa } 2831203134Sthompsa 2832203134Sthompsa ant = run_maxrssi_chain(sc, rxwi); 2833203134Sthompsa rssi = rxwi->rssi[ant]; 2834203134Sthompsa nf = run_rssi2dbm(sc, rssi, ant); 2835203134Sthompsa 2836203134Sthompsa m->m_pkthdr.rcvif = ifp; 2837203134Sthompsa m->m_pkthdr.len = m->m_len = len; 2838203134Sthompsa 2839203134Sthompsa if (ni != NULL) { 2840203134Sthompsa (void)ieee80211_input(ni, m, rssi, nf); 2841203134Sthompsa ieee80211_free_node(ni); 2842203134Sthompsa } else { 2843203134Sthompsa (void)ieee80211_input_all(ic, m, rssi, nf); 2844203134Sthompsa } 2845203134Sthompsa 2846209917Sthompsa if (__predict_false(ieee80211_radiotap_active(ic))) { 2847203134Sthompsa struct run_rx_radiotap_header *tap = &sc->sc_rxtap; 2848259453Shselasky uint16_t phy; 2849203134Sthompsa 2850203134Sthompsa tap->wr_flags = 0; 2851236439Shselasky tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); 2852236439Shselasky tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); 2853203134Sthompsa tap->wr_antsignal = rssi; 2854203134Sthompsa tap->wr_antenna = ant; 2855203134Sthompsa tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant); 2856203134Sthompsa tap->wr_rate = 2; /* in case it can't be found below */ 2857203134Sthompsa phy = le16toh(rxwi->phy); 2858203134Sthompsa switch (phy & RT2860_PHY_MODE) { 2859203134Sthompsa case RT2860_PHY_CCK: 2860203134Sthompsa switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) { 2861203134Sthompsa case 0: tap->wr_rate = 2; break; 2862203134Sthompsa case 1: tap->wr_rate = 4; break; 2863203134Sthompsa case 2: tap->wr_rate = 11; break; 2864203134Sthompsa case 3: tap->wr_rate = 22; break; 2865203134Sthompsa } 2866203134Sthompsa if (phy & RT2860_PHY_SHPRE) 2867203134Sthompsa tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 2868203134Sthompsa break; 2869203134Sthompsa case RT2860_PHY_OFDM: 2870203134Sthompsa switch (phy & RT2860_PHY_MCS) { 2871203134Sthompsa case 0: tap->wr_rate = 12; break; 2872203134Sthompsa case 1: tap->wr_rate = 18; break; 2873203134Sthompsa case 2: tap->wr_rate = 24; break; 2874203134Sthompsa case 3: tap->wr_rate = 36; break; 2875203134Sthompsa case 4: tap->wr_rate = 48; break; 2876203134Sthompsa case 5: tap->wr_rate = 72; break; 2877203134Sthompsa case 6: tap->wr_rate = 96; break; 2878203134Sthompsa case 7: tap->wr_rate = 108; break; 2879203134Sthompsa } 2880203134Sthompsa break; 2881203134Sthompsa } 2882203134Sthompsa } 2883203134Sthompsa} 2884203134Sthompsa 2885203134Sthompsastatic void 2886203134Sthompsarun_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) 2887203134Sthompsa{ 2888203134Sthompsa struct run_softc *sc = usbd_xfer_softc(xfer); 2889203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 2890203134Sthompsa struct mbuf *m = NULL; 2891203134Sthompsa struct mbuf *m0; 2892203134Sthompsa uint32_t dmalen; 2893259453Shselasky uint16_t rxwisize; 2894203134Sthompsa int xferlen; 2895203134Sthompsa 2896261868Skevlo rxwisize = sizeof(struct rt2860_rxwi); 2897261868Skevlo if (sc->mac_ver == 0x5592) 2898261868Skevlo rxwisize += sizeof(uint64_t); 2899261868Skevlo else if (sc->mac_ver == 0x3593) 2900261868Skevlo rxwisize += sizeof(uint32_t); 2901259453Shselasky 2902203134Sthompsa usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL); 2903203134Sthompsa 2904203134Sthompsa switch (USB_GET_STATE(xfer)) { 2905203134Sthompsa case USB_ST_TRANSFERRED: 2906203134Sthompsa 2907203134Sthompsa DPRINTFN(15, "rx done, actlen=%d\n", xferlen); 2908203134Sthompsa 2909259453Shselasky if (xferlen < (int)(sizeof(uint32_t) + rxwisize + 2910259453Shselasky sizeof(struct rt2870_rxd))) { 2911203134Sthompsa DPRINTF("xfer too short %d\n", xferlen); 2912203134Sthompsa goto tr_setup; 2913203134Sthompsa } 2914203134Sthompsa 2915203134Sthompsa m = sc->rx_m; 2916203134Sthompsa sc->rx_m = NULL; 2917203134Sthompsa 2918203134Sthompsa /* FALLTHROUGH */ 2919203134Sthompsa case USB_ST_SETUP: 2920203134Sthompsatr_setup: 2921203134Sthompsa if (sc->rx_m == NULL) { 2922243857Sglebius sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, 2923203134Sthompsa MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */); 2924203134Sthompsa } 2925203134Sthompsa if (sc->rx_m == NULL) { 2926203134Sthompsa DPRINTF("could not allocate mbuf - idle with stall\n"); 2927203134Sthompsa ifp->if_ierrors++; 2928203134Sthompsa usbd_xfer_set_stall(xfer); 2929203134Sthompsa usbd_xfer_set_frames(xfer, 0); 2930203134Sthompsa } else { 2931203134Sthompsa /* 2932203134Sthompsa * Directly loading a mbuf cluster into DMA to 2933203134Sthompsa * save some data copying. This works because 2934203134Sthompsa * there is only one cluster. 2935203134Sthompsa */ 2936203134Sthompsa usbd_xfer_set_frame_data(xfer, 0, 2937203134Sthompsa mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ); 2938203134Sthompsa usbd_xfer_set_frames(xfer, 1); 2939203134Sthompsa } 2940203134Sthompsa usbd_transfer_submit(xfer); 2941203134Sthompsa break; 2942203134Sthompsa 2943203134Sthompsa default: /* Error */ 2944203134Sthompsa if (error != USB_ERR_CANCELLED) { 2945203134Sthompsa /* try to clear stall first */ 2946203134Sthompsa usbd_xfer_set_stall(xfer); 2947203134Sthompsa 2948203134Sthompsa if (error == USB_ERR_TIMEOUT) 2949203134Sthompsa device_printf(sc->sc_dev, "device timeout\n"); 2950203134Sthompsa 2951203134Sthompsa ifp->if_ierrors++; 2952203134Sthompsa 2953203134Sthompsa goto tr_setup; 2954203134Sthompsa } 2955209917Sthompsa if (sc->rx_m != NULL) { 2956203134Sthompsa m_freem(sc->rx_m); 2957203134Sthompsa sc->rx_m = NULL; 2958203134Sthompsa } 2959203134Sthompsa break; 2960203134Sthompsa } 2961203134Sthompsa 2962203134Sthompsa if (m == NULL) 2963203134Sthompsa return; 2964203134Sthompsa 2965203134Sthompsa /* inputting all the frames must be last */ 2966203134Sthompsa 2967203134Sthompsa RUN_UNLOCK(sc); 2968203134Sthompsa 2969203134Sthompsa m->m_pkthdr.len = m->m_len = xferlen; 2970203134Sthompsa 2971203134Sthompsa /* HW can aggregate multiple 802.11 frames in a single USB xfer */ 2972203134Sthompsa for(;;) { 2973203134Sthompsa dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff; 2974203134Sthompsa 2975233774Shselasky if ((dmalen >= (uint32_t)-8) || (dmalen == 0) || 2976233774Shselasky ((dmalen & 3) != 0)) { 2977203134Sthompsa DPRINTF("bad DMA length %u\n", dmalen); 2978203134Sthompsa break; 2979203134Sthompsa } 2980233774Shselasky if ((dmalen + 8) > (uint32_t)xferlen) { 2981203134Sthompsa DPRINTF("bad DMA length %u > %d\n", 2982203134Sthompsa dmalen + 8, xferlen); 2983203134Sthompsa break; 2984203134Sthompsa } 2985203134Sthompsa 2986203134Sthompsa /* If it is the last one or a single frame, we won't copy. */ 2987209917Sthompsa if ((xferlen -= dmalen + 8) <= 8) { 2988203134Sthompsa /* trim 32-bit DMA-len header */ 2989203134Sthompsa m->m_data += 4; 2990203134Sthompsa m->m_pkthdr.len = m->m_len -= 4; 2991203134Sthompsa run_rx_frame(sc, m, dmalen); 2992259453Shselasky m = NULL; /* don't free source buffer */ 2993203134Sthompsa break; 2994203134Sthompsa } 2995203134Sthompsa 2996203134Sthompsa /* copy aggregated frames to another mbuf */ 2997243857Sglebius m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 2998203134Sthompsa if (__predict_false(m0 == NULL)) { 2999203134Sthompsa DPRINTF("could not allocate mbuf\n"); 3000203134Sthompsa ifp->if_ierrors++; 3001203134Sthompsa break; 3002203134Sthompsa } 3003203134Sthompsa m_copydata(m, 4 /* skip 32-bit DMA-len header */, 3004203134Sthompsa dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t)); 3005203134Sthompsa m0->m_pkthdr.len = m0->m_len = 3006203134Sthompsa dmalen + sizeof(struct rt2870_rxd); 3007203134Sthompsa run_rx_frame(sc, m0, dmalen); 3008203134Sthompsa 3009203134Sthompsa /* update data ptr */ 3010203134Sthompsa m->m_data += dmalen + 8; 3011203134Sthompsa m->m_pkthdr.len = m->m_len -= dmalen + 8; 3012203134Sthompsa } 3013203134Sthompsa 3014259453Shselasky /* make sure we free the source buffer, if any */ 3015259453Shselasky m_freem(m); 3016259453Shselasky 3017203134Sthompsa RUN_LOCK(sc); 3018203134Sthompsa} 3019203134Sthompsa 3020203134Sthompsastatic void 3021203134Sthompsarun_tx_free(struct run_endpoint_queue *pq, 3022203134Sthompsa struct run_tx_data *data, int txerr) 3023203134Sthompsa{ 3024203134Sthompsa if (data->m != NULL) { 3025203134Sthompsa if (data->m->m_flags & M_TXCB) 3026203134Sthompsa ieee80211_process_callback(data->ni, data->m, 3027203134Sthompsa txerr ? ETIMEDOUT : 0); 3028203134Sthompsa m_freem(data->m); 3029203134Sthompsa data->m = NULL; 3030203134Sthompsa 3031209917Sthompsa if (data->ni == NULL) { 3032203134Sthompsa DPRINTF("no node\n"); 3033203134Sthompsa } else { 3034203134Sthompsa ieee80211_free_node(data->ni); 3035203134Sthompsa data->ni = NULL; 3036203134Sthompsa } 3037203134Sthompsa } 3038203134Sthompsa 3039203134Sthompsa STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); 3040203134Sthompsa pq->tx_nfree++; 3041203134Sthompsa} 3042203134Sthompsa 3043203134Sthompsastatic void 3044259453Shselaskyrun_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index) 3045203134Sthompsa{ 3046203134Sthompsa struct run_softc *sc = usbd_xfer_softc(xfer); 3047203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 3048208019Sthompsa struct ieee80211com *ic = ifp->if_l2com; 3049203134Sthompsa struct run_tx_data *data; 3050203134Sthompsa struct ieee80211vap *vap = NULL; 3051203134Sthompsa struct usb_page_cache *pc; 3052203134Sthompsa struct run_endpoint_queue *pq = &sc->sc_epq[index]; 3053203134Sthompsa struct mbuf *m; 3054203134Sthompsa usb_frlength_t size; 3055203134Sthompsa int actlen; 3056203134Sthompsa int sumlen; 3057203134Sthompsa 3058203134Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 3059203134Sthompsa 3060209917Sthompsa switch (USB_GET_STATE(xfer)) { 3061203134Sthompsa case USB_ST_TRANSFERRED: 3062203134Sthompsa DPRINTFN(11, "transfer complete: %d " 3063203134Sthompsa "bytes @ index %d\n", actlen, index); 3064203134Sthompsa 3065203134Sthompsa data = usbd_xfer_get_priv(xfer); 3066203134Sthompsa 3067203134Sthompsa run_tx_free(pq, data, 0); 3068203134Sthompsa ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 3069203134Sthompsa 3070203134Sthompsa usbd_xfer_set_priv(xfer, NULL); 3071203134Sthompsa 3072203134Sthompsa ifp->if_opackets++; 3073203134Sthompsa 3074203134Sthompsa /* FALLTHROUGH */ 3075203134Sthompsa case USB_ST_SETUP: 3076203134Sthompsatr_setup: 3077203134Sthompsa data = STAILQ_FIRST(&pq->tx_qh); 3078209917Sthompsa if (data == NULL) 3079203134Sthompsa break; 3080203134Sthompsa 3081203134Sthompsa STAILQ_REMOVE_HEAD(&pq->tx_qh, next); 3082203134Sthompsa 3083203134Sthompsa m = data->m; 3084261868Skevlo size = (sc->mac_ver == 0x5592) ? 3085261868Skevlo sizeof(data->desc) + sizeof(uint32_t) : sizeof(data->desc); 3086228508Shselasky if ((m->m_pkthdr.len + 3087261868Skevlo size + 3 + 8) > RUN_MAX_TXSZ) { 3088203134Sthompsa DPRINTF("data overflow, %u bytes\n", 3089203134Sthompsa m->m_pkthdr.len); 3090203134Sthompsa 3091203134Sthompsa ifp->if_oerrors++; 3092203134Sthompsa 3093203134Sthompsa run_tx_free(pq, data, 1); 3094203134Sthompsa 3095203134Sthompsa goto tr_setup; 3096203134Sthompsa } 3097203134Sthompsa 3098203134Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 3099203134Sthompsa usbd_copy_in(pc, 0, &data->desc, size); 3100203134Sthompsa usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len); 3101228508Shselasky size += m->m_pkthdr.len; 3102228508Shselasky /* 3103228508Shselasky * Align end on a 4-byte boundary, pad 8 bytes (CRC + 3104228508Shselasky * 4-byte padding), and be sure to zero those trailing 3105228508Shselasky * bytes: 3106228508Shselasky */ 3107228508Shselasky usbd_frame_zero(pc, size, ((-size) & 3) + 8); 3108228508Shselasky size += ((-size) & 3) + 8; 3109203134Sthompsa 3110203134Sthompsa vap = data->ni->ni_vap; 3111203134Sthompsa if (ieee80211_radiotap_active_vap(vap)) { 3112203134Sthompsa struct run_tx_radiotap_header *tap = &sc->sc_txtap; 3113259453Shselasky struct rt2860_txwi *txwi = 3114208019Sthompsa (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd)); 3115203134Sthompsa tap->wt_flags = 0; 3116203134Sthompsa tap->wt_rate = rt2860_rates[data->ridx].rate; 3117236439Shselasky tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 3118236439Shselasky tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 3119203134Sthompsa tap->wt_hwqueue = index; 3120208019Sthompsa if (le16toh(txwi->phy) & RT2860_PHY_SHPRE) 3121203134Sthompsa tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 3122203134Sthompsa 3123203134Sthompsa ieee80211_radiotap_tx(vap, m); 3124203134Sthompsa } 3125203134Sthompsa 3126228508Shselasky DPRINTFN(11, "sending frame len=%u/%u @ index %d\n", 3127228508Shselasky m->m_pkthdr.len, size, index); 3128203134Sthompsa 3129228508Shselasky usbd_xfer_set_frame_len(xfer, 0, size); 3130203134Sthompsa usbd_xfer_set_priv(xfer, data); 3131203134Sthompsa 3132203134Sthompsa usbd_transfer_submit(xfer); 3133203134Sthompsa 3134203134Sthompsa RUN_UNLOCK(sc); 3135203134Sthompsa run_start(ifp); 3136203134Sthompsa RUN_LOCK(sc); 3137203134Sthompsa 3138203134Sthompsa break; 3139203134Sthompsa 3140203134Sthompsa default: 3141203134Sthompsa DPRINTF("USB transfer error, %s\n", 3142203134Sthompsa usbd_errstr(error)); 3143203134Sthompsa 3144203134Sthompsa data = usbd_xfer_get_priv(xfer); 3145203134Sthompsa 3146203134Sthompsa ifp->if_oerrors++; 3147203134Sthompsa 3148203134Sthompsa if (data != NULL) { 3149208019Sthompsa if(data->ni != NULL) 3150208019Sthompsa vap = data->ni->ni_vap; 3151203134Sthompsa run_tx_free(pq, data, error); 3152203134Sthompsa usbd_xfer_set_priv(xfer, NULL); 3153203134Sthompsa } 3154209917Sthompsa if (vap == NULL) 3155208019Sthompsa vap = TAILQ_FIRST(&ic->ic_vaps); 3156203134Sthompsa 3157203134Sthompsa if (error != USB_ERR_CANCELLED) { 3158203134Sthompsa if (error == USB_ERR_TIMEOUT) { 3159203134Sthompsa device_printf(sc->sc_dev, "device timeout\n"); 3160208019Sthompsa uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 3161208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 3162208019Sthompsa sc->cmdq[i].func = run_usb_timeout_cb; 3163208019Sthompsa sc->cmdq[i].arg0 = vap; 3164208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 3165203134Sthompsa } 3166203134Sthompsa 3167203134Sthompsa /* 3168203134Sthompsa * Try to clear stall first, also if other 3169203134Sthompsa * errors occur, hence clearing stall 3170203134Sthompsa * introduces a 50 ms delay: 3171203134Sthompsa */ 3172203134Sthompsa usbd_xfer_set_stall(xfer); 3173203134Sthompsa goto tr_setup; 3174203134Sthompsa } 3175203134Sthompsa break; 3176203134Sthompsa } 3177203134Sthompsa} 3178203134Sthompsa 3179203134Sthompsastatic void 3180203134Sthompsarun_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error) 3181203134Sthompsa{ 3182203134Sthompsa run_bulk_tx_callbackN(xfer, error, 0); 3183203134Sthompsa} 3184203134Sthompsa 3185203134Sthompsastatic void 3186203134Sthompsarun_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error) 3187203134Sthompsa{ 3188203134Sthompsa run_bulk_tx_callbackN(xfer, error, 1); 3189203134Sthompsa} 3190203134Sthompsa 3191203134Sthompsastatic void 3192203134Sthompsarun_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error) 3193203134Sthompsa{ 3194203134Sthompsa run_bulk_tx_callbackN(xfer, error, 2); 3195203134Sthompsa} 3196203134Sthompsa 3197203134Sthompsastatic void 3198203134Sthompsarun_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error) 3199203134Sthompsa{ 3200203134Sthompsa run_bulk_tx_callbackN(xfer, error, 3); 3201203134Sthompsa} 3202203134Sthompsa 3203203134Sthompsastatic void 3204203134Sthompsarun_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error) 3205203134Sthompsa{ 3206203134Sthompsa run_bulk_tx_callbackN(xfer, error, 4); 3207203134Sthompsa} 3208203134Sthompsa 3209203134Sthompsastatic void 3210203134Sthompsarun_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error) 3211203134Sthompsa{ 3212203134Sthompsa run_bulk_tx_callbackN(xfer, error, 5); 3213203134Sthompsa} 3214203134Sthompsa 3215203134Sthompsastatic void 3216208019Sthompsarun_set_tx_desc(struct run_softc *sc, struct run_tx_data *data) 3217203134Sthompsa{ 3218203134Sthompsa struct mbuf *m = data->m; 3219203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 3220208019Sthompsa struct ieee80211vap *vap = data->ni->ni_vap; 3221203134Sthompsa struct ieee80211_frame *wh; 3222203134Sthompsa struct rt2870_txd *txd; 3223203134Sthompsa struct rt2860_txwi *txwi; 3224259453Shselasky uint16_t xferlen, txwisize; 3225208019Sthompsa uint16_t mcs; 3226203134Sthompsa uint8_t ridx = data->ridx; 3227208019Sthompsa uint8_t pad; 3228203134Sthompsa 3229203134Sthompsa /* get MCS code from rate index */ 3230208019Sthompsa mcs = rt2860_rates[ridx].mcs; 3231203134Sthompsa 3232259453Shselasky txwisize = (sc->mac_ver == 0x5592) ? 3233259453Shselasky sizeof(*txwi) + sizeof(uint32_t) : sizeof(*txwi); 3234259453Shselasky xferlen = txwisize + m->m_pkthdr.len; 3235203134Sthompsa 3236203134Sthompsa /* roundup to 32-bit alignment */ 3237203134Sthompsa xferlen = (xferlen + 3) & ~3; 3238203134Sthompsa 3239203134Sthompsa txd = (struct rt2870_txd *)&data->desc; 3240203134Sthompsa txd->len = htole16(xferlen); 3241203134Sthompsa 3242208019Sthompsa wh = mtod(m, struct ieee80211_frame *); 3243208019Sthompsa 3244208019Sthompsa /* 3245208019Sthompsa * Ether both are true or both are false, the header 3246208019Sthompsa * are nicely aligned to 32-bit. So, no L2 padding. 3247208019Sthompsa */ 3248208019Sthompsa if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh)) 3249208019Sthompsa pad = 0; 3250208019Sthompsa else 3251208019Sthompsa pad = 2; 3252208019Sthompsa 3253203134Sthompsa /* setup TX Wireless Information */ 3254203134Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3255203134Sthompsa txwi->len = htole16(m->m_pkthdr.len - pad); 3256203134Sthompsa if (rt2860_rates[ridx].phy == IEEE80211_T_DS) { 3257270515Skevlo mcs |= RT2860_PHY_CCK; 3258203134Sthompsa if (ridx != RT2860_RIDX_CCK1 && 3259203134Sthompsa (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 3260203134Sthompsa mcs |= RT2860_PHY_SHPRE; 3261203134Sthompsa } else 3262270515Skevlo mcs |= RT2860_PHY_OFDM; 3263270515Skevlo txwi->phy = htole16(mcs); 3264203134Sthompsa 3265203134Sthompsa /* check if RTS/CTS or CTS-to-self protection is required */ 3266203134Sthompsa if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 3267203134Sthompsa (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold || 3268203134Sthompsa ((ic->ic_flags & IEEE80211_F_USEPROT) && 3269203134Sthompsa rt2860_rates[ridx].phy == IEEE80211_T_OFDM))) 3270208019Sthompsa txwi->txop |= RT2860_TX_TXOP_HT; 3271203134Sthompsa else 3272208019Sthompsa txwi->txop |= RT2860_TX_TXOP_BACKOFF; 3273209144Sthompsa 3274209917Sthompsa if (vap->iv_opmode != IEEE80211_M_STA && !IEEE80211_QOS_HAS_SEQ(wh)) 3275209144Sthompsa txwi->xflags |= RT2860_TX_NSEQ; 3276203134Sthompsa} 3277203134Sthompsa 3278203134Sthompsa/* This function must be called locked */ 3279203134Sthompsastatic int 3280203134Sthompsarun_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) 3281203134Sthompsa{ 3282203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 3283208019Sthompsa struct ieee80211vap *vap = ni->ni_vap; 3284203134Sthompsa struct ieee80211_frame *wh; 3285208019Sthompsa struct ieee80211_channel *chan; 3286203134Sthompsa const struct ieee80211_txparam *tp; 3287208019Sthompsa struct run_node *rn = (void *)ni; 3288203134Sthompsa struct run_tx_data *data; 3289208019Sthompsa struct rt2870_txd *txd; 3290208019Sthompsa struct rt2860_txwi *txwi; 3291203134Sthompsa uint16_t qos; 3292203134Sthompsa uint16_t dur; 3293208019Sthompsa uint16_t qid; 3294203134Sthompsa uint8_t type; 3295203134Sthompsa uint8_t tid; 3296208019Sthompsa uint8_t ridx; 3297208019Sthompsa uint8_t ctl_ridx; 3298203134Sthompsa uint8_t qflags; 3299203134Sthompsa uint8_t xflags = 0; 3300203134Sthompsa int hasqos; 3301203134Sthompsa 3302203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3303203134Sthompsa 3304203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3305203134Sthompsa 3306203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3307203134Sthompsa 3308203134Sthompsa /* 3309203134Sthompsa * There are 7 bulk endpoints: 1 for RX 3310203134Sthompsa * and 6 for TX (4 EDCAs + HCCA + Prio). 3311203134Sthompsa * Update 03-14-2009: some devices like the Planex GW-US300MiniS 3312203134Sthompsa * seem to have only 4 TX bulk endpoints (Fukaumi Naoki). 3313203134Sthompsa */ 3314203134Sthompsa if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) { 3315203134Sthompsa uint8_t *frm; 3316203134Sthompsa 3317203134Sthompsa if(IEEE80211_HAS_ADDR4(wh)) 3318203134Sthompsa frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos; 3319203134Sthompsa else 3320203134Sthompsa frm =((struct ieee80211_qosframe *)wh)->i_qos; 3321203134Sthompsa 3322203134Sthompsa qos = le16toh(*(const uint16_t *)frm); 3323203134Sthompsa tid = qos & IEEE80211_QOS_TID; 3324203134Sthompsa qid = TID_TO_WME_AC(tid); 3325203134Sthompsa } else { 3326203134Sthompsa qos = 0; 3327203134Sthompsa tid = 0; 3328203134Sthompsa qid = WME_AC_BE; 3329203134Sthompsa } 3330203134Sthompsa qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA; 3331203134Sthompsa 3332203134Sthompsa DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n", 3333203134Sthompsa qos, qid, tid, qflags); 3334203134Sthompsa 3335208019Sthompsa chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan; 3336208019Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(chan)]; 3337203134Sthompsa 3338203134Sthompsa /* pickup a rate index */ 3339203134Sthompsa if (IEEE80211_IS_MULTICAST(wh->i_addr1) || 3340270515Skevlo type != IEEE80211_FC0_TYPE_DATA || m->m_flags & M_EAPOL) { 3341203134Sthompsa ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? 3342203134Sthompsa RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; 3343203134Sthompsa ctl_ridx = rt2860_rates[ridx].ctl_ridx; 3344203134Sthompsa } else { 3345208019Sthompsa if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) 3346208019Sthompsa ridx = rn->fix_ridx; 3347208019Sthompsa else 3348208019Sthompsa ridx = rn->amrr_ridx; 3349203134Sthompsa ctl_ridx = rt2860_rates[ridx].ctl_ridx; 3350203134Sthompsa } 3351203134Sthompsa 3352203134Sthompsa if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 3353203134Sthompsa (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) != 3354203134Sthompsa IEEE80211_QOS_ACKPOLICY_NOACK)) { 3355209144Sthompsa xflags |= RT2860_TX_ACK; 3356203134Sthompsa if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 3357208019Sthompsa dur = rt2860_rates[ctl_ridx].sp_ack_dur; 3358203134Sthompsa else 3359208019Sthompsa dur = rt2860_rates[ctl_ridx].lp_ack_dur; 3360259453Shselasky USETW(wh->i_dur, dur); 3361203134Sthompsa } 3362203134Sthompsa 3363203134Sthompsa /* reserve slots for mgmt packets, just in case */ 3364203134Sthompsa if (sc->sc_epq[qid].tx_nfree < 3) { 3365203134Sthompsa DPRINTFN(10, "tx ring %d is full\n", qid); 3366203134Sthompsa return (-1); 3367203134Sthompsa } 3368203134Sthompsa 3369203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh); 3370203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next); 3371203134Sthompsa sc->sc_epq[qid].tx_nfree--; 3372203134Sthompsa 3373208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3374208019Sthompsa txd->flags = qflags; 3375208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3376208019Sthompsa txwi->xflags = xflags; 3377259453Shselasky if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 3378245047Shselasky txwi->wcid = 0; 3379259453Shselasky else 3380245047Shselasky txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 3381245047Shselasky 1 : RUN_AID2WCID(ni->ni_associd); 3382259453Shselasky 3383208019Sthompsa /* clear leftover garbage bits */ 3384208019Sthompsa txwi->flags = 0; 3385208019Sthompsa txwi->txop = 0; 3386208019Sthompsa 3387203134Sthompsa data->m = m; 3388203134Sthompsa data->ni = ni; 3389203134Sthompsa data->ridx = ridx; 3390203134Sthompsa 3391208019Sthompsa run_set_tx_desc(sc, data); 3392203134Sthompsa 3393208019Sthompsa /* 3394208019Sthompsa * The chip keeps track of 2 kind of Tx stats, 3395208019Sthompsa * * TX_STAT_FIFO, for per WCID stats, and 3396208019Sthompsa * * TX_STA_CNT0 for all-TX-in-one stats. 3397208019Sthompsa * 3398208019Sthompsa * To use FIFO stats, we need to store MCS into the driver-private 3399208019Sthompsa * PacketID field. So that, we can tell whose stats when we read them. 3400208019Sthompsa * We add 1 to the MCS because setting the PacketID field to 0 means 3401208019Sthompsa * that we don't want feedback in TX_STAT_FIFO. 3402208019Sthompsa * And, that's what we want for STA mode, since TX_STA_CNT0 does the job. 3403208019Sthompsa * 3404208019Sthompsa * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx(). 3405208019Sthompsa */ 3406209917Sthompsa if (sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP || 3407209917Sthompsa vap->iv_opmode == IEEE80211_M_MBSS) { 3408208019Sthompsa uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf; 3409208019Sthompsa txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT); 3410208019Sthompsa 3411208019Sthompsa /* 3412208019Sthompsa * Unlike PCI based devices, we don't get any interrupt from 3413208019Sthompsa * USB devices, so we simulate FIFO-is-full interrupt here. 3414208019Sthompsa * Ralink recomends to drain FIFO stats every 100 ms, but 16 slots 3415208019Sthompsa * quickly get fulled. To prevent overflow, increment a counter on 3416208019Sthompsa * every FIFO stat request, so we know how many slots are left. 3417208019Sthompsa * We do this only in HOSTAP or multiple vap mode since FIFO stats 3418208019Sthompsa * are used only in those modes. 3419208019Sthompsa * We just drain stats. AMRR gets updated every 1 sec by 3420208019Sthompsa * run_ratectl_cb() via callout. 3421208019Sthompsa * Call it early. Otherwise overflow. 3422208019Sthompsa */ 3423209917Sthompsa if (sc->fifo_cnt++ == 10) { 3424208019Sthompsa /* 3425208019Sthompsa * With multiple vaps or if_bridge, if_start() is called 3426208019Sthompsa * with a non-sleepable lock, tcpinp. So, need to defer. 3427208019Sthompsa */ 3428208019Sthompsa uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 3429208019Sthompsa DPRINTFN(6, "cmdq_store=%d\n", i); 3430208019Sthompsa sc->cmdq[i].func = run_drain_fifo; 3431208019Sthompsa sc->cmdq[i].arg0 = sc; 3432208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 3433208019Sthompsa } 3434208019Sthompsa } 3435208019Sthompsa 3436203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next); 3437203134Sthompsa 3438203134Sthompsa usbd_transfer_start(sc->sc_xfer[qid]); 3439203134Sthompsa 3440259453Shselasky DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n", 3441259453Shselasky m->m_pkthdr.len + (int)(sizeof(struct rt2870_txd) + 3442259453Shselasky sizeof(struct rt2860_txwi)), rt2860_rates[ridx].rate, qid); 3443203134Sthompsa 3444203134Sthompsa return (0); 3445203134Sthompsa} 3446203134Sthompsa 3447203134Sthompsastatic int 3448203134Sthompsarun_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) 3449203134Sthompsa{ 3450203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 3451203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 3452208019Sthompsa struct run_node *rn = (void *)ni; 3453203134Sthompsa struct run_tx_data *data; 3454203134Sthompsa struct ieee80211_frame *wh; 3455208019Sthompsa struct rt2870_txd *txd; 3456208019Sthompsa struct rt2860_txwi *txwi; 3457203134Sthompsa uint16_t dur; 3458208019Sthompsa uint8_t ridx = rn->mgt_ridx; 3459203134Sthompsa uint8_t type; 3460203134Sthompsa uint8_t xflags = 0; 3461208019Sthompsa uint8_t wflags = 0; 3462203134Sthompsa 3463203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3464203134Sthompsa 3465203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3466203134Sthompsa 3467203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3468203134Sthompsa 3469208019Sthompsa /* tell hardware to add timestamp for probe responses */ 3470208019Sthompsa if ((wh->i_fc[0] & 3471208019Sthompsa (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == 3472208019Sthompsa (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) 3473208019Sthompsa wflags |= RT2860_TX_TS; 3474208019Sthompsa else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 3475203134Sthompsa xflags |= RT2860_TX_ACK; 3476203134Sthompsa 3477208019Sthompsa dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate, 3478203134Sthompsa ic->ic_flags & IEEE80211_F_SHPREAMBLE); 3479259453Shselasky USETW(wh->i_dur, dur); 3480203134Sthompsa } 3481203134Sthompsa 3482203134Sthompsa if (sc->sc_epq[0].tx_nfree == 0) { 3483203134Sthompsa /* let caller free mbuf */ 3484203134Sthompsa ifp->if_drv_flags |= IFF_DRV_OACTIVE; 3485203134Sthompsa return (EIO); 3486203134Sthompsa } 3487203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3488203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3489203134Sthompsa sc->sc_epq[0].tx_nfree--; 3490203134Sthompsa 3491208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3492208019Sthompsa txd->flags = RT2860_TX_QSEL_EDCA; 3493208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3494208019Sthompsa txwi->wcid = 0xff; 3495208019Sthompsa txwi->flags = wflags; 3496208019Sthompsa txwi->xflags = xflags; 3497208019Sthompsa txwi->txop = 0; /* clear leftover garbage bits */ 3498208019Sthompsa 3499203134Sthompsa data->m = m; 3500203134Sthompsa data->ni = ni; 3501203134Sthompsa data->ridx = ridx; 3502203134Sthompsa 3503208019Sthompsa run_set_tx_desc(sc, data); 3504203134Sthompsa 3505203134Sthompsa DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len + 3506259453Shselasky (int)(sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi)), 3507208019Sthompsa rt2860_rates[ridx].rate); 3508203134Sthompsa 3509203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3510203134Sthompsa 3511203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 3512203134Sthompsa 3513203134Sthompsa return (0); 3514203134Sthompsa} 3515203134Sthompsa 3516203134Sthompsastatic int 3517203134Sthompsarun_sendprot(struct run_softc *sc, 3518203134Sthompsa const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) 3519203134Sthompsa{ 3520203134Sthompsa struct ieee80211com *ic = ni->ni_ic; 3521203134Sthompsa struct ieee80211_frame *wh; 3522203134Sthompsa struct run_tx_data *data; 3523208019Sthompsa struct rt2870_txd *txd; 3524208019Sthompsa struct rt2860_txwi *txwi; 3525203134Sthompsa struct mbuf *mprot; 3526203134Sthompsa int ridx; 3527203134Sthompsa int protrate; 3528203134Sthompsa int ackrate; 3529203134Sthompsa int pktlen; 3530203134Sthompsa int isshort; 3531203134Sthompsa uint16_t dur; 3532203134Sthompsa uint8_t type; 3533208019Sthompsa uint8_t wflags = 0; 3534208019Sthompsa uint8_t xflags = 0; 3535203134Sthompsa 3536203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3537203134Sthompsa 3538203134Sthompsa KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, 3539203134Sthompsa ("protection %d", prot)); 3540203134Sthompsa 3541203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3542203134Sthompsa pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; 3543203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3544203134Sthompsa 3545203134Sthompsa protrate = ieee80211_ctl_rate(ic->ic_rt, rate); 3546203134Sthompsa ackrate = ieee80211_ack_rate(ic->ic_rt, rate); 3547203134Sthompsa 3548203134Sthompsa isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; 3549209189Sjkim dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort) 3550203134Sthompsa + ieee80211_ack_duration(ic->ic_rt, rate, isshort); 3551203134Sthompsa wflags = RT2860_TX_FRAG; 3552203134Sthompsa 3553203134Sthompsa /* check that there are free slots before allocating the mbuf */ 3554203134Sthompsa if (sc->sc_epq[0].tx_nfree == 0) { 3555203134Sthompsa /* let caller free mbuf */ 3556203134Sthompsa sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 3557203134Sthompsa return (ENOBUFS); 3558203134Sthompsa } 3559203134Sthompsa 3560203134Sthompsa if (prot == IEEE80211_PROT_RTSCTS) { 3561203134Sthompsa /* NB: CTS is the same size as an ACK */ 3562203134Sthompsa dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); 3563208019Sthompsa xflags |= RT2860_TX_ACK; 3564203134Sthompsa mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); 3565203134Sthompsa } else { 3566203134Sthompsa mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); 3567203134Sthompsa } 3568203134Sthompsa if (mprot == NULL) { 3569203134Sthompsa sc->sc_ifp->if_oerrors++; 3570203134Sthompsa DPRINTF("could not allocate mbuf\n"); 3571203134Sthompsa return (ENOBUFS); 3572203134Sthompsa } 3573203134Sthompsa 3574203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3575203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3576203134Sthompsa sc->sc_epq[0].tx_nfree--; 3577203134Sthompsa 3578208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3579208019Sthompsa txd->flags = RT2860_TX_QSEL_EDCA; 3580208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3581208019Sthompsa txwi->wcid = 0xff; 3582208019Sthompsa txwi->flags = wflags; 3583208019Sthompsa txwi->xflags = xflags; 3584208019Sthompsa txwi->txop = 0; /* clear leftover garbage bits */ 3585208019Sthompsa 3586203134Sthompsa data->m = mprot; 3587203134Sthompsa data->ni = ieee80211_ref_node(ni); 3588203134Sthompsa 3589203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 3590203134Sthompsa if (rt2860_rates[ridx].rate == protrate) 3591203134Sthompsa break; 3592203134Sthompsa data->ridx = ridx; 3593203134Sthompsa 3594208019Sthompsa run_set_tx_desc(sc, data); 3595203134Sthompsa 3596203134Sthompsa DPRINTFN(1, "sending prot len=%u rate=%u\n", 3597203134Sthompsa m->m_pkthdr.len, rate); 3598203134Sthompsa 3599203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3600203134Sthompsa 3601203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 3602203134Sthompsa 3603203134Sthompsa return (0); 3604203134Sthompsa} 3605203134Sthompsa 3606203134Sthompsastatic int 3607203134Sthompsarun_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, 3608203134Sthompsa const struct ieee80211_bpf_params *params) 3609203134Sthompsa{ 3610203134Sthompsa struct ieee80211com *ic = ni->ni_ic; 3611203134Sthompsa struct ieee80211_frame *wh; 3612203134Sthompsa struct run_tx_data *data; 3613208019Sthompsa struct rt2870_txd *txd; 3614208019Sthompsa struct rt2860_txwi *txwi; 3615203134Sthompsa uint8_t type; 3616208019Sthompsa uint8_t ridx; 3617208019Sthompsa uint8_t rate; 3618208019Sthompsa uint8_t opflags = 0; 3619208019Sthompsa uint8_t xflags = 0; 3620203134Sthompsa int error; 3621203134Sthompsa 3622203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3623203134Sthompsa 3624203134Sthompsa KASSERT(params != NULL, ("no raw xmit params")); 3625203134Sthompsa 3626203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3627203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3628203134Sthompsa 3629203134Sthompsa rate = params->ibp_rate0; 3630203134Sthompsa if (!ieee80211_isratevalid(ic->ic_rt, rate)) { 3631203134Sthompsa /* let caller free mbuf */ 3632203134Sthompsa return (EINVAL); 3633203134Sthompsa } 3634203134Sthompsa 3635203134Sthompsa if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) 3636208019Sthompsa xflags |= RT2860_TX_ACK; 3637203134Sthompsa if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { 3638203134Sthompsa error = run_sendprot(sc, m, ni, 3639203134Sthompsa params->ibp_flags & IEEE80211_BPF_RTS ? 3640203134Sthompsa IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, 3641203134Sthompsa rate); 3642203134Sthompsa if (error) { 3643203134Sthompsa /* let caller free mbuf */ 3644209917Sthompsa return error; 3645203134Sthompsa } 3646203134Sthompsa opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS; 3647203134Sthompsa } 3648203134Sthompsa 3649203134Sthompsa if (sc->sc_epq[0].tx_nfree == 0) { 3650203134Sthompsa /* let caller free mbuf */ 3651203134Sthompsa sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 3652203134Sthompsa DPRINTF("sending raw frame, but tx ring is full\n"); 3653203134Sthompsa return (EIO); 3654203134Sthompsa } 3655203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3656203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3657203134Sthompsa sc->sc_epq[0].tx_nfree--; 3658203134Sthompsa 3659208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3660208019Sthompsa txd->flags = RT2860_TX_QSEL_EDCA; 3661208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3662208019Sthompsa txwi->wcid = 0xff; 3663208019Sthompsa txwi->xflags = xflags; 3664208019Sthompsa txwi->txop = opflags; 3665208019Sthompsa txwi->flags = 0; /* clear leftover garbage bits */ 3666208019Sthompsa 3667203134Sthompsa data->m = m; 3668203134Sthompsa data->ni = ni; 3669203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 3670203134Sthompsa if (rt2860_rates[ridx].rate == rate) 3671203134Sthompsa break; 3672203134Sthompsa data->ridx = ridx; 3673203134Sthompsa 3674208019Sthompsa run_set_tx_desc(sc, data); 3675203134Sthompsa 3676203134Sthompsa DPRINTFN(10, "sending raw frame len=%u rate=%u\n", 3677203134Sthompsa m->m_pkthdr.len, rate); 3678203134Sthompsa 3679203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3680203134Sthompsa 3681203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 3682203134Sthompsa 3683209917Sthompsa return (0); 3684203134Sthompsa} 3685203134Sthompsa 3686203134Sthompsastatic int 3687203134Sthompsarun_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 3688203134Sthompsa const struct ieee80211_bpf_params *params) 3689203134Sthompsa{ 3690203134Sthompsa struct ifnet *ifp = ni->ni_ic->ic_ifp; 3691203134Sthompsa struct run_softc *sc = ifp->if_softc; 3692208019Sthompsa int error = 0; 3693208019Sthompsa 3694203134Sthompsa RUN_LOCK(sc); 3695203134Sthompsa 3696203134Sthompsa /* prevent management frames from being sent if we're not ready */ 3697203134Sthompsa if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 3698203134Sthompsa error = ENETDOWN; 3699208019Sthompsa goto done; 3700203134Sthompsa } 3701203134Sthompsa 3702203134Sthompsa if (params == NULL) { 3703203134Sthompsa /* tx mgt packet */ 3704209917Sthompsa if ((error = run_tx_mgt(sc, m, ni)) != 0) { 3705203134Sthompsa ifp->if_oerrors++; 3706203134Sthompsa DPRINTF("mgt tx failed\n"); 3707208019Sthompsa goto done; 3708203134Sthompsa } 3709203134Sthompsa } else { 3710203134Sthompsa /* tx raw packet with param */ 3711209917Sthompsa if ((error = run_tx_param(sc, m, ni, params)) != 0) { 3712203134Sthompsa ifp->if_oerrors++; 3713203134Sthompsa DPRINTF("tx with param failed\n"); 3714208019Sthompsa goto done; 3715203134Sthompsa } 3716203134Sthompsa } 3717203134Sthompsa 3718203134Sthompsa ifp->if_opackets++; 3719203134Sthompsa 3720208019Sthompsadone: 3721203134Sthompsa RUN_UNLOCK(sc); 3722203134Sthompsa 3723209917Sthompsa if (error != 0) { 3724208019Sthompsa if(m != NULL) 3725208019Sthompsa m_freem(m); 3726208019Sthompsa ieee80211_free_node(ni); 3727208019Sthompsa } 3728203134Sthompsa 3729203134Sthompsa return (error); 3730203134Sthompsa} 3731203134Sthompsa 3732203134Sthompsastatic void 3733203134Sthompsarun_start(struct ifnet *ifp) 3734203134Sthompsa{ 3735203134Sthompsa struct run_softc *sc = ifp->if_softc; 3736203134Sthompsa struct ieee80211_node *ni; 3737203134Sthompsa struct mbuf *m; 3738203134Sthompsa 3739203134Sthompsa RUN_LOCK(sc); 3740203134Sthompsa 3741203134Sthompsa if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 3742203134Sthompsa RUN_UNLOCK(sc); 3743203134Sthompsa return; 3744203134Sthompsa } 3745203134Sthompsa 3746203134Sthompsa for (;;) { 3747203134Sthompsa /* send data frames */ 3748203134Sthompsa IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 3749203134Sthompsa if (m == NULL) 3750203134Sthompsa break; 3751203134Sthompsa 3752203134Sthompsa ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 3753203134Sthompsa if (run_tx(sc, m, ni) != 0) { 3754203134Sthompsa IFQ_DRV_PREPEND(&ifp->if_snd, m); 3755203134Sthompsa ifp->if_drv_flags |= IFF_DRV_OACTIVE; 3756203134Sthompsa break; 3757203134Sthompsa } 3758203134Sthompsa } 3759203134Sthompsa 3760203134Sthompsa RUN_UNLOCK(sc); 3761203134Sthompsa} 3762203134Sthompsa 3763203134Sthompsastatic int 3764203134Sthompsarun_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 3765203134Sthompsa{ 3766203134Sthompsa struct run_softc *sc = ifp->if_softc; 3767203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 3768203134Sthompsa struct ifreq *ifr = (struct ifreq *) data; 3769208019Sthompsa int startall = 0; 3770246614Shselasky int error; 3771203134Sthompsa 3772246614Shselasky RUN_LOCK(sc); 3773246614Shselasky error = sc->sc_detached ? ENXIO : 0; 3774246614Shselasky RUN_UNLOCK(sc); 3775246614Shselasky if (error) 3776246614Shselasky return (error); 3777246614Shselasky 3778203134Sthompsa switch (cmd) { 3779203134Sthompsa case SIOCSIFFLAGS: 3780203134Sthompsa RUN_LOCK(sc); 3781203134Sthompsa if (ifp->if_flags & IFF_UP) { 3782203134Sthompsa if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)){ 3783208019Sthompsa startall = 1; 3784203134Sthompsa run_init_locked(sc); 3785203134Sthompsa } else 3786203134Sthompsa run_update_promisc_locked(ifp); 3787203134Sthompsa } else { 3788209917Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING && 3789209917Sthompsa (ic->ic_nrunning == 0 || sc->rvp_cnt <= 1)) { 3790208019Sthompsa run_stop(sc); 3791208019Sthompsa } 3792203134Sthompsa } 3793203134Sthompsa RUN_UNLOCK(sc); 3794209917Sthompsa if (startall) 3795208019Sthompsa ieee80211_start_all(ic); 3796203134Sthompsa break; 3797203134Sthompsa case SIOCGIFMEDIA: 3798203134Sthompsa error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); 3799203134Sthompsa break; 3800203134Sthompsa case SIOCGIFADDR: 3801203134Sthompsa error = ether_ioctl(ifp, cmd, data); 3802203134Sthompsa break; 3803203134Sthompsa default: 3804203134Sthompsa error = EINVAL; 3805203134Sthompsa break; 3806203134Sthompsa } 3807203134Sthompsa 3808203134Sthompsa return (error); 3809203134Sthompsa} 3810203134Sthompsa 3811203134Sthompsastatic void 3812261868Skevlorun_iq_calib(struct run_softc *sc, u_int chan) 3813261868Skevlo{ 3814261868Skevlo uint16_t val; 3815261868Skevlo 3816261868Skevlo /* Tx0 IQ gain. */ 3817261868Skevlo run_bbp_write(sc, 158, 0x2c); 3818261868Skevlo if (chan <= 14) 3819261868Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX0_2GHZ, &val, 1); 3820261868Skevlo else if (chan <= 64) { 3821261868Skevlo run_efuse_read(sc, 3822261868Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5GHZ, 3823261868Skevlo &val, 1); 3824261868Skevlo } else if (chan <= 138) { 3825261868Skevlo run_efuse_read(sc, 3826261868Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5GHZ, 3827261868Skevlo &val, 1); 3828261868Skevlo } else if (chan <= 165) { 3829261868Skevlo run_efuse_read(sc, 3830261868Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5GHZ, 3831261868Skevlo &val, 1); 3832261868Skevlo } else 3833261868Skevlo val = 0; 3834261868Skevlo run_bbp_write(sc, 159, val); 3835261868Skevlo 3836261868Skevlo /* Tx0 IQ phase. */ 3837261868Skevlo run_bbp_write(sc, 158, 0x2d); 3838261868Skevlo if (chan <= 14) { 3839261868Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX0_2GHZ, 3840261868Skevlo &val, 1); 3841261868Skevlo } else if (chan <= 64) { 3842261868Skevlo run_efuse_read(sc, 3843261868Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5GHZ, 3844261868Skevlo &val, 1); 3845261868Skevlo } else if (chan <= 138) { 3846261868Skevlo run_efuse_read(sc, 3847261868Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5GHZ, 3848261868Skevlo &val, 1); 3849261868Skevlo } else if (chan <= 165) { 3850261868Skevlo run_efuse_read(sc, 3851261868Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5GHZ, 3852261868Skevlo &val, 1); 3853261868Skevlo } else 3854261868Skevlo val = 0; 3855261868Skevlo run_bbp_write(sc, 159, val); 3856261868Skevlo 3857261868Skevlo /* Tx1 IQ gain. */ 3858261868Skevlo run_bbp_write(sc, 158, 0x4a); 3859261868Skevlo if (chan <= 14) { 3860261868Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX1_2GHZ, 3861261868Skevlo &val, 1); 3862261868Skevlo } else if (chan <= 64) { 3863261868Skevlo run_efuse_read(sc, 3864261868Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5GHZ, 3865261868Skevlo &val, 1); 3866261868Skevlo } else if (chan <= 138) { 3867261868Skevlo run_efuse_read(sc, 3868261868Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5GHZ, 3869261868Skevlo &val, 1); 3870261868Skevlo } else if (chan <= 165) { 3871261868Skevlo run_efuse_read(sc, 3872261868Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5GHZ, 3873261868Skevlo &val, 1); 3874261868Skevlo } else 3875261868Skevlo val = 0; 3876261868Skevlo run_bbp_write(sc, 159, val); 3877261868Skevlo 3878261868Skevlo /* Tx1 IQ phase. */ 3879261868Skevlo run_bbp_write(sc, 158, 0x4b); 3880261868Skevlo if (chan <= 14) { 3881261868Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX1_2GHZ, 3882261868Skevlo &val, 1); 3883261868Skevlo } else if (chan <= 64) { 3884261868Skevlo run_efuse_read(sc, 3885261868Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5GHZ, 3886261868Skevlo &val, 1); 3887261868Skevlo } else if (chan <= 138) { 3888261868Skevlo run_efuse_read(sc, 3889261868Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5GHZ, 3890261868Skevlo &val, 1); 3891261868Skevlo } else if (chan <= 165) { 3892261868Skevlo run_efuse_read(sc, 3893261868Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5GHZ, 3894261868Skevlo &val, 1); 3895261868Skevlo } else 3896261868Skevlo val = 0; 3897261868Skevlo run_bbp_write(sc, 159, val); 3898261868Skevlo 3899261868Skevlo /* RF IQ compensation control. */ 3900261868Skevlo run_bbp_write(sc, 158, 0x04); 3901261868Skevlo run_efuse_read(sc, RT5390_EEPROM_RF_IQ_COMPENSATION_CTL, 3902261868Skevlo &val, 1); 3903261868Skevlo run_bbp_write(sc, 159, val); 3904261868Skevlo 3905261868Skevlo /* RF IQ imbalance compensation control. */ 3906261868Skevlo run_bbp_write(sc, 158, 0x03); 3907261868Skevlo run_efuse_read(sc, 3908261868Skevlo RT5390_EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CTL, &val, 1); 3909261868Skevlo run_bbp_write(sc, 159, val); 3910261868Skevlo} 3911261868Skevlo 3912261868Skevlostatic void 3913205042Sthompsarun_set_agc(struct run_softc *sc, uint8_t agc) 3914205042Sthompsa{ 3915205042Sthompsa uint8_t bbp; 3916205042Sthompsa 3917205042Sthompsa if (sc->mac_ver == 0x3572) { 3918205042Sthompsa run_bbp_read(sc, 27, &bbp); 3919205042Sthompsa bbp &= ~(0x3 << 5); 3920205042Sthompsa run_bbp_write(sc, 27, bbp | 0 << 5); /* select Rx0 */ 3921205042Sthompsa run_bbp_write(sc, 66, agc); 3922205042Sthompsa run_bbp_write(sc, 27, bbp | 1 << 5); /* select Rx1 */ 3923205042Sthompsa run_bbp_write(sc, 66, agc); 3924205042Sthompsa } else 3925205042Sthompsa run_bbp_write(sc, 66, agc); 3926205042Sthompsa} 3927205042Sthompsa 3928205042Sthompsastatic void 3929203134Sthompsarun_select_chan_group(struct run_softc *sc, int group) 3930203134Sthompsa{ 3931203134Sthompsa uint32_t tmp; 3932205042Sthompsa uint8_t agc; 3933203134Sthompsa 3934203134Sthompsa run_bbp_write(sc, 62, 0x37 - sc->lna[group]); 3935203134Sthompsa run_bbp_write(sc, 63, 0x37 - sc->lna[group]); 3936203134Sthompsa run_bbp_write(sc, 64, 0x37 - sc->lna[group]); 3937259453Shselasky if (sc->mac_ver < 0x3572) 3938259453Shselasky run_bbp_write(sc, 86, 0x00); 3939203134Sthompsa 3940261868Skevlo if (sc->mac_ver == 0x3593) { 3941261868Skevlo run_bbp_write(sc, 77, 0x98); 3942261868Skevlo run_bbp_write(sc, 83, (group == 0) ? 0x8a : 0x9a); 3943261868Skevlo } 3944261868Skevlo 3945203134Sthompsa if (group == 0) { 3946203134Sthompsa if (sc->ext_2ghz_lna) { 3947259453Shselasky if (sc->mac_ver >= 0x5390) 3948259453Shselasky run_bbp_write(sc, 75, 0x52); 3949259453Shselasky else { 3950259453Shselasky run_bbp_write(sc, 82, 0x62); 3951259453Shselasky run_bbp_write(sc, 75, 0x46); 3952259453Shselasky } 3953203134Sthompsa } else { 3954259453Shselasky if (sc->mac_ver == 0x5592) { 3955259453Shselasky run_bbp_write(sc, 79, 0x1c); 3956259453Shselasky run_bbp_write(sc, 80, 0x0e); 3957259453Shselasky run_bbp_write(sc, 81, 0x3a); 3958259453Shselasky run_bbp_write(sc, 82, 0x62); 3959259453Shselasky 3960259453Shselasky run_bbp_write(sc, 195, 0x80); 3961259453Shselasky run_bbp_write(sc, 196, 0xe0); 3962259453Shselasky run_bbp_write(sc, 195, 0x81); 3963259453Shselasky run_bbp_write(sc, 196, 0x1f); 3964259453Shselasky run_bbp_write(sc, 195, 0x82); 3965259453Shselasky run_bbp_write(sc, 196, 0x38); 3966259453Shselasky run_bbp_write(sc, 195, 0x83); 3967259453Shselasky run_bbp_write(sc, 196, 0x32); 3968259453Shselasky run_bbp_write(sc, 195, 0x85); 3969259453Shselasky run_bbp_write(sc, 196, 0x28); 3970259453Shselasky run_bbp_write(sc, 195, 0x86); 3971259453Shselasky run_bbp_write(sc, 196, 0x19); 3972259453Shselasky } else if (sc->mac_ver >= 0x5390) 3973259453Shselasky run_bbp_write(sc, 75, 0x50); 3974259453Shselasky else { 3975261868Skevlo run_bbp_write(sc, 82, 3976261868Skevlo (sc->mac_ver == 0x3593) ? 0x62 : 0x84); 3977259453Shselasky run_bbp_write(sc, 75, 0x50); 3978259453Shselasky } 3979203134Sthompsa } 3980203134Sthompsa } else { 3981259453Shselasky if (sc->mac_ver == 0x5592) { 3982259453Shselasky run_bbp_write(sc, 79, 0x18); 3983259453Shselasky run_bbp_write(sc, 80, 0x08); 3984259453Shselasky run_bbp_write(sc, 81, 0x38); 3985259453Shselasky run_bbp_write(sc, 82, 0x92); 3986259453Shselasky 3987259453Shselasky run_bbp_write(sc, 195, 0x80); 3988259453Shselasky run_bbp_write(sc, 196, 0xf0); 3989259453Shselasky run_bbp_write(sc, 195, 0x81); 3990259453Shselasky run_bbp_write(sc, 196, 0x1e); 3991259453Shselasky run_bbp_write(sc, 195, 0x82); 3992259453Shselasky run_bbp_write(sc, 196, 0x28); 3993259453Shselasky run_bbp_write(sc, 195, 0x83); 3994259453Shselasky run_bbp_write(sc, 196, 0x20); 3995259453Shselasky run_bbp_write(sc, 195, 0x85); 3996259453Shselasky run_bbp_write(sc, 196, 0x7f); 3997259453Shselasky run_bbp_write(sc, 195, 0x86); 3998259453Shselasky run_bbp_write(sc, 196, 0x7f); 3999259453Shselasky } else if (sc->mac_ver == 0x3572) 4000205042Sthompsa run_bbp_write(sc, 82, 0x94); 4001205042Sthompsa else 4002261868Skevlo run_bbp_write(sc, 82, 4003261868Skevlo (sc->mac_ver == 0x3593) ? 0x82 : 0xf2); 4004205042Sthompsa if (sc->ext_5ghz_lna) 4005203134Sthompsa run_bbp_write(sc, 75, 0x46); 4006205042Sthompsa else 4007203134Sthompsa run_bbp_write(sc, 75, 0x50); 4008203134Sthompsa } 4009203134Sthompsa 4010203134Sthompsa run_read(sc, RT2860_TX_BAND_CFG, &tmp); 4011203134Sthompsa tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P); 4012203134Sthompsa tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P; 4013203134Sthompsa run_write(sc, RT2860_TX_BAND_CFG, tmp); 4014203134Sthompsa 4015203134Sthompsa /* enable appropriate Power Amplifiers and Low Noise Amplifiers */ 4016208019Sthompsa tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN; 4017261868Skevlo if (sc->mac_ver == 0x3593) 4018261868Skevlo tmp |= 1 << 29 | 1 << 28; 4019208019Sthompsa if (sc->nrxchains > 1) 4020208019Sthompsa tmp |= RT2860_LNA_PE1_EN; 4021203134Sthompsa if (group == 0) { /* 2GHz */ 4022208019Sthompsa tmp |= RT2860_PA_PE_G0_EN; 4023203134Sthompsa if (sc->ntxchains > 1) 4024203134Sthompsa tmp |= RT2860_PA_PE_G1_EN; 4025261868Skevlo if (sc->mac_ver == 0x3593) { 4026261868Skevlo if (sc->ntxchains > 2) 4027261868Skevlo tmp |= 1 << 25; 4028261868Skevlo } 4029203134Sthompsa } else { /* 5GHz */ 4030208019Sthompsa tmp |= RT2860_PA_PE_A0_EN; 4031203134Sthompsa if (sc->ntxchains > 1) 4032203134Sthompsa tmp |= RT2860_PA_PE_A1_EN; 4033203134Sthompsa } 4034205042Sthompsa if (sc->mac_ver == 0x3572) { 4035205042Sthompsa run_rt3070_rf_write(sc, 8, 0x00); 4036205042Sthompsa run_write(sc, RT2860_TX_PIN_CFG, tmp); 4037205042Sthompsa run_rt3070_rf_write(sc, 8, 0x80); 4038205042Sthompsa } else 4039205042Sthompsa run_write(sc, RT2860_TX_PIN_CFG, tmp); 4040203134Sthompsa 4041259453Shselasky if (sc->mac_ver == 0x5592) { 4042259453Shselasky run_bbp_write(sc, 195, 0x8d); 4043259453Shselasky run_bbp_write(sc, 196, 0x1a); 4044259453Shselasky } 4045259453Shselasky 4046261868Skevlo if (sc->mac_ver == 0x3593) { 4047261868Skevlo run_read(sc, RT2860_GPIO_CTRL, &tmp); 4048261868Skevlo tmp &= ~0x01010000; 4049261868Skevlo if (group == 0) 4050261868Skevlo tmp |= 0x00010000; 4051261868Skevlo tmp = (tmp & ~0x00009090) | 0x00000090; 4052261868Skevlo run_write(sc, RT2860_GPIO_CTRL, tmp); 4053261868Skevlo } 4054261868Skevlo 4055203134Sthompsa /* set initial AGC value */ 4056205042Sthompsa if (group == 0) { /* 2GHz band */ 4057205042Sthompsa if (sc->mac_ver >= 0x3070) 4058205042Sthompsa agc = 0x1c + sc->lna[0] * 2; 4059205042Sthompsa else 4060205042Sthompsa agc = 0x2e + sc->lna[0]; 4061205042Sthompsa } else { /* 5GHz band */ 4062259453Shselasky if (sc->mac_ver == 0x5592) 4063259453Shselasky agc = 0x24 + sc->lna[group] * 2; 4064261868Skevlo else if (sc->mac_ver == 0x3572 || sc->mac_ver == 0x3593) 4065205042Sthompsa agc = 0x22 + (sc->lna[group] * 5) / 3; 4066205042Sthompsa else 4067205042Sthompsa agc = 0x32 + (sc->lna[group] * 5) / 3; 4068205042Sthompsa } 4069205042Sthompsa run_set_agc(sc, agc); 4070203134Sthompsa} 4071203134Sthompsa 4072203134Sthompsastatic void 4073259453Shselaskyrun_rt2870_set_chan(struct run_softc *sc, u_int chan) 4074203134Sthompsa{ 4075203134Sthompsa const struct rfprog *rfprog = rt2860_rf2850; 4076203134Sthompsa uint32_t r2, r3, r4; 4077203134Sthompsa int8_t txpow1, txpow2; 4078203134Sthompsa int i; 4079203134Sthompsa 4080203134Sthompsa /* find the settings for this channel (we know it exists) */ 4081203134Sthompsa for (i = 0; rfprog[i].chan != chan; i++); 4082203134Sthompsa 4083203134Sthompsa r2 = rfprog[i].r2; 4084203134Sthompsa if (sc->ntxchains == 1) 4085259453Shselasky r2 |= 1 << 14; /* 1T: disable Tx chain 2 */ 4086203134Sthompsa if (sc->nrxchains == 1) 4087259453Shselasky r2 |= 1 << 17 | 1 << 6; /* 1R: disable Rx chains 2 & 3 */ 4088203134Sthompsa else if (sc->nrxchains == 2) 4089259453Shselasky r2 |= 1 << 6; /* 2R: disable Rx chain 3 */ 4090203134Sthompsa 4091203134Sthompsa /* use Tx power values from EEPROM */ 4092203134Sthompsa txpow1 = sc->txpow1[i]; 4093203134Sthompsa txpow2 = sc->txpow2[i]; 4094259453Shselasky 4095259453Shselasky /* Initialize RF R3 and R4. */ 4096259453Shselasky r3 = rfprog[i].r3 & 0xffffc1ff; 4097259453Shselasky r4 = (rfprog[i].r4 & ~(0x001f87c0)) | (sc->freq << 15); 4098203134Sthompsa if (chan > 14) { 4099259453Shselasky if (txpow1 >= 0) { 4100259453Shselasky txpow1 = (txpow1 > 0xf) ? (0xf) : (txpow1); 4101259453Shselasky r3 |= (txpow1 << 10) | (1 << 9); 4102259453Shselasky } else { 4103259453Shselasky txpow1 += 7; 4104259453Shselasky 4105259453Shselasky /* txpow1 is not possible larger than 15. */ 4106259453Shselasky r3 |= (txpow1 << 10); 4107259453Shselasky } 4108259453Shselasky if (txpow2 >= 0) { 4109259453Shselasky txpow2 = (txpow2 > 0xf) ? (0xf) : (txpow2); 4110259453Shselasky r4 |= (txpow2 << 7) | (1 << 6); 4111259453Shselasky } else { 4112259453Shselasky txpow2 += 7; 4113259453Shselasky r4 |= (txpow2 << 7); 4114259453Shselasky } 4115259453Shselasky } else { 4116259453Shselasky /* Set Tx0 power. */ 4117259453Shselasky r3 |= (txpow1 << 9); 4118259453Shselasky 4119259453Shselasky /* Set frequency offset and Tx1 power. */ 4120259453Shselasky r4 |= (txpow2 << 6); 4121203134Sthompsa } 4122203134Sthompsa 4123259453Shselasky run_rt2870_rf_write(sc, rfprog[i].r1); 4124259453Shselasky run_rt2870_rf_write(sc, r2); 4125259453Shselasky run_rt2870_rf_write(sc, r3 & ~(1 << 2)); 4126259453Shselasky run_rt2870_rf_write(sc, r4); 4127203134Sthompsa 4128203134Sthompsa run_delay(sc, 10); 4129203134Sthompsa 4130259453Shselasky run_rt2870_rf_write(sc, rfprog[i].r1); 4131259453Shselasky run_rt2870_rf_write(sc, r2); 4132259453Shselasky run_rt2870_rf_write(sc, r3 | (1 << 2)); 4133259453Shselasky run_rt2870_rf_write(sc, r4); 4134203134Sthompsa 4135203134Sthompsa run_delay(sc, 10); 4136203134Sthompsa 4137259453Shselasky run_rt2870_rf_write(sc, rfprog[i].r1); 4138259453Shselasky run_rt2870_rf_write(sc, r2); 4139259453Shselasky run_rt2870_rf_write(sc, r3 & ~(1 << 2)); 4140259453Shselasky run_rt2870_rf_write(sc, r4); 4141203134Sthompsa} 4142203134Sthompsa 4143203134Sthompsastatic void 4144259453Shselaskyrun_rt3070_set_chan(struct run_softc *sc, u_int chan) 4145203134Sthompsa{ 4146203134Sthompsa int8_t txpow1, txpow2; 4147203134Sthompsa uint8_t rf; 4148205042Sthompsa int i; 4149203134Sthompsa 4150205042Sthompsa /* find the settings for this channel (we know it exists) */ 4151205042Sthompsa for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4152205042Sthompsa 4153203134Sthompsa /* use Tx power values from EEPROM */ 4154205042Sthompsa txpow1 = sc->txpow1[i]; 4155205042Sthompsa txpow2 = sc->txpow2[i]; 4156203134Sthompsa 4157205042Sthompsa run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n); 4158259453Shselasky 4159259453Shselasky /* RT3370/RT3390: RF R3 [7:4] is not reserved bits. */ 4160259453Shselasky run_rt3070_rf_read(sc, 3, &rf); 4161259453Shselasky rf = (rf & ~0x0f) | rt3070_freqs[i].k; 4162259453Shselasky run_rt3070_rf_write(sc, 3, rf); 4163259453Shselasky 4164203134Sthompsa run_rt3070_rf_read(sc, 6, &rf); 4165205042Sthompsa rf = (rf & ~0x03) | rt3070_freqs[i].r; 4166203134Sthompsa run_rt3070_rf_write(sc, 6, rf); 4167203134Sthompsa 4168203134Sthompsa /* set Tx0 power */ 4169203134Sthompsa run_rt3070_rf_read(sc, 12, &rf); 4170203134Sthompsa rf = (rf & ~0x1f) | txpow1; 4171203134Sthompsa run_rt3070_rf_write(sc, 12, rf); 4172203134Sthompsa 4173203134Sthompsa /* set Tx1 power */ 4174203134Sthompsa run_rt3070_rf_read(sc, 13, &rf); 4175203134Sthompsa rf = (rf & ~0x1f) | txpow2; 4176203134Sthompsa run_rt3070_rf_write(sc, 13, rf); 4177203134Sthompsa 4178203134Sthompsa run_rt3070_rf_read(sc, 1, &rf); 4179203134Sthompsa rf &= ~0xfc; 4180203134Sthompsa if (sc->ntxchains == 1) 4181203134Sthompsa rf |= 1 << 7 | 1 << 5; /* 1T: disable Tx chains 2 & 3 */ 4182203134Sthompsa else if (sc->ntxchains == 2) 4183203134Sthompsa rf |= 1 << 7; /* 2T: disable Tx chain 3 */ 4184203134Sthompsa if (sc->nrxchains == 1) 4185203134Sthompsa rf |= 1 << 6 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 4186203134Sthompsa else if (sc->nrxchains == 2) 4187203134Sthompsa rf |= 1 << 6; /* 2R: disable Rx chain 3 */ 4188203134Sthompsa run_rt3070_rf_write(sc, 1, rf); 4189203134Sthompsa 4190203134Sthompsa /* set RF offset */ 4191203134Sthompsa run_rt3070_rf_read(sc, 23, &rf); 4192203134Sthompsa rf = (rf & ~0x7f) | sc->freq; 4193203134Sthompsa run_rt3070_rf_write(sc, 23, rf); 4194203134Sthompsa 4195203134Sthompsa /* program RF filter */ 4196205042Sthompsa run_rt3070_rf_read(sc, 24, &rf); /* Tx */ 4197205042Sthompsa rf = (rf & ~0x3f) | sc->rf24_20mhz; 4198205042Sthompsa run_rt3070_rf_write(sc, 24, rf); 4199205042Sthompsa run_rt3070_rf_read(sc, 31, &rf); /* Rx */ 4200205042Sthompsa rf = (rf & ~0x3f) | sc->rf24_20mhz; 4201205042Sthompsa run_rt3070_rf_write(sc, 31, rf); 4202203134Sthompsa 4203203134Sthompsa /* enable RF tuning */ 4204203134Sthompsa run_rt3070_rf_read(sc, 7, &rf); 4205203134Sthompsa run_rt3070_rf_write(sc, 7, rf | 0x01); 4206203134Sthompsa} 4207203134Sthompsa 4208203134Sthompsastatic void 4209205042Sthompsarun_rt3572_set_chan(struct run_softc *sc, u_int chan) 4210205042Sthompsa{ 4211205042Sthompsa int8_t txpow1, txpow2; 4212205042Sthompsa uint32_t tmp; 4213205042Sthompsa uint8_t rf; 4214205042Sthompsa int i; 4215205042Sthompsa 4216205042Sthompsa /* find the settings for this channel (we know it exists) */ 4217205042Sthompsa for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4218205042Sthompsa 4219205042Sthompsa /* use Tx power values from EEPROM */ 4220205042Sthompsa txpow1 = sc->txpow1[i]; 4221205042Sthompsa txpow2 = sc->txpow2[i]; 4222205042Sthompsa 4223205042Sthompsa if (chan <= 14) { 4224205042Sthompsa run_bbp_write(sc, 25, sc->bbp25); 4225205042Sthompsa run_bbp_write(sc, 26, sc->bbp26); 4226205042Sthompsa } else { 4227205042Sthompsa /* enable IQ phase correction */ 4228205042Sthompsa run_bbp_write(sc, 25, 0x09); 4229205042Sthompsa run_bbp_write(sc, 26, 0xff); 4230205042Sthompsa } 4231205042Sthompsa 4232205042Sthompsa run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n); 4233205042Sthompsa run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k); 4234205042Sthompsa run_rt3070_rf_read(sc, 6, &rf); 4235205042Sthompsa rf = (rf & ~0x0f) | rt3070_freqs[i].r; 4236205042Sthompsa rf |= (chan <= 14) ? 0x08 : 0x04; 4237205042Sthompsa run_rt3070_rf_write(sc, 6, rf); 4238205042Sthompsa 4239205042Sthompsa /* set PLL mode */ 4240205042Sthompsa run_rt3070_rf_read(sc, 5, &rf); 4241205042Sthompsa rf &= ~(0x08 | 0x04); 4242205042Sthompsa rf |= (chan <= 14) ? 0x04 : 0x08; 4243205042Sthompsa run_rt3070_rf_write(sc, 5, rf); 4244205042Sthompsa 4245205042Sthompsa /* set Tx power for chain 0 */ 4246205042Sthompsa if (chan <= 14) 4247205042Sthompsa rf = 0x60 | txpow1; 4248205042Sthompsa else 4249205042Sthompsa rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3); 4250205042Sthompsa run_rt3070_rf_write(sc, 12, rf); 4251205042Sthompsa 4252205042Sthompsa /* set Tx power for chain 1 */ 4253205042Sthompsa if (chan <= 14) 4254205042Sthompsa rf = 0x60 | txpow2; 4255205042Sthompsa else 4256205042Sthompsa rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3); 4257205042Sthompsa run_rt3070_rf_write(sc, 13, rf); 4258205042Sthompsa 4259205042Sthompsa /* set Tx/Rx streams */ 4260205042Sthompsa run_rt3070_rf_read(sc, 1, &rf); 4261205042Sthompsa rf &= ~0xfc; 4262205042Sthompsa if (sc->ntxchains == 1) 4263205042Sthompsa rf |= 1 << 7 | 1 << 5; /* 1T: disable Tx chains 2 & 3 */ 4264205042Sthompsa else if (sc->ntxchains == 2) 4265205042Sthompsa rf |= 1 << 7; /* 2T: disable Tx chain 3 */ 4266205042Sthompsa if (sc->nrxchains == 1) 4267205042Sthompsa rf |= 1 << 6 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 4268205042Sthompsa else if (sc->nrxchains == 2) 4269205042Sthompsa rf |= 1 << 6; /* 2R: disable Rx chain 3 */ 4270205042Sthompsa run_rt3070_rf_write(sc, 1, rf); 4271205042Sthompsa 4272205042Sthompsa /* set RF offset */ 4273205042Sthompsa run_rt3070_rf_read(sc, 23, &rf); 4274205042Sthompsa rf = (rf & ~0x7f) | sc->freq; 4275205042Sthompsa run_rt3070_rf_write(sc, 23, rf); 4276205042Sthompsa 4277205042Sthompsa /* program RF filter */ 4278205042Sthompsa rf = sc->rf24_20mhz; 4279205042Sthompsa run_rt3070_rf_write(sc, 24, rf); /* Tx */ 4280205042Sthompsa run_rt3070_rf_write(sc, 31, rf); /* Rx */ 4281205042Sthompsa 4282205042Sthompsa /* enable RF tuning */ 4283205042Sthompsa run_rt3070_rf_read(sc, 7, &rf); 4284205042Sthompsa rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14); 4285205042Sthompsa run_rt3070_rf_write(sc, 7, rf); 4286205042Sthompsa 4287205042Sthompsa /* TSSI */ 4288205042Sthompsa rf = (chan <= 14) ? 0xc3 : 0xc0; 4289205042Sthompsa run_rt3070_rf_write(sc, 9, rf); 4290205042Sthompsa 4291205042Sthompsa /* set loop filter 1 */ 4292205042Sthompsa run_rt3070_rf_write(sc, 10, 0xf1); 4293205042Sthompsa /* set loop filter 2 */ 4294205042Sthompsa run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00); 4295205042Sthompsa 4296205042Sthompsa /* set tx_mx2_ic */ 4297205042Sthompsa run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43); 4298205042Sthompsa /* set tx_mx1_ic */ 4299205042Sthompsa if (chan <= 14) 4300205042Sthompsa rf = 0x48 | sc->txmixgain_2ghz; 4301205042Sthompsa else 4302205042Sthompsa rf = 0x78 | sc->txmixgain_5ghz; 4303205042Sthompsa run_rt3070_rf_write(sc, 16, rf); 4304205042Sthompsa 4305205042Sthompsa /* set tx_lo1 */ 4306205042Sthompsa run_rt3070_rf_write(sc, 17, 0x23); 4307205042Sthompsa /* set tx_lo2 */ 4308205042Sthompsa if (chan <= 14) 4309205042Sthompsa rf = 0x93; 4310205042Sthompsa else if (chan <= 64) 4311205042Sthompsa rf = 0xb7; 4312205042Sthompsa else if (chan <= 128) 4313205042Sthompsa rf = 0x74; 4314205042Sthompsa else 4315205042Sthompsa rf = 0x72; 4316205042Sthompsa run_rt3070_rf_write(sc, 19, rf); 4317205042Sthompsa 4318205042Sthompsa /* set rx_lo1 */ 4319205042Sthompsa if (chan <= 14) 4320205042Sthompsa rf = 0xb3; 4321205042Sthompsa else if (chan <= 64) 4322205042Sthompsa rf = 0xf6; 4323205042Sthompsa else if (chan <= 128) 4324205042Sthompsa rf = 0xf4; 4325205042Sthompsa else 4326205042Sthompsa rf = 0xf3; 4327205042Sthompsa run_rt3070_rf_write(sc, 20, rf); 4328205042Sthompsa 4329205042Sthompsa /* set pfd_delay */ 4330205042Sthompsa if (chan <= 14) 4331205042Sthompsa rf = 0x15; 4332205042Sthompsa else if (chan <= 64) 4333205042Sthompsa rf = 0x3d; 4334205042Sthompsa else 4335205042Sthompsa rf = 0x01; 4336205042Sthompsa run_rt3070_rf_write(sc, 25, rf); 4337205042Sthompsa 4338205042Sthompsa /* set rx_lo2 */ 4339205042Sthompsa run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87); 4340205042Sthompsa /* set ldo_rf_vc */ 4341205042Sthompsa run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01); 4342205042Sthompsa /* set drv_cc */ 4343205042Sthompsa run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f); 4344205042Sthompsa 4345205042Sthompsa run_read(sc, RT2860_GPIO_CTRL, &tmp); 4346205042Sthompsa tmp &= ~0x8080; 4347205042Sthompsa if (chan <= 14) 4348205042Sthompsa tmp |= 0x80; 4349205042Sthompsa run_write(sc, RT2860_GPIO_CTRL, tmp); 4350205042Sthompsa 4351205042Sthompsa /* enable RF tuning */ 4352205042Sthompsa run_rt3070_rf_read(sc, 7, &rf); 4353205042Sthompsa run_rt3070_rf_write(sc, 7, rf | 0x01); 4354205042Sthompsa 4355205042Sthompsa run_delay(sc, 2); 4356205042Sthompsa} 4357205042Sthompsa 4358205042Sthompsastatic void 4359261868Skevlorun_rt3593_set_chan(struct run_softc *sc, u_int chan) 4360261868Skevlo{ 4361261868Skevlo int8_t txpow1, txpow2, txpow3; 4362261868Skevlo uint8_t h20mhz, rf; 4363261868Skevlo int i; 4364261868Skevlo 4365261868Skevlo /* find the settings for this channel (we know it exists) */ 4366261868Skevlo for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4367261868Skevlo 4368261868Skevlo /* use Tx power values from EEPROM */ 4369261868Skevlo txpow1 = sc->txpow1[i]; 4370261868Skevlo txpow2 = sc->txpow2[i]; 4371261868Skevlo txpow3 = (sc->ntxchains == 3) ? sc->txpow3[i] : 0; 4372261868Skevlo 4373261868Skevlo if (chan <= 14) { 4374261868Skevlo run_bbp_write(sc, 25, sc->bbp25); 4375261868Skevlo run_bbp_write(sc, 26, sc->bbp26); 4376261868Skevlo } else { 4377261868Skevlo /* Enable IQ phase correction. */ 4378261868Skevlo run_bbp_write(sc, 25, 0x09); 4379261868Skevlo run_bbp_write(sc, 26, 0xff); 4380261868Skevlo } 4381261868Skevlo 4382261868Skevlo run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n); 4383261868Skevlo run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f); 4384261868Skevlo run_rt3070_rf_read(sc, 11, &rf); 4385261868Skevlo rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03); 4386261868Skevlo run_rt3070_rf_write(sc, 11, rf); 4387261868Skevlo 4388261868Skevlo /* Set pll_idoh. */ 4389261868Skevlo run_rt3070_rf_read(sc, 11, &rf); 4390261868Skevlo rf &= ~0x4c; 4391261868Skevlo rf |= (chan <= 14) ? 0x44 : 0x48; 4392261868Skevlo run_rt3070_rf_write(sc, 11, rf); 4393261868Skevlo 4394261868Skevlo if (chan <= 14) 4395261868Skevlo rf = txpow1 & 0x1f; 4396261868Skevlo else 4397261868Skevlo rf = 0x40 | ((txpow1 & 0x18) << 1) | (txpow1 & 0x07); 4398261868Skevlo run_rt3070_rf_write(sc, 53, rf); 4399261868Skevlo 4400261868Skevlo if (chan <= 14) 4401261868Skevlo rf = txpow2 & 0x1f; 4402261868Skevlo else 4403261868Skevlo rf = 0x40 | ((txpow2 & 0x18) << 1) | (txpow2 & 0x07); 4404261868Skevlo run_rt3070_rf_write(sc, 55, rf); 4405261868Skevlo 4406261868Skevlo if (chan <= 14) 4407261868Skevlo rf = txpow3 & 0x1f; 4408261868Skevlo else 4409261868Skevlo rf = 0x40 | ((txpow3 & 0x18) << 1) | (txpow3 & 0x07); 4410261868Skevlo run_rt3070_rf_write(sc, 54, rf); 4411261868Skevlo 4412261868Skevlo rf = RT3070_RF_BLOCK | RT3070_PLL_PD; 4413261868Skevlo if (sc->ntxchains == 3) 4414261868Skevlo rf |= RT3070_TX0_PD | RT3070_TX1_PD | RT3070_TX2_PD; 4415261868Skevlo else 4416261868Skevlo rf |= RT3070_TX0_PD | RT3070_TX1_PD; 4417261868Skevlo rf |= RT3070_RX0_PD | RT3070_RX1_PD | RT3070_RX2_PD; 4418261868Skevlo run_rt3070_rf_write(sc, 1, rf); 4419261868Skevlo 4420261868Skevlo run_adjust_freq_offset(sc); 4421261868Skevlo 4422261868Skevlo run_rt3070_rf_write(sc, 31, (chan <= 14) ? 0xa0 : 0x80); 4423261868Skevlo 4424261868Skevlo h20mhz = (sc->rf24_20mhz & 0x20) >> 5; 4425261868Skevlo run_rt3070_rf_read(sc, 30, &rf); 4426261868Skevlo rf = (rf & ~0x06) | (h20mhz << 1) | (h20mhz << 2); 4427261868Skevlo run_rt3070_rf_write(sc, 30, rf); 4428261868Skevlo 4429261868Skevlo run_rt3070_rf_read(sc, 36, &rf); 4430261868Skevlo if (chan <= 14) 4431261868Skevlo rf |= 0x80; 4432261868Skevlo else 4433261868Skevlo rf &= ~0x80; 4434261868Skevlo run_rt3070_rf_write(sc, 36, rf); 4435261868Skevlo 4436261868Skevlo /* Set vcolo_bs. */ 4437261868Skevlo run_rt3070_rf_write(sc, 34, (chan <= 14) ? 0x3c : 0x20); 4438261868Skevlo /* Set pfd_delay. */ 4439261868Skevlo run_rt3070_rf_write(sc, 12, (chan <= 14) ? 0x1a : 0x12); 4440261868Skevlo 4441261868Skevlo /* Set vco bias current control. */ 4442261868Skevlo run_rt3070_rf_read(sc, 6, &rf); 4443261868Skevlo rf &= ~0xc0; 4444261868Skevlo if (chan <= 14) 4445261868Skevlo rf |= 0x40; 4446261868Skevlo else if (chan <= 128) 4447261868Skevlo rf |= 0x80; 4448261868Skevlo else 4449261868Skevlo rf |= 0x40; 4450261868Skevlo run_rt3070_rf_write(sc, 6, rf); 4451261868Skevlo 4452261868Skevlo run_rt3070_rf_read(sc, 30, &rf); 4453261868Skevlo rf = (rf & ~0x18) | 0x10; 4454261868Skevlo run_rt3070_rf_write(sc, 30, rf); 4455261868Skevlo 4456261868Skevlo run_rt3070_rf_write(sc, 10, (chan <= 14) ? 0xd3 : 0xd8); 4457261868Skevlo run_rt3070_rf_write(sc, 13, (chan <= 14) ? 0x12 : 0x23); 4458261868Skevlo 4459261868Skevlo run_rt3070_rf_read(sc, 51, &rf); 4460261868Skevlo rf = (rf & ~0x03) | 0x01; 4461261868Skevlo run_rt3070_rf_write(sc, 51, rf); 4462261868Skevlo /* Set tx_mx1_cc. */ 4463261868Skevlo run_rt3070_rf_read(sc, 51, &rf); 4464261868Skevlo rf &= ~0x1c; 4465261868Skevlo rf |= (chan <= 14) ? 0x14 : 0x10; 4466261868Skevlo run_rt3070_rf_write(sc, 51, rf); 4467261868Skevlo /* Set tx_mx1_ic. */ 4468261868Skevlo run_rt3070_rf_read(sc, 51, &rf); 4469261868Skevlo rf &= ~0xe0; 4470261868Skevlo rf |= (chan <= 14) ? 0x60 : 0x40; 4471261868Skevlo run_rt3070_rf_write(sc, 51, rf); 4472261868Skevlo /* Set tx_lo1_ic. */ 4473261868Skevlo run_rt3070_rf_read(sc, 49, &rf); 4474261868Skevlo rf &= ~0x1c; 4475261868Skevlo rf |= (chan <= 14) ? 0x0c : 0x08; 4476261868Skevlo run_rt3070_rf_write(sc, 49, rf); 4477261868Skevlo /* Set tx_lo1_en. */ 4478261868Skevlo run_rt3070_rf_read(sc, 50, &rf); 4479261868Skevlo run_rt3070_rf_write(sc, 50, rf & ~0x20); 4480261868Skevlo /* Set drv_cc. */ 4481261868Skevlo run_rt3070_rf_read(sc, 57, &rf); 4482261868Skevlo rf &= ~0xfc; 4483261868Skevlo rf |= (chan <= 14) ? 0x6c : 0x3c; 4484261868Skevlo run_rt3070_rf_write(sc, 57, rf); 4485261868Skevlo /* Set rx_mix1_ic, rxa_lnactr, lna_vc, lna_inbias_en and lna_en. */ 4486261868Skevlo run_rt3070_rf_write(sc, 44, (chan <= 14) ? 0x93 : 0x9b); 4487261868Skevlo /* Set drv_gnd_a, tx_vga_cc_a and tx_mx2_gain. */ 4488261868Skevlo run_rt3070_rf_write(sc, 52, (chan <= 14) ? 0x45 : 0x05); 4489261868Skevlo /* Enable VCO calibration. */ 4490261868Skevlo run_rt3070_rf_read(sc, 3, &rf); 4491261868Skevlo rf &= ~RT5390_VCOCAL; 4492261868Skevlo rf |= (chan <= 14) ? RT5390_VCOCAL : 0xbe; 4493261868Skevlo run_rt3070_rf_write(sc, 3, rf); 4494261868Skevlo 4495261868Skevlo if (chan <= 14) 4496261868Skevlo rf = 0x23; 4497261868Skevlo else if (chan <= 64) 4498261868Skevlo rf = 0x36; 4499261868Skevlo else if (chan <= 128) 4500261868Skevlo rf = 0x32; 4501261868Skevlo else 4502261868Skevlo rf = 0x30; 4503261868Skevlo run_rt3070_rf_write(sc, 39, rf); 4504261868Skevlo if (chan <= 14) 4505261868Skevlo rf = 0xbb; 4506261868Skevlo else if (chan <= 64) 4507261868Skevlo rf = 0xeb; 4508261868Skevlo else if (chan <= 128) 4509261868Skevlo rf = 0xb3; 4510261868Skevlo else 4511261868Skevlo rf = 0x9b; 4512261868Skevlo run_rt3070_rf_write(sc, 45, rf); 4513261868Skevlo 4514261868Skevlo /* Set FEQ/AEQ control. */ 4515261868Skevlo run_bbp_write(sc, 105, 0x34); 4516261868Skevlo} 4517261868Skevlo 4518261868Skevlostatic void 4519259453Shselaskyrun_rt5390_set_chan(struct run_softc *sc, u_int chan) 4520259453Shselasky{ 4521259453Shselasky int8_t txpow1, txpow2; 4522259453Shselasky uint8_t rf; 4523259453Shselasky int i; 4524259453Shselasky 4525259453Shselasky /* find the settings for this channel (we know it exists) */ 4526259453Shselasky for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4527259453Shselasky 4528259453Shselasky /* use Tx power values from EEPROM */ 4529259453Shselasky txpow1 = sc->txpow1[i]; 4530259453Shselasky txpow2 = sc->txpow2[i]; 4531259453Shselasky 4532259453Shselasky run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n); 4533259453Shselasky run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f); 4534259453Shselasky run_rt3070_rf_read(sc, 11, &rf); 4535259453Shselasky rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03); 4536259453Shselasky run_rt3070_rf_write(sc, 11, rf); 4537259453Shselasky 4538259453Shselasky run_rt3070_rf_read(sc, 49, &rf); 4539259453Shselasky rf = (rf & ~0x3f) | (txpow1 & 0x3f); 4540259453Shselasky /* The valid range of the RF R49 is 0x00 to 0x27. */ 4541259453Shselasky if ((rf & 0x3f) > 0x27) 4542259453Shselasky rf = (rf & ~0x3f) | 0x27; 4543259453Shselasky run_rt3070_rf_write(sc, 49, rf); 4544259453Shselasky 4545259453Shselasky if (sc->mac_ver == 0x5392) { 4546259453Shselasky run_rt3070_rf_read(sc, 50, &rf); 4547259453Shselasky rf = (rf & ~0x3f) | (txpow2 & 0x3f); 4548259453Shselasky /* The valid range of the RF R50 is 0x00 to 0x27. */ 4549259453Shselasky if ((rf & 0x3f) > 0x27) 4550259453Shselasky rf = (rf & ~0x3f) | 0x27; 4551259453Shselasky run_rt3070_rf_write(sc, 50, rf); 4552259453Shselasky } 4553259453Shselasky 4554259453Shselasky run_rt3070_rf_read(sc, 1, &rf); 4555259453Shselasky rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD; 4556259453Shselasky if (sc->mac_ver == 0x5392) 4557259453Shselasky rf |= RT3070_RX1_PD | RT3070_TX1_PD; 4558259453Shselasky run_rt3070_rf_write(sc, 1, rf); 4559259453Shselasky 4560259453Shselasky if (sc->mac_ver != 0x5392) { 4561259453Shselasky run_rt3070_rf_read(sc, 2, &rf); 4562259453Shselasky rf |= 0x80; 4563259453Shselasky run_rt3070_rf_write(sc, 2, rf); 4564259453Shselasky run_delay(sc, 10); 4565259453Shselasky rf &= 0x7f; 4566259453Shselasky run_rt3070_rf_write(sc, 2, rf); 4567259453Shselasky } 4568259453Shselasky 4569259453Shselasky run_adjust_freq_offset(sc); 4570259453Shselasky 4571259453Shselasky if (sc->mac_ver == 0x5392) { 4572259453Shselasky /* Fix for RT5392C. */ 4573259453Shselasky if (sc->mac_rev >= 0x0223) { 4574259453Shselasky if (chan <= 4) 4575259453Shselasky rf = 0x0f; 4576259453Shselasky else if (chan >= 5 && chan <= 7) 4577259453Shselasky rf = 0x0e; 4578259453Shselasky else 4579259453Shselasky rf = 0x0d; 4580259453Shselasky run_rt3070_rf_write(sc, 23, rf); 4581259453Shselasky 4582259453Shselasky if (chan <= 4) 4583259453Shselasky rf = 0x0c; 4584259453Shselasky else if (chan == 5) 4585259453Shselasky rf = 0x0b; 4586259453Shselasky else if (chan >= 6 && chan <= 7) 4587259453Shselasky rf = 0x0a; 4588259453Shselasky else if (chan >= 8 && chan <= 10) 4589259453Shselasky rf = 0x09; 4590259453Shselasky else 4591259453Shselasky rf = 0x08; 4592259453Shselasky run_rt3070_rf_write(sc, 59, rf); 4593259453Shselasky } else { 4594259453Shselasky if (chan <= 11) 4595259453Shselasky rf = 0x0f; 4596259453Shselasky else 4597259453Shselasky rf = 0x0b; 4598259453Shselasky run_rt3070_rf_write(sc, 59, rf); 4599259453Shselasky } 4600259453Shselasky } else { 4601259453Shselasky /* Fix for RT5390F. */ 4602259453Shselasky if (sc->mac_rev >= 0x0502) { 4603259453Shselasky if (chan <= 11) 4604259453Shselasky rf = 0x43; 4605259453Shselasky else 4606259453Shselasky rf = 0x23; 4607259453Shselasky run_rt3070_rf_write(sc, 55, rf); 4608259453Shselasky 4609259453Shselasky if (chan <= 11) 4610259453Shselasky rf = 0x0f; 4611259453Shselasky else if (chan == 12) 4612259453Shselasky rf = 0x0d; 4613259453Shselasky else 4614259453Shselasky rf = 0x0b; 4615259453Shselasky run_rt3070_rf_write(sc, 59, rf); 4616259453Shselasky } else { 4617259453Shselasky run_rt3070_rf_write(sc, 55, 0x44); 4618259453Shselasky run_rt3070_rf_write(sc, 59, 0x8f); 4619259453Shselasky } 4620259453Shselasky } 4621259453Shselasky 4622259453Shselasky /* Enable VCO calibration. */ 4623259453Shselasky run_rt3070_rf_read(sc, 3, &rf); 4624259453Shselasky rf |= RT5390_VCOCAL; 4625259453Shselasky run_rt3070_rf_write(sc, 3, rf); 4626259453Shselasky} 4627259453Shselasky 4628259453Shselaskystatic void 4629259453Shselaskyrun_rt5592_set_chan(struct run_softc *sc, u_int chan) 4630259453Shselasky{ 4631259453Shselasky const struct rt5592_freqs *freqs; 4632259453Shselasky uint32_t tmp; 4633259453Shselasky uint8_t reg, rf, txpow_bound; 4634259453Shselasky int8_t txpow1, txpow2; 4635259453Shselasky int i; 4636259453Shselasky 4637259453Shselasky run_read(sc, RT5592_DEBUG_INDEX, &tmp); 4638259453Shselasky freqs = (tmp & RT5592_SEL_XTAL) ? 4639259453Shselasky rt5592_freqs_40mhz : rt5592_freqs_20mhz; 4640259453Shselasky 4641259453Shselasky /* find the settings for this channel (we know it exists) */ 4642259453Shselasky for (i = 0; rt2860_rf2850[i].chan != chan; i++, freqs++); 4643259453Shselasky 4644259453Shselasky /* use Tx power values from EEPROM */ 4645259453Shselasky txpow1 = sc->txpow1[i]; 4646259453Shselasky txpow2 = sc->txpow2[i]; 4647259453Shselasky 4648259453Shselasky run_read(sc, RT3070_LDO_CFG0, &tmp); 4649259453Shselasky tmp &= ~0x1c000000; 4650259453Shselasky if (chan > 14) 4651259453Shselasky tmp |= 0x14000000; 4652259453Shselasky run_write(sc, RT3070_LDO_CFG0, tmp); 4653259453Shselasky 4654259453Shselasky /* N setting. */ 4655259453Shselasky run_rt3070_rf_write(sc, 8, freqs->n & 0xff); 4656259453Shselasky run_rt3070_rf_read(sc, 9, &rf); 4657259453Shselasky rf &= ~(1 << 4); 4658259453Shselasky rf |= ((freqs->n & 0x0100) >> 8) << 4; 4659259453Shselasky run_rt3070_rf_write(sc, 9, rf); 4660259453Shselasky 4661259453Shselasky /* K setting. */ 4662259453Shselasky run_rt3070_rf_read(sc, 9, &rf); 4663259453Shselasky rf &= ~0x0f; 4664259453Shselasky rf |= (freqs->k & 0x0f); 4665259453Shselasky run_rt3070_rf_write(sc, 9, rf); 4666259453Shselasky 4667259453Shselasky /* Mode setting. */ 4668259453Shselasky run_rt3070_rf_read(sc, 11, &rf); 4669259453Shselasky rf &= ~0x0c; 4670259453Shselasky rf |= ((freqs->m - 0x8) & 0x3) << 2; 4671259453Shselasky run_rt3070_rf_write(sc, 11, rf); 4672259453Shselasky run_rt3070_rf_read(sc, 9, &rf); 4673259453Shselasky rf &= ~(1 << 7); 4674259453Shselasky rf |= (((freqs->m - 0x8) & 0x4) >> 2) << 7; 4675259453Shselasky run_rt3070_rf_write(sc, 9, rf); 4676259453Shselasky 4677259453Shselasky /* R setting. */ 4678259453Shselasky run_rt3070_rf_read(sc, 11, &rf); 4679259453Shselasky rf &= ~0x03; 4680259453Shselasky rf |= (freqs->r - 0x1); 4681259453Shselasky run_rt3070_rf_write(sc, 11, rf); 4682259453Shselasky 4683259453Shselasky if (chan <= 14) { 4684259453Shselasky /* Initialize RF registers for 2GHZ. */ 4685259453Shselasky for (i = 0; i < nitems(rt5592_2ghz_def_rf); i++) { 4686259453Shselasky run_rt3070_rf_write(sc, rt5592_2ghz_def_rf[i].reg, 4687259453Shselasky rt5592_2ghz_def_rf[i].val); 4688259453Shselasky } 4689259453Shselasky 4690259453Shselasky rf = (chan <= 10) ? 0x07 : 0x06; 4691259453Shselasky run_rt3070_rf_write(sc, 23, rf); 4692259453Shselasky run_rt3070_rf_write(sc, 59, rf); 4693259453Shselasky 4694259453Shselasky run_rt3070_rf_write(sc, 55, 0x43); 4695259453Shselasky 4696259453Shselasky /* 4697259453Shselasky * RF R49/R50 Tx power ALC code. 4698259453Shselasky * G-band bit<7:6>=1:0, bit<5:0> range from 0x0 ~ 0x27. 4699259453Shselasky */ 4700259453Shselasky reg = 2; 4701259453Shselasky txpow_bound = 0x27; 4702259453Shselasky } else { 4703259453Shselasky /* Initialize RF registers for 5GHZ. */ 4704259453Shselasky for (i = 0; i < nitems(rt5592_5ghz_def_rf); i++) { 4705259453Shselasky run_rt3070_rf_write(sc, rt5592_5ghz_def_rf[i].reg, 4706259453Shselasky rt5592_5ghz_def_rf[i].val); 4707259453Shselasky } 4708259453Shselasky for (i = 0; i < nitems(rt5592_chan_5ghz); i++) { 4709259453Shselasky if (chan >= rt5592_chan_5ghz[i].firstchan && 4710259453Shselasky chan <= rt5592_chan_5ghz[i].lastchan) { 4711259453Shselasky run_rt3070_rf_write(sc, rt5592_chan_5ghz[i].reg, 4712259453Shselasky rt5592_chan_5ghz[i].val); 4713259453Shselasky } 4714259453Shselasky } 4715259453Shselasky 4716259453Shselasky /* 4717259453Shselasky * RF R49/R50 Tx power ALC code. 4718259453Shselasky * A-band bit<7:6>=1:1, bit<5:0> range from 0x0 ~ 0x2b. 4719259453Shselasky */ 4720259453Shselasky reg = 3; 4721259453Shselasky txpow_bound = 0x2b; 4722259453Shselasky } 4723259453Shselasky 4724259453Shselasky /* RF R49 ch0 Tx power ALC code. */ 4725259453Shselasky run_rt3070_rf_read(sc, 49, &rf); 4726259453Shselasky rf &= ~0xc0; 4727259453Shselasky rf |= (reg << 6); 4728259453Shselasky rf = (rf & ~0x3f) | (txpow1 & 0x3f); 4729259453Shselasky if ((rf & 0x3f) > txpow_bound) 4730259453Shselasky rf = (rf & ~0x3f) | txpow_bound; 4731259453Shselasky run_rt3070_rf_write(sc, 49, rf); 4732259453Shselasky 4733259453Shselasky /* RF R50 ch1 Tx power ALC code. */ 4734259453Shselasky run_rt3070_rf_read(sc, 50, &rf); 4735259453Shselasky rf &= ~(1 << 7 | 1 << 6); 4736259453Shselasky rf |= (reg << 6); 4737259453Shselasky rf = (rf & ~0x3f) | (txpow2 & 0x3f); 4738259453Shselasky if ((rf & 0x3f) > txpow_bound) 4739259453Shselasky rf = (rf & ~0x3f) | txpow_bound; 4740259453Shselasky run_rt3070_rf_write(sc, 50, rf); 4741259453Shselasky 4742259453Shselasky /* Enable RF_BLOCK, PLL_PD, RX0_PD, and TX0_PD. */ 4743259453Shselasky run_rt3070_rf_read(sc, 1, &rf); 4744259453Shselasky rf |= (RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD); 4745259453Shselasky if (sc->ntxchains > 1) 4746259453Shselasky rf |= RT3070_TX1_PD; 4747259453Shselasky if (sc->nrxchains > 1) 4748259453Shselasky rf |= RT3070_RX1_PD; 4749259453Shselasky run_rt3070_rf_write(sc, 1, rf); 4750259453Shselasky 4751259453Shselasky run_rt3070_rf_write(sc, 6, 0xe4); 4752259453Shselasky 4753259453Shselasky run_rt3070_rf_write(sc, 30, 0x10); 4754259453Shselasky run_rt3070_rf_write(sc, 31, 0x80); 4755259453Shselasky run_rt3070_rf_write(sc, 32, 0x80); 4756259453Shselasky 4757259453Shselasky run_adjust_freq_offset(sc); 4758259453Shselasky 4759259453Shselasky /* Enable VCO calibration. */ 4760259453Shselasky run_rt3070_rf_read(sc, 3, &rf); 4761259453Shselasky rf |= RT5390_VCOCAL; 4762259453Shselasky run_rt3070_rf_write(sc, 3, rf); 4763259453Shselasky} 4764259453Shselasky 4765259453Shselaskystatic void 4766203134Sthompsarun_set_rx_antenna(struct run_softc *sc, int aux) 4767203134Sthompsa{ 4768203134Sthompsa uint32_t tmp; 4769259453Shselasky uint8_t bbp152; 4770203134Sthompsa 4771203134Sthompsa if (aux) { 4772259453Shselasky if (sc->rf_rev == RT5390_RF_5370) { 4773259453Shselasky run_bbp_read(sc, 152, &bbp152); 4774259453Shselasky run_bbp_write(sc, 152, bbp152 & ~0x80); 4775259453Shselasky } else { 4776259453Shselasky run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0); 4777259453Shselasky run_read(sc, RT2860_GPIO_CTRL, &tmp); 4778259453Shselasky run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08); 4779259453Shselasky } 4780203134Sthompsa } else { 4781259453Shselasky if (sc->rf_rev == RT5390_RF_5370) { 4782259453Shselasky run_bbp_read(sc, 152, &bbp152); 4783259453Shselasky run_bbp_write(sc, 152, bbp152 | 0x80); 4784259453Shselasky } else { 4785259453Shselasky run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1); 4786259453Shselasky run_read(sc, RT2860_GPIO_CTRL, &tmp); 4787259453Shselasky run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808); 4788259453Shselasky } 4789203134Sthompsa } 4790203134Sthompsa} 4791203134Sthompsa 4792203134Sthompsastatic int 4793203134Sthompsarun_set_chan(struct run_softc *sc, struct ieee80211_channel *c) 4794203134Sthompsa{ 4795203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 4796259453Shselasky u_int chan, group; 4797203134Sthompsa 4798203134Sthompsa chan = ieee80211_chan2ieee(ic, c); 4799203134Sthompsa if (chan == 0 || chan == IEEE80211_CHAN_ANY) 4800209917Sthompsa return (EINVAL); 4801203134Sthompsa 4802259453Shselasky if (sc->mac_ver == 0x5592) 4803259453Shselasky run_rt5592_set_chan(sc, chan); 4804259453Shselasky else if (sc->mac_ver >= 0x5390) 4805259453Shselasky run_rt5390_set_chan(sc, chan); 4806261868Skevlo else if (sc->mac_ver == 0x3593) 4807261868Skevlo run_rt3593_set_chan(sc, chan); 4808259453Shselasky else if (sc->mac_ver == 0x3572) 4809205042Sthompsa run_rt3572_set_chan(sc, chan); 4810205042Sthompsa else if (sc->mac_ver >= 0x3070) 4811203134Sthompsa run_rt3070_set_chan(sc, chan); 4812203134Sthompsa else 4813203134Sthompsa run_rt2870_set_chan(sc, chan); 4814203134Sthompsa 4815203134Sthompsa /* determine channel group */ 4816203134Sthompsa if (chan <= 14) 4817203134Sthompsa group = 0; 4818203134Sthompsa else if (chan <= 64) 4819203134Sthompsa group = 1; 4820203134Sthompsa else if (chan <= 128) 4821203134Sthompsa group = 2; 4822203134Sthompsa else 4823203134Sthompsa group = 3; 4824203134Sthompsa 4825203134Sthompsa /* XXX necessary only when group has changed! */ 4826203134Sthompsa run_select_chan_group(sc, group); 4827203134Sthompsa 4828203134Sthompsa run_delay(sc, 10); 4829203134Sthompsa 4830261868Skevlo /* Perform IQ calibration. */ 4831261868Skevlo if (sc->mac_ver >= 0x5392) 4832261868Skevlo run_iq_calib(sc, chan); 4833261868Skevlo 4834209917Sthompsa return (0); 4835203134Sthompsa} 4836203134Sthompsa 4837203134Sthompsastatic void 4838203134Sthompsarun_set_channel(struct ieee80211com *ic) 4839203134Sthompsa{ 4840203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 4841203134Sthompsa 4842203134Sthompsa RUN_LOCK(sc); 4843203134Sthompsa run_set_chan(sc, ic->ic_curchan); 4844203134Sthompsa RUN_UNLOCK(sc); 4845203134Sthompsa 4846203134Sthompsa return; 4847203134Sthompsa} 4848203134Sthompsa 4849203134Sthompsastatic void 4850203134Sthompsarun_scan_start(struct ieee80211com *ic) 4851203134Sthompsa{ 4852203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 4853203134Sthompsa uint32_t tmp; 4854203134Sthompsa 4855203134Sthompsa RUN_LOCK(sc); 4856203134Sthompsa 4857203134Sthompsa /* abort TSF synchronization */ 4858203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 4859203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, 4860203134Sthompsa tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 4861203134Sthompsa RT2860_TBTT_TIMER_EN)); 4862203134Sthompsa run_set_bssid(sc, sc->sc_ifp->if_broadcastaddr); 4863203134Sthompsa 4864203134Sthompsa RUN_UNLOCK(sc); 4865203134Sthompsa 4866203134Sthompsa return; 4867203134Sthompsa} 4868203134Sthompsa 4869203134Sthompsastatic void 4870203134Sthompsarun_scan_end(struct ieee80211com *ic) 4871203134Sthompsa{ 4872203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 4873203134Sthompsa 4874203134Sthompsa RUN_LOCK(sc); 4875203134Sthompsa 4876203134Sthompsa run_enable_tsf_sync(sc); 4877203134Sthompsa /* XXX keep local copy */ 4878203134Sthompsa run_set_bssid(sc, sc->sc_bssid); 4879203134Sthompsa 4880203134Sthompsa RUN_UNLOCK(sc); 4881203134Sthompsa 4882203134Sthompsa return; 4883203134Sthompsa} 4884203134Sthompsa 4885208019Sthompsa/* 4886208019Sthompsa * Could be called from ieee80211_node_timeout() 4887208019Sthompsa * (non-sleepable thread) 4888208019Sthompsa */ 4889208019Sthompsastatic void 4890208019Sthompsarun_update_beacon(struct ieee80211vap *vap, int item) 4891203134Sthompsa{ 4892208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 4893208019Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 4894218492Sbschmidt struct run_vap *rvp = RUN_VAP(vap); 4895218492Sbschmidt int mcast = 0; 4896208019Sthompsa uint32_t i; 4897208019Sthompsa 4898218492Sbschmidt KASSERT(vap != NULL, ("no beacon")); 4899218492Sbschmidt 4900218492Sbschmidt switch (item) { 4901218492Sbschmidt case IEEE80211_BEACON_ERP: 4902218492Sbschmidt run_updateslot(ic->ic_ifp); 4903218492Sbschmidt break; 4904218492Sbschmidt case IEEE80211_BEACON_HTINFO: 4905218492Sbschmidt run_updateprot(ic); 4906218492Sbschmidt break; 4907218492Sbschmidt case IEEE80211_BEACON_TIM: 4908218492Sbschmidt mcast = 1; /*TODO*/ 4909218492Sbschmidt break; 4910218492Sbschmidt default: 4911218492Sbschmidt break; 4912218492Sbschmidt } 4913218492Sbschmidt 4914218492Sbschmidt setbit(rvp->bo.bo_flags, item); 4915273636Skevlo if (rvp->beacon_mbuf == NULL) { 4916273636Skevlo rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss, 4917273636Skevlo &rvp->bo); 4918273636Skevlo if (rvp->beacon_mbuf == NULL) 4919273636Skevlo return; 4920273636Skevlo } 4921218492Sbschmidt ieee80211_beacon_update(vap->iv_bss, &rvp->bo, rvp->beacon_mbuf, mcast); 4922218492Sbschmidt 4923208019Sthompsa i = RUN_CMDQ_GET(&sc->cmdq_store); 4924208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 4925208019Sthompsa sc->cmdq[i].func = run_update_beacon_cb; 4926208019Sthompsa sc->cmdq[i].arg0 = vap; 4927208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 4928208019Sthompsa 4929208019Sthompsa return; 4930203134Sthompsa} 4931203134Sthompsa 4932203134Sthompsastatic void 4933208019Sthompsarun_update_beacon_cb(void *arg) 4934203134Sthompsa{ 4935208019Sthompsa struct ieee80211vap *vap = arg; 4936218492Sbschmidt struct run_vap *rvp = RUN_VAP(vap); 4937203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 4938203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 4939203134Sthompsa struct rt2860_txwi txwi; 4940203134Sthompsa struct mbuf *m; 4941259453Shselasky uint16_t txwisize; 4942208019Sthompsa uint8_t ridx; 4943203134Sthompsa 4944209917Sthompsa if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC) 4945208019Sthompsa return; 4946236439Shselasky if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) 4947236439Shselasky return; 4948208019Sthompsa 4949218492Sbschmidt /* 4950218492Sbschmidt * No need to call ieee80211_beacon_update(), run_update_beacon() 4951218492Sbschmidt * is taking care of apropriate calls. 4952218492Sbschmidt */ 4953218492Sbschmidt if (rvp->beacon_mbuf == NULL) { 4954218492Sbschmidt rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss, 4955218492Sbschmidt &rvp->bo); 4956218492Sbschmidt if (rvp->beacon_mbuf == NULL) 4957218492Sbschmidt return; 4958218492Sbschmidt } 4959218492Sbschmidt m = rvp->beacon_mbuf; 4960203134Sthompsa 4961259453Shselasky memset(&txwi, 0, sizeof(txwi)); 4962203134Sthompsa txwi.wcid = 0xff; 4963203134Sthompsa txwi.len = htole16(m->m_pkthdr.len); 4964259453Shselasky 4965203134Sthompsa /* send beacons at the lowest available rate */ 4966208019Sthompsa ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? 4967208019Sthompsa RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; 4968208019Sthompsa txwi.phy = htole16(rt2860_rates[ridx].mcs); 4969208019Sthompsa if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM) 4970259453Shselasky txwi.phy |= htole16(RT2860_PHY_OFDM); 4971203134Sthompsa txwi.txop = RT2860_TX_TXOP_HT; 4972203134Sthompsa txwi.flags = RT2860_TX_TS; 4973209144Sthompsa txwi.xflags = RT2860_TX_NSEQ; 4974203134Sthompsa 4975259453Shselasky txwisize = (sc->mac_ver == 0x5592) ? 4976259453Shselasky sizeof(txwi) + sizeof(uint32_t) : sizeof(txwi); 4977259453Shselasky run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id), (uint8_t *)&txwi, 4978259453Shselasky txwisize); 4979259453Shselasky run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id) + txwisize, 4980259453Shselasky mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1); 4981203134Sthompsa} 4982203134Sthompsa 4983203134Sthompsastatic void 4984203134Sthompsarun_updateprot(struct ieee80211com *ic) 4985203134Sthompsa{ 4986203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 4987218492Sbschmidt uint32_t i; 4988218492Sbschmidt 4989218492Sbschmidt i = RUN_CMDQ_GET(&sc->cmdq_store); 4990218492Sbschmidt DPRINTF("cmdq_store=%d\n", i); 4991218492Sbschmidt sc->cmdq[i].func = run_updateprot_cb; 4992218492Sbschmidt sc->cmdq[i].arg0 = ic; 4993218492Sbschmidt ieee80211_runtask(ic, &sc->cmdq_task); 4994218492Sbschmidt} 4995218492Sbschmidt 4996218492Sbschmidtstatic void 4997218492Sbschmidtrun_updateprot_cb(void *arg) 4998218492Sbschmidt{ 4999218492Sbschmidt struct ieee80211com *ic = arg; 5000218492Sbschmidt struct run_softc *sc = ic->ic_ifp->if_softc; 5001203134Sthompsa uint32_t tmp; 5002203134Sthompsa 5003203134Sthompsa tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL; 5004203134Sthompsa /* setup protection frame rate (MCS code) */ 5005203134Sthompsa tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ? 5006270515Skevlo rt2860_rates[RT2860_RIDX_OFDM6].mcs | RT2860_PHY_OFDM : 5007203134Sthompsa rt2860_rates[RT2860_RIDX_CCK11].mcs; 5008203134Sthompsa 5009203134Sthompsa /* CCK frames don't require protection */ 5010203134Sthompsa run_write(sc, RT2860_CCK_PROT_CFG, tmp); 5011203134Sthompsa if (ic->ic_flags & IEEE80211_F_USEPROT) { 5012203134Sthompsa if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) 5013203134Sthompsa tmp |= RT2860_PROT_CTRL_RTS_CTS; 5014203134Sthompsa else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) 5015203134Sthompsa tmp |= RT2860_PROT_CTRL_CTS; 5016203134Sthompsa } 5017203134Sthompsa run_write(sc, RT2860_OFDM_PROT_CFG, tmp); 5018203134Sthompsa} 5019203134Sthompsa 5020203134Sthompsastatic void 5021208019Sthompsarun_usb_timeout_cb(void *arg) 5022203134Sthompsa{ 5023208019Sthompsa struct ieee80211vap *vap = arg; 5024208019Sthompsa struct run_softc *sc = vap->iv_ic->ic_ifp->if_softc; 5025203134Sthompsa 5026208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 5027203134Sthompsa 5028203134Sthompsa if(vap->iv_state == IEEE80211_S_RUN && 5029203134Sthompsa vap->iv_opmode != IEEE80211_M_STA) 5030203134Sthompsa run_reset_livelock(sc); 5031209917Sthompsa else if (vap->iv_state == IEEE80211_S_SCAN) { 5032203134Sthompsa DPRINTF("timeout caused by scan\n"); 5033203134Sthompsa /* cancel bgscan */ 5034203134Sthompsa ieee80211_cancel_scan(vap); 5035203134Sthompsa } else 5036203134Sthompsa DPRINTF("timeout by unknown cause\n"); 5037203134Sthompsa} 5038203134Sthompsa 5039203134Sthompsastatic void 5040203134Sthompsarun_reset_livelock(struct run_softc *sc) 5041203134Sthompsa{ 5042203134Sthompsa uint32_t tmp; 5043203134Sthompsa 5044208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 5045208019Sthompsa 5046203134Sthompsa /* 5047203134Sthompsa * In IBSS or HostAP modes (when the hardware sends beacons), the MAC 5048203134Sthompsa * can run into a livelock and start sending CTS-to-self frames like 5049203134Sthompsa * crazy if protection is enabled. Reset MAC/BBP for a while 5050203134Sthompsa */ 5051203134Sthompsa run_read(sc, RT2860_DEBUG, &tmp); 5052208019Sthompsa DPRINTFN(3, "debug reg %08x\n", tmp); 5053209917Sthompsa if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) { 5054203134Sthompsa DPRINTF("CTS-to-self livelock detected\n"); 5055203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST); 5056203134Sthompsa run_delay(sc, 1); 5057203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 5058203134Sthompsa RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 5059203134Sthompsa } 5060203134Sthompsa} 5061203134Sthompsa 5062203134Sthompsastatic void 5063203134Sthompsarun_update_promisc_locked(struct ifnet *ifp) 5064203134Sthompsa{ 5065203134Sthompsa struct run_softc *sc = ifp->if_softc; 5066203134Sthompsa uint32_t tmp; 5067203134Sthompsa 5068203134Sthompsa run_read(sc, RT2860_RX_FILTR_CFG, &tmp); 5069203134Sthompsa 5070203134Sthompsa tmp |= RT2860_DROP_UC_NOME; 5071203134Sthompsa if (ifp->if_flags & IFF_PROMISC) 5072203134Sthompsa tmp &= ~RT2860_DROP_UC_NOME; 5073203134Sthompsa 5074203134Sthompsa run_write(sc, RT2860_RX_FILTR_CFG, tmp); 5075203134Sthompsa 5076203134Sthompsa DPRINTF("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ? 5077203134Sthompsa "entering" : "leaving"); 5078203134Sthompsa} 5079203134Sthompsa 5080203134Sthompsastatic void 5081203134Sthompsarun_update_promisc(struct ifnet *ifp) 5082203134Sthompsa{ 5083203134Sthompsa struct run_softc *sc = ifp->if_softc; 5084203134Sthompsa 5085203134Sthompsa if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 5086203134Sthompsa return; 5087203134Sthompsa 5088203134Sthompsa RUN_LOCK(sc); 5089203134Sthompsa run_update_promisc_locked(ifp); 5090203134Sthompsa RUN_UNLOCK(sc); 5091203134Sthompsa} 5092203134Sthompsa 5093203134Sthompsastatic void 5094203134Sthompsarun_enable_tsf_sync(struct run_softc *sc) 5095203134Sthompsa{ 5096208019Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 5097203134Sthompsa struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 5098203134Sthompsa uint32_t tmp; 5099203134Sthompsa 5100259453Shselasky DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id, 5101259453Shselasky ic->ic_opmode); 5102208019Sthompsa 5103203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 5104203134Sthompsa tmp &= ~0x1fffff; 5105203134Sthompsa tmp |= vap->iv_bss->ni_intval * 16; 5106203134Sthompsa tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN; 5107203134Sthompsa 5108208019Sthompsa if (ic->ic_opmode == IEEE80211_M_STA) { 5109203134Sthompsa /* 5110203134Sthompsa * Local TSF is always updated with remote TSF on beacon 5111203134Sthompsa * reception. 5112203134Sthompsa */ 5113203134Sthompsa tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT; 5114208019Sthompsa } else if (ic->ic_opmode == IEEE80211_M_IBSS) { 5115203134Sthompsa tmp |= RT2860_BCN_TX_EN; 5116203134Sthompsa /* 5117203134Sthompsa * Local TSF is updated with remote TSF on beacon reception 5118203134Sthompsa * only if the remote TSF is greater than local TSF. 5119203134Sthompsa */ 5120203134Sthompsa tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT; 5121208019Sthompsa } else if (ic->ic_opmode == IEEE80211_M_HOSTAP || 5122208019Sthompsa ic->ic_opmode == IEEE80211_M_MBSS) { 5123203134Sthompsa tmp |= RT2860_BCN_TX_EN; 5124203134Sthompsa /* SYNC with nobody */ 5125203134Sthompsa tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT; 5126208019Sthompsa } else { 5127203134Sthompsa DPRINTF("Enabling TSF failed. undefined opmode\n"); 5128208019Sthompsa return; 5129208019Sthompsa } 5130203134Sthompsa 5131203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, tmp); 5132203134Sthompsa} 5133203134Sthompsa 5134203134Sthompsastatic void 5135203134Sthompsarun_enable_mrr(struct run_softc *sc) 5136203134Sthompsa{ 5137261868Skevlo#define CCK(mcs) (mcs) 5138261868Skevlo#define OFDM(mcs) (1 << 3 | (mcs)) 5139203134Sthompsa run_write(sc, RT2860_LG_FBK_CFG0, 5140203134Sthompsa OFDM(6) << 28 | /* 54->48 */ 5141203134Sthompsa OFDM(5) << 24 | /* 48->36 */ 5142203134Sthompsa OFDM(4) << 20 | /* 36->24 */ 5143203134Sthompsa OFDM(3) << 16 | /* 24->18 */ 5144203134Sthompsa OFDM(2) << 12 | /* 18->12 */ 5145203134Sthompsa OFDM(1) << 8 | /* 12-> 9 */ 5146203134Sthompsa OFDM(0) << 4 | /* 9-> 6 */ 5147203134Sthompsa OFDM(0)); /* 6-> 6 */ 5148203134Sthompsa 5149203134Sthompsa run_write(sc, RT2860_LG_FBK_CFG1, 5150203134Sthompsa CCK(2) << 12 | /* 11->5.5 */ 5151203134Sthompsa CCK(1) << 8 | /* 5.5-> 2 */ 5152203134Sthompsa CCK(0) << 4 | /* 2-> 1 */ 5153203134Sthompsa CCK(0)); /* 1-> 1 */ 5154203134Sthompsa#undef OFDM 5155203134Sthompsa#undef CCK 5156203134Sthompsa} 5157203134Sthompsa 5158203134Sthompsastatic void 5159203134Sthompsarun_set_txpreamble(struct run_softc *sc) 5160203134Sthompsa{ 5161203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 5162203134Sthompsa uint32_t tmp; 5163203134Sthompsa 5164203134Sthompsa run_read(sc, RT2860_AUTO_RSP_CFG, &tmp); 5165203134Sthompsa if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 5166203134Sthompsa tmp |= RT2860_CCK_SHORT_EN; 5167203134Sthompsa else 5168203134Sthompsa tmp &= ~RT2860_CCK_SHORT_EN; 5169203134Sthompsa run_write(sc, RT2860_AUTO_RSP_CFG, tmp); 5170203134Sthompsa} 5171203134Sthompsa 5172203134Sthompsastatic void 5173203134Sthompsarun_set_basicrates(struct run_softc *sc) 5174203134Sthompsa{ 5175203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 5176203134Sthompsa 5177203134Sthompsa /* set basic rates mask */ 5178203134Sthompsa if (ic->ic_curmode == IEEE80211_MODE_11B) 5179203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003); 5180203134Sthompsa else if (ic->ic_curmode == IEEE80211_MODE_11A) 5181203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150); 5182203134Sthompsa else /* 11g */ 5183203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f); 5184203134Sthompsa} 5185203134Sthompsa 5186203134Sthompsastatic void 5187203134Sthompsarun_set_leds(struct run_softc *sc, uint16_t which) 5188203134Sthompsa{ 5189203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS, 5190203134Sthompsa which | (sc->leds & 0x7f)); 5191203134Sthompsa} 5192203134Sthompsa 5193203134Sthompsastatic void 5194203134Sthompsarun_set_bssid(struct run_softc *sc, const uint8_t *bssid) 5195203134Sthompsa{ 5196203134Sthompsa run_write(sc, RT2860_MAC_BSSID_DW0, 5197203134Sthompsa bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24); 5198203134Sthompsa run_write(sc, RT2860_MAC_BSSID_DW1, 5199203134Sthompsa bssid[4] | bssid[5] << 8); 5200203134Sthompsa} 5201203134Sthompsa 5202203134Sthompsastatic void 5203203134Sthompsarun_set_macaddr(struct run_softc *sc, const uint8_t *addr) 5204203134Sthompsa{ 5205203134Sthompsa run_write(sc, RT2860_MAC_ADDR_DW0, 5206203134Sthompsa addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24); 5207203134Sthompsa run_write(sc, RT2860_MAC_ADDR_DW1, 5208203134Sthompsa addr[4] | addr[5] << 8 | 0xff << 16); 5209203134Sthompsa} 5210203134Sthompsa 5211203134Sthompsastatic void 5212203134Sthompsarun_updateslot(struct ifnet *ifp) 5213203134Sthompsa{ 5214203134Sthompsa struct run_softc *sc = ifp->if_softc; 5215203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 5216218492Sbschmidt uint32_t i; 5217218492Sbschmidt 5218218492Sbschmidt i = RUN_CMDQ_GET(&sc->cmdq_store); 5219218492Sbschmidt DPRINTF("cmdq_store=%d\n", i); 5220218492Sbschmidt sc->cmdq[i].func = run_updateslot_cb; 5221218492Sbschmidt sc->cmdq[i].arg0 = ifp; 5222218492Sbschmidt ieee80211_runtask(ic, &sc->cmdq_task); 5223218492Sbschmidt 5224218492Sbschmidt return; 5225218492Sbschmidt} 5226218492Sbschmidt 5227218492Sbschmidt/* ARGSUSED */ 5228218492Sbschmidtstatic void 5229218492Sbschmidtrun_updateslot_cb(void *arg) 5230218492Sbschmidt{ 5231218492Sbschmidt struct ifnet *ifp = arg; 5232218492Sbschmidt struct run_softc *sc = ifp->if_softc; 5233218492Sbschmidt struct ieee80211com *ic = ifp->if_l2com; 5234203134Sthompsa uint32_t tmp; 5235203134Sthompsa 5236203134Sthompsa run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp); 5237203134Sthompsa tmp &= ~0xff; 5238203134Sthompsa tmp |= (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; 5239203134Sthompsa run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp); 5240203134Sthompsa} 5241203134Sthompsa 5242208019Sthompsastatic void 5243208019Sthompsarun_update_mcast(struct ifnet *ifp) 5244208019Sthompsa{ 5245208019Sthompsa /* h/w filter supports getting everything or nothing */ 5246208019Sthompsa ifp->if_flags |= IFF_ALLMULTI; 5247208019Sthompsa} 5248208019Sthompsa 5249203134Sthompsastatic int8_t 5250203134Sthompsarun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain) 5251203134Sthompsa{ 5252203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 5253203134Sthompsa struct ieee80211_channel *c = ic->ic_curchan; 5254203134Sthompsa int delta; 5255203134Sthompsa 5256203134Sthompsa if (IEEE80211_IS_CHAN_5GHZ(c)) { 5257259453Shselasky u_int chan = ieee80211_chan2ieee(ic, c); 5258203134Sthompsa delta = sc->rssi_5ghz[rxchain]; 5259203134Sthompsa 5260203134Sthompsa /* determine channel group */ 5261203134Sthompsa if (chan <= 64) 5262203134Sthompsa delta -= sc->lna[1]; 5263203134Sthompsa else if (chan <= 128) 5264203134Sthompsa delta -= sc->lna[2]; 5265203134Sthompsa else 5266203134Sthompsa delta -= sc->lna[3]; 5267203134Sthompsa } else 5268203134Sthompsa delta = sc->rssi_2ghz[rxchain] - sc->lna[0]; 5269203134Sthompsa 5270209917Sthompsa return (-12 - delta - rssi); 5271203134Sthompsa} 5272203134Sthompsa 5273259453Shselaskystatic void 5274259453Shselaskyrun_rt5390_bbp_init(struct run_softc *sc) 5275259453Shselasky{ 5276259453Shselasky int i; 5277259453Shselasky uint8_t bbp; 5278259453Shselasky 5279259453Shselasky /* Apply maximum likelihood detection for 2 stream case. */ 5280259453Shselasky run_bbp_read(sc, 105, &bbp); 5281259453Shselasky if (sc->nrxchains > 1) 5282259453Shselasky run_bbp_write(sc, 105, bbp | RT5390_MLD); 5283259453Shselasky 5284259453Shselasky /* Avoid data lost and CRC error. */ 5285259453Shselasky run_bbp_read(sc, 4, &bbp); 5286259453Shselasky run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 5287259453Shselasky 5288259453Shselasky if (sc->mac_ver == 0x5592) { 5289259453Shselasky for (i = 0; i < nitems(rt5592_def_bbp); i++) { 5290259453Shselasky run_bbp_write(sc, rt5592_def_bbp[i].reg, 5291259453Shselasky rt5592_def_bbp[i].val); 5292259453Shselasky } 5293259453Shselasky for (i = 0; i < nitems(rt5592_bbp_r196); i++) { 5294259453Shselasky run_bbp_write(sc, 195, i + 0x80); 5295259453Shselasky run_bbp_write(sc, 196, rt5592_bbp_r196[i]); 5296259453Shselasky } 5297259453Shselasky } else { 5298259453Shselasky for (i = 0; i < nitems(rt5390_def_bbp); i++) { 5299259453Shselasky run_bbp_write(sc, rt5390_def_bbp[i].reg, 5300259453Shselasky rt5390_def_bbp[i].val); 5301259453Shselasky } 5302259453Shselasky } 5303259453Shselasky if (sc->mac_ver == 0x5392) { 5304259453Shselasky run_bbp_write(sc, 88, 0x90); 5305259453Shselasky run_bbp_write(sc, 95, 0x9a); 5306259453Shselasky run_bbp_write(sc, 98, 0x12); 5307259453Shselasky run_bbp_write(sc, 106, 0x12); 5308259453Shselasky run_bbp_write(sc, 134, 0xd0); 5309259453Shselasky run_bbp_write(sc, 135, 0xf6); 5310259453Shselasky run_bbp_write(sc, 148, 0x84); 5311259453Shselasky } 5312259453Shselasky 5313259453Shselasky run_bbp_read(sc, 152, &bbp); 5314259453Shselasky run_bbp_write(sc, 152, bbp | 0x80); 5315259453Shselasky 5316259453Shselasky /* Fix BBP254 for RT5592C. */ 5317259453Shselasky if (sc->mac_ver == 0x5592 && sc->mac_rev >= 0x0221) { 5318259453Shselasky run_bbp_read(sc, 254, &bbp); 5319259453Shselasky run_bbp_write(sc, 254, bbp | 0x80); 5320259453Shselasky } 5321259453Shselasky 5322259453Shselasky /* Disable hardware antenna diversity. */ 5323259453Shselasky if (sc->mac_ver == 0x5390) 5324259453Shselasky run_bbp_write(sc, 154, 0); 5325259453Shselasky 5326259453Shselasky /* Initialize Rx CCK/OFDM frequency offset report. */ 5327259453Shselasky run_bbp_write(sc, 142, 1); 5328259453Shselasky run_bbp_write(sc, 143, 57); 5329259453Shselasky} 5330259453Shselasky 5331203134Sthompsastatic int 5332203134Sthompsarun_bbp_init(struct run_softc *sc) 5333203134Sthompsa{ 5334203134Sthompsa int i, error, ntries; 5335203134Sthompsa uint8_t bbp0; 5336203134Sthompsa 5337203134Sthompsa /* wait for BBP to wake up */ 5338203134Sthompsa for (ntries = 0; ntries < 20; ntries++) { 5339203134Sthompsa if ((error = run_bbp_read(sc, 0, &bbp0)) != 0) 5340203134Sthompsa return error; 5341203134Sthompsa if (bbp0 != 0 && bbp0 != 0xff) 5342203134Sthompsa break; 5343203134Sthompsa } 5344203134Sthompsa if (ntries == 20) 5345209917Sthompsa return (ETIMEDOUT); 5346203134Sthompsa 5347203134Sthompsa /* initialize BBP registers to default values */ 5348259453Shselasky if (sc->mac_ver >= 0x5390) 5349259453Shselasky run_rt5390_bbp_init(sc); 5350259453Shselasky else { 5351259453Shselasky for (i = 0; i < nitems(rt2860_def_bbp); i++) { 5352259453Shselasky run_bbp_write(sc, rt2860_def_bbp[i].reg, 5353259453Shselasky rt2860_def_bbp[i].val); 5354259453Shselasky } 5355203134Sthompsa } 5356203134Sthompsa 5357261868Skevlo if (sc->mac_ver == 0x3593) { 5358261868Skevlo run_bbp_write(sc, 79, 0x13); 5359261868Skevlo run_bbp_write(sc, 80, 0x05); 5360261868Skevlo run_bbp_write(sc, 81, 0x33); 5361261868Skevlo run_bbp_write(sc, 86, 0x46); 5362261868Skevlo run_bbp_write(sc, 137, 0x0f); 5363261868Skevlo } 5364261868Skevlo 5365203134Sthompsa /* fix BBP84 for RT2860E */ 5366205042Sthompsa if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101) 5367205042Sthompsa run_bbp_write(sc, 84, 0x19); 5368203134Sthompsa 5369261868Skevlo if (sc->mac_ver >= 0x3070 && (sc->mac_ver != 0x3593 && 5370261868Skevlo sc->mac_ver != 0x5592)) { 5371203134Sthompsa run_bbp_write(sc, 79, 0x13); 5372203134Sthompsa run_bbp_write(sc, 80, 0x05); 5373203134Sthompsa run_bbp_write(sc, 81, 0x33); 5374205042Sthompsa } else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) { 5375203134Sthompsa run_bbp_write(sc, 69, 0x16); 5376203134Sthompsa run_bbp_write(sc, 73, 0x12); 5377203134Sthompsa } 5378209917Sthompsa return (0); 5379203134Sthompsa} 5380203134Sthompsa 5381203134Sthompsastatic int 5382203134Sthompsarun_rt3070_rf_init(struct run_softc *sc) 5383203134Sthompsa{ 5384203134Sthompsa uint32_t tmp; 5385259453Shselasky uint8_t bbp4, mingain, rf, target; 5386203134Sthompsa int i; 5387203134Sthompsa 5388203134Sthompsa run_rt3070_rf_read(sc, 30, &rf); 5389203134Sthompsa /* toggle RF R30 bit 7 */ 5390203134Sthompsa run_rt3070_rf_write(sc, 30, rf | 0x80); 5391203134Sthompsa run_delay(sc, 10); 5392203134Sthompsa run_rt3070_rf_write(sc, 30, rf & ~0x80); 5393203134Sthompsa 5394203134Sthompsa /* initialize RF registers to default value */ 5395205042Sthompsa if (sc->mac_ver == 0x3572) { 5396259453Shselasky for (i = 0; i < nitems(rt3572_def_rf); i++) { 5397205042Sthompsa run_rt3070_rf_write(sc, rt3572_def_rf[i].reg, 5398205042Sthompsa rt3572_def_rf[i].val); 5399205042Sthompsa } 5400205042Sthompsa } else { 5401259453Shselasky for (i = 0; i < nitems(rt3070_def_rf); i++) { 5402205042Sthompsa run_rt3070_rf_write(sc, rt3070_def_rf[i].reg, 5403205042Sthompsa rt3070_def_rf[i].val); 5404205042Sthompsa } 5405203134Sthompsa } 5406205042Sthompsa 5407259453Shselasky if (sc->mac_ver == 0x3070 && sc->mac_rev < 0x0201) { 5408259453Shselasky /* 5409259453Shselasky * Change voltage from 1.2V to 1.35V for RT3070. 5410259453Shselasky * The DAC issue (RT3070_LDO_CFG0) has been fixed 5411259453Shselasky * in RT3070(F). 5412259453Shselasky */ 5413203134Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 5414203134Sthompsa tmp = (tmp & ~0x0f000000) | 0x0d000000; 5415203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5416203134Sthompsa 5417205042Sthompsa } else if (sc->mac_ver == 0x3071) { 5418203134Sthompsa run_rt3070_rf_read(sc, 6, &rf); 5419203134Sthompsa run_rt3070_rf_write(sc, 6, rf | 0x40); 5420203134Sthompsa run_rt3070_rf_write(sc, 31, 0x14); 5421203134Sthompsa 5422203134Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 5423203134Sthompsa tmp &= ~0x1f000000; 5424205042Sthompsa if (sc->mac_rev < 0x0211) 5425205042Sthompsa tmp |= 0x0d000000; /* 1.3V */ 5426203134Sthompsa else 5427205042Sthompsa tmp |= 0x01000000; /* 1.2V */ 5428203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5429203134Sthompsa 5430203134Sthompsa /* patch LNA_PE_G1 */ 5431203134Sthompsa run_read(sc, RT3070_GPIO_SWITCH, &tmp); 5432203134Sthompsa run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20); 5433208019Sthompsa 5434209917Sthompsa } else if (sc->mac_ver == 0x3572) { 5435205042Sthompsa run_rt3070_rf_read(sc, 6, &rf); 5436205042Sthompsa run_rt3070_rf_write(sc, 6, rf | 0x40); 5437205042Sthompsa 5438208019Sthompsa /* increase voltage from 1.2V to 1.35V */ 5439208019Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 5440208019Sthompsa tmp = (tmp & ~0x1f000000) | 0x0d000000; 5441208019Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5442203134Sthompsa 5443209917Sthompsa if (sc->mac_rev < 0x0211 || !sc->patch_dac) { 5444203134Sthompsa run_delay(sc, 1); /* wait for 1msec */ 5445205042Sthompsa /* decrease voltage back to 1.2V */ 5446203134Sthompsa tmp = (tmp & ~0x1f000000) | 0x01000000; 5447203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5448203134Sthompsa } 5449203134Sthompsa } 5450203134Sthompsa 5451203134Sthompsa /* select 20MHz bandwidth */ 5452203134Sthompsa run_rt3070_rf_read(sc, 31, &rf); 5453203134Sthompsa run_rt3070_rf_write(sc, 31, rf & ~0x20); 5454203134Sthompsa 5455203134Sthompsa /* calibrate filter for 20MHz bandwidth */ 5456203134Sthompsa sc->rf24_20mhz = 0x1f; /* default value */ 5457205042Sthompsa target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13; 5458205042Sthompsa run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz); 5459203134Sthompsa 5460203134Sthompsa /* select 40MHz bandwidth */ 5461203134Sthompsa run_bbp_read(sc, 4, &bbp4); 5462259453Shselasky run_bbp_write(sc, 4, (bbp4 & ~0x18) | 0x10); 5463205042Sthompsa run_rt3070_rf_read(sc, 31, &rf); 5464205042Sthompsa run_rt3070_rf_write(sc, 31, rf | 0x20); 5465203134Sthompsa 5466203134Sthompsa /* calibrate filter for 40MHz bandwidth */ 5467203134Sthompsa sc->rf24_40mhz = 0x2f; /* default value */ 5468205042Sthompsa target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15; 5469205042Sthompsa run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz); 5470203134Sthompsa 5471203134Sthompsa /* go back to 20MHz bandwidth */ 5472203134Sthompsa run_bbp_read(sc, 4, &bbp4); 5473203134Sthompsa run_bbp_write(sc, 4, bbp4 & ~0x18); 5474203134Sthompsa 5475205042Sthompsa if (sc->mac_ver == 0x3572) { 5476205042Sthompsa /* save default BBP registers 25 and 26 values */ 5477205042Sthompsa run_bbp_read(sc, 25, &sc->bbp25); 5478205042Sthompsa run_bbp_read(sc, 26, &sc->bbp26); 5479259453Shselasky } else if (sc->mac_rev < 0x0201 || sc->mac_rev < 0x0211) 5480203134Sthompsa run_rt3070_rf_write(sc, 27, 0x03); 5481203134Sthompsa 5482203134Sthompsa run_read(sc, RT3070_OPT_14, &tmp); 5483203134Sthompsa run_write(sc, RT3070_OPT_14, tmp | 1); 5484203134Sthompsa 5485205042Sthompsa if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) { 5486205042Sthompsa run_rt3070_rf_read(sc, 17, &rf); 5487205042Sthompsa rf &= ~RT3070_TX_LO1; 5488205042Sthompsa if ((sc->mac_ver == 0x3070 || 5489205042Sthompsa (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) && 5490205042Sthompsa !sc->ext_2ghz_lna) 5491205042Sthompsa rf |= 0x20; /* fix for long range Rx issue */ 5492259453Shselasky mingain = (sc->mac_ver == 0x3070) ? 1 : 2; 5493259453Shselasky if (sc->txmixgain_2ghz >= mingain) 5494205042Sthompsa rf = (rf & ~0x7) | sc->txmixgain_2ghz; 5495205042Sthompsa run_rt3070_rf_write(sc, 17, rf); 5496205042Sthompsa } 5497205042Sthompsa 5498270843Skevlo if (sc->mac_ver == 0x3071) { 5499203134Sthompsa run_rt3070_rf_read(sc, 1, &rf); 5500203134Sthompsa rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD); 5501203134Sthompsa rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD; 5502203134Sthompsa run_rt3070_rf_write(sc, 1, rf); 5503203134Sthompsa 5504203134Sthompsa run_rt3070_rf_read(sc, 15, &rf); 5505203134Sthompsa run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2); 5506203134Sthompsa 5507203134Sthompsa run_rt3070_rf_read(sc, 20, &rf); 5508203134Sthompsa run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1); 5509203134Sthompsa 5510203134Sthompsa run_rt3070_rf_read(sc, 21, &rf); 5511203134Sthompsa run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2); 5512205042Sthompsa } 5513203134Sthompsa 5514205042Sthompsa if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) { 5515205042Sthompsa /* fix Tx to Rx IQ glitch by raising RF voltage */ 5516203134Sthompsa run_rt3070_rf_read(sc, 27, &rf); 5517203134Sthompsa rf &= ~0x77; 5518205042Sthompsa if (sc->mac_rev < 0x0211) 5519203134Sthompsa rf |= 0x03; 5520203134Sthompsa run_rt3070_rf_write(sc, 27, rf); 5521203134Sthompsa } 5522209917Sthompsa return (0); 5523203134Sthompsa} 5524203134Sthompsa 5525259453Shselaskystatic void 5526261868Skevlorun_rt3593_rf_init(struct run_softc *sc) 5527261868Skevlo{ 5528261868Skevlo uint32_t tmp; 5529261868Skevlo uint8_t rf; 5530261868Skevlo int i; 5531261868Skevlo 5532261868Skevlo /* Disable the GPIO bits 4 and 7 for LNA PE control. */ 5533261868Skevlo run_read(sc, RT3070_GPIO_SWITCH, &tmp); 5534261868Skevlo tmp &= ~(1 << 4 | 1 << 7); 5535261868Skevlo run_write(sc, RT3070_GPIO_SWITCH, tmp); 5536261868Skevlo 5537261868Skevlo /* Initialize RF registers to default value. */ 5538261868Skevlo for (i = 0; i < nitems(rt3593_def_rf); i++) { 5539261868Skevlo run_rt3070_rf_write(sc, rt3593_def_rf[i].reg, 5540261868Skevlo rt3593_def_rf[i].val); 5541261868Skevlo } 5542261868Skevlo 5543261868Skevlo /* Toggle RF R2 to initiate calibration. */ 5544261868Skevlo run_rt3070_rf_write(sc, 2, RT5390_RESCAL); 5545261868Skevlo 5546261868Skevlo /* Initialize RF frequency offset. */ 5547261868Skevlo run_adjust_freq_offset(sc); 5548261868Skevlo 5549261868Skevlo run_rt3070_rf_read(sc, 18, &rf); 5550261868Skevlo run_rt3070_rf_write(sc, 18, rf | RT3593_AUTOTUNE_BYPASS); 5551261868Skevlo 5552261868Skevlo /* 5553261868Skevlo * Increase voltage from 1.2V to 1.35V, wait for 1 msec to 5554261868Skevlo * decrease voltage back to 1.2V. 5555261868Skevlo */ 5556261868Skevlo run_read(sc, RT3070_LDO_CFG0, &tmp); 5557261868Skevlo tmp = (tmp & ~0x1f000000) | 0x0d000000; 5558261868Skevlo run_write(sc, RT3070_LDO_CFG0, tmp); 5559261868Skevlo run_delay(sc, 1); 5560261868Skevlo tmp = (tmp & ~0x1f000000) | 0x01000000; 5561261868Skevlo run_write(sc, RT3070_LDO_CFG0, tmp); 5562261868Skevlo 5563261868Skevlo sc->rf24_20mhz = 0x1f; 5564261868Skevlo sc->rf24_40mhz = 0x2f; 5565261868Skevlo 5566261868Skevlo /* Save default BBP registers 25 and 26 values. */ 5567261868Skevlo run_bbp_read(sc, 25, &sc->bbp25); 5568261868Skevlo run_bbp_read(sc, 26, &sc->bbp26); 5569261868Skevlo 5570261868Skevlo run_read(sc, RT3070_OPT_14, &tmp); 5571261868Skevlo run_write(sc, RT3070_OPT_14, tmp | 1); 5572261868Skevlo} 5573261868Skevlo 5574261868Skevlostatic void 5575259453Shselaskyrun_rt5390_rf_init(struct run_softc *sc) 5576259453Shselasky{ 5577259453Shselasky uint32_t tmp; 5578259453Shselasky uint8_t rf; 5579259453Shselasky int i; 5580259453Shselasky 5581259453Shselasky /* Toggle RF R2 to initiate calibration. */ 5582259453Shselasky if (sc->mac_ver == 0x5390) { 5583259453Shselasky run_rt3070_rf_read(sc, 2, &rf); 5584259453Shselasky run_rt3070_rf_write(sc, 2, rf | RT5390_RESCAL); 5585259453Shselasky run_delay(sc, 10); 5586259453Shselasky run_rt3070_rf_write(sc, 2, rf & ~RT5390_RESCAL); 5587259453Shselasky } else { 5588259453Shselasky run_rt3070_rf_write(sc, 2, RT5390_RESCAL); 5589259453Shselasky run_delay(sc, 10); 5590259453Shselasky } 5591259453Shselasky 5592259453Shselasky /* Initialize RF registers to default value. */ 5593259453Shselasky if (sc->mac_ver == 0x5592) { 5594259453Shselasky for (i = 0; i < nitems(rt5592_def_rf); i++) { 5595259453Shselasky run_rt3070_rf_write(sc, rt5592_def_rf[i].reg, 5596259453Shselasky rt5592_def_rf[i].val); 5597259453Shselasky } 5598259453Shselasky /* Initialize RF frequency offset. */ 5599259453Shselasky run_adjust_freq_offset(sc); 5600259453Shselasky } else if (sc->mac_ver == 0x5392) { 5601259453Shselasky for (i = 0; i < nitems(rt5392_def_rf); i++) { 5602259453Shselasky run_rt3070_rf_write(sc, rt5392_def_rf[i].reg, 5603259453Shselasky rt5392_def_rf[i].val); 5604259453Shselasky } 5605259453Shselasky if (sc->mac_rev >= 0x0223) { 5606259453Shselasky run_rt3070_rf_write(sc, 23, 0x0f); 5607259453Shselasky run_rt3070_rf_write(sc, 24, 0x3e); 5608259453Shselasky run_rt3070_rf_write(sc, 51, 0x32); 5609259453Shselasky run_rt3070_rf_write(sc, 53, 0x22); 5610259453Shselasky run_rt3070_rf_write(sc, 56, 0xc1); 5611259453Shselasky run_rt3070_rf_write(sc, 59, 0x0f); 5612259453Shselasky } 5613259453Shselasky } else { 5614259453Shselasky for (i = 0; i < nitems(rt5390_def_rf); i++) { 5615259453Shselasky run_rt3070_rf_write(sc, rt5390_def_rf[i].reg, 5616259453Shselasky rt5390_def_rf[i].val); 5617259453Shselasky } 5618259453Shselasky if (sc->mac_rev >= 0x0502) { 5619259453Shselasky run_rt3070_rf_write(sc, 6, 0xe0); 5620259453Shselasky run_rt3070_rf_write(sc, 25, 0x80); 5621259453Shselasky run_rt3070_rf_write(sc, 46, 0x73); 5622259453Shselasky run_rt3070_rf_write(sc, 53, 0x00); 5623259453Shselasky run_rt3070_rf_write(sc, 56, 0x42); 5624259453Shselasky run_rt3070_rf_write(sc, 61, 0xd1); 5625259453Shselasky } 5626259453Shselasky } 5627259453Shselasky 5628259453Shselasky sc->rf24_20mhz = 0x1f; /* default value */ 5629259453Shselasky sc->rf24_40mhz = (sc->mac_ver == 0x5592) ? 0 : 0x2f; 5630259453Shselasky 5631259453Shselasky if (sc->mac_rev < 0x0211) 5632259453Shselasky run_rt3070_rf_write(sc, 27, 0x3); 5633259453Shselasky 5634259453Shselasky run_read(sc, RT3070_OPT_14, &tmp); 5635259453Shselasky run_write(sc, RT3070_OPT_14, tmp | 1); 5636259453Shselasky} 5637259453Shselasky 5638203134Sthompsastatic int 5639203134Sthompsarun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target, 5640203134Sthompsa uint8_t *val) 5641203134Sthompsa{ 5642203134Sthompsa uint8_t rf22, rf24; 5643203134Sthompsa uint8_t bbp55_pb, bbp55_sb, delta; 5644203134Sthompsa int ntries; 5645203134Sthompsa 5646203134Sthompsa /* program filter */ 5647205042Sthompsa run_rt3070_rf_read(sc, 24, &rf24); 5648205042Sthompsa rf24 = (rf24 & 0xc0) | init; /* initial filter value */ 5649203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 5650203134Sthompsa 5651203134Sthompsa /* enable baseband loopback mode */ 5652203134Sthompsa run_rt3070_rf_read(sc, 22, &rf22); 5653203134Sthompsa run_rt3070_rf_write(sc, 22, rf22 | 0x01); 5654203134Sthompsa 5655203134Sthompsa /* set power and frequency of passband test tone */ 5656203134Sthompsa run_bbp_write(sc, 24, 0x00); 5657203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5658203134Sthompsa /* transmit test tone */ 5659203134Sthompsa run_bbp_write(sc, 25, 0x90); 5660203134Sthompsa run_delay(sc, 10); 5661203134Sthompsa /* read received power */ 5662203134Sthompsa run_bbp_read(sc, 55, &bbp55_pb); 5663203134Sthompsa if (bbp55_pb != 0) 5664203134Sthompsa break; 5665203134Sthompsa } 5666203134Sthompsa if (ntries == 100) 5667259453Shselasky return (ETIMEDOUT); 5668203134Sthompsa 5669203134Sthompsa /* set power and frequency of stopband test tone */ 5670203134Sthompsa run_bbp_write(sc, 24, 0x06); 5671203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5672203134Sthompsa /* transmit test tone */ 5673203134Sthompsa run_bbp_write(sc, 25, 0x90); 5674203134Sthompsa run_delay(sc, 10); 5675203134Sthompsa /* read received power */ 5676203134Sthompsa run_bbp_read(sc, 55, &bbp55_sb); 5677203134Sthompsa 5678203134Sthompsa delta = bbp55_pb - bbp55_sb; 5679203134Sthompsa if (delta > target) 5680203134Sthompsa break; 5681203134Sthompsa 5682203134Sthompsa /* reprogram filter */ 5683203134Sthompsa rf24++; 5684203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 5685203134Sthompsa } 5686203134Sthompsa if (ntries < 100) { 5687203134Sthompsa if (rf24 != init) 5688203134Sthompsa rf24--; /* backtrack */ 5689203134Sthompsa *val = rf24; 5690203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 5691203134Sthompsa } 5692203134Sthompsa 5693203134Sthompsa /* restore initial state */ 5694203134Sthompsa run_bbp_write(sc, 24, 0x00); 5695203134Sthompsa 5696203134Sthompsa /* disable baseband loopback mode */ 5697203134Sthompsa run_rt3070_rf_read(sc, 22, &rf22); 5698203134Sthompsa run_rt3070_rf_write(sc, 22, rf22 & ~0x01); 5699203134Sthompsa 5700209917Sthompsa return (0); 5701203134Sthompsa} 5702203134Sthompsa 5703205042Sthompsastatic void 5704205042Sthompsarun_rt3070_rf_setup(struct run_softc *sc) 5705205042Sthompsa{ 5706205042Sthompsa uint8_t bbp, rf; 5707205042Sthompsa int i; 5708205042Sthompsa 5709261868Skevlo if (sc->mac_ver == 0x3572) { 5710205042Sthompsa /* enable DC filter */ 5711205042Sthompsa if (sc->mac_rev >= 0x0201) 5712205042Sthompsa run_bbp_write(sc, 103, 0xc0); 5713205042Sthompsa 5714205042Sthompsa run_bbp_read(sc, 138, &bbp); 5715205042Sthompsa if (sc->ntxchains == 1) 5716205042Sthompsa bbp |= 0x20; /* turn off DAC1 */ 5717205042Sthompsa if (sc->nrxchains == 1) 5718205042Sthompsa bbp &= ~0x02; /* turn off ADC1 */ 5719205042Sthompsa run_bbp_write(sc, 138, bbp); 5720205042Sthompsa 5721205042Sthompsa if (sc->mac_rev >= 0x0211) { 5722205042Sthompsa /* improve power consumption */ 5723205042Sthompsa run_bbp_read(sc, 31, &bbp); 5724205042Sthompsa run_bbp_write(sc, 31, bbp & ~0x03); 5725205042Sthompsa } 5726205042Sthompsa 5727205042Sthompsa run_rt3070_rf_read(sc, 16, &rf); 5728205042Sthompsa rf = (rf & ~0x07) | sc->txmixgain_2ghz; 5729205042Sthompsa run_rt3070_rf_write(sc, 16, rf); 5730205042Sthompsa 5731205042Sthompsa } else if (sc->mac_ver == 0x3071) { 5732259453Shselasky if (sc->mac_rev >= 0x0211) { 5733259453Shselasky /* enable DC filter */ 5734205042Sthompsa run_bbp_write(sc, 103, 0xc0); 5735205042Sthompsa 5736259453Shselasky /* improve power consumption */ 5737259453Shselasky run_bbp_read(sc, 31, &bbp); 5738259453Shselasky run_bbp_write(sc, 31, bbp & ~0x03); 5739259453Shselasky } 5740259453Shselasky 5741205042Sthompsa run_bbp_read(sc, 138, &bbp); 5742205042Sthompsa if (sc->ntxchains == 1) 5743205042Sthompsa bbp |= 0x20; /* turn off DAC1 */ 5744205042Sthompsa if (sc->nrxchains == 1) 5745205042Sthompsa bbp &= ~0x02; /* turn off ADC1 */ 5746205042Sthompsa run_bbp_write(sc, 138, bbp); 5747205042Sthompsa 5748205042Sthompsa run_write(sc, RT2860_TX_SW_CFG1, 0); 5749205042Sthompsa if (sc->mac_rev < 0x0211) { 5750205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 5751205042Sthompsa sc->patch_dac ? 0x2c : 0x0f); 5752205042Sthompsa } else 5753205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0); 5754205042Sthompsa 5755205042Sthompsa } else if (sc->mac_ver == 0x3070) { 5756205042Sthompsa if (sc->mac_rev >= 0x0201) { 5757205042Sthompsa /* enable DC filter */ 5758205042Sthompsa run_bbp_write(sc, 103, 0xc0); 5759205042Sthompsa 5760205042Sthompsa /* improve power consumption */ 5761205042Sthompsa run_bbp_read(sc, 31, &bbp); 5762205042Sthompsa run_bbp_write(sc, 31, bbp & ~0x03); 5763205042Sthompsa } 5764205042Sthompsa 5765259453Shselasky if (sc->mac_rev < 0x0201) { 5766205042Sthompsa run_write(sc, RT2860_TX_SW_CFG1, 0); 5767205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0x2c); 5768205042Sthompsa } else 5769205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0); 5770205042Sthompsa } 5771205042Sthompsa 5772205042Sthompsa /* initialize RF registers from ROM for >=RT3071*/ 5773261868Skevlo if (sc->mac_ver >= 0x3071) { 5774205042Sthompsa for (i = 0; i < 10; i++) { 5775205042Sthompsa if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff) 5776205042Sthompsa continue; 5777205042Sthompsa run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val); 5778205042Sthompsa } 5779205042Sthompsa } 5780205042Sthompsa} 5781205042Sthompsa 5782261868Skevlostatic void 5783261868Skevlorun_rt3593_rf_setup(struct run_softc *sc) 5784261868Skevlo{ 5785261868Skevlo uint8_t bbp, rf; 5786261868Skevlo 5787261868Skevlo if (sc->mac_rev >= 0x0211) { 5788261868Skevlo /* Enable DC filter. */ 5789261868Skevlo run_bbp_write(sc, 103, 0xc0); 5790261868Skevlo } 5791261868Skevlo run_write(sc, RT2860_TX_SW_CFG1, 0); 5792261868Skevlo if (sc->mac_rev < 0x0211) { 5793261868Skevlo run_write(sc, RT2860_TX_SW_CFG2, 5794261868Skevlo sc->patch_dac ? 0x2c : 0x0f); 5795261868Skevlo } else 5796261868Skevlo run_write(sc, RT2860_TX_SW_CFG2, 0); 5797261868Skevlo 5798261868Skevlo run_rt3070_rf_read(sc, 50, &rf); 5799261868Skevlo run_rt3070_rf_write(sc, 50, rf & ~RT3593_TX_LO2); 5800261868Skevlo 5801261868Skevlo run_rt3070_rf_read(sc, 51, &rf); 5802261868Skevlo rf = (rf & ~(RT3593_TX_LO1 | 0x0c)) | 5803261868Skevlo ((sc->txmixgain_2ghz & 0x07) << 2); 5804261868Skevlo run_rt3070_rf_write(sc, 51, rf); 5805261868Skevlo 5806261868Skevlo run_rt3070_rf_read(sc, 38, &rf); 5807261868Skevlo run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1); 5808261868Skevlo 5809261868Skevlo run_rt3070_rf_read(sc, 39, &rf); 5810261868Skevlo run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2); 5811261868Skevlo 5812261868Skevlo run_rt3070_rf_read(sc, 1, &rf); 5813261868Skevlo run_rt3070_rf_write(sc, 1, rf & ~(RT3070_RF_BLOCK | RT3070_PLL_PD)); 5814261868Skevlo 5815261868Skevlo run_rt3070_rf_read(sc, 30, &rf); 5816261868Skevlo rf = (rf & ~0x18) | 0x10; 5817261868Skevlo run_rt3070_rf_write(sc, 30, rf); 5818261868Skevlo 5819261868Skevlo /* Apply maximum likelihood detection for 2 stream case. */ 5820261868Skevlo run_bbp_read(sc, 105, &bbp); 5821261868Skevlo if (sc->nrxchains > 1) 5822261868Skevlo run_bbp_write(sc, 105, bbp | RT5390_MLD); 5823261868Skevlo 5824261868Skevlo /* Avoid data lost and CRC error. */ 5825261868Skevlo run_bbp_read(sc, 4, &bbp); 5826261868Skevlo run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 5827261868Skevlo 5828261868Skevlo run_bbp_write(sc, 92, 0x02); 5829261868Skevlo run_bbp_write(sc, 82, 0x82); 5830261868Skevlo run_bbp_write(sc, 106, 0x05); 5831261868Skevlo run_bbp_write(sc, 104, 0x92); 5832261868Skevlo run_bbp_write(sc, 88, 0x90); 5833261868Skevlo run_bbp_write(sc, 148, 0xc8); 5834261868Skevlo run_bbp_write(sc, 47, 0x48); 5835261868Skevlo run_bbp_write(sc, 120, 0x50); 5836261868Skevlo 5837261868Skevlo run_bbp_write(sc, 163, 0x9d); 5838261868Skevlo 5839261868Skevlo /* SNR mapping. */ 5840261868Skevlo run_bbp_write(sc, 142, 0x06); 5841261868Skevlo run_bbp_write(sc, 143, 0xa0); 5842261868Skevlo run_bbp_write(sc, 142, 0x07); 5843261868Skevlo run_bbp_write(sc, 143, 0xa1); 5844261868Skevlo run_bbp_write(sc, 142, 0x08); 5845261868Skevlo run_bbp_write(sc, 143, 0xa2); 5846261868Skevlo 5847261868Skevlo run_bbp_write(sc, 31, 0x08); 5848261868Skevlo run_bbp_write(sc, 68, 0x0b); 5849261868Skevlo run_bbp_write(sc, 105, 0x04); 5850261868Skevlo} 5851261868Skevlo 5852261868Skevlostatic void 5853261868Skevlorun_rt5390_rf_setup(struct run_softc *sc) 5854261868Skevlo{ 5855261868Skevlo uint8_t bbp, rf; 5856261868Skevlo 5857261868Skevlo if (sc->mac_rev >= 0x0211) { 5858261868Skevlo /* Enable DC filter. */ 5859261868Skevlo run_bbp_write(sc, 103, 0xc0); 5860261868Skevlo 5861261868Skevlo if (sc->mac_ver != 0x5592) { 5862261868Skevlo /* Improve power consumption. */ 5863261868Skevlo run_bbp_read(sc, 31, &bbp); 5864261868Skevlo run_bbp_write(sc, 31, bbp & ~0x03); 5865261868Skevlo } 5866261868Skevlo } 5867261868Skevlo 5868261868Skevlo run_bbp_read(sc, 138, &bbp); 5869261868Skevlo if (sc->ntxchains == 1) 5870261868Skevlo bbp |= 0x20; /* turn off DAC1 */ 5871261868Skevlo if (sc->nrxchains == 1) 5872261868Skevlo bbp &= ~0x02; /* turn off ADC1 */ 5873261868Skevlo run_bbp_write(sc, 138, bbp); 5874261868Skevlo 5875261868Skevlo run_rt3070_rf_read(sc, 38, &rf); 5876261868Skevlo run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1); 5877261868Skevlo 5878261868Skevlo run_rt3070_rf_read(sc, 39, &rf); 5879261868Skevlo run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2); 5880261868Skevlo 5881261868Skevlo /* Avoid data lost and CRC error. */ 5882261868Skevlo run_bbp_read(sc, 4, &bbp); 5883261868Skevlo run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 5884261868Skevlo 5885261868Skevlo run_rt3070_rf_read(sc, 30, &rf); 5886261868Skevlo rf = (rf & ~0x18) | 0x10; 5887261868Skevlo run_rt3070_rf_write(sc, 30, rf); 5888261868Skevlo 5889261868Skevlo if (sc->mac_ver != 0x5592) { 5890261868Skevlo run_write(sc, RT2860_TX_SW_CFG1, 0); 5891261868Skevlo if (sc->mac_rev < 0x0211) { 5892261868Skevlo run_write(sc, RT2860_TX_SW_CFG2, 5893261868Skevlo sc->patch_dac ? 0x2c : 0x0f); 5894261868Skevlo } else 5895261868Skevlo run_write(sc, RT2860_TX_SW_CFG2, 0); 5896261868Skevlo } 5897261868Skevlo} 5898261868Skevlo 5899203134Sthompsastatic int 5900203134Sthompsarun_txrx_enable(struct run_softc *sc) 5901203134Sthompsa{ 5902203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 5903203134Sthompsa uint32_t tmp; 5904203134Sthompsa int error, ntries; 5905203134Sthompsa 5906203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN); 5907203134Sthompsa for (ntries = 0; ntries < 200; ntries++) { 5908203134Sthompsa if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0) 5909259453Shselasky return (error); 5910203134Sthompsa if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 5911203134Sthompsa break; 5912203134Sthompsa run_delay(sc, 50); 5913203134Sthompsa } 5914203134Sthompsa if (ntries == 200) 5915259453Shselasky return (ETIMEDOUT); 5916203134Sthompsa 5917203134Sthompsa run_delay(sc, 50); 5918203134Sthompsa 5919203134Sthompsa tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE; 5920203134Sthompsa run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 5921203134Sthompsa 5922203134Sthompsa /* enable Rx bulk aggregation (set timeout and limit) */ 5923203134Sthompsa tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN | 5924203134Sthompsa RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2); 5925203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, tmp); 5926203134Sthompsa 5927203134Sthompsa /* set Rx filter */ 5928203134Sthompsa tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR; 5929203134Sthompsa if (ic->ic_opmode != IEEE80211_M_MONITOR) { 5930203134Sthompsa tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL | 5931203134Sthompsa RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK | 5932203134Sthompsa RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV | 5933203134Sthompsa RT2860_DROP_CFACK | RT2860_DROP_CFEND; 5934203134Sthompsa if (ic->ic_opmode == IEEE80211_M_STA) 5935203134Sthompsa tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL; 5936203134Sthompsa } 5937203134Sthompsa run_write(sc, RT2860_RX_FILTR_CFG, tmp); 5938203134Sthompsa 5939203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 5940203134Sthompsa RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 5941203134Sthompsa 5942209917Sthompsa return (0); 5943203134Sthompsa} 5944203134Sthompsa 5945203134Sthompsastatic void 5946259453Shselaskyrun_adjust_freq_offset(struct run_softc *sc) 5947259453Shselasky{ 5948259453Shselasky uint8_t rf, tmp; 5949259453Shselasky 5950259453Shselasky run_rt3070_rf_read(sc, 17, &rf); 5951259453Shselasky tmp = rf; 5952259453Shselasky rf = (rf & ~0x7f) | (sc->freq & 0x7f); 5953259453Shselasky rf = MIN(rf, 0x5f); 5954259453Shselasky 5955259453Shselasky if (tmp != rf) 5956259453Shselasky run_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf); 5957259453Shselasky} 5958259453Shselasky 5959259453Shselaskystatic void 5960203134Sthompsarun_init_locked(struct run_softc *sc) 5961203134Sthompsa{ 5962203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 5963203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 5964203134Sthompsa uint32_t tmp; 5965203134Sthompsa uint8_t bbp1, bbp3; 5966203134Sthompsa int i; 5967203134Sthompsa int ridx; 5968203134Sthompsa int ntries; 5969203134Sthompsa 5970209917Sthompsa if (ic->ic_nrunning > 1) 5971208019Sthompsa return; 5972208019Sthompsa 5973203134Sthompsa run_stop(sc); 5974203134Sthompsa 5975233283Sbschmidt if (run_load_microcode(sc) != 0) { 5976233283Sbschmidt device_printf(sc->sc_dev, "could not load 8051 microcode\n"); 5977233283Sbschmidt goto fail; 5978233283Sbschmidt } 5979233283Sbschmidt 5980203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5981203134Sthompsa if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0) 5982203134Sthompsa goto fail; 5983203134Sthompsa if (tmp != 0 && tmp != 0xffffffff) 5984203134Sthompsa break; 5985203134Sthompsa run_delay(sc, 10); 5986203134Sthompsa } 5987203134Sthompsa if (ntries == 100) 5988203134Sthompsa goto fail; 5989203134Sthompsa 5990203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 5991203134Sthompsa run_setup_tx_list(sc, &sc->sc_epq[i]); 5992203134Sthompsa 5993203134Sthompsa run_set_macaddr(sc, IF_LLADDR(ifp)); 5994203134Sthompsa 5995203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5996203134Sthompsa if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 5997203134Sthompsa goto fail; 5998203134Sthompsa if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 5999203134Sthompsa break; 6000203134Sthompsa run_delay(sc, 10); 6001203134Sthompsa } 6002203134Sthompsa if (ntries == 100) { 6003203138Sthompsa device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); 6004203134Sthompsa goto fail; 6005203134Sthompsa } 6006203134Sthompsa tmp &= 0xff0; 6007203134Sthompsa tmp |= RT2860_TX_WB_DDONE; 6008203134Sthompsa run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 6009203134Sthompsa 6010203134Sthompsa /* turn off PME_OEN to solve high-current issue */ 6011203134Sthompsa run_read(sc, RT2860_SYS_CTRL, &tmp); 6012203134Sthompsa run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN); 6013203134Sthompsa 6014203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 6015203134Sthompsa RT2860_BBP_HRST | RT2860_MAC_SRST); 6016203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, 0); 6017203134Sthompsa 6018203134Sthompsa if (run_reset(sc) != 0) { 6019203138Sthompsa device_printf(sc->sc_dev, "could not reset chipset\n"); 6020203134Sthompsa goto fail; 6021203134Sthompsa } 6022203134Sthompsa 6023203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 0); 6024203134Sthompsa 6025203134Sthompsa /* init Tx power for all Tx rates (from EEPROM) */ 6026203134Sthompsa for (ridx = 0; ridx < 5; ridx++) { 6027203134Sthompsa if (sc->txpow20mhz[ridx] == 0xffffffff) 6028203134Sthompsa continue; 6029203134Sthompsa run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]); 6030203134Sthompsa } 6031203134Sthompsa 6032259453Shselasky for (i = 0; i < nitems(rt2870_def_mac); i++) 6033203134Sthompsa run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val); 6034203134Sthompsa run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273); 6035203134Sthompsa run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344); 6036203134Sthompsa run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa); 6037203134Sthompsa 6038259453Shselasky if (sc->mac_ver >= 0x5390) { 6039259453Shselasky run_write(sc, RT2860_TX_SW_CFG0, 6040259453Shselasky 4 << RT2860_DLY_PAPE_EN_SHIFT | 4); 6041259453Shselasky if (sc->mac_ver >= 0x5392) { 6042259453Shselasky run_write(sc, RT2860_MAX_LEN_CFG, 0x00002fff); 6043259453Shselasky if (sc->mac_ver == 0x5592) { 6044259453Shselasky run_write(sc, RT2860_HT_FBK_CFG1, 0xedcba980); 6045259453Shselasky run_write(sc, RT2860_TXOP_HLDR_ET, 0x00000082); 6046259453Shselasky } else { 6047259453Shselasky run_write(sc, RT2860_HT_FBK_CFG1, 0xedcb4980); 6048259453Shselasky run_write(sc, RT2860_LG_FBK_CFG0, 0xedcba322); 6049259453Shselasky } 6050259453Shselasky } 6051261868Skevlo } else if (sc->mac_ver == 0x3593) { 6052261868Skevlo run_write(sc, RT2860_TX_SW_CFG0, 6053261868Skevlo 4 << RT2860_DLY_PAPE_EN_SHIFT | 2); 6054259453Shselasky } else if (sc->mac_ver >= 0x3070) { 6055203134Sthompsa /* set delay of PA_PE assertion to 1us (unit of 0.25us) */ 6056203134Sthompsa run_write(sc, RT2860_TX_SW_CFG0, 6057203134Sthompsa 4 << RT2860_DLY_PAPE_EN_SHIFT); 6058203134Sthompsa } 6059203134Sthompsa 6060203134Sthompsa /* wait while MAC is busy */ 6061203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 6062203134Sthompsa if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0) 6063203134Sthompsa goto fail; 6064203134Sthompsa if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY))) 6065203134Sthompsa break; 6066203134Sthompsa run_delay(sc, 10); 6067203134Sthompsa } 6068203134Sthompsa if (ntries == 100) 6069203134Sthompsa goto fail; 6070203134Sthompsa 6071203134Sthompsa /* clear Host to MCU mailbox */ 6072203134Sthompsa run_write(sc, RT2860_H2M_BBPAGENT, 0); 6073203134Sthompsa run_write(sc, RT2860_H2M_MAILBOX, 0); 6074203134Sthompsa run_delay(sc, 10); 6075203134Sthompsa 6076203134Sthompsa if (run_bbp_init(sc) != 0) { 6077203138Sthompsa device_printf(sc->sc_dev, "could not initialize BBP\n"); 6078203134Sthompsa goto fail; 6079203134Sthompsa } 6080203134Sthompsa 6081203134Sthompsa /* abort TSF synchronization */ 6082203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 6083203134Sthompsa tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 6084203134Sthompsa RT2860_TBTT_TIMER_EN); 6085203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, tmp); 6086203134Sthompsa 6087203134Sthompsa /* clear RX WCID search table */ 6088203134Sthompsa run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512); 6089203134Sthompsa /* clear WCID attribute table */ 6090203134Sthompsa run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32); 6091203134Sthompsa 6092209144Sthompsa /* hostapd sets a key before init. So, don't clear it. */ 6093209917Sthompsa if (sc->cmdq_key_set != RUN_CMDQ_GO) { 6094209144Sthompsa /* clear shared key table */ 6095209144Sthompsa run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32); 6096209144Sthompsa /* clear shared key mode */ 6097209144Sthompsa run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4); 6098209144Sthompsa } 6099209144Sthompsa 6100203134Sthompsa run_read(sc, RT2860_US_CYC_CNT, &tmp); 6101203134Sthompsa tmp = (tmp & ~0xff) | 0x1e; 6102203134Sthompsa run_write(sc, RT2860_US_CYC_CNT, tmp); 6103203134Sthompsa 6104205042Sthompsa if (sc->mac_rev != 0x0101) 6105203134Sthompsa run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f); 6106203134Sthompsa 6107203134Sthompsa run_write(sc, RT2860_WMM_TXOP0_CFG, 0); 6108203134Sthompsa run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96); 6109203134Sthompsa 6110203134Sthompsa /* write vendor-specific BBP values (from EEPROM) */ 6111261868Skevlo if (sc->mac_ver < 0x3593) { 6112259453Shselasky for (i = 0; i < 10; i++) { 6113259453Shselasky if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff) 6114259453Shselasky continue; 6115259453Shselasky run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val); 6116259453Shselasky } 6117203134Sthompsa } 6118203134Sthompsa 6119203134Sthompsa /* select Main antenna for 1T1R devices */ 6120259453Shselasky if (sc->rf_rev == RT3070_RF_3020 || sc->rf_rev == RT5390_RF_5370) 6121203134Sthompsa run_set_rx_antenna(sc, 0); 6122203134Sthompsa 6123203134Sthompsa /* send LEDs operating mode to microcontroller */ 6124203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]); 6125203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]); 6126203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]); 6127203134Sthompsa 6128259453Shselasky if (sc->mac_ver >= 0x5390) 6129259453Shselasky run_rt5390_rf_init(sc); 6130261868Skevlo else if (sc->mac_ver == 0x3593) 6131261868Skevlo run_rt3593_rf_init(sc); 6132259453Shselasky else if (sc->mac_ver >= 0x3070) 6133205042Sthompsa run_rt3070_rf_init(sc); 6134205042Sthompsa 6135203134Sthompsa /* disable non-existing Rx chains */ 6136203134Sthompsa run_bbp_read(sc, 3, &bbp3); 6137203134Sthompsa bbp3 &= ~(1 << 3 | 1 << 4); 6138203134Sthompsa if (sc->nrxchains == 2) 6139203134Sthompsa bbp3 |= 1 << 3; 6140203134Sthompsa else if (sc->nrxchains == 3) 6141203134Sthompsa bbp3 |= 1 << 4; 6142203134Sthompsa run_bbp_write(sc, 3, bbp3); 6143203134Sthompsa 6144203134Sthompsa /* disable non-existing Tx chains */ 6145203134Sthompsa run_bbp_read(sc, 1, &bbp1); 6146203134Sthompsa if (sc->ntxchains == 1) 6147203134Sthompsa bbp1 &= ~(1 << 3 | 1 << 4); 6148203134Sthompsa run_bbp_write(sc, 1, bbp1); 6149203134Sthompsa 6150261868Skevlo if (sc->mac_ver >= 0x5390) 6151261868Skevlo run_rt5390_rf_setup(sc); 6152261868Skevlo else if (sc->mac_ver == 0x3593) 6153261868Skevlo run_rt3593_rf_setup(sc); 6154261868Skevlo else if (sc->mac_ver >= 0x3070) 6155205042Sthompsa run_rt3070_rf_setup(sc); 6156203134Sthompsa 6157203134Sthompsa /* select default channel */ 6158203134Sthompsa run_set_chan(sc, ic->ic_curchan); 6159203134Sthompsa 6160203134Sthompsa /* setup initial protection mode */ 6161218492Sbschmidt run_updateprot_cb(ic); 6162203134Sthompsa 6163203134Sthompsa /* turn radio LED on */ 6164203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO); 6165203134Sthompsa 6166203134Sthompsa ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 6167203134Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 6168208019Sthompsa sc->cmdq_run = RUN_CMDQ_GO; 6169203134Sthompsa 6170209917Sthompsa for (i = 0; i != RUN_N_XFER; i++) 6171203134Sthompsa usbd_xfer_set_stall(sc->sc_xfer[i]); 6172203134Sthompsa 6173203134Sthompsa usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]); 6174203134Sthompsa 6175203134Sthompsa if (run_txrx_enable(sc) != 0) 6176203134Sthompsa goto fail; 6177203134Sthompsa 6178203134Sthompsa return; 6179203134Sthompsa 6180203134Sthompsafail: 6181203134Sthompsa run_stop(sc); 6182203134Sthompsa} 6183203134Sthompsa 6184203134Sthompsastatic void 6185203134Sthompsarun_init(void *arg) 6186203134Sthompsa{ 6187203134Sthompsa struct run_softc *sc = arg; 6188203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 6189203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 6190203134Sthompsa 6191203134Sthompsa RUN_LOCK(sc); 6192203134Sthompsa run_init_locked(sc); 6193203134Sthompsa RUN_UNLOCK(sc); 6194203134Sthompsa 6195203134Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING) 6196208019Sthompsa ieee80211_start_all(ic); 6197203134Sthompsa} 6198203134Sthompsa 6199203134Sthompsastatic void 6200203134Sthompsarun_stop(void *arg) 6201203134Sthompsa{ 6202203134Sthompsa struct run_softc *sc = (struct run_softc *)arg; 6203203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 6204203134Sthompsa uint32_t tmp; 6205203134Sthompsa int i; 6206203134Sthompsa int ntries; 6207203134Sthompsa 6208203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 6209203134Sthompsa 6210203134Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING) 6211203134Sthompsa run_set_leds(sc, 0); /* turn all LEDs off */ 6212203134Sthompsa 6213203134Sthompsa ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 6214203134Sthompsa 6215208019Sthompsa sc->ratectl_run = RUN_RATECTL_OFF; 6216209144Sthompsa sc->cmdq_run = sc->cmdq_key_set; 6217208019Sthompsa 6218203134Sthompsa RUN_UNLOCK(sc); 6219203134Sthompsa 6220203134Sthompsa for(i = 0; i < RUN_N_XFER; i++) 6221203134Sthompsa usbd_transfer_drain(sc->sc_xfer[i]); 6222203134Sthompsa 6223203134Sthompsa RUN_LOCK(sc); 6224203134Sthompsa 6225209917Sthompsa if (sc->rx_m != NULL) { 6226203134Sthompsa m_free(sc->rx_m); 6227203134Sthompsa sc->rx_m = NULL; 6228203134Sthompsa } 6229203134Sthompsa 6230259453Shselasky /* Disable Tx/Rx DMA. */ 6231259453Shselasky if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 6232259453Shselasky return; 6233259453Shselasky tmp &= ~(RT2860_RX_DMA_EN | RT2860_TX_DMA_EN); 6234259453Shselasky run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 6235259453Shselasky 6236259453Shselasky for (ntries = 0; ntries < 100; ntries++) { 6237259453Shselasky if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 6238259453Shselasky return; 6239259453Shselasky if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 6240259453Shselasky break; 6241259453Shselasky run_delay(sc, 10); 6242259453Shselasky } 6243259453Shselasky if (ntries == 100) { 6244259453Shselasky device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); 6245259453Shselasky return; 6246259453Shselasky } 6247259453Shselasky 6248203134Sthompsa /* disable Tx/Rx */ 6249203134Sthompsa run_read(sc, RT2860_MAC_SYS_CTRL, &tmp); 6250203134Sthompsa tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 6251203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, tmp); 6252203134Sthompsa 6253203134Sthompsa /* wait for pending Tx to complete */ 6254203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 6255209917Sthompsa if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0) { 6256203134Sthompsa DPRINTF("Cannot read Tx queue count\n"); 6257203134Sthompsa break; 6258203134Sthompsa } 6259209917Sthompsa if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0) { 6260203134Sthompsa DPRINTF("All Tx cleared\n"); 6261203134Sthompsa break; 6262203134Sthompsa } 6263203134Sthompsa run_delay(sc, 10); 6264203134Sthompsa } 6265209917Sthompsa if (ntries >= 100) 6266203134Sthompsa DPRINTF("There are still pending Tx\n"); 6267203134Sthompsa run_delay(sc, 10); 6268203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, 0); 6269203134Sthompsa 6270203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST); 6271203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 0); 6272203134Sthompsa 6273203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 6274203134Sthompsa run_unsetup_tx_list(sc, &sc->sc_epq[i]); 6275203134Sthompsa} 6276203134Sthompsa 6277203134Sthompsastatic void 6278259453Shselaskyrun_delay(struct run_softc *sc, u_int ms) 6279203134Sthompsa{ 6280203134Sthompsa usb_pause_mtx(mtx_owned(&sc->sc_mtx) ? 6281203134Sthompsa &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms)); 6282203134Sthompsa} 6283203134Sthompsa 6284203134Sthompsastatic device_method_t run_methods[] = { 6285203134Sthompsa /* Device interface */ 6286203134Sthompsa DEVMETHOD(device_probe, run_match), 6287203134Sthompsa DEVMETHOD(device_attach, run_attach), 6288203134Sthompsa DEVMETHOD(device_detach, run_detach), 6289246614Shselasky DEVMETHOD_END 6290203134Sthompsa}; 6291203134Sthompsa 6292203134Sthompsastatic driver_t run_driver = { 6293233774Shselasky .name = "run", 6294233774Shselasky .methods = run_methods, 6295233774Shselasky .size = sizeof(struct run_softc) 6296203134Sthompsa}; 6297203134Sthompsa 6298203134Sthompsastatic devclass_t run_devclass; 6299203134Sthompsa 6300261868SkevloDRIVER_MODULE(run, uhub, run_driver, run_devclass, run_driver_loaded, NULL); 6301212122SthompsaMODULE_DEPEND(run, wlan, 1, 1, 1); 6302212122SthompsaMODULE_DEPEND(run, usb, 1, 1, 1); 6303212122SthompsaMODULE_DEPEND(run, firmware, 1, 1, 1); 6304212122SthompsaMODULE_VERSION(run, 1); 6305