if_run.c revision 301302
1203134Sthompsa/*- 2205042Sthompsa * Copyright (c) 2008,2010 Damien Bergamini <damien.bergamini@free.fr> 3205042Sthompsa * ported to FreeBSD by Akinori Furukoshi <moonlightakkiy@yahoo.ca> 4205042Sthompsa * USB Consulting, Hans Petter Selasky <hselasky@freebsd.org> 5260219Skevlo * Copyright (c) 2013-2014 Kevin Lo 6203134Sthompsa * 7203134Sthompsa * Permission to use, copy, modify, and distribute this software for any 8203134Sthompsa * purpose with or without fee is hereby granted, provided that the above 9203134Sthompsa * copyright notice and this permission notice appear in all copies. 10203134Sthompsa * 11203134Sthompsa * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12203134Sthompsa * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13203134Sthompsa * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14203134Sthompsa * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15203134Sthompsa * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16203134Sthompsa * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17203134Sthompsa * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18203134Sthompsa */ 19203134Sthompsa 20203134Sthompsa#include <sys/cdefs.h> 21203134Sthompsa__FBSDID("$FreeBSD: head/sys/dev/usb/wlan/if_run.c 301302 2016-06-04 07:18:39Z adrian $"); 22203134Sthompsa 23203134Sthompsa/*- 24257955Skevlo * Ralink Technology RT2700U/RT2800U/RT3000U/RT3900E chipset driver. 25203134Sthompsa * http://www.ralinktech.com/ 26203134Sthompsa */ 27203134Sthompsa 28203134Sthompsa#include <sys/param.h> 29203134Sthompsa#include <sys/sockio.h> 30203134Sthompsa#include <sys/sysctl.h> 31203134Sthompsa#include <sys/lock.h> 32203134Sthompsa#include <sys/mutex.h> 33203134Sthompsa#include <sys/mbuf.h> 34203134Sthompsa#include <sys/kernel.h> 35203134Sthompsa#include <sys/socket.h> 36203134Sthompsa#include <sys/systm.h> 37203134Sthompsa#include <sys/malloc.h> 38203134Sthompsa#include <sys/module.h> 39203134Sthompsa#include <sys/bus.h> 40203134Sthompsa#include <sys/endian.h> 41203134Sthompsa#include <sys/linker.h> 42203134Sthompsa#include <sys/firmware.h> 43203134Sthompsa#include <sys/kdb.h> 44203134Sthompsa 45203134Sthompsa#include <machine/bus.h> 46203134Sthompsa#include <machine/resource.h> 47203134Sthompsa#include <sys/rman.h> 48203134Sthompsa 49203134Sthompsa#include <net/bpf.h> 50203134Sthompsa#include <net/if.h> 51257176Sglebius#include <net/if_var.h> 52203134Sthompsa#include <net/if_arp.h> 53203134Sthompsa#include <net/ethernet.h> 54203134Sthompsa#include <net/if_dl.h> 55203134Sthompsa#include <net/if_media.h> 56203134Sthompsa#include <net/if_types.h> 57203134Sthompsa 58203134Sthompsa#include <netinet/in.h> 59203134Sthompsa#include <netinet/in_systm.h> 60203134Sthompsa#include <netinet/in_var.h> 61203134Sthompsa#include <netinet/if_ether.h> 62203134Sthompsa#include <netinet/ip.h> 63203134Sthompsa 64203134Sthompsa#include <net80211/ieee80211_var.h> 65203134Sthompsa#include <net80211/ieee80211_regdomain.h> 66203134Sthompsa#include <net80211/ieee80211_radiotap.h> 67206358Srpaulo#include <net80211/ieee80211_ratectl.h> 68203134Sthompsa 69203134Sthompsa#include <dev/usb/usb.h> 70203134Sthompsa#include <dev/usb/usbdi.h> 71203134Sthompsa#include "usbdevs.h" 72203134Sthompsa 73259546Skevlo#define USB_DEBUG_VAR run_debug 74203134Sthompsa#include <dev/usb/usb_debug.h> 75259812Skevlo#include <dev/usb/usb_msctest.h> 76203134Sthompsa 77220235Skevlo#include <dev/usb/wlan/if_runreg.h> 78220235Skevlo#include <dev/usb/wlan/if_runvar.h> 79203134Sthompsa 80207077Sthompsa#ifdef USB_DEBUG 81259546Skevlo#define RUN_DEBUG 82203134Sthompsa#endif 83203134Sthompsa 84203134Sthompsa#ifdef RUN_DEBUG 85203134Sthompsaint run_debug = 0; 86227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, run, CTLFLAG_RW, 0, "USB run"); 87276701ShselaskySYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RWTUN, &run_debug, 0, 88203134Sthompsa "run debug level"); 89203134Sthompsa#endif 90203134Sthompsa 91287552Skevlo#define IEEE80211_HAS_ADDR4(wh) IEEE80211_IS_DSTODS(wh) 92203134Sthompsa 93208019Sthompsa/* 94208019Sthompsa * Because of LOR in run_key_delete(), use atomic instead. 95208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[]. 96208019Sthompsa */ 97259546Skevlo#define RUN_CMDQ_GET(c) (atomic_fetchadd_32((c), 1) & RUN_CMDQ_MASQ) 98208019Sthompsa 99223486Shselaskystatic const STRUCT_USB_HOST_ID run_devs[] = { 100259546Skevlo#define RUN_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } 101259812Skevlo#define RUN_DEV_EJECT(v,p) \ 102262465Skevlo { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RUN_EJECT) } 103262465Skevlo#define RUN_EJECT 1 104209918Sthompsa RUN_DEV(ABOCOM, RT2770), 105209918Sthompsa RUN_DEV(ABOCOM, RT2870), 106209918Sthompsa RUN_DEV(ABOCOM, RT3070), 107209918Sthompsa RUN_DEV(ABOCOM, RT3071), 108209918Sthompsa RUN_DEV(ABOCOM, RT3072), 109209918Sthompsa RUN_DEV(ABOCOM2, RT2870_1), 110209918Sthompsa RUN_DEV(ACCTON, RT2770), 111209918Sthompsa RUN_DEV(ACCTON, RT2870_1), 112209918Sthompsa RUN_DEV(ACCTON, RT2870_2), 113209918Sthompsa RUN_DEV(ACCTON, RT2870_3), 114209918Sthompsa RUN_DEV(ACCTON, RT2870_4), 115209918Sthompsa RUN_DEV(ACCTON, RT2870_5), 116209918Sthompsa RUN_DEV(ACCTON, RT3070), 117209918Sthompsa RUN_DEV(ACCTON, RT3070_1), 118209918Sthompsa RUN_DEV(ACCTON, RT3070_2), 119209918Sthompsa RUN_DEV(ACCTON, RT3070_3), 120209918Sthompsa RUN_DEV(ACCTON, RT3070_4), 121209918Sthompsa RUN_DEV(ACCTON, RT3070_5), 122209918Sthompsa RUN_DEV(AIRTIES, RT3070), 123209918Sthompsa RUN_DEV(ALLWIN, RT2070), 124209918Sthompsa RUN_DEV(ALLWIN, RT2770), 125209918Sthompsa RUN_DEV(ALLWIN, RT2870), 126209918Sthompsa RUN_DEV(ALLWIN, RT3070), 127209918Sthompsa RUN_DEV(ALLWIN, RT3071), 128209918Sthompsa RUN_DEV(ALLWIN, RT3072), 129209918Sthompsa RUN_DEV(ALLWIN, RT3572), 130209918Sthompsa RUN_DEV(AMIGO, RT2870_1), 131209918Sthompsa RUN_DEV(AMIGO, RT2870_2), 132209918Sthompsa RUN_DEV(AMIT, CGWLUSB2GNR), 133209918Sthompsa RUN_DEV(AMIT, RT2870_1), 134209918Sthompsa RUN_DEV(AMIT2, RT2870), 135209918Sthompsa RUN_DEV(ASUS, RT2870_1), 136209918Sthompsa RUN_DEV(ASUS, RT2870_2), 137209918Sthompsa RUN_DEV(ASUS, RT2870_3), 138209918Sthompsa RUN_DEV(ASUS, RT2870_4), 139209918Sthompsa RUN_DEV(ASUS, RT2870_5), 140209918Sthompsa RUN_DEV(ASUS, USBN13), 141209918Sthompsa RUN_DEV(ASUS, RT3070_1), 142260219Skevlo RUN_DEV(ASUS, USBN66), 143239358Shselasky RUN_DEV(ASUS, USB_N53), 144209918Sthompsa RUN_DEV(ASUS2, USBN11), 145209918Sthompsa RUN_DEV(AZUREWAVE, RT2870_1), 146209918Sthompsa RUN_DEV(AZUREWAVE, RT2870_2), 147209918Sthompsa RUN_DEV(AZUREWAVE, RT3070_1), 148209918Sthompsa RUN_DEV(AZUREWAVE, RT3070_2), 149209918Sthompsa RUN_DEV(AZUREWAVE, RT3070_3), 150260219Skevlo RUN_DEV(BELKIN, F9L1103), 151209918Sthompsa RUN_DEV(BELKIN, F5D8053V3), 152209918Sthompsa RUN_DEV(BELKIN, F5D8055), 153226534Shselasky RUN_DEV(BELKIN, F5D8055V2), 154209918Sthompsa RUN_DEV(BELKIN, F6D4050V1), 155256500Shselasky RUN_DEV(BELKIN, F6D4050V2), 156209918Sthompsa RUN_DEV(BELKIN, RT2870_1), 157209918Sthompsa RUN_DEV(BELKIN, RT2870_2), 158226534Shselasky RUN_DEV(CISCOLINKSYS, AE1000), 159209918Sthompsa RUN_DEV(CISCOLINKSYS2, RT3070), 160209918Sthompsa RUN_DEV(CISCOLINKSYS3, RT3070), 161209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_1), 162209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_2), 163209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_3), 164209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_4), 165209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_5), 166209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_6), 167209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_7), 168209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_8), 169209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT3070_1), 170209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT3070_2), 171209918Sthompsa RUN_DEV(CONCEPTRONIC2, VIGORN61), 172209918Sthompsa RUN_DEV(COREGA, CGWLUSB300GNM), 173209918Sthompsa RUN_DEV(COREGA, RT2870_1), 174209918Sthompsa RUN_DEV(COREGA, RT2870_2), 175209918Sthompsa RUN_DEV(COREGA, RT2870_3), 176209918Sthompsa RUN_DEV(COREGA, RT3070), 177209918Sthompsa RUN_DEV(CYBERTAN, RT2870), 178209918Sthompsa RUN_DEV(DLINK, RT2870), 179209918Sthompsa RUN_DEV(DLINK, RT3072), 180255238Sbr RUN_DEV(DLINK, DWA127), 181257955Skevlo RUN_DEV(DLINK, DWA140B3), 182259032Skevlo RUN_DEV(DLINK, DWA160B2), 183267089Skevlo RUN_DEV(DLINK, DWA140D1), 184260219Skevlo RUN_DEV(DLINK, DWA162), 185209918Sthompsa RUN_DEV(DLINK2, DWA130), 186209918Sthompsa RUN_DEV(DLINK2, RT2870_1), 187209918Sthompsa RUN_DEV(DLINK2, RT2870_2), 188209918Sthompsa RUN_DEV(DLINK2, RT3070_1), 189209918Sthompsa RUN_DEV(DLINK2, RT3070_2), 190209918Sthompsa RUN_DEV(DLINK2, RT3070_3), 191209918Sthompsa RUN_DEV(DLINK2, RT3070_4), 192209918Sthompsa RUN_DEV(DLINK2, RT3070_5), 193209918Sthompsa RUN_DEV(DLINK2, RT3072), 194209918Sthompsa RUN_DEV(DLINK2, RT3072_1), 195209918Sthompsa RUN_DEV(EDIMAX, EW7717), 196209918Sthompsa RUN_DEV(EDIMAX, EW7718), 197260219Skevlo RUN_DEV(EDIMAX, EW7733UND), 198209918Sthompsa RUN_DEV(EDIMAX, RT2870_1), 199209918Sthompsa RUN_DEV(ENCORE, RT3070_1), 200209918Sthompsa RUN_DEV(ENCORE, RT3070_2), 201209918Sthompsa RUN_DEV(ENCORE, RT3070_3), 202209918Sthompsa RUN_DEV(GIGABYTE, GNWB31N), 203209918Sthompsa RUN_DEV(GIGABYTE, GNWB32L), 204209918Sthompsa RUN_DEV(GIGABYTE, RT2870_1), 205209918Sthompsa RUN_DEV(GIGASET, RT3070_1), 206209918Sthompsa RUN_DEV(GIGASET, RT3070_2), 207209918Sthompsa RUN_DEV(GUILLEMOT, HWNU300), 208209918Sthompsa RUN_DEV(HAWKING, HWUN2), 209209918Sthompsa RUN_DEV(HAWKING, RT2870_1), 210209918Sthompsa RUN_DEV(HAWKING, RT2870_2), 211209918Sthompsa RUN_DEV(HAWKING, RT3070), 212209918Sthompsa RUN_DEV(IODATA, RT3072_1), 213209918Sthompsa RUN_DEV(IODATA, RT3072_2), 214209918Sthompsa RUN_DEV(IODATA, RT3072_3), 215209918Sthompsa RUN_DEV(IODATA, RT3072_4), 216209918Sthompsa RUN_DEV(LINKSYS4, RT3070), 217209918Sthompsa RUN_DEV(LINKSYS4, WUSB100), 218209918Sthompsa RUN_DEV(LINKSYS4, WUSB54GCV3), 219209918Sthompsa RUN_DEV(LINKSYS4, WUSB600N), 220209918Sthompsa RUN_DEV(LINKSYS4, WUSB600NV2), 221209918Sthompsa RUN_DEV(LOGITEC, RT2870_1), 222209918Sthompsa RUN_DEV(LOGITEC, RT2870_2), 223209918Sthompsa RUN_DEV(LOGITEC, RT2870_3), 224230333Shselasky RUN_DEV(LOGITEC, LANW300NU2), 225238274Shrs RUN_DEV(LOGITEC, LANW150NU2), 226248458Shselasky RUN_DEV(LOGITEC, LANW300NU2S), 227281745Skevlo RUN_DEV(MELCO, WLIUCG300HP), 228209918Sthompsa RUN_DEV(MELCO, RT2870_2), 229209918Sthompsa RUN_DEV(MELCO, WLIUCAG300N), 230209918Sthompsa RUN_DEV(MELCO, WLIUCG300N), 231219257Sdaichi RUN_DEV(MELCO, WLIUCG301N), 232209918Sthompsa RUN_DEV(MELCO, WLIUCGN), 233227781Shselasky RUN_DEV(MELCO, WLIUCGNM), 234281745Skevlo RUN_DEV(MELCO, WLIUCG300HPV1), 235238274Shrs RUN_DEV(MELCO, WLIUCGNM2), 236209918Sthompsa RUN_DEV(MOTOROLA4, RT2770), 237209918Sthompsa RUN_DEV(MOTOROLA4, RT3070), 238209918Sthompsa RUN_DEV(MSI, RT3070_1), 239209918Sthompsa RUN_DEV(MSI, RT3070_2), 240209918Sthompsa RUN_DEV(MSI, RT3070_3), 241209918Sthompsa RUN_DEV(MSI, RT3070_4), 242209918Sthompsa RUN_DEV(MSI, RT3070_5), 243209918Sthompsa RUN_DEV(MSI, RT3070_6), 244209918Sthompsa RUN_DEV(MSI, RT3070_7), 245209918Sthompsa RUN_DEV(MSI, RT3070_8), 246209918Sthompsa RUN_DEV(MSI, RT3070_9), 247209918Sthompsa RUN_DEV(MSI, RT3070_10), 248209918Sthompsa RUN_DEV(MSI, RT3070_11), 249289028Sgavin RUN_DEV(NETGEAR, WNDA4100), 250209918Sthompsa RUN_DEV(OVISLINK, RT3072), 251209918Sthompsa RUN_DEV(PARA, RT3070), 252209918Sthompsa RUN_DEV(PEGATRON, RT2870), 253209918Sthompsa RUN_DEV(PEGATRON, RT3070), 254209918Sthompsa RUN_DEV(PEGATRON, RT3070_2), 255209918Sthompsa RUN_DEV(PEGATRON, RT3070_3), 256209918Sthompsa RUN_DEV(PHILIPS, RT2870), 257209918Sthompsa RUN_DEV(PLANEX2, GWUS300MINIS), 258209918Sthompsa RUN_DEV(PLANEX2, GWUSMICRON), 259209918Sthompsa RUN_DEV(PLANEX2, RT2870), 260209918Sthompsa RUN_DEV(PLANEX2, RT3070), 261209918Sthompsa RUN_DEV(QCOM, RT2870), 262209918Sthompsa RUN_DEV(QUANTA, RT3070), 263209918Sthompsa RUN_DEV(RALINK, RT2070), 264209918Sthompsa RUN_DEV(RALINK, RT2770), 265209918Sthompsa RUN_DEV(RALINK, RT2870), 266209918Sthompsa RUN_DEV(RALINK, RT3070), 267209918Sthompsa RUN_DEV(RALINK, RT3071), 268209918Sthompsa RUN_DEV(RALINK, RT3072), 269209918Sthompsa RUN_DEV(RALINK, RT3370), 270209918Sthompsa RUN_DEV(RALINK, RT3572), 271260219Skevlo RUN_DEV(RALINK, RT3573), 272257955Skevlo RUN_DEV(RALINK, RT5370), 273259032Skevlo RUN_DEV(RALINK, RT5572), 274209918Sthompsa RUN_DEV(RALINK, RT8070), 275226534Shselasky RUN_DEV(SAMSUNG, WIS09ABGN), 276209918Sthompsa RUN_DEV(SAMSUNG2, RT2870_1), 277209918Sthompsa RUN_DEV(SENAO, RT2870_1), 278209918Sthompsa RUN_DEV(SENAO, RT2870_2), 279209918Sthompsa RUN_DEV(SENAO, RT2870_3), 280209918Sthompsa RUN_DEV(SENAO, RT2870_4), 281209918Sthompsa RUN_DEV(SENAO, RT3070), 282209918Sthompsa RUN_DEV(SENAO, RT3071), 283209918Sthompsa RUN_DEV(SENAO, RT3072_1), 284209918Sthompsa RUN_DEV(SENAO, RT3072_2), 285209918Sthompsa RUN_DEV(SENAO, RT3072_3), 286209918Sthompsa RUN_DEV(SENAO, RT3072_4), 287209918Sthompsa RUN_DEV(SENAO, RT3072_5), 288209918Sthompsa RUN_DEV(SITECOMEU, RT2770), 289209918Sthompsa RUN_DEV(SITECOMEU, RT2870_1), 290209918Sthompsa RUN_DEV(SITECOMEU, RT2870_2), 291209918Sthompsa RUN_DEV(SITECOMEU, RT2870_3), 292209918Sthompsa RUN_DEV(SITECOMEU, RT2870_4), 293209918Sthompsa RUN_DEV(SITECOMEU, RT3070), 294209918Sthompsa RUN_DEV(SITECOMEU, RT3070_2), 295209918Sthompsa RUN_DEV(SITECOMEU, RT3070_3), 296209918Sthompsa RUN_DEV(SITECOMEU, RT3070_4), 297209918Sthompsa RUN_DEV(SITECOMEU, RT3071), 298209918Sthompsa RUN_DEV(SITECOMEU, RT3072_1), 299209918Sthompsa RUN_DEV(SITECOMEU, RT3072_2), 300209918Sthompsa RUN_DEV(SITECOMEU, RT3072_3), 301209918Sthompsa RUN_DEV(SITECOMEU, RT3072_4), 302209918Sthompsa RUN_DEV(SITECOMEU, RT3072_5), 303209918Sthompsa RUN_DEV(SITECOMEU, RT3072_6), 304209918Sthompsa RUN_DEV(SITECOMEU, WL608), 305209918Sthompsa RUN_DEV(SPARKLAN, RT2870_1), 306209918Sthompsa RUN_DEV(SPARKLAN, RT3070), 307209918Sthompsa RUN_DEV(SWEEX2, LW153), 308209918Sthompsa RUN_DEV(SWEEX2, LW303), 309209918Sthompsa RUN_DEV(SWEEX2, LW313), 310209918Sthompsa RUN_DEV(TOSHIBA, RT3070), 311209918Sthompsa RUN_DEV(UMEDIA, RT2870_1), 312209918Sthompsa RUN_DEV(ZCOM, RT2870_1), 313209918Sthompsa RUN_DEV(ZCOM, RT2870_2), 314209918Sthompsa RUN_DEV(ZINWELL, RT2870_1), 315209918Sthompsa RUN_DEV(ZINWELL, RT2870_2), 316209918Sthompsa RUN_DEV(ZINWELL, RT3070), 317209918Sthompsa RUN_DEV(ZINWELL, RT3072_1), 318209918Sthompsa RUN_DEV(ZINWELL, RT3072_2), 319209918Sthompsa RUN_DEV(ZYXEL, RT2870_1), 320209918Sthompsa RUN_DEV(ZYXEL, RT2870_2), 321263985Shselasky RUN_DEV(ZYXEL, RT3070), 322262465Skevlo RUN_DEV_EJECT(ZYXEL, NWD2705), 323259812Skevlo RUN_DEV_EJECT(RALINK, RT_STOR), 324259812Skevlo#undef RUN_DEV_EJECT 325209918Sthompsa#undef RUN_DEV 326203134Sthompsa}; 327203134Sthompsa 328203134Sthompsastatic device_probe_t run_match; 329203134Sthompsastatic device_attach_t run_attach; 330203134Sthompsastatic device_detach_t run_detach; 331203134Sthompsa 332203134Sthompsastatic usb_callback_t run_bulk_rx_callback; 333203134Sthompsastatic usb_callback_t run_bulk_tx_callback0; 334203134Sthompsastatic usb_callback_t run_bulk_tx_callback1; 335203134Sthompsastatic usb_callback_t run_bulk_tx_callback2; 336203134Sthompsastatic usb_callback_t run_bulk_tx_callback3; 337203134Sthompsastatic usb_callback_t run_bulk_tx_callback4; 338203134Sthompsastatic usb_callback_t run_bulk_tx_callback5; 339203134Sthompsa 340259812Skevlostatic void run_autoinst(void *, struct usb_device *, 341259812Skevlo struct usb_attach_arg *); 342259812Skevlostatic int run_driver_loaded(struct module *, int, void *); 343203134Sthompsastatic void run_bulk_tx_callbackN(struct usb_xfer *xfer, 344257429Shselasky usb_error_t error, u_int index); 345203134Sthompsastatic struct ieee80211vap *run_vap_create(struct ieee80211com *, 346228621Sbschmidt const char [IFNAMSIZ], int, enum ieee80211_opmode, int, 347228621Sbschmidt const uint8_t [IEEE80211_ADDR_LEN], 348228621Sbschmidt const uint8_t [IEEE80211_ADDR_LEN]); 349203134Sthompsastatic void run_vap_delete(struct ieee80211vap *); 350208019Sthompsastatic void run_cmdq_cb(void *, int); 351203134Sthompsastatic void run_setup_tx_list(struct run_softc *, 352203134Sthompsa struct run_endpoint_queue *); 353203134Sthompsastatic void run_unsetup_tx_list(struct run_softc *, 354203134Sthompsa struct run_endpoint_queue *); 355203134Sthompsastatic int run_load_microcode(struct run_softc *); 356203134Sthompsastatic int run_reset(struct run_softc *); 357203134Sthompsastatic usb_error_t run_do_request(struct run_softc *, 358203134Sthompsa struct usb_device_request *, void *); 359203134Sthompsastatic int run_read(struct run_softc *, uint16_t, uint32_t *); 360203134Sthompsastatic int run_read_region_1(struct run_softc *, uint16_t, uint8_t *, int); 361203134Sthompsastatic int run_write_2(struct run_softc *, uint16_t, uint16_t); 362203134Sthompsastatic int run_write(struct run_softc *, uint16_t, uint32_t); 363203134Sthompsastatic int run_write_region_1(struct run_softc *, uint16_t, 364203134Sthompsa const uint8_t *, int); 365203134Sthompsastatic int run_set_region_4(struct run_softc *, uint16_t, uint32_t, int); 366259544Skevlostatic int run_efuse_read(struct run_softc *, uint16_t, uint16_t *, int); 367203134Sthompsastatic int run_efuse_read_2(struct run_softc *, uint16_t, uint16_t *); 368203134Sthompsastatic int run_eeprom_read_2(struct run_softc *, uint16_t, uint16_t *); 369258733Skevlostatic int run_rt2870_rf_write(struct run_softc *, uint32_t); 370203134Sthompsastatic int run_rt3070_rf_read(struct run_softc *, uint8_t, uint8_t *); 371203134Sthompsastatic int run_rt3070_rf_write(struct run_softc *, uint8_t, uint8_t); 372203134Sthompsastatic int run_bbp_read(struct run_softc *, uint8_t, uint8_t *); 373203134Sthompsastatic int run_bbp_write(struct run_softc *, uint8_t, uint8_t); 374203134Sthompsastatic int run_mcu_cmd(struct run_softc *, uint8_t, uint16_t); 375257955Skevlostatic const char *run_get_rf(uint16_t); 376260219Skevlostatic void run_rt3593_get_txpower(struct run_softc *); 377260219Skevlostatic void run_get_txpower(struct run_softc *); 378203134Sthompsastatic int run_read_eeprom(struct run_softc *); 379203134Sthompsastatic struct ieee80211_node *run_node_alloc(struct ieee80211vap *, 380203134Sthompsa const uint8_t mac[IEEE80211_ADDR_LEN]); 381203134Sthompsastatic int run_media_change(struct ifnet *); 382203134Sthompsastatic int run_newstate(struct ieee80211vap *, enum ieee80211_state, int); 383203134Sthompsastatic int run_wme_update(struct ieee80211com *); 384208019Sthompsastatic void run_key_set_cb(void *); 385288635Sadrianstatic int run_key_set(struct ieee80211vap *, struct ieee80211_key *); 386208019Sthompsastatic void run_key_delete_cb(void *); 387208019Sthompsastatic int run_key_delete(struct ieee80211vap *, struct ieee80211_key *); 388206358Srpaulostatic void run_ratectl_to(void *); 389206358Srpaulostatic void run_ratectl_cb(void *, int); 390208019Sthompsastatic void run_drain_fifo(void *); 391203134Sthompsastatic void run_iter_func(void *, struct ieee80211_node *); 392208019Sthompsastatic void run_newassoc_cb(void *); 393203134Sthompsastatic void run_newassoc(struct ieee80211_node *, int); 394288603Sadrianstatic void run_recv_mgmt(struct ieee80211_node *, struct mbuf *, int, 395288603Sadrian const struct ieee80211_rx_stats *, int, int); 396203134Sthompsastatic void run_rx_frame(struct run_softc *, struct mbuf *, uint32_t); 397203134Sthompsastatic void run_tx_free(struct run_endpoint_queue *pq, 398203134Sthompsa struct run_tx_data *, int); 399208019Sthompsastatic void run_set_tx_desc(struct run_softc *, struct run_tx_data *); 400203134Sthompsastatic int run_tx(struct run_softc *, struct mbuf *, 401203134Sthompsa struct ieee80211_node *); 402203134Sthompsastatic int run_tx_mgt(struct run_softc *, struct mbuf *, 403203134Sthompsa struct ieee80211_node *); 404203134Sthompsastatic int run_sendprot(struct run_softc *, const struct mbuf *, 405203134Sthompsa struct ieee80211_node *, int, int); 406203134Sthompsastatic int run_tx_param(struct run_softc *, struct mbuf *, 407203134Sthompsa struct ieee80211_node *, 408203134Sthompsa const struct ieee80211_bpf_params *); 409203134Sthompsastatic int run_raw_xmit(struct ieee80211_node *, struct mbuf *, 410203134Sthompsa const struct ieee80211_bpf_params *); 411287197Sglebiusstatic int run_transmit(struct ieee80211com *, struct mbuf *); 412287197Sglebiusstatic void run_start(struct run_softc *); 413287197Sglebiusstatic void run_parent(struct ieee80211com *); 414259544Skevlostatic void run_iq_calib(struct run_softc *, u_int); 415205042Sthompsastatic void run_set_agc(struct run_softc *, uint8_t); 416203134Sthompsastatic void run_select_chan_group(struct run_softc *, int); 417203134Sthompsastatic void run_set_rx_antenna(struct run_softc *, int); 418203134Sthompsastatic void run_rt2870_set_chan(struct run_softc *, u_int); 419203134Sthompsastatic void run_rt3070_set_chan(struct run_softc *, u_int); 420205042Sthompsastatic void run_rt3572_set_chan(struct run_softc *, u_int); 421260219Skevlostatic void run_rt3593_set_chan(struct run_softc *, u_int); 422257955Skevlostatic void run_rt5390_set_chan(struct run_softc *, u_int); 423259032Skevlostatic void run_rt5592_set_chan(struct run_softc *, u_int); 424203134Sthompsastatic int run_set_chan(struct run_softc *, struct ieee80211_channel *); 425203134Sthompsastatic void run_set_channel(struct ieee80211com *); 426300748Savosstatic void run_getradiocaps(struct ieee80211com *, int, int *, 427300748Savos struct ieee80211_channel[]); 428203134Sthompsastatic void run_scan_start(struct ieee80211com *); 429203134Sthompsastatic void run_scan_end(struct ieee80211com *); 430203134Sthompsastatic void run_update_beacon(struct ieee80211vap *, int); 431208019Sthompsastatic void run_update_beacon_cb(void *); 432203134Sthompsastatic void run_updateprot(struct ieee80211com *); 433218492Sbschmidtstatic void run_updateprot_cb(void *); 434208019Sthompsastatic void run_usb_timeout_cb(void *); 435203134Sthompsastatic void run_reset_livelock(struct run_softc *); 436203134Sthompsastatic void run_enable_tsf_sync(struct run_softc *); 437287555Skevlostatic void run_enable_tsf(struct run_softc *); 438287554Skevlostatic void run_get_tsf(struct run_softc *, uint64_t *); 439203134Sthompsastatic void run_enable_mrr(struct run_softc *); 440203134Sthompsastatic void run_set_txpreamble(struct run_softc *); 441203134Sthompsastatic void run_set_basicrates(struct run_softc *); 442203134Sthompsastatic void run_set_leds(struct run_softc *, uint16_t); 443203134Sthompsastatic void run_set_bssid(struct run_softc *, const uint8_t *); 444203134Sthompsastatic void run_set_macaddr(struct run_softc *, const uint8_t *); 445283540Sglebiusstatic void run_updateslot(struct ieee80211com *); 446218492Sbschmidtstatic void run_updateslot_cb(void *); 447283540Sglebiusstatic void run_update_mcast(struct ieee80211com *); 448203134Sthompsastatic int8_t run_rssi2dbm(struct run_softc *, uint8_t, uint8_t); 449283540Sglebiusstatic void run_update_promisc_locked(struct run_softc *); 450283540Sglebiusstatic void run_update_promisc(struct ieee80211com *); 451257955Skevlostatic void run_rt5390_bbp_init(struct run_softc *); 452203134Sthompsastatic int run_bbp_init(struct run_softc *); 453203134Sthompsastatic int run_rt3070_rf_init(struct run_softc *); 454260219Skevlostatic void run_rt3593_rf_init(struct run_softc *); 455257955Skevlostatic void run_rt5390_rf_init(struct run_softc *); 456203134Sthompsastatic int run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t, 457203134Sthompsa uint8_t *); 458205042Sthompsastatic void run_rt3070_rf_setup(struct run_softc *); 459260219Skevlostatic void run_rt3593_rf_setup(struct run_softc *); 460260219Skevlostatic void run_rt5390_rf_setup(struct run_softc *); 461203134Sthompsastatic int run_txrx_enable(struct run_softc *); 462257955Skevlostatic void run_adjust_freq_offset(struct run_softc *); 463203134Sthompsastatic void run_init_locked(struct run_softc *); 464203134Sthompsastatic void run_stop(void *); 465257429Shselaskystatic void run_delay(struct run_softc *, u_int); 466203134Sthompsa 467259812Skevlostatic eventhandler_tag run_etag; 468259812Skevlo 469259544Skevlostatic const struct rt2860_rate { 470259544Skevlo uint8_t rate; 471259544Skevlo uint8_t mcs; 472259544Skevlo enum ieee80211_phytype phy; 473259544Skevlo uint8_t ctl_ridx; 474259544Skevlo uint16_t sp_ack_dur; 475259544Skevlo uint16_t lp_ack_dur; 476259544Skevlo} rt2860_rates[] = { 477259544Skevlo { 2, 0, IEEE80211_T_DS, 0, 314, 314 }, 478259544Skevlo { 4, 1, IEEE80211_T_DS, 1, 258, 162 }, 479259544Skevlo { 11, 2, IEEE80211_T_DS, 2, 223, 127 }, 480259544Skevlo { 22, 3, IEEE80211_T_DS, 3, 213, 117 }, 481259544Skevlo { 12, 0, IEEE80211_T_OFDM, 4, 60, 60 }, 482259544Skevlo { 18, 1, IEEE80211_T_OFDM, 4, 52, 52 }, 483259544Skevlo { 24, 2, IEEE80211_T_OFDM, 6, 48, 48 }, 484259544Skevlo { 36, 3, IEEE80211_T_OFDM, 6, 44, 44 }, 485259544Skevlo { 48, 4, IEEE80211_T_OFDM, 8, 44, 44 }, 486259544Skevlo { 72, 5, IEEE80211_T_OFDM, 8, 40, 40 }, 487259544Skevlo { 96, 6, IEEE80211_T_OFDM, 8, 40, 40 }, 488259544Skevlo { 108, 7, IEEE80211_T_OFDM, 8, 40, 40 } 489259544Skevlo}; 490259544Skevlo 491203134Sthompsastatic const struct { 492208019Sthompsa uint16_t reg; 493203134Sthompsa uint32_t val; 494203134Sthompsa} rt2870_def_mac[] = { 495203134Sthompsa RT2870_DEF_MAC 496203134Sthompsa}; 497203134Sthompsa 498203134Sthompsastatic const struct { 499203134Sthompsa uint8_t reg; 500203134Sthompsa uint8_t val; 501203134Sthompsa} rt2860_def_bbp[] = { 502203134Sthompsa RT2860_DEF_BBP 503257955Skevlo},rt5390_def_bbp[] = { 504257955Skevlo RT5390_DEF_BBP 505259032Skevlo},rt5592_def_bbp[] = { 506259032Skevlo RT5592_DEF_BBP 507203134Sthompsa}; 508203134Sthompsa 509259032Skevlo/* 510259032Skevlo * Default values for BBP register R196 for RT5592. 511259032Skevlo */ 512259032Skevlostatic const uint8_t rt5592_bbp_r196[] = { 513259032Skevlo 0xe0, 0x1f, 0x38, 0x32, 0x08, 0x28, 0x19, 0x0a, 0xff, 0x00, 514259032Skevlo 0x16, 0x10, 0x10, 0x0b, 0x36, 0x2c, 0x26, 0x24, 0x42, 0x36, 515259032Skevlo 0x30, 0x2d, 0x4c, 0x46, 0x3d, 0x40, 0x3e, 0x42, 0x3d, 0x40, 516259032Skevlo 0x3c, 0x34, 0x2c, 0x2f, 0x3c, 0x35, 0x2e, 0x2a, 0x49, 0x41, 517259032Skevlo 0x36, 0x31, 0x30, 0x30, 0x0e, 0x0d, 0x28, 0x21, 0x1c, 0x16, 518259032Skevlo 0x50, 0x4a, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 519259032Skevlo 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 520259032Skevlo 0x00, 0x00, 0x7d, 0x14, 0x32, 0x2c, 0x36, 0x4c, 0x43, 0x2c, 521259032Skevlo 0x2e, 0x36, 0x30, 0x6e 522259032Skevlo}; 523259032Skevlo 524203134Sthompsastatic const struct rfprog { 525203134Sthompsa uint8_t chan; 526203134Sthompsa uint32_t r1, r2, r3, r4; 527203134Sthompsa} rt2860_rf2850[] = { 528203134Sthompsa RT2860_RF2850 529203134Sthompsa}; 530203134Sthompsa 531203134Sthompsastruct { 532203134Sthompsa uint8_t n, r, k; 533205042Sthompsa} rt3070_freqs[] = { 534205042Sthompsa RT3070_RF3052 535203134Sthompsa}; 536203134Sthompsa 537259032Skevlostatic const struct rt5592_freqs { 538259032Skevlo uint16_t n; 539259032Skevlo uint8_t k, m, r; 540259032Skevlo} rt5592_freqs_20mhz[] = { 541259032Skevlo RT5592_RF5592_20MHZ 542259032Skevlo},rt5592_freqs_40mhz[] = { 543259032Skevlo RT5592_RF5592_40MHZ 544259032Skevlo}; 545259032Skevlo 546203134Sthompsastatic const struct { 547203134Sthompsa uint8_t reg; 548203134Sthompsa uint8_t val; 549203134Sthompsa} rt3070_def_rf[] = { 550203134Sthompsa RT3070_DEF_RF 551205042Sthompsa},rt3572_def_rf[] = { 552205042Sthompsa RT3572_DEF_RF 553260219Skevlo},rt3593_def_rf[] = { 554260219Skevlo RT3593_DEF_RF 555257955Skevlo},rt5390_def_rf[] = { 556257955Skevlo RT5390_DEF_RF 557257955Skevlo},rt5392_def_rf[] = { 558257955Skevlo RT5392_DEF_RF 559259032Skevlo},rt5592_def_rf[] = { 560259032Skevlo RT5592_DEF_RF 561259032Skevlo},rt5592_2ghz_def_rf[] = { 562259032Skevlo RT5592_2GHZ_DEF_RF 563259032Skevlo},rt5592_5ghz_def_rf[] = { 564259032Skevlo RT5592_5GHZ_DEF_RF 565203134Sthompsa}; 566203134Sthompsa 567259032Skevlostatic const struct { 568259032Skevlo u_int firstchan; 569259032Skevlo u_int lastchan; 570259032Skevlo uint8_t reg; 571259032Skevlo uint8_t val; 572259032Skevlo} rt5592_chan_5ghz[] = { 573259032Skevlo RT5592_CHAN_5GHZ 574259032Skevlo}; 575259032Skevlo 576203134Sthompsastatic const struct usb_config run_config[RUN_N_XFER] = { 577203134Sthompsa [RUN_BULK_TX_BE] = { 578203134Sthompsa .type = UE_BULK, 579203134Sthompsa .endpoint = UE_ADDR_ANY, 580203134Sthompsa .ep_index = 0, 581203134Sthompsa .direction = UE_DIR_OUT, 582203134Sthompsa .bufsize = RUN_MAX_TXSZ, 583203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 584203134Sthompsa .callback = run_bulk_tx_callback0, 585203134Sthompsa .timeout = 5000, /* ms */ 586203134Sthompsa }, 587203134Sthompsa [RUN_BULK_TX_BK] = { 588203134Sthompsa .type = UE_BULK, 589203134Sthompsa .endpoint = UE_ADDR_ANY, 590203134Sthompsa .direction = UE_DIR_OUT, 591203134Sthompsa .ep_index = 1, 592203134Sthompsa .bufsize = RUN_MAX_TXSZ, 593203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 594203134Sthompsa .callback = run_bulk_tx_callback1, 595203134Sthompsa .timeout = 5000, /* ms */ 596203134Sthompsa }, 597203134Sthompsa [RUN_BULK_TX_VI] = { 598203134Sthompsa .type = UE_BULK, 599203134Sthompsa .endpoint = UE_ADDR_ANY, 600203134Sthompsa .direction = UE_DIR_OUT, 601203134Sthompsa .ep_index = 2, 602203134Sthompsa .bufsize = RUN_MAX_TXSZ, 603203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 604203134Sthompsa .callback = run_bulk_tx_callback2, 605203134Sthompsa .timeout = 5000, /* ms */ 606203134Sthompsa }, 607203134Sthompsa [RUN_BULK_TX_VO] = { 608203134Sthompsa .type = UE_BULK, 609203134Sthompsa .endpoint = UE_ADDR_ANY, 610203134Sthompsa .direction = UE_DIR_OUT, 611203134Sthompsa .ep_index = 3, 612203134Sthompsa .bufsize = RUN_MAX_TXSZ, 613203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 614203134Sthompsa .callback = run_bulk_tx_callback3, 615203134Sthompsa .timeout = 5000, /* ms */ 616203134Sthompsa }, 617203134Sthompsa [RUN_BULK_TX_HCCA] = { 618203134Sthompsa .type = UE_BULK, 619203134Sthompsa .endpoint = UE_ADDR_ANY, 620203134Sthompsa .direction = UE_DIR_OUT, 621203134Sthompsa .ep_index = 4, 622203134Sthompsa .bufsize = RUN_MAX_TXSZ, 623203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 624203134Sthompsa .callback = run_bulk_tx_callback4, 625203134Sthompsa .timeout = 5000, /* ms */ 626203134Sthompsa }, 627203134Sthompsa [RUN_BULK_TX_PRIO] = { 628203134Sthompsa .type = UE_BULK, 629203134Sthompsa .endpoint = UE_ADDR_ANY, 630203134Sthompsa .direction = UE_DIR_OUT, 631203134Sthompsa .ep_index = 5, 632203134Sthompsa .bufsize = RUN_MAX_TXSZ, 633203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 634203134Sthompsa .callback = run_bulk_tx_callback5, 635203134Sthompsa .timeout = 5000, /* ms */ 636203134Sthompsa }, 637203134Sthompsa [RUN_BULK_RX] = { 638203134Sthompsa .type = UE_BULK, 639203134Sthompsa .endpoint = UE_ADDR_ANY, 640203134Sthompsa .direction = UE_DIR_IN, 641203134Sthompsa .bufsize = RUN_MAX_RXSZ, 642203134Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 643203134Sthompsa .callback = run_bulk_rx_callback, 644203134Sthompsa } 645203134Sthompsa}; 646203134Sthompsa 647259812Skevlostatic void 648259812Skevlorun_autoinst(void *arg, struct usb_device *udev, 649259812Skevlo struct usb_attach_arg *uaa) 650259812Skevlo{ 651259812Skevlo struct usb_interface *iface; 652259812Skevlo struct usb_interface_descriptor *id; 653259812Skevlo 654259812Skevlo if (uaa->dev_state != UAA_DEV_READY) 655259812Skevlo return; 656259812Skevlo 657259812Skevlo iface = usbd_get_iface(udev, 0); 658259812Skevlo if (iface == NULL) 659259812Skevlo return; 660259812Skevlo id = iface->idesc; 661259812Skevlo if (id == NULL || id->bInterfaceClass != UICLASS_MASS) 662259812Skevlo return; 663259812Skevlo if (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa)) 664259812Skevlo return; 665259812Skevlo 666259812Skevlo if (usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT) == 0) 667259812Skevlo uaa->dev_state = UAA_DEV_EJECTING; 668259812Skevlo} 669259812Skevlo 670220235Skevlostatic int 671259812Skevlorun_driver_loaded(struct module *mod, int what, void *arg) 672259812Skevlo{ 673259812Skevlo switch (what) { 674259812Skevlo case MOD_LOAD: 675259812Skevlo run_etag = EVENTHANDLER_REGISTER(usb_dev_configured, 676259812Skevlo run_autoinst, NULL, EVENTHANDLER_PRI_ANY); 677259812Skevlo break; 678259812Skevlo case MOD_UNLOAD: 679259812Skevlo EVENTHANDLER_DEREGISTER(usb_dev_configured, run_etag); 680259812Skevlo break; 681259812Skevlo default: 682259812Skevlo return (EOPNOTSUPP); 683259812Skevlo } 684259812Skevlo return (0); 685259812Skevlo} 686259812Skevlo 687259812Skevlostatic int 688203134Sthompsarun_match(device_t self) 689203134Sthompsa{ 690203134Sthompsa struct usb_attach_arg *uaa = device_get_ivars(self); 691203134Sthompsa 692203134Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 693203134Sthompsa return (ENXIO); 694203134Sthompsa if (uaa->info.bConfigIndex != 0) 695203134Sthompsa return (ENXIO); 696203134Sthompsa if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX) 697203134Sthompsa return (ENXIO); 698203134Sthompsa 699203134Sthompsa return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa)); 700203134Sthompsa} 701203134Sthompsa 702203134Sthompsastatic int 703203134Sthompsarun_attach(device_t self) 704203134Sthompsa{ 705203134Sthompsa struct run_softc *sc = device_get_softc(self); 706203134Sthompsa struct usb_attach_arg *uaa = device_get_ivars(self); 707287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 708205042Sthompsa uint32_t ver; 709293339Savos uint8_t iface_index; 710258082Skevlo int ntries, error; 711203134Sthompsa 712203134Sthompsa device_set_usb_desc(self); 713203134Sthompsa sc->sc_udev = uaa->device; 714203134Sthompsa sc->sc_dev = self; 715262465Skevlo if (USB_GET_DRIVER_INFO(uaa) != RUN_EJECT) 716262465Skevlo sc->sc_flags |= RUN_FLAG_FWLOAD_NEEDED; 717203134Sthompsa 718203134Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), 719203134Sthompsa MTX_NETWORK_LOCK, MTX_DEF); 720287197Sglebius mbufq_init(&sc->sc_snd, ifqmaxlen); 721203134Sthompsa 722203134Sthompsa iface_index = RT2860_IFACE_INDEX; 723208019Sthompsa 724203134Sthompsa error = usbd_transfer_setup(uaa->device, &iface_index, 725203134Sthompsa sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx); 726203134Sthompsa if (error) { 727205042Sthompsa device_printf(self, "could not allocate USB transfers, " 728203134Sthompsa "err=%s\n", usbd_errstr(error)); 729203134Sthompsa goto detach; 730203134Sthompsa } 731203134Sthompsa 732203134Sthompsa RUN_LOCK(sc); 733203134Sthompsa 734203134Sthompsa /* wait for the chip to settle */ 735203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 736209917Sthompsa if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0) { 737203134Sthompsa RUN_UNLOCK(sc); 738203134Sthompsa goto detach; 739203134Sthompsa } 740205042Sthompsa if (ver != 0 && ver != 0xffffffff) 741203134Sthompsa break; 742203134Sthompsa run_delay(sc, 10); 743203134Sthompsa } 744203134Sthompsa if (ntries == 100) { 745203138Sthompsa device_printf(sc->sc_dev, 746203138Sthompsa "timeout waiting for NIC to initialize\n"); 747203134Sthompsa RUN_UNLOCK(sc); 748203134Sthompsa goto detach; 749203134Sthompsa } 750205042Sthompsa sc->mac_ver = ver >> 16; 751205042Sthompsa sc->mac_rev = ver & 0xffff; 752203134Sthompsa 753203134Sthompsa /* retrieve RF rev. no and various other things from EEPROM */ 754203134Sthompsa run_read_eeprom(sc); 755203134Sthompsa 756203138Sthompsa device_printf(sc->sc_dev, 757203138Sthompsa "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n", 758205042Sthompsa sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev), 759287197Sglebius sc->ntxchains, sc->nrxchains, ether_sprintf(ic->ic_macaddr)); 760203134Sthompsa 761203134Sthompsa RUN_UNLOCK(sc); 762203134Sthompsa 763283537Sglebius ic->ic_softc = sc; 764283527Sglebius ic->ic_name = device_get_nameunit(self); 765203134Sthompsa ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 766203134Sthompsa ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 767208019Sthompsa 768203134Sthompsa /* set device capabilities */ 769203134Sthompsa ic->ic_caps = 770203134Sthompsa IEEE80211_C_STA | /* station mode supported */ 771203134Sthompsa IEEE80211_C_MONITOR | /* monitor mode supported */ 772203134Sthompsa IEEE80211_C_IBSS | 773203134Sthompsa IEEE80211_C_HOSTAP | 774208019Sthompsa IEEE80211_C_WDS | /* 4-address traffic works */ 775208019Sthompsa IEEE80211_C_MBSS | 776203134Sthompsa IEEE80211_C_SHPREAMBLE | /* short preamble supported */ 777203134Sthompsa IEEE80211_C_SHSLOT | /* short slot time supported */ 778203134Sthompsa IEEE80211_C_WME | /* WME */ 779214894Sbschmidt IEEE80211_C_WPA; /* WPA1|WPA2(RSN) */ 780203134Sthompsa 781203134Sthompsa ic->ic_cryptocaps = 782203134Sthompsa IEEE80211_CRYPTO_WEP | 783203134Sthompsa IEEE80211_CRYPTO_AES_CCM | 784203134Sthompsa IEEE80211_CRYPTO_TKIPMIC | 785203134Sthompsa IEEE80211_CRYPTO_TKIP; 786203134Sthompsa 787203134Sthompsa ic->ic_flags |= IEEE80211_F_DATAPAD; 788203134Sthompsa ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; 789203134Sthompsa 790300748Savos run_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans, 791300748Savos ic->ic_channels); 792203134Sthompsa 793287197Sglebius ieee80211_ifattach(ic); 794203134Sthompsa 795203134Sthompsa ic->ic_scan_start = run_scan_start; 796203134Sthompsa ic->ic_scan_end = run_scan_end; 797203134Sthompsa ic->ic_set_channel = run_set_channel; 798300748Savos ic->ic_getradiocaps = run_getradiocaps; 799203134Sthompsa ic->ic_node_alloc = run_node_alloc; 800203134Sthompsa ic->ic_newassoc = run_newassoc; 801218492Sbschmidt ic->ic_updateslot = run_updateslot; 802208019Sthompsa ic->ic_update_mcast = run_update_mcast; 803203134Sthompsa ic->ic_wme.wme_update = run_wme_update; 804203134Sthompsa ic->ic_raw_xmit = run_raw_xmit; 805203134Sthompsa ic->ic_update_promisc = run_update_promisc; 806203134Sthompsa ic->ic_vap_create = run_vap_create; 807203134Sthompsa ic->ic_vap_delete = run_vap_delete; 808287197Sglebius ic->ic_transmit = run_transmit; 809287197Sglebius ic->ic_parent = run_parent; 810203134Sthompsa 811203134Sthompsa ieee80211_radiotap_attach(ic, 812203134Sthompsa &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), 813203134Sthompsa RUN_TX_RADIOTAP_PRESENT, 814203134Sthompsa &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 815203134Sthompsa RUN_RX_RADIOTAP_PRESENT); 816203134Sthompsa 817208019Sthompsa TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc); 818208019Sthompsa TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc); 819257712Shselasky usb_callout_init_mtx(&sc->ratectl_ch, &sc->sc_mtx, 0); 820208019Sthompsa 821203134Sthompsa if (bootverbose) 822203134Sthompsa ieee80211_announce(ic); 823203134Sthompsa 824209917Sthompsa return (0); 825203134Sthompsa 826203134Sthompsadetach: 827203134Sthompsa run_detach(self); 828209917Sthompsa return (ENXIO); 829203134Sthompsa} 830203134Sthompsa 831288649Sadrianstatic void 832288649Sadrianrun_drain_mbufq(struct run_softc *sc) 833288649Sadrian{ 834288649Sadrian struct mbuf *m; 835288649Sadrian struct ieee80211_node *ni; 836288649Sadrian 837288649Sadrian RUN_LOCK_ASSERT(sc, MA_OWNED); 838288649Sadrian while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { 839288649Sadrian ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 840288649Sadrian m->m_pkthdr.rcvif = NULL; 841288649Sadrian ieee80211_free_node(ni); 842288649Sadrian m_freem(m); 843288649Sadrian } 844288649Sadrian} 845288649Sadrian 846203134Sthompsastatic int 847203134Sthompsarun_detach(device_t self) 848203134Sthompsa{ 849203134Sthompsa struct run_softc *sc = device_get_softc(self); 850287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 851203134Sthompsa int i; 852203134Sthompsa 853246614Shselasky RUN_LOCK(sc); 854246614Shselasky sc->sc_detached = 1; 855246614Shselasky RUN_UNLOCK(sc); 856246614Shselasky 857203134Sthompsa /* stop all USB transfers */ 858203134Sthompsa usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER); 859203134Sthompsa 860203134Sthompsa RUN_LOCK(sc); 861209144Sthompsa sc->ratectl_run = RUN_RATECTL_OFF; 862209144Sthompsa sc->cmdq_run = sc->cmdq_key_set = RUN_CMDQ_ABORT; 863209144Sthompsa 864203134Sthompsa /* free TX list, if any */ 865203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 866203134Sthompsa run_unsetup_tx_list(sc, &sc->sc_epq[i]); 867288649Sadrian 868288649Sadrian /* Free TX queue */ 869288649Sadrian run_drain_mbufq(sc); 870203134Sthompsa RUN_UNLOCK(sc); 871203134Sthompsa 872287197Sglebius if (sc->sc_ic.ic_softc == sc) { 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 } 879203134Sthompsa 880203134Sthompsa mtx_destroy(&sc->sc_mtx); 881203134Sthompsa 882203134Sthompsa return (0); 883203134Sthompsa} 884203134Sthompsa 885203134Sthompsastatic struct ieee80211vap * 886228621Sbschmidtrun_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, 887228621Sbschmidt enum ieee80211_opmode opmode, int flags, 888203134Sthompsa const uint8_t bssid[IEEE80211_ADDR_LEN], 889203134Sthompsa const uint8_t mac[IEEE80211_ADDR_LEN]) 890203134Sthompsa{ 891286950Sadrian struct run_softc *sc = ic->ic_softc; 892203134Sthompsa struct run_vap *rvp; 893203134Sthompsa struct ieee80211vap *vap; 894208019Sthompsa int i; 895203134Sthompsa 896209917Sthompsa if (sc->rvp_cnt >= RUN_VAP_MAX) { 897287197Sglebius device_printf(sc->sc_dev, "number of VAPs maxed out\n"); 898209917Sthompsa return (NULL); 899208019Sthompsa } 900208019Sthompsa 901208019Sthompsa switch (opmode) { 902208019Sthompsa case IEEE80211_M_STA: 903208019Sthompsa /* enable s/w bmiss handling for sta mode */ 904208019Sthompsa flags |= IEEE80211_CLONE_NOBEACONS; 905208019Sthompsa /* fall though */ 906208019Sthompsa case IEEE80211_M_IBSS: 907208019Sthompsa case IEEE80211_M_MONITOR: 908208019Sthompsa case IEEE80211_M_HOSTAP: 909208019Sthompsa case IEEE80211_M_MBSS: 910208019Sthompsa /* other than WDS vaps, only one at a time */ 911208019Sthompsa if (!TAILQ_EMPTY(&ic->ic_vaps)) 912209917Sthompsa return (NULL); 913208019Sthompsa break; 914208019Sthompsa case IEEE80211_M_WDS: 915208019Sthompsa TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next){ 916208019Sthompsa if(vap->iv_opmode != IEEE80211_M_HOSTAP) 917208019Sthompsa continue; 918208019Sthompsa /* WDS vap's always share the local mac address. */ 919208019Sthompsa flags &= ~IEEE80211_CLONE_BSSID; 920208019Sthompsa break; 921208019Sthompsa } 922209917Sthompsa if (vap == NULL) { 923287197Sglebius device_printf(sc->sc_dev, 924287197Sglebius "wds only supported in ap mode\n"); 925209917Sthompsa return (NULL); 926208019Sthompsa } 927208019Sthompsa break; 928208019Sthompsa default: 929287197Sglebius device_printf(sc->sc_dev, "unknown opmode %d\n", opmode); 930209917Sthompsa return (NULL); 931208019Sthompsa } 932208019Sthompsa 933287197Sglebius rvp = malloc(sizeof(struct run_vap), M_80211_VAP, M_WAITOK | M_ZERO); 934203134Sthompsa vap = &rvp->vap; 935203134Sthompsa 936287197Sglebius if (ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, 937287197Sglebius bssid) != 0) { 938257743Shselasky /* out of memory */ 939257743Shselasky free(rvp, M_80211_VAP); 940257743Shselasky return (NULL); 941257743Shselasky } 942257743Shselasky 943203134Sthompsa vap->iv_update_beacon = run_update_beacon; 944208019Sthompsa vap->iv_max_aid = RT2870_WCID_MAX; 945208019Sthompsa /* 946208019Sthompsa * To delete the right key from h/w, we need wcid. 947208019Sthompsa * Luckily, there is unused space in ieee80211_key{}, wk_pad, 948208019Sthompsa * and matching wcid will be written into there. So, cast 949208019Sthompsa * some spells to remove 'const' from ieee80211_key{} 950208019Sthompsa */ 951208019Sthompsa vap->iv_key_delete = (void *)run_key_delete; 952208019Sthompsa vap->iv_key_set = (void *)run_key_set; 953203134Sthompsa 954203134Sthompsa /* override state transition machine */ 955203134Sthompsa rvp->newstate = vap->iv_newstate; 956203134Sthompsa vap->iv_newstate = run_newstate; 957288603Sadrian if (opmode == IEEE80211_M_IBSS) { 958288603Sadrian rvp->recv_mgmt = vap->iv_recv_mgmt; 959288603Sadrian vap->iv_recv_mgmt = run_recv_mgmt; 960288603Sadrian } 961203134Sthompsa 962206358Srpaulo ieee80211_ratectl_init(vap); 963206358Srpaulo ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */); 964203134Sthompsa 965203134Sthompsa /* complete setup */ 966287197Sglebius ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status, 967287197Sglebius mac); 968208019Sthompsa 969208019Sthompsa /* make sure id is always unique */ 970209917Sthompsa for (i = 0; i < RUN_VAP_MAX; i++) { 971208019Sthompsa if((sc->rvp_bmap & 1 << i) == 0){ 972208019Sthompsa sc->rvp_bmap |= 1 << i; 973208019Sthompsa rvp->rvp_id = i; 974208019Sthompsa break; 975208019Sthompsa } 976208019Sthompsa } 977209917Sthompsa if (sc->rvp_cnt++ == 0) 978208019Sthompsa ic->ic_opmode = opmode; 979208019Sthompsa 980209917Sthompsa if (opmode == IEEE80211_M_HOSTAP) 981209144Sthompsa sc->cmdq_run = RUN_CMDQ_GO; 982209144Sthompsa 983208019Sthompsa DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n", 984208019Sthompsa rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt); 985208019Sthompsa 986209917Sthompsa return (vap); 987203134Sthompsa} 988203134Sthompsa 989203134Sthompsastatic void 990203134Sthompsarun_vap_delete(struct ieee80211vap *vap) 991203134Sthompsa{ 992203134Sthompsa struct run_vap *rvp = RUN_VAP(vap); 993203134Sthompsa struct ieee80211com *ic; 994203134Sthompsa struct run_softc *sc; 995208019Sthompsa uint8_t rvp_id; 996203134Sthompsa 997209917Sthompsa if (vap == NULL) 998203134Sthompsa return; 999203134Sthompsa 1000203134Sthompsa ic = vap->iv_ic; 1001286950Sadrian sc = ic->ic_softc; 1002203134Sthompsa 1003205042Sthompsa RUN_LOCK(sc); 1004208019Sthompsa 1005218492Sbschmidt m_freem(rvp->beacon_mbuf); 1006218492Sbschmidt rvp->beacon_mbuf = NULL; 1007218492Sbschmidt 1008208019Sthompsa rvp_id = rvp->rvp_id; 1009208019Sthompsa sc->ratectl_run &= ~(1 << rvp_id); 1010208019Sthompsa sc->rvp_bmap &= ~(1 << rvp_id); 1011208019Sthompsa run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128); 1012208019Sthompsa run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512); 1013208019Sthompsa --sc->rvp_cnt; 1014208019Sthompsa 1015208019Sthompsa DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n", 1016208019Sthompsa vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt); 1017208019Sthompsa 1018205042Sthompsa RUN_UNLOCK(sc); 1019203134Sthompsa 1020206358Srpaulo ieee80211_ratectl_deinit(vap); 1021203134Sthompsa ieee80211_vap_detach(vap); 1022203134Sthompsa free(rvp, M_80211_VAP); 1023203134Sthompsa} 1024203134Sthompsa 1025208019Sthompsa/* 1026208019Sthompsa * There are numbers of functions need to be called in context thread. 1027208019Sthompsa * Rather than creating taskqueue event for each of those functions, 1028208019Sthompsa * here is all-for-one taskqueue callback function. This function 1029298932Spfg * guarantees deferred functions are executed in the same order they 1030208019Sthompsa * were enqueued. 1031208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[]. 1032208019Sthompsa */ 1033203134Sthompsastatic void 1034208019Sthompsarun_cmdq_cb(void *arg, int pending) 1035208019Sthompsa{ 1036208019Sthompsa struct run_softc *sc = arg; 1037208019Sthompsa uint8_t i; 1038208019Sthompsa 1039208019Sthompsa /* call cmdq[].func locked */ 1040208019Sthompsa RUN_LOCK(sc); 1041209917Sthompsa for (i = sc->cmdq_exec; sc->cmdq[i].func && pending; 1042209917Sthompsa i = sc->cmdq_exec, pending--) { 1043208019Sthompsa DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending); 1044209917Sthompsa if (sc->cmdq_run == RUN_CMDQ_GO) { 1045208019Sthompsa /* 1046208019Sthompsa * If arg0 is NULL, callback func needs more 1047208019Sthompsa * than one arg. So, pass ptr to cmdq struct. 1048208019Sthompsa */ 1049209917Sthompsa if (sc->cmdq[i].arg0) 1050208019Sthompsa sc->cmdq[i].func(sc->cmdq[i].arg0); 1051208019Sthompsa else 1052208019Sthompsa sc->cmdq[i].func(&sc->cmdq[i]); 1053208019Sthompsa } 1054208019Sthompsa sc->cmdq[i].arg0 = NULL; 1055208019Sthompsa sc->cmdq[i].func = NULL; 1056208019Sthompsa sc->cmdq_exec++; 1057208019Sthompsa sc->cmdq_exec &= RUN_CMDQ_MASQ; 1058208019Sthompsa } 1059208019Sthompsa RUN_UNLOCK(sc); 1060208019Sthompsa} 1061208019Sthompsa 1062208019Sthompsastatic void 1063203134Sthompsarun_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq) 1064203134Sthompsa{ 1065203134Sthompsa struct run_tx_data *data; 1066203134Sthompsa 1067203134Sthompsa memset(pq, 0, sizeof(*pq)); 1068203134Sthompsa 1069203134Sthompsa STAILQ_INIT(&pq->tx_qh); 1070203134Sthompsa STAILQ_INIT(&pq->tx_fh); 1071203134Sthompsa 1072203134Sthompsa for (data = &pq->tx_data[0]; 1073203134Sthompsa data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) { 1074203134Sthompsa data->sc = sc; 1075203134Sthompsa STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); 1076203134Sthompsa } 1077203134Sthompsa pq->tx_nfree = RUN_TX_RING_COUNT; 1078203134Sthompsa} 1079203134Sthompsa 1080203134Sthompsastatic void 1081203134Sthompsarun_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq) 1082203134Sthompsa{ 1083203134Sthompsa struct run_tx_data *data; 1084203134Sthompsa 1085203134Sthompsa /* make sure any subsequent use of the queues will fail */ 1086203134Sthompsa pq->tx_nfree = 0; 1087203134Sthompsa STAILQ_INIT(&pq->tx_fh); 1088203134Sthompsa STAILQ_INIT(&pq->tx_qh); 1089203134Sthompsa 1090203134Sthompsa /* free up all node references and mbufs */ 1091203134Sthompsa for (data = &pq->tx_data[0]; 1092209917Sthompsa data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) { 1093203134Sthompsa if (data->m != NULL) { 1094203134Sthompsa m_freem(data->m); 1095203134Sthompsa data->m = NULL; 1096203134Sthompsa } 1097203134Sthompsa if (data->ni != NULL) { 1098203134Sthompsa ieee80211_free_node(data->ni); 1099203134Sthompsa data->ni = NULL; 1100203134Sthompsa } 1101203134Sthompsa } 1102203134Sthompsa} 1103203134Sthompsa 1104220235Skevlostatic int 1105203134Sthompsarun_load_microcode(struct run_softc *sc) 1106203134Sthompsa{ 1107203134Sthompsa usb_device_request_t req; 1108203137Sthompsa const struct firmware *fw; 1109203134Sthompsa const u_char *base; 1110203134Sthompsa uint32_t tmp; 1111203134Sthompsa int ntries, error; 1112203134Sthompsa const uint64_t *temp; 1113203134Sthompsa uint64_t bytes; 1114203134Sthompsa 1115205042Sthompsa RUN_UNLOCK(sc); 1116203137Sthompsa fw = firmware_get("runfw"); 1117205042Sthompsa RUN_LOCK(sc); 1118209917Sthompsa if (fw == NULL) { 1119203138Sthompsa device_printf(sc->sc_dev, 1120203138Sthompsa "failed loadfirmware of file %s\n", "runfw"); 1121203134Sthompsa return ENOENT; 1122203134Sthompsa } 1123203134Sthompsa 1124203137Sthompsa if (fw->datasize != 8192) { 1125203138Sthompsa device_printf(sc->sc_dev, 1126203138Sthompsa "invalid firmware size (should be 8KB)\n"); 1127203137Sthompsa error = EINVAL; 1128203137Sthompsa goto fail; 1129203134Sthompsa } 1130203134Sthompsa 1131203134Sthompsa /* 1132203134Sthompsa * RT3071/RT3072 use a different firmware 1133203134Sthompsa * run-rt2870 (8KB) contains both, 1134203134Sthompsa * first half (4KB) is for rt2870, 1135203134Sthompsa * last half is for rt3071. 1136203134Sthompsa */ 1137203137Sthompsa base = fw->data; 1138205042Sthompsa if ((sc->mac_ver) != 0x2860 && 1139205042Sthompsa (sc->mac_ver) != 0x2872 && 1140209917Sthompsa (sc->mac_ver) != 0x3070) { 1141203134Sthompsa base += 4096; 1142205042Sthompsa } 1143203134Sthompsa 1144203134Sthompsa /* cheap sanity check */ 1145203137Sthompsa temp = fw->data; 1146203134Sthompsa bytes = *temp; 1147257712Shselasky if (bytes != be64toh(0xffffff0210280210ULL)) { 1148203138Sthompsa device_printf(sc->sc_dev, "firmware checksum failed\n"); 1149203137Sthompsa error = EINVAL; 1150203137Sthompsa goto fail; 1151203137Sthompsa } 1152203134Sthompsa 1153203134Sthompsa /* write microcode image */ 1154262465Skevlo if (sc->sc_flags & RUN_FLAG_FWLOAD_NEEDED) { 1155260219Skevlo run_write_region_1(sc, RT2870_FW_BASE, base, 4096); 1156260219Skevlo run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff); 1157260219Skevlo run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff); 1158260219Skevlo } 1159203134Sthompsa 1160203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1161203134Sthompsa req.bRequest = RT2870_RESET; 1162203134Sthompsa USETW(req.wValue, 8); 1163203134Sthompsa USETW(req.wIndex, 0); 1164203134Sthompsa USETW(req.wLength, 0); 1165220235Skevlo if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)) 1166220235Skevlo != 0) { 1167203138Sthompsa device_printf(sc->sc_dev, "firmware reset failed\n"); 1168203137Sthompsa goto fail; 1169203137Sthompsa } 1170203134Sthompsa 1171203134Sthompsa run_delay(sc, 10); 1172203134Sthompsa 1173260219Skevlo run_write(sc, RT2860_H2M_BBPAGENT, 0); 1174203134Sthompsa run_write(sc, RT2860_H2M_MAILBOX, 0); 1175260219Skevlo run_write(sc, RT2860_H2M_INTSRC, 0); 1176205042Sthompsa if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0) 1177203137Sthompsa goto fail; 1178203134Sthompsa 1179203134Sthompsa /* wait until microcontroller is ready */ 1180203134Sthompsa for (ntries = 0; ntries < 1000; ntries++) { 1181260219Skevlo if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0) 1182203137Sthompsa goto fail; 1183203134Sthompsa if (tmp & RT2860_MCU_READY) 1184203134Sthompsa break; 1185203134Sthompsa run_delay(sc, 10); 1186203134Sthompsa } 1187203134Sthompsa if (ntries == 1000) { 1188203138Sthompsa device_printf(sc->sc_dev, 1189203138Sthompsa "timeout waiting for MCU to initialize\n"); 1190203137Sthompsa error = ETIMEDOUT; 1191203137Sthompsa goto fail; 1192203134Sthompsa } 1193233283Sbschmidt device_printf(sc->sc_dev, "firmware %s ver. %u.%u loaded\n", 1194233283Sbschmidt (base == fw->data) ? "RT2870" : "RT3071", 1195233283Sbschmidt *(base + 4092), *(base + 4093)); 1196203134Sthompsa 1197203137Sthompsafail: 1198203137Sthompsa firmware_put(fw, FIRMWARE_UNLOAD); 1199203137Sthompsa return (error); 1200203134Sthompsa} 1201203134Sthompsa 1202258641Shselaskystatic int 1203203134Sthompsarun_reset(struct run_softc *sc) 1204203134Sthompsa{ 1205203134Sthompsa usb_device_request_t req; 1206203134Sthompsa 1207203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1208203134Sthompsa req.bRequest = RT2870_RESET; 1209203134Sthompsa USETW(req.wValue, 1); 1210203134Sthompsa USETW(req.wIndex, 0); 1211203134Sthompsa USETW(req.wLength, 0); 1212209917Sthompsa return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)); 1213203134Sthompsa} 1214203134Sthompsa 1215203134Sthompsastatic usb_error_t 1216203134Sthompsarun_do_request(struct run_softc *sc, 1217203134Sthompsa struct usb_device_request *req, void *data) 1218203134Sthompsa{ 1219203134Sthompsa usb_error_t err; 1220203134Sthompsa int ntries = 10; 1221203134Sthompsa 1222203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 1223203134Sthompsa 1224203134Sthompsa while (ntries--) { 1225203134Sthompsa err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, 1226203134Sthompsa req, data, 0, NULL, 250 /* ms */); 1227203134Sthompsa if (err == 0) 1228203134Sthompsa break; 1229203134Sthompsa DPRINTFN(1, "Control request failed, %s (retrying)\n", 1230203134Sthompsa usbd_errstr(err)); 1231203134Sthompsa run_delay(sc, 10); 1232203134Sthompsa } 1233203134Sthompsa return (err); 1234203134Sthompsa} 1235203134Sthompsa 1236203134Sthompsastatic int 1237203134Sthompsarun_read(struct run_softc *sc, uint16_t reg, uint32_t *val) 1238203134Sthompsa{ 1239203134Sthompsa uint32_t tmp; 1240203134Sthompsa int error; 1241203134Sthompsa 1242203134Sthompsa error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp); 1243203134Sthompsa if (error == 0) 1244203134Sthompsa *val = le32toh(tmp); 1245203134Sthompsa else 1246203134Sthompsa *val = 0xffffffff; 1247209917Sthompsa return (error); 1248203134Sthompsa} 1249203134Sthompsa 1250203134Sthompsastatic int 1251203134Sthompsarun_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len) 1252203134Sthompsa{ 1253203134Sthompsa usb_device_request_t req; 1254203134Sthompsa 1255203134Sthompsa req.bmRequestType = UT_READ_VENDOR_DEVICE; 1256203134Sthompsa req.bRequest = RT2870_READ_REGION_1; 1257203134Sthompsa USETW(req.wValue, 0); 1258203134Sthompsa USETW(req.wIndex, reg); 1259203134Sthompsa USETW(req.wLength, len); 1260203134Sthompsa 1261209917Sthompsa return (run_do_request(sc, &req, buf)); 1262203134Sthompsa} 1263203134Sthompsa 1264203134Sthompsastatic int 1265203134Sthompsarun_write_2(struct run_softc *sc, uint16_t reg, uint16_t val) 1266203134Sthompsa{ 1267203134Sthompsa usb_device_request_t req; 1268203134Sthompsa 1269203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1270203134Sthompsa req.bRequest = RT2870_WRITE_2; 1271203134Sthompsa USETW(req.wValue, val); 1272203134Sthompsa USETW(req.wIndex, reg); 1273203134Sthompsa USETW(req.wLength, 0); 1274203134Sthompsa 1275209917Sthompsa return (run_do_request(sc, &req, NULL)); 1276203134Sthompsa} 1277203134Sthompsa 1278203134Sthompsastatic int 1279203134Sthompsarun_write(struct run_softc *sc, uint16_t reg, uint32_t val) 1280203134Sthompsa{ 1281203134Sthompsa int error; 1282203134Sthompsa 1283203134Sthompsa if ((error = run_write_2(sc, reg, val & 0xffff)) == 0) 1284203134Sthompsa error = run_write_2(sc, reg + 2, val >> 16); 1285209917Sthompsa return (error); 1286203134Sthompsa} 1287203134Sthompsa 1288203134Sthompsastatic int 1289203134Sthompsarun_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf, 1290203134Sthompsa int len) 1291203134Sthompsa{ 1292203134Sthompsa#if 1 1293203134Sthompsa int i, error = 0; 1294203134Sthompsa /* 1295203134Sthompsa * NB: the WRITE_REGION_1 command is not stable on RT2860. 1296203134Sthompsa * We thus issue multiple WRITE_2 commands instead. 1297203134Sthompsa */ 1298203134Sthompsa KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n")); 1299203134Sthompsa for (i = 0; i < len && error == 0; i += 2) 1300203134Sthompsa error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8); 1301209917Sthompsa return (error); 1302203134Sthompsa#else 1303203134Sthompsa usb_device_request_t req; 1304257958Skevlo int error = 0; 1305203134Sthompsa 1306257958Skevlo /* 1307257958Skevlo * NOTE: It appears the WRITE_REGION_1 command cannot be 1308257958Skevlo * passed a huge amount of data, which will crash the 1309257958Skevlo * firmware. Limit amount of data passed to 64-bytes at a 1310257958Skevlo * time. 1311257958Skevlo */ 1312257958Skevlo while (len > 0) { 1313257958Skevlo int delta = 64; 1314257958Skevlo if (delta > len) 1315257958Skevlo delta = len; 1316257958Skevlo 1317257958Skevlo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1318257958Skevlo req.bRequest = RT2870_WRITE_REGION_1; 1319257958Skevlo USETW(req.wValue, 0); 1320257958Skevlo USETW(req.wIndex, reg); 1321257958Skevlo USETW(req.wLength, delta); 1322257958Skevlo error = run_do_request(sc, &req, __DECONST(uint8_t *, buf)); 1323257958Skevlo if (error != 0) 1324257958Skevlo break; 1325257958Skevlo reg += delta; 1326257958Skevlo buf += delta; 1327257958Skevlo len -= delta; 1328257958Skevlo } 1329257958Skevlo return (error); 1330203134Sthompsa#endif 1331203134Sthompsa} 1332203134Sthompsa 1333203134Sthompsastatic int 1334203134Sthompsarun_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len) 1335203134Sthompsa{ 1336203134Sthompsa int i, error = 0; 1337203134Sthompsa 1338203134Sthompsa KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n")); 1339203134Sthompsa for (i = 0; i < len && error == 0; i += 4) 1340203134Sthompsa error = run_write(sc, reg + i, val); 1341209917Sthompsa return (error); 1342203134Sthompsa} 1343203134Sthompsa 1344203134Sthompsastatic int 1345259544Skevlorun_efuse_read(struct run_softc *sc, uint16_t addr, uint16_t *val, int count) 1346203134Sthompsa{ 1347203134Sthompsa uint32_t tmp; 1348203134Sthompsa uint16_t reg; 1349203134Sthompsa int error, ntries; 1350203134Sthompsa 1351203134Sthompsa if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0) 1352209917Sthompsa return (error); 1353203134Sthompsa 1354261076Shselasky if (count == 2) 1355261076Shselasky addr *= 2; 1356203134Sthompsa /*- 1357203134Sthompsa * Read one 16-byte block into registers EFUSE_DATA[0-3]: 1358203134Sthompsa * DATA0: F E D C 1359203134Sthompsa * DATA1: B A 9 8 1360203134Sthompsa * DATA2: 7 6 5 4 1361203134Sthompsa * DATA3: 3 2 1 0 1362203134Sthompsa */ 1363203134Sthompsa tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK); 1364203134Sthompsa tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK; 1365203134Sthompsa run_write(sc, RT3070_EFUSE_CTRL, tmp); 1366203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1367203134Sthompsa if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0) 1368209917Sthompsa return (error); 1369203134Sthompsa if (!(tmp & RT3070_EFSROM_KICK)) 1370203134Sthompsa break; 1371203134Sthompsa run_delay(sc, 2); 1372203134Sthompsa } 1373203134Sthompsa if (ntries == 100) 1374209917Sthompsa return (ETIMEDOUT); 1375203134Sthompsa 1376261076Shselasky if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) { 1377261076Shselasky *val = 0xffff; /* address not found */ 1378209917Sthompsa return (0); 1379261076Shselasky } 1380203134Sthompsa /* determine to which 32-bit register our 16-bit word belongs */ 1381203134Sthompsa reg = RT3070_EFUSE_DATA3 - (addr & 0xc); 1382203134Sthompsa if ((error = run_read(sc, reg, &tmp)) != 0) 1383209917Sthompsa return (error); 1384203134Sthompsa 1385261118Skevlo tmp >>= (8 * (addr & 0x3)); 1386261118Skevlo *val = (addr & 1) ? tmp >> 16 : tmp & 0xffff; 1387261118Skevlo 1388209917Sthompsa return (0); 1389203134Sthompsa} 1390203134Sthompsa 1391261124Skevlo/* Read 16-bit from eFUSE ROM for RT3xxx. */ 1392203134Sthompsastatic int 1393259544Skevlorun_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val) 1394259544Skevlo{ 1395259544Skevlo return (run_efuse_read(sc, addr, val, 2)); 1396259544Skevlo} 1397259544Skevlo 1398259544Skevlostatic int 1399203134Sthompsarun_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val) 1400203134Sthompsa{ 1401203134Sthompsa usb_device_request_t req; 1402203134Sthompsa uint16_t tmp; 1403203134Sthompsa int error; 1404203134Sthompsa 1405203134Sthompsa addr *= 2; 1406203134Sthompsa req.bmRequestType = UT_READ_VENDOR_DEVICE; 1407203134Sthompsa req.bRequest = RT2870_EEPROM_READ; 1408203134Sthompsa USETW(req.wValue, 0); 1409203134Sthompsa USETW(req.wIndex, addr); 1410260219Skevlo USETW(req.wLength, sizeof(tmp)); 1411203134Sthompsa 1412203134Sthompsa error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp); 1413203134Sthompsa if (error == 0) 1414203134Sthompsa *val = le16toh(tmp); 1415203134Sthompsa else 1416203134Sthompsa *val = 0xffff; 1417209917Sthompsa return (error); 1418203134Sthompsa} 1419203134Sthompsa 1420203134Sthompsastatic __inline int 1421203134Sthompsarun_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val) 1422203134Sthompsa{ 1423203134Sthompsa /* either eFUSE ROM or EEPROM */ 1424203134Sthompsa return sc->sc_srom_read(sc, addr, val); 1425203134Sthompsa} 1426203134Sthompsa 1427203134Sthompsastatic int 1428258733Skevlorun_rt2870_rf_write(struct run_softc *sc, uint32_t val) 1429203134Sthompsa{ 1430203134Sthompsa uint32_t tmp; 1431203134Sthompsa int error, ntries; 1432203134Sthompsa 1433203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1434203134Sthompsa if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0) 1435209917Sthompsa return (error); 1436203134Sthompsa if (!(tmp & RT2860_RF_REG_CTRL)) 1437203134Sthompsa break; 1438203134Sthompsa } 1439203134Sthompsa if (ntries == 10) 1440209917Sthompsa return (ETIMEDOUT); 1441203134Sthompsa 1442258732Skevlo return (run_write(sc, RT2860_RF_CSR_CFG0, val)); 1443203134Sthompsa} 1444203134Sthompsa 1445203134Sthompsastatic int 1446203134Sthompsarun_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val) 1447203134Sthompsa{ 1448203134Sthompsa uint32_t tmp; 1449203134Sthompsa int error, ntries; 1450203134Sthompsa 1451203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1452203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1453209917Sthompsa return (error); 1454203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1455203134Sthompsa break; 1456203134Sthompsa } 1457203134Sthompsa if (ntries == 100) 1458209917Sthompsa return (ETIMEDOUT); 1459203134Sthompsa 1460203134Sthompsa tmp = RT3070_RF_KICK | reg << 8; 1461203134Sthompsa if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0) 1462209917Sthompsa return (error); 1463203134Sthompsa 1464203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1465203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1466209917Sthompsa return (error); 1467203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1468203134Sthompsa break; 1469203134Sthompsa } 1470203134Sthompsa if (ntries == 100) 1471209917Sthompsa return (ETIMEDOUT); 1472203134Sthompsa 1473203134Sthompsa *val = tmp & 0xff; 1474209917Sthompsa return (0); 1475203134Sthompsa} 1476203134Sthompsa 1477203134Sthompsastatic int 1478203134Sthompsarun_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val) 1479203134Sthompsa{ 1480203134Sthompsa uint32_t tmp; 1481203134Sthompsa int error, ntries; 1482203134Sthompsa 1483203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1484203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1485209917Sthompsa return (error); 1486203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1487203134Sthompsa break; 1488203134Sthompsa } 1489203134Sthompsa if (ntries == 10) 1490209917Sthompsa return (ETIMEDOUT); 1491203134Sthompsa 1492203134Sthompsa tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val; 1493209917Sthompsa return (run_write(sc, RT3070_RF_CSR_CFG, tmp)); 1494203134Sthompsa} 1495203134Sthompsa 1496203134Sthompsastatic int 1497203134Sthompsarun_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val) 1498203134Sthompsa{ 1499203134Sthompsa uint32_t tmp; 1500203134Sthompsa int ntries, error; 1501203134Sthompsa 1502203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1503203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1504209917Sthompsa return (error); 1505203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1506203134Sthompsa break; 1507203134Sthompsa } 1508203134Sthompsa if (ntries == 10) 1509209917Sthompsa return (ETIMEDOUT); 1510203134Sthompsa 1511203134Sthompsa tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8; 1512203134Sthompsa if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0) 1513209917Sthompsa return (error); 1514203134Sthompsa 1515203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1516203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1517209917Sthompsa return (error); 1518203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1519203134Sthompsa break; 1520203134Sthompsa } 1521203134Sthompsa if (ntries == 10) 1522209917Sthompsa return (ETIMEDOUT); 1523203134Sthompsa 1524203134Sthompsa *val = tmp & 0xff; 1525209917Sthompsa return (0); 1526203134Sthompsa} 1527203134Sthompsa 1528203134Sthompsastatic int 1529203134Sthompsarun_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val) 1530203134Sthompsa{ 1531203134Sthompsa uint32_t tmp; 1532203134Sthompsa int ntries, error; 1533203134Sthompsa 1534203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1535203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1536209917Sthompsa return (error); 1537203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1538203134Sthompsa break; 1539203134Sthompsa } 1540203134Sthompsa if (ntries == 10) 1541209917Sthompsa return (ETIMEDOUT); 1542203134Sthompsa 1543203134Sthompsa tmp = RT2860_BBP_CSR_KICK | reg << 8 | val; 1544209917Sthompsa return (run_write(sc, RT2860_BBP_CSR_CFG, tmp)); 1545203134Sthompsa} 1546203134Sthompsa 1547203134Sthompsa/* 1548203134Sthompsa * Send a command to the 8051 microcontroller unit. 1549203134Sthompsa */ 1550203134Sthompsastatic int 1551203134Sthompsarun_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg) 1552203134Sthompsa{ 1553203134Sthompsa uint32_t tmp; 1554203134Sthompsa int error, ntries; 1555203134Sthompsa 1556203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1557203134Sthompsa if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0) 1558203134Sthompsa return error; 1559203134Sthompsa if (!(tmp & RT2860_H2M_BUSY)) 1560203134Sthompsa break; 1561203134Sthompsa } 1562203134Sthompsa if (ntries == 100) 1563203134Sthompsa return ETIMEDOUT; 1564203134Sthompsa 1565203134Sthompsa tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg; 1566203134Sthompsa if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0) 1567203134Sthompsa error = run_write(sc, RT2860_HOST_CMD, cmd); 1568209917Sthompsa return (error); 1569203134Sthompsa} 1570203134Sthompsa 1571203134Sthompsa/* 1572203134Sthompsa * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word. 1573203134Sthompsa * Used to adjust per-rate Tx power registers. 1574203134Sthompsa */ 1575203134Sthompsastatic __inline uint32_t 1576203134Sthompsab4inc(uint32_t b32, int8_t delta) 1577203134Sthompsa{ 1578203134Sthompsa int8_t i, b4; 1579203134Sthompsa 1580203134Sthompsa for (i = 0; i < 8; i++) { 1581203134Sthompsa b4 = b32 & 0xf; 1582203134Sthompsa b4 += delta; 1583203134Sthompsa if (b4 < 0) 1584203134Sthompsa b4 = 0; 1585203134Sthompsa else if (b4 > 0xf) 1586203134Sthompsa b4 = 0xf; 1587203134Sthompsa b32 = b32 >> 4 | b4 << 28; 1588203134Sthompsa } 1589209917Sthompsa return (b32); 1590203134Sthompsa} 1591203134Sthompsa 1592203134Sthompsastatic const char * 1593257955Skevlorun_get_rf(uint16_t rev) 1594203134Sthompsa{ 1595203134Sthompsa switch (rev) { 1596203134Sthompsa case RT2860_RF_2820: return "RT2820"; 1597203134Sthompsa case RT2860_RF_2850: return "RT2850"; 1598203134Sthompsa case RT2860_RF_2720: return "RT2720"; 1599203134Sthompsa case RT2860_RF_2750: return "RT2750"; 1600203134Sthompsa case RT3070_RF_3020: return "RT3020"; 1601203134Sthompsa case RT3070_RF_2020: return "RT2020"; 1602203134Sthompsa case RT3070_RF_3021: return "RT3021"; 1603203134Sthompsa case RT3070_RF_3022: return "RT3022"; 1604203134Sthompsa case RT3070_RF_3052: return "RT3052"; 1605260219Skevlo case RT3593_RF_3053: return "RT3053"; 1606259032Skevlo case RT5592_RF_5592: return "RT5592"; 1607257955Skevlo case RT5390_RF_5370: return "RT5370"; 1608257955Skevlo case RT5390_RF_5372: return "RT5372"; 1609203134Sthompsa } 1610209917Sthompsa return ("unknown"); 1611203134Sthompsa} 1612203134Sthompsa 1613260219Skevlostatic void 1614260219Skevlorun_rt3593_get_txpower(struct run_softc *sc) 1615260219Skevlo{ 1616260219Skevlo uint16_t addr, val; 1617260219Skevlo int i; 1618260219Skevlo 1619260219Skevlo /* Read power settings for 2GHz channels. */ 1620260219Skevlo for (i = 0; i < 14; i += 2) { 1621260219Skevlo addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE1 : 1622260219Skevlo RT2860_EEPROM_PWR2GHZ_BASE1; 1623260219Skevlo run_srom_read(sc, addr + i / 2, &val); 1624260219Skevlo sc->txpow1[i + 0] = (int8_t)(val & 0xff); 1625260219Skevlo sc->txpow1[i + 1] = (int8_t)(val >> 8); 1626260219Skevlo 1627260219Skevlo addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE2 : 1628260219Skevlo RT2860_EEPROM_PWR2GHZ_BASE2; 1629260219Skevlo run_srom_read(sc, addr + i / 2, &val); 1630260219Skevlo sc->txpow2[i + 0] = (int8_t)(val & 0xff); 1631260219Skevlo sc->txpow2[i + 1] = (int8_t)(val >> 8); 1632260219Skevlo 1633260219Skevlo if (sc->ntxchains == 3) { 1634260219Skevlo run_srom_read(sc, RT3593_EEPROM_PWR2GHZ_BASE3 + i / 2, 1635260219Skevlo &val); 1636260219Skevlo sc->txpow3[i + 0] = (int8_t)(val & 0xff); 1637260219Skevlo sc->txpow3[i + 1] = (int8_t)(val >> 8); 1638260219Skevlo } 1639260219Skevlo } 1640260219Skevlo /* Fix broken Tx power entries. */ 1641260219Skevlo for (i = 0; i < 14; i++) { 1642260542Skevlo if (sc->txpow1[i] > 31) 1643260219Skevlo sc->txpow1[i] = 5; 1644260542Skevlo if (sc->txpow2[i] > 31) 1645260219Skevlo sc->txpow2[i] = 5; 1646260219Skevlo if (sc->ntxchains == 3) { 1647260542Skevlo if (sc->txpow3[i] > 31) 1648260219Skevlo sc->txpow3[i] = 5; 1649260219Skevlo } 1650260219Skevlo } 1651260219Skevlo /* Read power settings for 5GHz channels. */ 1652260219Skevlo for (i = 0; i < 40; i += 2) { 1653260219Skevlo run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE1 + i / 2, &val); 1654260219Skevlo sc->txpow1[i + 14] = (int8_t)(val & 0xff); 1655260219Skevlo sc->txpow1[i + 15] = (int8_t)(val >> 8); 1656260219Skevlo 1657260219Skevlo run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE2 + i / 2, &val); 1658260219Skevlo sc->txpow2[i + 14] = (int8_t)(val & 0xff); 1659260219Skevlo sc->txpow2[i + 15] = (int8_t)(val >> 8); 1660260219Skevlo 1661260219Skevlo if (sc->ntxchains == 3) { 1662260219Skevlo run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE3 + i / 2, 1663260219Skevlo &val); 1664260219Skevlo sc->txpow3[i + 14] = (int8_t)(val & 0xff); 1665260219Skevlo sc->txpow3[i + 15] = (int8_t)(val >> 8); 1666260219Skevlo } 1667260219Skevlo } 1668260219Skevlo} 1669260219Skevlo 1670260219Skevlostatic void 1671260219Skevlorun_get_txpower(struct run_softc *sc) 1672260219Skevlo{ 1673260219Skevlo uint16_t val; 1674260219Skevlo int i; 1675260219Skevlo 1676260219Skevlo /* Read power settings for 2GHz channels. */ 1677260219Skevlo for (i = 0; i < 14; i += 2) { 1678260219Skevlo run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val); 1679260219Skevlo sc->txpow1[i + 0] = (int8_t)(val & 0xff); 1680260219Skevlo sc->txpow1[i + 1] = (int8_t)(val >> 8); 1681260219Skevlo 1682260219Skevlo if (sc->mac_ver != 0x5390) { 1683260219Skevlo run_srom_read(sc, 1684260219Skevlo RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val); 1685260219Skevlo sc->txpow2[i + 0] = (int8_t)(val & 0xff); 1686260219Skevlo sc->txpow2[i + 1] = (int8_t)(val >> 8); 1687260219Skevlo } 1688260219Skevlo } 1689260219Skevlo /* Fix broken Tx power entries. */ 1690260219Skevlo for (i = 0; i < 14; i++) { 1691260219Skevlo if (sc->mac_ver >= 0x5390) { 1692288666Skevlo if (sc->txpow1[i] < 0 || sc->txpow1[i] > 39) 1693260219Skevlo sc->txpow1[i] = 5; 1694260219Skevlo } else { 1695260219Skevlo if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31) 1696260219Skevlo sc->txpow1[i] = 5; 1697260219Skevlo } 1698260219Skevlo if (sc->mac_ver > 0x5390) { 1699288666Skevlo if (sc->txpow2[i] < 0 || sc->txpow2[i] > 39) 1700260219Skevlo sc->txpow2[i] = 5; 1701260219Skevlo } else if (sc->mac_ver < 0x5390) { 1702260219Skevlo if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31) 1703260219Skevlo sc->txpow2[i] = 5; 1704260219Skevlo } 1705260219Skevlo DPRINTF("chan %d: power1=%d, power2=%d\n", 1706260219Skevlo rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]); 1707260219Skevlo } 1708260219Skevlo /* Read power settings for 5GHz channels. */ 1709260219Skevlo for (i = 0; i < 40; i += 2) { 1710260219Skevlo run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val); 1711260219Skevlo sc->txpow1[i + 14] = (int8_t)(val & 0xff); 1712260219Skevlo sc->txpow1[i + 15] = (int8_t)(val >> 8); 1713260219Skevlo 1714260219Skevlo run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val); 1715260219Skevlo sc->txpow2[i + 14] = (int8_t)(val & 0xff); 1716260219Skevlo sc->txpow2[i + 15] = (int8_t)(val >> 8); 1717260219Skevlo } 1718260219Skevlo /* Fix broken Tx power entries. */ 1719260219Skevlo for (i = 0; i < 40; i++ ) { 1720260219Skevlo if (sc->mac_ver != 0x5592) { 1721260219Skevlo if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15) 1722260219Skevlo sc->txpow1[14 + i] = 5; 1723260219Skevlo if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15) 1724260219Skevlo sc->txpow2[14 + i] = 5; 1725260219Skevlo } 1726260219Skevlo DPRINTF("chan %d: power1=%d, power2=%d\n", 1727260219Skevlo rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i], 1728260219Skevlo sc->txpow2[14 + i]); 1729260219Skevlo } 1730260219Skevlo} 1731260219Skevlo 1732258641Shselaskystatic int 1733203134Sthompsarun_read_eeprom(struct run_softc *sc) 1734203134Sthompsa{ 1735287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 1736203134Sthompsa int8_t delta_2ghz, delta_5ghz; 1737203134Sthompsa uint32_t tmp; 1738203134Sthompsa uint16_t val; 1739203134Sthompsa int ridx, ant, i; 1740203134Sthompsa 1741203134Sthompsa /* check whether the ROM is eFUSE ROM or EEPROM */ 1742203134Sthompsa sc->sc_srom_read = run_eeprom_read_2; 1743205042Sthompsa if (sc->mac_ver >= 0x3070) { 1744203134Sthompsa run_read(sc, RT3070_EFUSE_CTRL, &tmp); 1745203134Sthompsa DPRINTF("EFUSE_CTRL=0x%08x\n", tmp); 1746261118Skevlo if ((tmp & RT3070_SEL_EFUSE) || sc->mac_ver == 0x3593) 1747203134Sthompsa sc->sc_srom_read = run_efuse_read_2; 1748203134Sthompsa } 1749203134Sthompsa 1750203134Sthompsa /* read ROM version */ 1751203134Sthompsa run_srom_read(sc, RT2860_EEPROM_VERSION, &val); 1752287853Skevlo DPRINTF("EEPROM rev=%d, FAE=%d\n", val >> 8, val & 0xff); 1753203134Sthompsa 1754203134Sthompsa /* read MAC address */ 1755203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC01, &val); 1756287197Sglebius ic->ic_macaddr[0] = val & 0xff; 1757287197Sglebius ic->ic_macaddr[1] = val >> 8; 1758203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC23, &val); 1759287197Sglebius ic->ic_macaddr[2] = val & 0xff; 1760287197Sglebius ic->ic_macaddr[3] = val >> 8; 1761203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC45, &val); 1762287197Sglebius ic->ic_macaddr[4] = val & 0xff; 1763287197Sglebius ic->ic_macaddr[5] = val >> 8; 1764203134Sthompsa 1765260219Skevlo if (sc->mac_ver < 0x3593) { 1766257955Skevlo /* read vender BBP settings */ 1767205042Sthompsa for (i = 0; i < 10; i++) { 1768257955Skevlo run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val); 1769257955Skevlo sc->bbp[i].val = val & 0xff; 1770257955Skevlo sc->bbp[i].reg = val >> 8; 1771257955Skevlo DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg, 1772257955Skevlo sc->bbp[i].val); 1773205042Sthompsa } 1774257955Skevlo if (sc->mac_ver >= 0x3071) { 1775257955Skevlo /* read vendor RF settings */ 1776257955Skevlo for (i = 0; i < 10; i++) { 1777257955Skevlo run_srom_read(sc, RT3071_EEPROM_RF_BASE + i, 1778257955Skevlo &val); 1779257955Skevlo sc->rf[i].val = val & 0xff; 1780257955Skevlo sc->rf[i].reg = val >> 8; 1781257955Skevlo DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg, 1782257955Skevlo sc->rf[i].val); 1783257955Skevlo } 1784257955Skevlo } 1785205042Sthompsa } 1786203134Sthompsa 1787203134Sthompsa /* read RF frequency offset from EEPROM */ 1788260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS : 1789260219Skevlo RT3593_EEPROM_FREQ, &val); 1790203134Sthompsa sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0; 1791203134Sthompsa DPRINTF("EEPROM freq offset %d\n", sc->freq & 0xff); 1792203134Sthompsa 1793260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS : 1794260219Skevlo RT3593_EEPROM_FREQ_LEDS, &val); 1795205042Sthompsa if (val >> 8 != 0xff) { 1796203134Sthompsa /* read LEDs operating mode */ 1797205042Sthompsa sc->leds = val >> 8; 1798260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED1 : 1799260219Skevlo RT3593_EEPROM_LED1, &sc->led[0]); 1800260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED2 : 1801260219Skevlo RT3593_EEPROM_LED2, &sc->led[1]); 1802260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED3 : 1803260219Skevlo RT3593_EEPROM_LED3, &sc->led[2]); 1804203134Sthompsa } else { 1805203134Sthompsa /* broken EEPROM, use default settings */ 1806203134Sthompsa sc->leds = 0x01; 1807203134Sthompsa sc->led[0] = 0x5555; 1808203134Sthompsa sc->led[1] = 0x2221; 1809203134Sthompsa sc->led[2] = 0x5627; /* differs from RT2860 */ 1810203134Sthompsa } 1811203134Sthompsa DPRINTF("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n", 1812203134Sthompsa sc->leds, sc->led[0], sc->led[1], sc->led[2]); 1813203134Sthompsa 1814203134Sthompsa /* read RF information */ 1815259032Skevlo if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) 1816257955Skevlo run_srom_read(sc, 0x00, &val); 1817257955Skevlo else 1818257955Skevlo run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val); 1819257955Skevlo 1820203134Sthompsa if (val == 0xffff) { 1821260219Skevlo device_printf(sc->sc_dev, 1822260219Skevlo "invalid EEPROM antenna info, using default\n"); 1823203134Sthompsa DPRINTF("invalid EEPROM antenna info, using default\n"); 1824205042Sthompsa if (sc->mac_ver == 0x3572) { 1825205042Sthompsa /* default to RF3052 2T2R */ 1826205042Sthompsa sc->rf_rev = RT3070_RF_3052; 1827205042Sthompsa sc->ntxchains = 2; 1828205042Sthompsa sc->nrxchains = 2; 1829205042Sthompsa } else if (sc->mac_ver >= 0x3070) { 1830203134Sthompsa /* default to RF3020 1T1R */ 1831203134Sthompsa sc->rf_rev = RT3070_RF_3020; 1832203134Sthompsa sc->ntxchains = 1; 1833203134Sthompsa sc->nrxchains = 1; 1834203134Sthompsa } else { 1835203134Sthompsa /* default to RF2820 1T2R */ 1836203134Sthompsa sc->rf_rev = RT2860_RF_2820; 1837203134Sthompsa sc->ntxchains = 1; 1838203134Sthompsa sc->nrxchains = 2; 1839203134Sthompsa } 1840203134Sthompsa } else { 1841259032Skevlo if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) { 1842257955Skevlo sc->rf_rev = val; 1843257955Skevlo run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val); 1844257955Skevlo } else 1845257955Skevlo sc->rf_rev = (val >> 8) & 0xf; 1846203134Sthompsa sc->ntxchains = (val >> 4) & 0xf; 1847203134Sthompsa sc->nrxchains = val & 0xf; 1848203134Sthompsa } 1849257955Skevlo DPRINTF("EEPROM RF rev=0x%04x chains=%dT%dR\n", 1850203134Sthompsa sc->rf_rev, sc->ntxchains, sc->nrxchains); 1851203134Sthompsa 1852208019Sthompsa /* check if RF supports automatic Tx access gain control */ 1853203134Sthompsa run_srom_read(sc, RT2860_EEPROM_CONFIG, &val); 1854203134Sthompsa DPRINTF("EEPROM CFG 0x%04x\n", val); 1855205042Sthompsa /* check if driver should patch the DAC issue */ 1856205042Sthompsa if ((val >> 8) != 0xff) 1857205042Sthompsa sc->patch_dac = (val >> 15) & 1; 1858203134Sthompsa if ((val & 0xff) != 0xff) { 1859203134Sthompsa sc->ext_5ghz_lna = (val >> 3) & 1; 1860203134Sthompsa sc->ext_2ghz_lna = (val >> 2) & 1; 1861205042Sthompsa /* check if RF supports automatic Tx access gain control */ 1862203134Sthompsa sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1; 1863205042Sthompsa /* check if we have a hardware radio switch */ 1864205042Sthompsa sc->rfswitch = val & 1; 1865203134Sthompsa } 1866203134Sthompsa 1867260219Skevlo /* Read Tx power settings. */ 1868260219Skevlo if (sc->mac_ver == 0x3593) 1869260219Skevlo run_rt3593_get_txpower(sc); 1870260219Skevlo else 1871260219Skevlo run_get_txpower(sc); 1872203134Sthompsa 1873203134Sthompsa /* read Tx power compensation for each Tx rate */ 1874203134Sthompsa run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val); 1875203134Sthompsa delta_2ghz = delta_5ghz = 0; 1876203134Sthompsa if ((val & 0xff) != 0xff && (val & 0x80)) { 1877203134Sthompsa delta_2ghz = val & 0xf; 1878203134Sthompsa if (!(val & 0x40)) /* negative number */ 1879203134Sthompsa delta_2ghz = -delta_2ghz; 1880203134Sthompsa } 1881203134Sthompsa val >>= 8; 1882203134Sthompsa if ((val & 0xff) != 0xff && (val & 0x80)) { 1883203134Sthompsa delta_5ghz = val & 0xf; 1884203134Sthompsa if (!(val & 0x40)) /* negative number */ 1885203134Sthompsa delta_5ghz = -delta_5ghz; 1886203134Sthompsa } 1887203134Sthompsa DPRINTF("power compensation=%d (2GHz), %d (5GHz)\n", 1888203134Sthompsa delta_2ghz, delta_5ghz); 1889203134Sthompsa 1890203134Sthompsa for (ridx = 0; ridx < 5; ridx++) { 1891203134Sthompsa uint32_t reg; 1892203134Sthompsa 1893208019Sthompsa run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val); 1894208019Sthompsa reg = val; 1895208019Sthompsa run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val); 1896208019Sthompsa reg |= (uint32_t)val << 16; 1897203134Sthompsa 1898203134Sthompsa sc->txpow20mhz[ridx] = reg; 1899203134Sthompsa sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz); 1900203134Sthompsa sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz); 1901203134Sthompsa 1902203134Sthompsa DPRINTF("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, " 1903203134Sthompsa "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx], 1904203134Sthompsa sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]); 1905203134Sthompsa } 1906203134Sthompsa 1907260219Skevlo /* Read RSSI offsets and LNA gains from EEPROM. */ 1908260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_2GHZ : 1909260219Skevlo RT3593_EEPROM_RSSI1_2GHZ, &val); 1910203134Sthompsa sc->rssi_2ghz[0] = val & 0xff; /* Ant A */ 1911203134Sthompsa sc->rssi_2ghz[1] = val >> 8; /* Ant B */ 1912260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_2GHZ : 1913260219Skevlo RT3593_EEPROM_RSSI2_2GHZ, &val); 1914205042Sthompsa if (sc->mac_ver >= 0x3070) { 1915260219Skevlo if (sc->mac_ver == 0x3593) { 1916260219Skevlo sc->txmixgain_2ghz = 0; 1917260219Skevlo sc->rssi_2ghz[2] = val & 0xff; /* Ant C */ 1918260219Skevlo } else { 1919260219Skevlo /* 1920260219Skevlo * On RT3070 chips (limited to 2 Rx chains), this ROM 1921260219Skevlo * field contains the Tx mixer gain for the 2GHz band. 1922260219Skevlo */ 1923260219Skevlo if ((val & 0xff) != 0xff) 1924260219Skevlo sc->txmixgain_2ghz = val & 0x7; 1925260219Skevlo } 1926205042Sthompsa DPRINTF("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz); 1927205042Sthompsa } else 1928205042Sthompsa sc->rssi_2ghz[2] = val & 0xff; /* Ant C */ 1929260219Skevlo if (sc->mac_ver == 0x3593) 1930260219Skevlo run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val); 1931203134Sthompsa sc->lna[2] = val >> 8; /* channel group 2 */ 1932203134Sthompsa 1933260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_5GHZ : 1934260219Skevlo RT3593_EEPROM_RSSI1_5GHZ, &val); 1935203134Sthompsa sc->rssi_5ghz[0] = val & 0xff; /* Ant A */ 1936203134Sthompsa sc->rssi_5ghz[1] = val >> 8; /* Ant B */ 1937260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_5GHZ : 1938260219Skevlo RT3593_EEPROM_RSSI2_5GHZ, &val); 1939205042Sthompsa if (sc->mac_ver == 0x3572) { 1940205042Sthompsa /* 1941205042Sthompsa * On RT3572 chips (limited to 2 Rx chains), this ROM 1942205042Sthompsa * field contains the Tx mixer gain for the 5GHz band. 1943205042Sthompsa */ 1944205042Sthompsa if ((val & 0xff) != 0xff) 1945205042Sthompsa sc->txmixgain_5ghz = val & 0x7; 1946205042Sthompsa DPRINTF("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz); 1947205042Sthompsa } else 1948205042Sthompsa sc->rssi_5ghz[2] = val & 0xff; /* Ant C */ 1949260219Skevlo if (sc->mac_ver == 0x3593) { 1950260219Skevlo sc->txmixgain_5ghz = 0; 1951260219Skevlo run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val); 1952260219Skevlo } 1953203134Sthompsa sc->lna[3] = val >> 8; /* channel group 3 */ 1954203134Sthompsa 1955260219Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LNA : 1956260219Skevlo RT3593_EEPROM_LNA, &val); 1957203134Sthompsa sc->lna[0] = val & 0xff; /* channel group 0 */ 1958203134Sthompsa sc->lna[1] = val >> 8; /* channel group 1 */ 1959203134Sthompsa 1960203134Sthompsa /* fix broken 5GHz LNA entries */ 1961203134Sthompsa if (sc->lna[2] == 0 || sc->lna[2] == 0xff) { 1962203134Sthompsa DPRINTF("invalid LNA for channel group %d\n", 2); 1963203134Sthompsa sc->lna[2] = sc->lna[1]; 1964203134Sthompsa } 1965203134Sthompsa if (sc->lna[3] == 0 || sc->lna[3] == 0xff) { 1966203134Sthompsa DPRINTF("invalid LNA for channel group %d\n", 3); 1967203134Sthompsa sc->lna[3] = sc->lna[1]; 1968203134Sthompsa } 1969203134Sthompsa 1970203134Sthompsa /* fix broken RSSI offset entries */ 1971203134Sthompsa for (ant = 0; ant < 3; ant++) { 1972203134Sthompsa if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) { 1973203134Sthompsa DPRINTF("invalid RSSI%d offset: %d (2GHz)\n", 1974203134Sthompsa ant + 1, sc->rssi_2ghz[ant]); 1975203134Sthompsa sc->rssi_2ghz[ant] = 0; 1976203134Sthompsa } 1977203134Sthompsa if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) { 1978203134Sthompsa DPRINTF("invalid RSSI%d offset: %d (5GHz)\n", 1979203134Sthompsa ant + 1, sc->rssi_5ghz[ant]); 1980203134Sthompsa sc->rssi_5ghz[ant] = 0; 1981203134Sthompsa } 1982203134Sthompsa } 1983209917Sthompsa return (0); 1984203134Sthompsa} 1985203134Sthompsa 1986218676Shselaskystatic struct ieee80211_node * 1987203134Sthompsarun_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) 1988203134Sthompsa{ 1989203134Sthompsa return malloc(sizeof (struct run_node), M_DEVBUF, M_NOWAIT | M_ZERO); 1990203134Sthompsa} 1991203134Sthompsa 1992203134Sthompsastatic int 1993203134Sthompsarun_media_change(struct ifnet *ifp) 1994203134Sthompsa{ 1995208019Sthompsa struct ieee80211vap *vap = ifp->if_softc; 1996208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 1997203134Sthompsa const struct ieee80211_txparam *tp; 1998286950Sadrian struct run_softc *sc = ic->ic_softc; 1999203134Sthompsa uint8_t rate, ridx; 2000203134Sthompsa int error; 2001203134Sthompsa 2002203134Sthompsa RUN_LOCK(sc); 2003203134Sthompsa 2004203134Sthompsa error = ieee80211_media_change(ifp); 2005209917Sthompsa if (error != ENETRESET) { 2006203134Sthompsa RUN_UNLOCK(sc); 2007209917Sthompsa return (error); 2008208019Sthompsa } 2009203134Sthompsa 2010203134Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 2011203134Sthompsa if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 2012212127Sthompsa struct ieee80211_node *ni; 2013212127Sthompsa struct run_node *rn; 2014212127Sthompsa 2015203134Sthompsa rate = ic->ic_sup_rates[ic->ic_curmode]. 2016203134Sthompsa rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL; 2017203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2018203134Sthompsa if (rt2860_rates[ridx].rate == rate) 2019203134Sthompsa break; 2020212127Sthompsa ni = ieee80211_ref_node(vap->iv_bss); 2021287552Skevlo rn = RUN_NODE(ni); 2022208019Sthompsa rn->fix_ridx = ridx; 2023208019Sthompsa DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx); 2024212127Sthompsa ieee80211_free_node(ni); 2025203134Sthompsa } 2026203134Sthompsa 2027208019Sthompsa#if 0 2028203134Sthompsa if ((ifp->if_flags & IFF_UP) && 2029287197Sglebius (ifp->if_drv_flags & RUN_RUNNING)){ 2030203134Sthompsa run_init_locked(sc); 2031203134Sthompsa } 2032208019Sthompsa#endif 2033203134Sthompsa 2034203134Sthompsa RUN_UNLOCK(sc); 2035203134Sthompsa 2036209917Sthompsa return (0); 2037203134Sthompsa} 2038203134Sthompsa 2039203134Sthompsastatic int 2040203134Sthompsarun_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 2041203134Sthompsa{ 2042203134Sthompsa const struct ieee80211_txparam *tp; 2043203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2044286950Sadrian struct run_softc *sc = ic->ic_softc; 2045203134Sthompsa struct run_vap *rvp = RUN_VAP(vap); 2046203134Sthompsa enum ieee80211_state ostate; 2047208019Sthompsa uint32_t sta[3]; 2048203134Sthompsa uint32_t tmp; 2049208019Sthompsa uint8_t ratectl; 2050208019Sthompsa uint8_t restart_ratectl = 0; 2051208019Sthompsa uint8_t bid = 1 << rvp->rvp_id; 2052203134Sthompsa 2053203134Sthompsa ostate = vap->iv_state; 2054203134Sthompsa DPRINTF("%s -> %s\n", 2055203134Sthompsa ieee80211_state_name[ostate], 2056203134Sthompsa ieee80211_state_name[nstate]); 2057203134Sthompsa 2058203134Sthompsa IEEE80211_UNLOCK(ic); 2059203134Sthompsa RUN_LOCK(sc); 2060203134Sthompsa 2061208019Sthompsa ratectl = sc->ratectl_run; /* remember current state */ 2062208019Sthompsa sc->ratectl_run = RUN_RATECTL_OFF; 2063208019Sthompsa usb_callout_stop(&sc->ratectl_ch); 2064203134Sthompsa 2065203134Sthompsa if (ostate == IEEE80211_S_RUN) { 2066203134Sthompsa /* turn link LED off */ 2067203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO); 2068203134Sthompsa } 2069203134Sthompsa 2070203134Sthompsa switch (nstate) { 2071203134Sthompsa case IEEE80211_S_INIT: 2072208019Sthompsa restart_ratectl = 1; 2073208019Sthompsa 2074208019Sthompsa if (ostate != IEEE80211_S_RUN) 2075208019Sthompsa break; 2076208019Sthompsa 2077208019Sthompsa ratectl &= ~bid; 2078208019Sthompsa sc->runbmap &= ~bid; 2079208019Sthompsa 2080208019Sthompsa /* abort TSF synchronization if there is no vap running */ 2081209917Sthompsa if (--sc->running == 0) { 2082203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 2083203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, 2084203134Sthompsa tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 2085203134Sthompsa RT2860_TBTT_TIMER_EN)); 2086203134Sthompsa } 2087203134Sthompsa break; 2088203134Sthompsa 2089203134Sthompsa case IEEE80211_S_RUN: 2090209917Sthompsa if (!(sc->runbmap & bid)) { 2091208019Sthompsa if(sc->running++) 2092208019Sthompsa restart_ratectl = 1; 2093208019Sthompsa sc->runbmap |= bid; 2094208019Sthompsa } 2095203134Sthompsa 2096218492Sbschmidt m_freem(rvp->beacon_mbuf); 2097218492Sbschmidt rvp->beacon_mbuf = NULL; 2098218492Sbschmidt 2099209917Sthompsa switch (vap->iv_opmode) { 2100208019Sthompsa case IEEE80211_M_HOSTAP: 2101208019Sthompsa case IEEE80211_M_MBSS: 2102208019Sthompsa sc->ap_running |= bid; 2103208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2104208019Sthompsa run_update_beacon_cb(vap); 2105208019Sthompsa break; 2106208019Sthompsa case IEEE80211_M_IBSS: 2107208019Sthompsa sc->adhoc_running |= bid; 2108209917Sthompsa if (!sc->ap_running) 2109208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2110208019Sthompsa run_update_beacon_cb(vap); 2111208019Sthompsa break; 2112208019Sthompsa case IEEE80211_M_STA: 2113208019Sthompsa sc->sta_running |= bid; 2114209917Sthompsa if (!sc->ap_running && !sc->adhoc_running) 2115208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2116208019Sthompsa 2117208019Sthompsa /* read statistic counters (clear on read) */ 2118208019Sthompsa run_read_region_1(sc, RT2860_TX_STA_CNT0, 2119208019Sthompsa (uint8_t *)sta, sizeof sta); 2120208019Sthompsa 2121208019Sthompsa break; 2122208019Sthompsa default: 2123208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2124208019Sthompsa break; 2125208019Sthompsa } 2126208019Sthompsa 2127203134Sthompsa if (vap->iv_opmode != IEEE80211_M_MONITOR) { 2128212127Sthompsa struct ieee80211_node *ni; 2129212127Sthompsa 2130236439Shselasky if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) { 2131236439Shselasky RUN_UNLOCK(sc); 2132236439Shselasky IEEE80211_LOCK(ic); 2133236439Shselasky return (-1); 2134236439Shselasky } 2135283540Sglebius run_updateslot(ic); 2136203134Sthompsa run_enable_mrr(sc); 2137203134Sthompsa run_set_txpreamble(sc); 2138203134Sthompsa run_set_basicrates(sc); 2139212127Sthompsa ni = ieee80211_ref_node(vap->iv_bss); 2140296356Savos IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); 2141296356Savos run_set_bssid(sc, sc->sc_bssid); 2142212127Sthompsa ieee80211_free_node(ni); 2143208019Sthompsa run_enable_tsf_sync(sc); 2144203134Sthompsa 2145208019Sthompsa /* enable automatic rate adaptation */ 2146208019Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 2147208019Sthompsa if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) 2148208019Sthompsa ratectl |= bid; 2149287555Skevlo } else 2150287555Skevlo run_enable_tsf(sc); 2151203134Sthompsa 2152203134Sthompsa /* turn link LED on */ 2153203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO | 2154208019Sthompsa (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 2155203134Sthompsa RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ)); 2156203134Sthompsa 2157203134Sthompsa break; 2158203134Sthompsa default: 2159203134Sthompsa DPRINTFN(6, "undefined case\n"); 2160203134Sthompsa break; 2161203134Sthompsa } 2162203134Sthompsa 2163208019Sthompsa /* restart amrr for running VAPs */ 2164209917Sthompsa if ((sc->ratectl_run = ratectl) && restart_ratectl) 2165208019Sthompsa usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2166208019Sthompsa 2167203134Sthompsa RUN_UNLOCK(sc); 2168203134Sthompsa IEEE80211_LOCK(ic); 2169203134Sthompsa 2170203134Sthompsa return(rvp->newstate(vap, nstate, arg)); 2171203134Sthompsa} 2172203134Sthompsa 2173290407Savosstatic int 2174290407Savosrun_wme_update(struct ieee80211com *ic) 2175203134Sthompsa{ 2176286950Sadrian struct run_softc *sc = ic->ic_softc; 2177288646Sadrian const struct wmeParams *ac = 2178288646Sadrian ic->ic_wme.wme_chanParams.cap_wmeParams; 2179203134Sthompsa int aci, error = 0; 2180203134Sthompsa 2181203134Sthompsa /* update MAC TX configuration registers */ 2182290407Savos RUN_LOCK(sc); 2183203134Sthompsa for (aci = 0; aci < WME_NUM_AC; aci++) { 2184203134Sthompsa error = run_write(sc, RT2860_EDCA_AC_CFG(aci), 2185288646Sadrian ac[aci].wmep_logcwmax << 16 | 2186288646Sadrian ac[aci].wmep_logcwmin << 12 | 2187288646Sadrian ac[aci].wmep_aifsn << 8 | 2188288646Sadrian ac[aci].wmep_txopLimit); 2189209917Sthompsa if (error) goto err; 2190203134Sthompsa } 2191203134Sthompsa 2192203134Sthompsa /* update SCH/DMA registers too */ 2193203134Sthompsa error = run_write(sc, RT2860_WMM_AIFSN_CFG, 2194288646Sadrian ac[WME_AC_VO].wmep_aifsn << 12 | 2195288646Sadrian ac[WME_AC_VI].wmep_aifsn << 8 | 2196288646Sadrian ac[WME_AC_BK].wmep_aifsn << 4 | 2197288646Sadrian ac[WME_AC_BE].wmep_aifsn); 2198209917Sthompsa if (error) goto err; 2199203134Sthompsa error = run_write(sc, RT2860_WMM_CWMIN_CFG, 2200288646Sadrian ac[WME_AC_VO].wmep_logcwmin << 12 | 2201288646Sadrian ac[WME_AC_VI].wmep_logcwmin << 8 | 2202288646Sadrian ac[WME_AC_BK].wmep_logcwmin << 4 | 2203288646Sadrian ac[WME_AC_BE].wmep_logcwmin); 2204209917Sthompsa if (error) goto err; 2205203134Sthompsa error = run_write(sc, RT2860_WMM_CWMAX_CFG, 2206288646Sadrian ac[WME_AC_VO].wmep_logcwmax << 12 | 2207288646Sadrian ac[WME_AC_VI].wmep_logcwmax << 8 | 2208288646Sadrian ac[WME_AC_BK].wmep_logcwmax << 4 | 2209288646Sadrian ac[WME_AC_BE].wmep_logcwmax); 2210209917Sthompsa if (error) goto err; 2211203134Sthompsa error = run_write(sc, RT2860_WMM_TXOP0_CFG, 2212288646Sadrian ac[WME_AC_BK].wmep_txopLimit << 16 | 2213288646Sadrian ac[WME_AC_BE].wmep_txopLimit); 2214209917Sthompsa if (error) goto err; 2215203134Sthompsa error = run_write(sc, RT2860_WMM_TXOP1_CFG, 2216288646Sadrian ac[WME_AC_VO].wmep_txopLimit << 16 | 2217288646Sadrian ac[WME_AC_VI].wmep_txopLimit); 2218203134Sthompsa 2219203134Sthompsaerr: 2220290407Savos RUN_UNLOCK(sc); 2221209917Sthompsa if (error) 2222203134Sthompsa DPRINTF("WME update failed\n"); 2223203134Sthompsa 2224290407Savos return (error); 2225203134Sthompsa} 2226203134Sthompsa 2227203134Sthompsastatic void 2228208019Sthompsarun_key_set_cb(void *arg) 2229203134Sthompsa{ 2230208019Sthompsa struct run_cmdq *cmdq = arg; 2231208019Sthompsa struct ieee80211vap *vap = cmdq->arg1; 2232208019Sthompsa struct ieee80211_key *k = cmdq->k; 2233203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2234286950Sadrian struct run_softc *sc = ic->ic_softc; 2235203134Sthompsa struct ieee80211_node *ni; 2236287553Skevlo u_int cipher = k->wk_cipher->ic_cipher; 2237203134Sthompsa uint32_t attr; 2238203134Sthompsa uint16_t base, associd; 2239209144Sthompsa uint8_t mode, wcid, iv[8]; 2240203134Sthompsa 2241208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2242203134Sthompsa 2243209917Sthompsa if (vap->iv_opmode == IEEE80211_M_HOSTAP) 2244208019Sthompsa ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac); 2245209144Sthompsa else 2246203134Sthompsa ni = vap->iv_bss; 2247208019Sthompsa associd = (ni != NULL) ? ni->ni_associd : 0; 2248203134Sthompsa 2249203134Sthompsa /* map net80211 cipher to RT2860 security mode */ 2250287553Skevlo switch (cipher) { 2251203134Sthompsa case IEEE80211_CIPHER_WEP: 2252203134Sthompsa if(k->wk_keylen < 8) 2253203134Sthompsa mode = RT2860_MODE_WEP40; 2254203134Sthompsa else 2255203134Sthompsa mode = RT2860_MODE_WEP104; 2256203134Sthompsa break; 2257203134Sthompsa case IEEE80211_CIPHER_TKIP: 2258203134Sthompsa mode = RT2860_MODE_TKIP; 2259203134Sthompsa break; 2260203134Sthompsa case IEEE80211_CIPHER_AES_CCM: 2261203134Sthompsa mode = RT2860_MODE_AES_CCMP; 2262203134Sthompsa break; 2263203134Sthompsa default: 2264203134Sthompsa DPRINTF("undefined case\n"); 2265208019Sthompsa return; 2266203134Sthompsa } 2267203134Sthompsa 2268208019Sthompsa DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n", 2269203134Sthompsa associd, k->wk_keyix, mode, 2270208019Sthompsa (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise", 2271208019Sthompsa (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off", 2272208019Sthompsa (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off"); 2273203134Sthompsa 2274203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 2275203134Sthompsa wcid = 0; /* NB: update WCID0 for group keys */ 2276208019Sthompsa base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix); 2277203134Sthompsa } else { 2278245047Shselasky wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 2279245047Shselasky 1 : RUN_AID2WCID(associd); 2280203134Sthompsa base = RT2860_PKEY(wcid); 2281203134Sthompsa } 2282203134Sthompsa 2283287553Skevlo if (cipher == IEEE80211_CIPHER_TKIP) { 2284203134Sthompsa if(run_write_region_1(sc, base, k->wk_key, 16)) 2285208019Sthompsa return; 2286209144Sthompsa if(run_write_region_1(sc, base + 16, &k->wk_key[16], 8)) /* wk_txmic */ 2287208019Sthompsa return; 2288209144Sthompsa if(run_write_region_1(sc, base + 24, &k->wk_key[24], 8)) /* wk_rxmic */ 2289208019Sthompsa return; 2290203134Sthompsa } else { 2291203134Sthompsa /* roundup len to 16-bit: XXX fix write_region_1() instead */ 2292203134Sthompsa if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1)) 2293208019Sthompsa return; 2294203134Sthompsa } 2295203134Sthompsa 2296203134Sthompsa if (!(k->wk_flags & IEEE80211_KEY_GROUP) || 2297203134Sthompsa (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) { 2298203134Sthompsa /* set initial packet number in IV+EIV */ 2299287553Skevlo if (cipher == IEEE80211_CIPHER_WEP) { 2300203134Sthompsa memset(iv, 0, sizeof iv); 2301208019Sthompsa iv[3] = vap->iv_def_txkey << 6; 2302203134Sthompsa } else { 2303287553Skevlo if (cipher == IEEE80211_CIPHER_TKIP) { 2304203134Sthompsa iv[0] = k->wk_keytsc >> 8; 2305203134Sthompsa iv[1] = (iv[0] | 0x20) & 0x7f; 2306203134Sthompsa iv[2] = k->wk_keytsc; 2307203134Sthompsa } else /* CCMP */ { 2308203134Sthompsa iv[0] = k->wk_keytsc; 2309203134Sthompsa iv[1] = k->wk_keytsc >> 8; 2310203134Sthompsa iv[2] = 0; 2311203134Sthompsa } 2312203134Sthompsa iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV; 2313203134Sthompsa iv[4] = k->wk_keytsc >> 16; 2314203134Sthompsa iv[5] = k->wk_keytsc >> 24; 2315203134Sthompsa iv[6] = k->wk_keytsc >> 32; 2316203134Sthompsa iv[7] = k->wk_keytsc >> 40; 2317203134Sthompsa } 2318209917Sthompsa if (run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8)) 2319208019Sthompsa return; 2320203134Sthompsa } 2321203134Sthompsa 2322203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 2323203134Sthompsa /* install group key */ 2324209917Sthompsa if (run_read(sc, RT2860_SKEY_MODE_0_7, &attr)) 2325208019Sthompsa return; 2326203134Sthompsa attr &= ~(0xf << (k->wk_keyix * 4)); 2327203134Sthompsa attr |= mode << (k->wk_keyix * 4); 2328209917Sthompsa if (run_write(sc, RT2860_SKEY_MODE_0_7, attr)) 2329208019Sthompsa return; 2330203134Sthompsa } else { 2331203134Sthompsa /* install pairwise key */ 2332209917Sthompsa if (run_read(sc, RT2860_WCID_ATTR(wcid), &attr)) 2333208019Sthompsa return; 2334203134Sthompsa attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN; 2335209917Sthompsa if (run_write(sc, RT2860_WCID_ATTR(wcid), attr)) 2336208019Sthompsa return; 2337203134Sthompsa } 2338203134Sthompsa 2339203134Sthompsa /* TODO create a pass-thru key entry? */ 2340203134Sthompsa 2341208019Sthompsa /* need wcid to delete the right key later */ 2342208019Sthompsa k->wk_pad = wcid; 2343203134Sthompsa} 2344203134Sthompsa 2345203134Sthompsa/* 2346208019Sthompsa * Don't have to be deferred, but in order to keep order of 2347208019Sthompsa * execution, i.e. with run_key_delete(), defer this and let 2348208019Sthompsa * run_cmdq_cb() maintain the order. 2349208019Sthompsa * 2350203134Sthompsa * return 0 on error 2351203134Sthompsa */ 2352203134Sthompsastatic int 2353288635Sadrianrun_key_set(struct ieee80211vap *vap, struct ieee80211_key *k) 2354203134Sthompsa{ 2355203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2356286950Sadrian struct run_softc *sc = ic->ic_softc; 2357208019Sthompsa uint32_t i; 2358208019Sthompsa 2359208019Sthompsa i = RUN_CMDQ_GET(&sc->cmdq_store); 2360208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 2361208019Sthompsa sc->cmdq[i].func = run_key_set_cb; 2362208019Sthompsa sc->cmdq[i].arg0 = NULL; 2363208019Sthompsa sc->cmdq[i].arg1 = vap; 2364208019Sthompsa sc->cmdq[i].k = k; 2365288635Sadrian IEEE80211_ADDR_COPY(sc->cmdq[i].mac, k->wk_macaddr); 2366208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2367208019Sthompsa 2368209144Sthompsa /* 2369209144Sthompsa * To make sure key will be set when hostapd 2370209144Sthompsa * calls iv_key_set() before if_init(). 2371209144Sthompsa */ 2372209917Sthompsa if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 2373209144Sthompsa RUN_LOCK(sc); 2374209144Sthompsa sc->cmdq_key_set = RUN_CMDQ_GO; 2375209144Sthompsa RUN_UNLOCK(sc); 2376209144Sthompsa } 2377209144Sthompsa 2378209917Sthompsa return (1); 2379208019Sthompsa} 2380208019Sthompsa 2381208019Sthompsa/* 2382208019Sthompsa * If wlan is destroyed without being brought down i.e. without 2383208019Sthompsa * wlan down or wpa_cli terminate, this function is called after 2384208019Sthompsa * vap is gone. Don't refer it. 2385208019Sthompsa */ 2386208019Sthompsastatic void 2387208019Sthompsarun_key_delete_cb(void *arg) 2388208019Sthompsa{ 2389208019Sthompsa struct run_cmdq *cmdq = arg; 2390208019Sthompsa struct run_softc *sc = cmdq->arg1; 2391208019Sthompsa struct ieee80211_key *k = &cmdq->key; 2392203134Sthompsa uint32_t attr; 2393203134Sthompsa uint8_t wcid; 2394203134Sthompsa 2395208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2396203134Sthompsa 2397203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 2398203134Sthompsa /* remove group key */ 2399208019Sthompsa DPRINTF("removing group key\n"); 2400208019Sthompsa run_read(sc, RT2860_SKEY_MODE_0_7, &attr); 2401203134Sthompsa attr &= ~(0xf << (k->wk_keyix * 4)); 2402208019Sthompsa run_write(sc, RT2860_SKEY_MODE_0_7, attr); 2403203134Sthompsa } else { 2404203134Sthompsa /* remove pairwise key */ 2405208019Sthompsa DPRINTF("removing key for wcid %x\n", k->wk_pad); 2406208019Sthompsa /* matching wcid was written to wk_pad in run_key_set() */ 2407208019Sthompsa wcid = k->wk_pad; 2408208019Sthompsa run_read(sc, RT2860_WCID_ATTR(wcid), &attr); 2409203134Sthompsa attr &= ~0xf; 2410208019Sthompsa run_write(sc, RT2860_WCID_ATTR(wcid), attr); 2411208019Sthompsa run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8); 2412203134Sthompsa } 2413203134Sthompsa 2414208019Sthompsa k->wk_pad = 0; 2415203134Sthompsa} 2416203134Sthompsa 2417208019Sthompsa/* 2418208019Sthompsa * return 0 on error 2419208019Sthompsa */ 2420208019Sthompsastatic int 2421208019Sthompsarun_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k) 2422203134Sthompsa{ 2423208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 2424286950Sadrian struct run_softc *sc = ic->ic_softc; 2425208019Sthompsa struct ieee80211_key *k0; 2426208019Sthompsa uint32_t i; 2427203134Sthompsa 2428208019Sthompsa /* 2429208019Sthompsa * When called back, key might be gone. So, make a copy 2430208019Sthompsa * of some values need to delete keys before deferring. 2431208019Sthompsa * But, because of LOR with node lock, cannot use lock here. 2432208019Sthompsa * So, use atomic instead. 2433208019Sthompsa */ 2434208019Sthompsa i = RUN_CMDQ_GET(&sc->cmdq_store); 2435208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 2436208019Sthompsa sc->cmdq[i].func = run_key_delete_cb; 2437208019Sthompsa sc->cmdq[i].arg0 = NULL; 2438208019Sthompsa sc->cmdq[i].arg1 = sc; 2439208019Sthompsa k0 = &sc->cmdq[i].key; 2440208019Sthompsa k0->wk_flags = k->wk_flags; 2441208019Sthompsa k0->wk_keyix = k->wk_keyix; 2442208019Sthompsa /* matching wcid was written to wk_pad in run_key_set() */ 2443208019Sthompsa k0->wk_pad = k->wk_pad; 2444208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2445208019Sthompsa return (1); /* return fake success */ 2446203134Sthompsa 2447203134Sthompsa} 2448203134Sthompsa 2449203134Sthompsastatic void 2450206358Srpaulorun_ratectl_to(void *arg) 2451203134Sthompsa{ 2452208019Sthompsa struct run_softc *sc = arg; 2453203134Sthompsa 2454203134Sthompsa /* do it in a process context, so it can go sleep */ 2455287197Sglebius ieee80211_runtask(&sc->sc_ic, &sc->ratectl_task); 2456203134Sthompsa /* next timeout will be rescheduled in the callback task */ 2457203134Sthompsa} 2458203134Sthompsa 2459203134Sthompsa/* ARGSUSED */ 2460203134Sthompsastatic void 2461206358Srpaulorun_ratectl_cb(void *arg, int pending) 2462203134Sthompsa{ 2463208019Sthompsa struct run_softc *sc = arg; 2464287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2465208019Sthompsa struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2466203134Sthompsa 2467209917Sthompsa if (vap == NULL) 2468208019Sthompsa return; 2469208019Sthompsa 2470262795Shselasky if (sc->rvp_cnt > 1 || vap->iv_opmode != IEEE80211_M_STA) { 2471203134Sthompsa /* 2472203134Sthompsa * run_reset_livelock() doesn't do anything with AMRR, 2473203134Sthompsa * but Ralink wants us to call it every 1 sec. So, we 2474203134Sthompsa * piggyback here rather than creating another callout. 2475203134Sthompsa * Livelock may occur only in HOSTAP or IBSS mode 2476203134Sthompsa * (when h/w is sending beacons). 2477203134Sthompsa */ 2478203134Sthompsa RUN_LOCK(sc); 2479203134Sthompsa run_reset_livelock(sc); 2480208019Sthompsa /* just in case, there are some stats to drain */ 2481208019Sthompsa run_drain_fifo(sc); 2482203134Sthompsa RUN_UNLOCK(sc); 2483203134Sthompsa } 2484203134Sthompsa 2485262795Shselasky ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc); 2486262795Shselasky 2487257712Shselasky RUN_LOCK(sc); 2488208019Sthompsa if(sc->ratectl_run != RUN_RATECTL_OFF) 2489208019Sthompsa usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2490257712Shselasky RUN_UNLOCK(sc); 2491203134Sthompsa} 2492203134Sthompsa 2493203134Sthompsastatic void 2494208019Sthompsarun_drain_fifo(void *arg) 2495203134Sthompsa{ 2496208019Sthompsa struct run_softc *sc = arg; 2497208019Sthompsa uint32_t stat; 2498218676Shselasky uint16_t (*wstat)[3]; 2499203134Sthompsa uint8_t wcid, mcs, pid; 2500218676Shselasky int8_t retry; 2501203134Sthompsa 2502208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2503203134Sthompsa 2504208019Sthompsa for (;;) { 2505203134Sthompsa /* drain Tx status FIFO (maxsize = 16) */ 2506203134Sthompsa run_read(sc, RT2860_TX_STAT_FIFO, &stat); 2507208019Sthompsa DPRINTFN(4, "tx stat 0x%08x\n", stat); 2508209917Sthompsa if (!(stat & RT2860_TXQ_VLD)) 2509208019Sthompsa break; 2510203134Sthompsa 2511208019Sthompsa wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff; 2512203134Sthompsa 2513208019Sthompsa /* if no ACK was requested, no feedback is available */ 2514208019Sthompsa if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX || 2515208019Sthompsa wcid == 0) 2516208019Sthompsa continue; 2517203134Sthompsa 2518218676Shselasky /* 2519218676Shselasky * Even though each stat is Tx-complete-status like format, 2520218676Shselasky * the device can poll stats. Because there is no guarantee 2521218676Shselasky * that the referring node is still around when read the stats. 2522218676Shselasky * So that, if we use ieee80211_ratectl_tx_update(), we will 2523218676Shselasky * have hard time not to refer already freed node. 2524218676Shselasky * 2525218676Shselasky * To eliminate such page faults, we poll stats in softc. 2526218676Shselasky * Then, update the rates later with ieee80211_ratectl_tx_update(). 2527218676Shselasky */ 2528218676Shselasky wstat = &(sc->wcid_stats[wcid]); 2529218676Shselasky (*wstat)[RUN_TXCNT]++; 2530218676Shselasky if (stat & RT2860_TXQ_OK) 2531218676Shselasky (*wstat)[RUN_SUCCESS]++; 2532218676Shselasky else 2533287197Sglebius counter_u64_add(sc->sc_ic.ic_oerrors, 1); 2534218676Shselasky /* 2535218676Shselasky * Check if there were retries, ie if the Tx success rate is 2536218676Shselasky * different from the requested rate. Note that it works only 2537218676Shselasky * because we do not allow rate fallback from OFDM to CCK. 2538218676Shselasky */ 2539218676Shselasky mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f; 2540218676Shselasky pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf; 2541218676Shselasky if ((retry = pid -1 - mcs) > 0) { 2542218676Shselasky (*wstat)[RUN_TXCNT] += retry; 2543218676Shselasky (*wstat)[RUN_RETRY] += retry; 2544203134Sthompsa } 2545208019Sthompsa } 2546208019Sthompsa DPRINTFN(3, "count=%d\n", sc->fifo_cnt); 2547208019Sthompsa 2548208019Sthompsa sc->fifo_cnt = 0; 2549208019Sthompsa} 2550208019Sthompsa 2551208019Sthompsastatic void 2552208019Sthompsarun_iter_func(void *arg, struct ieee80211_node *ni) 2553208019Sthompsa{ 2554208019Sthompsa struct run_softc *sc = arg; 2555208019Sthompsa struct ieee80211vap *vap = ni->ni_vap; 2556287552Skevlo struct run_node *rn = RUN_NODE(ni); 2557218676Shselasky union run_stats sta[2]; 2558218676Shselasky uint16_t (*wstat)[3]; 2559218676Shselasky int txcnt, success, retrycnt, error; 2560208019Sthompsa 2561218676Shselasky RUN_LOCK(sc); 2562218676Shselasky 2563262795Shselasky /* Check for special case */ 2564262795Shselasky if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA && 2565262795Shselasky ni != vap->iv_bss) 2566262795Shselasky goto fail; 2567262795Shselasky 2568209917Sthompsa if (sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS || 2569209917Sthompsa vap->iv_opmode == IEEE80211_M_STA)) { 2570203134Sthompsa /* read statistic counters (clear on read) and update AMRR state */ 2571203134Sthompsa error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta, 2572203134Sthompsa sizeof sta); 2573203134Sthompsa if (error != 0) 2574218676Shselasky goto fail; 2575203134Sthompsa 2576203134Sthompsa /* count failed TX as errors */ 2577287197Sglebius if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS, 2578287197Sglebius le16toh(sta[0].error.fail)); 2579203134Sthompsa 2580218676Shselasky retrycnt = le16toh(sta[1].tx.retry); 2581218676Shselasky success = le16toh(sta[1].tx.success); 2582218676Shselasky txcnt = retrycnt + success + le16toh(sta[0].error.fail); 2583203134Sthompsa 2584218676Shselasky DPRINTFN(3, "retrycnt=%d success=%d failcnt=%d\n", 2585218676Shselasky retrycnt, success, le16toh(sta[0].error.fail)); 2586218676Shselasky } else { 2587218676Shselasky wstat = &(sc->wcid_stats[RUN_AID2WCID(ni->ni_associd)]); 2588203134Sthompsa 2589218676Shselasky if (wstat == &(sc->wcid_stats[0]) || 2590218676Shselasky wstat > &(sc->wcid_stats[RT2870_WCID_MAX])) 2591218676Shselasky goto fail; 2592208019Sthompsa 2593218676Shselasky txcnt = (*wstat)[RUN_TXCNT]; 2594218676Shselasky success = (*wstat)[RUN_SUCCESS]; 2595218676Shselasky retrycnt = (*wstat)[RUN_RETRY]; 2596218676Shselasky DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n", 2597218676Shselasky retrycnt, txcnt, success); 2598208019Sthompsa 2599218676Shselasky memset(wstat, 0, sizeof(*wstat)); 2600203134Sthompsa } 2601203134Sthompsa 2602218676Shselasky ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt); 2603208019Sthompsa rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0); 2604218676Shselasky 2605218676Shselaskyfail: 2606218676Shselasky RUN_UNLOCK(sc); 2607218676Shselasky 2608208019Sthompsa DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx); 2609208019Sthompsa} 2610203134Sthompsa 2611208019Sthompsastatic void 2612208019Sthompsarun_newassoc_cb(void *arg) 2613208019Sthompsa{ 2614208019Sthompsa struct run_cmdq *cmdq = arg; 2615208019Sthompsa struct ieee80211_node *ni = cmdq->arg1; 2616286950Sadrian struct run_softc *sc = ni->ni_vap->iv_ic->ic_softc; 2617208019Sthompsa uint8_t wcid = cmdq->wcid; 2618203134Sthompsa 2619208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2620208019Sthompsa 2621208019Sthompsa run_write_region_1(sc, RT2860_WCID_ENTRY(wcid), 2622208019Sthompsa ni->ni_macaddr, IEEE80211_ADDR_LEN); 2623218676Shselasky 2624218676Shselasky memset(&(sc->wcid_stats[wcid]), 0, sizeof(sc->wcid_stats[wcid])); 2625203134Sthompsa} 2626203134Sthompsa 2627203134Sthompsastatic void 2628203134Sthompsarun_newassoc(struct ieee80211_node *ni, int isnew) 2629203134Sthompsa{ 2630287552Skevlo struct run_node *rn = RUN_NODE(ni); 2631203134Sthompsa struct ieee80211_rateset *rs = &ni->ni_rates; 2632208019Sthompsa struct ieee80211vap *vap = ni->ni_vap; 2633208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 2634286950Sadrian struct run_softc *sc = ic->ic_softc; 2635203134Sthompsa uint8_t rate; 2636208019Sthompsa uint8_t ridx; 2637245047Shselasky uint8_t wcid; 2638208019Sthompsa int i, j; 2639203134Sthompsa 2640245047Shselasky wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 2641245047Shselasky 1 : RUN_AID2WCID(ni->ni_associd); 2642245047Shselasky 2643209917Sthompsa if (wcid > RT2870_WCID_MAX) { 2644208019Sthompsa device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid); 2645208019Sthompsa return; 2646208019Sthompsa } 2647203134Sthompsa 2648208019Sthompsa /* only interested in true associations */ 2649209917Sthompsa if (isnew && ni->ni_associd != 0) { 2650208019Sthompsa 2651208019Sthompsa /* 2652208019Sthompsa * This function could is called though timeout function. 2653208019Sthompsa * Need to defer. 2654208019Sthompsa */ 2655208019Sthompsa uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store); 2656208019Sthompsa DPRINTF("cmdq_store=%d\n", cnt); 2657208019Sthompsa sc->cmdq[cnt].func = run_newassoc_cb; 2658208019Sthompsa sc->cmdq[cnt].arg0 = NULL; 2659208019Sthompsa sc->cmdq[cnt].arg1 = ni; 2660208019Sthompsa sc->cmdq[cnt].wcid = wcid; 2661208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2662208019Sthompsa } 2663208019Sthompsa 2664208019Sthompsa DPRINTF("new assoc isnew=%d associd=%x addr=%s\n", 2665208019Sthompsa isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr)); 2666208019Sthompsa 2667203134Sthompsa for (i = 0; i < rs->rs_nrates; i++) { 2668203134Sthompsa rate = rs->rs_rates[i] & IEEE80211_RATE_VAL; 2669203134Sthompsa /* convert 802.11 rate to hardware rate index */ 2670203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2671203134Sthompsa if (rt2860_rates[ridx].rate == rate) 2672203134Sthompsa break; 2673203134Sthompsa rn->ridx[i] = ridx; 2674203134Sthompsa /* determine rate of control response frames */ 2675203134Sthompsa for (j = i; j >= 0; j--) { 2676203134Sthompsa if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) && 2677203134Sthompsa rt2860_rates[rn->ridx[i]].phy == 2678203134Sthompsa rt2860_rates[rn->ridx[j]].phy) 2679203134Sthompsa break; 2680203134Sthompsa } 2681203134Sthompsa if (j >= 0) { 2682203134Sthompsa rn->ctl_ridx[i] = rn->ridx[j]; 2683203134Sthompsa } else { 2684203134Sthompsa /* no basic rate found, use mandatory one */ 2685203134Sthompsa rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx; 2686203134Sthompsa } 2687203134Sthompsa DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n", 2688203134Sthompsa rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]); 2689203134Sthompsa } 2690208019Sthompsa rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate; 2691208019Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2692208019Sthompsa if (rt2860_rates[ridx].rate == rate) 2693208019Sthompsa break; 2694208019Sthompsa rn->mgt_ridx = ridx; 2695208019Sthompsa DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx); 2696208019Sthompsa 2697262795Shselasky RUN_LOCK(sc); 2698262795Shselasky if(sc->ratectl_run != RUN_RATECTL_OFF) 2699262795Shselasky usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2700262795Shselasky RUN_UNLOCK(sc); 2701203134Sthompsa} 2702203134Sthompsa 2703203134Sthompsa/* 2704203134Sthompsa * Return the Rx chain with the highest RSSI for a given frame. 2705203134Sthompsa */ 2706203134Sthompsastatic __inline uint8_t 2707203134Sthompsarun_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi) 2708203134Sthompsa{ 2709203134Sthompsa uint8_t rxchain = 0; 2710203134Sthompsa 2711203134Sthompsa if (sc->nrxchains > 1) { 2712203134Sthompsa if (rxwi->rssi[1] > rxwi->rssi[rxchain]) 2713203134Sthompsa rxchain = 1; 2714203134Sthompsa if (sc->nrxchains > 2) 2715203134Sthompsa if (rxwi->rssi[2] > rxwi->rssi[rxchain]) 2716203134Sthompsa rxchain = 2; 2717203134Sthompsa } 2718209917Sthompsa return (rxchain); 2719203134Sthompsa} 2720203134Sthompsa 2721203134Sthompsastatic void 2722288603Sadrianrun_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, 2723288603Sadrian const struct ieee80211_rx_stats *rxs, int rssi, int nf) 2724288603Sadrian{ 2725288603Sadrian struct ieee80211vap *vap = ni->ni_vap; 2726288603Sadrian struct run_softc *sc = vap->iv_ic->ic_softc; 2727288603Sadrian struct run_vap *rvp = RUN_VAP(vap); 2728288603Sadrian uint64_t ni_tstamp, rx_tstamp; 2729288603Sadrian 2730288603Sadrian rvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf); 2731288603Sadrian 2732288603Sadrian if (vap->iv_state == IEEE80211_S_RUN && 2733288603Sadrian (subtype == IEEE80211_FC0_SUBTYPE_BEACON || 2734288603Sadrian subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) { 2735288603Sadrian ni_tstamp = le64toh(ni->ni_tstamp.tsf); 2736288603Sadrian RUN_LOCK(sc); 2737288603Sadrian run_get_tsf(sc, &rx_tstamp); 2738288603Sadrian RUN_UNLOCK(sc); 2739288603Sadrian rx_tstamp = le64toh(rx_tstamp); 2740288603Sadrian 2741288603Sadrian if (ni_tstamp >= rx_tstamp) { 2742288603Sadrian DPRINTF("ibss merge, tsf %ju tstamp %ju\n", 2743288603Sadrian (uintmax_t)rx_tstamp, (uintmax_t)ni_tstamp); 2744288603Sadrian (void) ieee80211_ibss_merge(ni); 2745288603Sadrian } 2746288603Sadrian } 2747288603Sadrian} 2748288603Sadrian 2749288603Sadrianstatic void 2750203134Sthompsarun_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) 2751203134Sthompsa{ 2752287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2753203134Sthompsa struct ieee80211_frame *wh; 2754203134Sthompsa struct ieee80211_node *ni; 2755203134Sthompsa struct rt2870_rxd *rxd; 2756203134Sthompsa struct rt2860_rxwi *rxwi; 2757203134Sthompsa uint32_t flags; 2758259032Skevlo uint16_t len, rxwisize; 2759203134Sthompsa uint8_t ant, rssi; 2760203134Sthompsa int8_t nf; 2761203134Sthompsa 2762203134Sthompsa rxwi = mtod(m, struct rt2860_rxwi *); 2763203134Sthompsa len = le16toh(rxwi->len) & 0xfff; 2764260219Skevlo rxwisize = sizeof(struct rt2860_rxwi); 2765260219Skevlo if (sc->mac_ver == 0x5592) 2766260219Skevlo rxwisize += sizeof(uint64_t); 2767260219Skevlo else if (sc->mac_ver == 0x3593) 2768260219Skevlo rxwisize += sizeof(uint32_t); 2769203134Sthompsa if (__predict_false(len > dmalen)) { 2770203134Sthompsa m_freem(m); 2771287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 2772203134Sthompsa DPRINTF("bad RXWI length %u > %u\n", len, dmalen); 2773203134Sthompsa return; 2774203134Sthompsa } 2775203134Sthompsa /* Rx descriptor is located at the end */ 2776203134Sthompsa rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen); 2777203134Sthompsa flags = le32toh(rxd->flags); 2778203134Sthompsa 2779203134Sthompsa if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) { 2780203134Sthompsa m_freem(m); 2781287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 2782203134Sthompsa DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV"); 2783203134Sthompsa return; 2784203134Sthompsa } 2785203134Sthompsa 2786259032Skevlo m->m_data += rxwisize; 2787259032Skevlo m->m_pkthdr.len = m->m_len -= rxwisize; 2788203134Sthompsa 2789203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 2790203134Sthompsa 2791260444Skevlo if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 2792260444Skevlo wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; 2793203134Sthompsa m->m_flags |= M_WEP; 2794203134Sthompsa } 2795203134Sthompsa 2796209917Sthompsa if (flags & RT2860_RX_L2PAD) { 2797203134Sthompsa DPRINTFN(8, "received RT2860_RX_L2PAD frame\n"); 2798203134Sthompsa len += 2; 2799203134Sthompsa } 2800203134Sthompsa 2801208019Sthompsa ni = ieee80211_find_rxnode(ic, 2802208019Sthompsa mtod(m, struct ieee80211_frame_min *)); 2803208019Sthompsa 2804203134Sthompsa if (__predict_false(flags & RT2860_RX_MICERR)) { 2805203134Sthompsa /* report MIC failures to net80211 for TKIP */ 2806209917Sthompsa if (ni != NULL) 2807259032Skevlo ieee80211_notify_michael_failure(ni->ni_vap, wh, 2808259032Skevlo rxwi->keyidx); 2809203134Sthompsa m_freem(m); 2810287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 2811203134Sthompsa DPRINTF("MIC error. Someone is lying.\n"); 2812203134Sthompsa return; 2813203134Sthompsa } 2814203134Sthompsa 2815203134Sthompsa ant = run_maxrssi_chain(sc, rxwi); 2816203134Sthompsa rssi = rxwi->rssi[ant]; 2817203134Sthompsa nf = run_rssi2dbm(sc, rssi, ant); 2818203134Sthompsa 2819203134Sthompsa m->m_pkthdr.len = m->m_len = len; 2820203134Sthompsa 2821209917Sthompsa if (__predict_false(ieee80211_radiotap_active(ic))) { 2822203134Sthompsa struct run_rx_radiotap_header *tap = &sc->sc_rxtap; 2823258643Shselasky uint16_t phy; 2824203134Sthompsa 2825203134Sthompsa tap->wr_flags = 0; 2826236439Shselasky tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); 2827236439Shselasky tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); 2828203134Sthompsa tap->wr_antsignal = rssi; 2829203134Sthompsa tap->wr_antenna = ant; 2830203134Sthompsa tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant); 2831203134Sthompsa tap->wr_rate = 2; /* in case it can't be found below */ 2832301302Sadrian RUN_LOCK(sc); 2833287554Skevlo run_get_tsf(sc, &tap->wr_tsf); 2834301302Sadrian RUN_UNLOCK(sc); 2835203134Sthompsa phy = le16toh(rxwi->phy); 2836203134Sthompsa switch (phy & RT2860_PHY_MODE) { 2837203134Sthompsa case RT2860_PHY_CCK: 2838203134Sthompsa switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) { 2839203134Sthompsa case 0: tap->wr_rate = 2; break; 2840203134Sthompsa case 1: tap->wr_rate = 4; break; 2841203134Sthompsa case 2: tap->wr_rate = 11; break; 2842203134Sthompsa case 3: tap->wr_rate = 22; break; 2843203134Sthompsa } 2844203134Sthompsa if (phy & RT2860_PHY_SHPRE) 2845203134Sthompsa tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 2846203134Sthompsa break; 2847203134Sthompsa case RT2860_PHY_OFDM: 2848203134Sthompsa switch (phy & RT2860_PHY_MCS) { 2849203134Sthompsa case 0: tap->wr_rate = 12; break; 2850203134Sthompsa case 1: tap->wr_rate = 18; break; 2851203134Sthompsa case 2: tap->wr_rate = 24; break; 2852203134Sthompsa case 3: tap->wr_rate = 36; break; 2853203134Sthompsa case 4: tap->wr_rate = 48; break; 2854203134Sthompsa case 5: tap->wr_rate = 72; break; 2855203134Sthompsa case 6: tap->wr_rate = 96; break; 2856203134Sthompsa case 7: tap->wr_rate = 108; break; 2857203134Sthompsa } 2858203134Sthompsa break; 2859203134Sthompsa } 2860203134Sthompsa } 2861289753Savos 2862289753Savos if (ni != NULL) { 2863289753Savos (void)ieee80211_input(ni, m, rssi, nf); 2864289753Savos ieee80211_free_node(ni); 2865289753Savos } else { 2866289753Savos (void)ieee80211_input_all(ic, m, rssi, nf); 2867289753Savos } 2868203134Sthompsa} 2869203134Sthompsa 2870203134Sthompsastatic void 2871203134Sthompsarun_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) 2872203134Sthompsa{ 2873203134Sthompsa struct run_softc *sc = usbd_xfer_softc(xfer); 2874287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2875203134Sthompsa struct mbuf *m = NULL; 2876203134Sthompsa struct mbuf *m0; 2877203134Sthompsa uint32_t dmalen; 2878259032Skevlo uint16_t rxwisize; 2879203134Sthompsa int xferlen; 2880203134Sthompsa 2881260219Skevlo rxwisize = sizeof(struct rt2860_rxwi); 2882260219Skevlo if (sc->mac_ver == 0x5592) 2883260219Skevlo rxwisize += sizeof(uint64_t); 2884260219Skevlo else if (sc->mac_ver == 0x3593) 2885260219Skevlo rxwisize += sizeof(uint32_t); 2886259032Skevlo 2887203134Sthompsa usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL); 2888203134Sthompsa 2889203134Sthompsa switch (USB_GET_STATE(xfer)) { 2890203134Sthompsa case USB_ST_TRANSFERRED: 2891203134Sthompsa 2892203134Sthompsa DPRINTFN(15, "rx done, actlen=%d\n", xferlen); 2893203134Sthompsa 2894259032Skevlo if (xferlen < (int)(sizeof(uint32_t) + rxwisize + 2895259032Skevlo sizeof(struct rt2870_rxd))) { 2896203134Sthompsa DPRINTF("xfer too short %d\n", xferlen); 2897203134Sthompsa goto tr_setup; 2898203134Sthompsa } 2899203134Sthompsa 2900203134Sthompsa m = sc->rx_m; 2901203134Sthompsa sc->rx_m = NULL; 2902203134Sthompsa 2903203134Sthompsa /* FALLTHROUGH */ 2904203134Sthompsa case USB_ST_SETUP: 2905203134Sthompsatr_setup: 2906203134Sthompsa if (sc->rx_m == NULL) { 2907243857Sglebius sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, 2908203134Sthompsa MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */); 2909203134Sthompsa } 2910203134Sthompsa if (sc->rx_m == NULL) { 2911203134Sthompsa DPRINTF("could not allocate mbuf - idle with stall\n"); 2912287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 2913203134Sthompsa usbd_xfer_set_stall(xfer); 2914203134Sthompsa usbd_xfer_set_frames(xfer, 0); 2915203134Sthompsa } else { 2916203134Sthompsa /* 2917203134Sthompsa * Directly loading a mbuf cluster into DMA to 2918203134Sthompsa * save some data copying. This works because 2919203134Sthompsa * there is only one cluster. 2920203134Sthompsa */ 2921203134Sthompsa usbd_xfer_set_frame_data(xfer, 0, 2922203134Sthompsa mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ); 2923203134Sthompsa usbd_xfer_set_frames(xfer, 1); 2924203134Sthompsa } 2925203134Sthompsa usbd_transfer_submit(xfer); 2926203134Sthompsa break; 2927203134Sthompsa 2928203134Sthompsa default: /* Error */ 2929203134Sthompsa if (error != USB_ERR_CANCELLED) { 2930203134Sthompsa /* try to clear stall first */ 2931203134Sthompsa usbd_xfer_set_stall(xfer); 2932203134Sthompsa if (error == USB_ERR_TIMEOUT) 2933203134Sthompsa device_printf(sc->sc_dev, "device timeout\n"); 2934287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 2935203134Sthompsa goto tr_setup; 2936203134Sthompsa } 2937209917Sthompsa if (sc->rx_m != NULL) { 2938203134Sthompsa m_freem(sc->rx_m); 2939203134Sthompsa sc->rx_m = NULL; 2940203134Sthompsa } 2941203134Sthompsa break; 2942203134Sthompsa } 2943203134Sthompsa 2944203134Sthompsa if (m == NULL) 2945203134Sthompsa return; 2946203134Sthompsa 2947203134Sthompsa /* inputting all the frames must be last */ 2948203134Sthompsa 2949203134Sthompsa RUN_UNLOCK(sc); 2950203134Sthompsa 2951203134Sthompsa m->m_pkthdr.len = m->m_len = xferlen; 2952203134Sthompsa 2953203134Sthompsa /* HW can aggregate multiple 802.11 frames in a single USB xfer */ 2954203134Sthompsa for(;;) { 2955203134Sthompsa dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff; 2956203134Sthompsa 2957233774Shselasky if ((dmalen >= (uint32_t)-8) || (dmalen == 0) || 2958233774Shselasky ((dmalen & 3) != 0)) { 2959203134Sthompsa DPRINTF("bad DMA length %u\n", dmalen); 2960203134Sthompsa break; 2961203134Sthompsa } 2962233774Shselasky if ((dmalen + 8) > (uint32_t)xferlen) { 2963203134Sthompsa DPRINTF("bad DMA length %u > %d\n", 2964203134Sthompsa dmalen + 8, xferlen); 2965203134Sthompsa break; 2966203134Sthompsa } 2967203134Sthompsa 2968203134Sthompsa /* If it is the last one or a single frame, we won't copy. */ 2969209917Sthompsa if ((xferlen -= dmalen + 8) <= 8) { 2970203134Sthompsa /* trim 32-bit DMA-len header */ 2971203134Sthompsa m->m_data += 4; 2972203134Sthompsa m->m_pkthdr.len = m->m_len -= 4; 2973203134Sthompsa run_rx_frame(sc, m, dmalen); 2974257435Shselasky m = NULL; /* don't free source buffer */ 2975203134Sthompsa break; 2976203134Sthompsa } 2977203134Sthompsa 2978203134Sthompsa /* copy aggregated frames to another mbuf */ 2979243857Sglebius m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 2980203134Sthompsa if (__predict_false(m0 == NULL)) { 2981203134Sthompsa DPRINTF("could not allocate mbuf\n"); 2982287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 2983203134Sthompsa break; 2984203134Sthompsa } 2985203134Sthompsa m_copydata(m, 4 /* skip 32-bit DMA-len header */, 2986203134Sthompsa dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t)); 2987203134Sthompsa m0->m_pkthdr.len = m0->m_len = 2988203134Sthompsa dmalen + sizeof(struct rt2870_rxd); 2989203134Sthompsa run_rx_frame(sc, m0, dmalen); 2990203134Sthompsa 2991203134Sthompsa /* update data ptr */ 2992203134Sthompsa m->m_data += dmalen + 8; 2993203134Sthompsa m->m_pkthdr.len = m->m_len -= dmalen + 8; 2994203134Sthompsa } 2995203134Sthompsa 2996257435Shselasky /* make sure we free the source buffer, if any */ 2997257435Shselasky m_freem(m); 2998257435Shselasky 2999203134Sthompsa RUN_LOCK(sc); 3000203134Sthompsa} 3001203134Sthompsa 3002203134Sthompsastatic void 3003203134Sthompsarun_tx_free(struct run_endpoint_queue *pq, 3004203134Sthompsa struct run_tx_data *data, int txerr) 3005203134Sthompsa{ 3006203134Sthompsa 3007289841Savos ieee80211_tx_complete(data->ni, data->m, txerr); 3008203134Sthompsa 3009289841Savos data->m = NULL; 3010289841Savos data->ni = NULL; 3011289841Savos 3012203134Sthompsa STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); 3013203134Sthompsa pq->tx_nfree++; 3014203134Sthompsa} 3015203134Sthompsa 3016203134Sthompsastatic void 3017257429Shselaskyrun_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index) 3018203134Sthompsa{ 3019203134Sthompsa struct run_softc *sc = usbd_xfer_softc(xfer); 3020287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3021203134Sthompsa struct run_tx_data *data; 3022203134Sthompsa struct ieee80211vap *vap = NULL; 3023203134Sthompsa struct usb_page_cache *pc; 3024203134Sthompsa struct run_endpoint_queue *pq = &sc->sc_epq[index]; 3025203134Sthompsa struct mbuf *m; 3026203134Sthompsa usb_frlength_t size; 3027203134Sthompsa int actlen; 3028203134Sthompsa int sumlen; 3029203134Sthompsa 3030203134Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 3031203134Sthompsa 3032209917Sthompsa switch (USB_GET_STATE(xfer)) { 3033203134Sthompsa case USB_ST_TRANSFERRED: 3034203134Sthompsa DPRINTFN(11, "transfer complete: %d " 3035203134Sthompsa "bytes @ index %d\n", actlen, index); 3036203134Sthompsa 3037203134Sthompsa data = usbd_xfer_get_priv(xfer); 3038203134Sthompsa run_tx_free(pq, data, 0); 3039203134Sthompsa usbd_xfer_set_priv(xfer, NULL); 3040203134Sthompsa 3041203134Sthompsa /* FALLTHROUGH */ 3042203134Sthompsa case USB_ST_SETUP: 3043203134Sthompsatr_setup: 3044203134Sthompsa data = STAILQ_FIRST(&pq->tx_qh); 3045209917Sthompsa if (data == NULL) 3046203134Sthompsa break; 3047203134Sthompsa 3048203134Sthompsa STAILQ_REMOVE_HEAD(&pq->tx_qh, next); 3049203134Sthompsa 3050203134Sthompsa m = data->m; 3051261330Shselasky size = (sc->mac_ver == 0x5592) ? 3052261330Shselasky sizeof(data->desc) + sizeof(uint32_t) : sizeof(data->desc); 3053261076Shselasky if ((m->m_pkthdr.len + 3054261330Shselasky size + 3 + 8) > RUN_MAX_TXSZ) { 3055203134Sthompsa DPRINTF("data overflow, %u bytes\n", 3056203134Sthompsa m->m_pkthdr.len); 3057203134Sthompsa run_tx_free(pq, data, 1); 3058203134Sthompsa goto tr_setup; 3059203134Sthompsa } 3060203134Sthompsa 3061203134Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 3062203134Sthompsa usbd_copy_in(pc, 0, &data->desc, size); 3063203134Sthompsa usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len); 3064228508Shselasky size += m->m_pkthdr.len; 3065228508Shselasky /* 3066228508Shselasky * Align end on a 4-byte boundary, pad 8 bytes (CRC + 3067228508Shselasky * 4-byte padding), and be sure to zero those trailing 3068228508Shselasky * bytes: 3069228508Shselasky */ 3070228508Shselasky usbd_frame_zero(pc, size, ((-size) & 3) + 8); 3071228508Shselasky size += ((-size) & 3) + 8; 3072203134Sthompsa 3073203134Sthompsa vap = data->ni->ni_vap; 3074203134Sthompsa if (ieee80211_radiotap_active_vap(vap)) { 3075203134Sthompsa struct run_tx_radiotap_header *tap = &sc->sc_txtap; 3076259032Skevlo struct rt2860_txwi *txwi = 3077208019Sthompsa (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd)); 3078203134Sthompsa tap->wt_flags = 0; 3079203134Sthompsa tap->wt_rate = rt2860_rates[data->ridx].rate; 3080287554Skevlo run_get_tsf(sc, &tap->wt_tsf); 3081236439Shselasky tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 3082236439Shselasky tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 3083203134Sthompsa tap->wt_hwqueue = index; 3084208019Sthompsa if (le16toh(txwi->phy) & RT2860_PHY_SHPRE) 3085203134Sthompsa tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 3086203134Sthompsa 3087203134Sthompsa ieee80211_radiotap_tx(vap, m); 3088203134Sthompsa } 3089203134Sthompsa 3090228508Shselasky DPRINTFN(11, "sending frame len=%u/%u @ index %d\n", 3091228508Shselasky m->m_pkthdr.len, size, index); 3092203134Sthompsa 3093228508Shselasky usbd_xfer_set_frame_len(xfer, 0, size); 3094203134Sthompsa usbd_xfer_set_priv(xfer, data); 3095203134Sthompsa usbd_transfer_submit(xfer); 3096287197Sglebius run_start(sc); 3097203134Sthompsa 3098203134Sthompsa break; 3099203134Sthompsa 3100203134Sthompsa default: 3101203134Sthompsa DPRINTF("USB transfer error, %s\n", 3102203134Sthompsa usbd_errstr(error)); 3103203134Sthompsa 3104203134Sthompsa data = usbd_xfer_get_priv(xfer); 3105203134Sthompsa 3106203134Sthompsa if (data != NULL) { 3107208019Sthompsa if(data->ni != NULL) 3108208019Sthompsa vap = data->ni->ni_vap; 3109203134Sthompsa run_tx_free(pq, data, error); 3110203134Sthompsa usbd_xfer_set_priv(xfer, NULL); 3111203134Sthompsa } 3112287197Sglebius 3113209917Sthompsa if (vap == NULL) 3114208019Sthompsa vap = TAILQ_FIRST(&ic->ic_vaps); 3115203134Sthompsa 3116203134Sthompsa if (error != USB_ERR_CANCELLED) { 3117203134Sthompsa if (error == USB_ERR_TIMEOUT) { 3118203134Sthompsa device_printf(sc->sc_dev, "device timeout\n"); 3119208019Sthompsa uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 3120208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 3121208019Sthompsa sc->cmdq[i].func = run_usb_timeout_cb; 3122208019Sthompsa sc->cmdq[i].arg0 = vap; 3123208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 3124203134Sthompsa } 3125203134Sthompsa 3126203134Sthompsa /* 3127203134Sthompsa * Try to clear stall first, also if other 3128203134Sthompsa * errors occur, hence clearing stall 3129203134Sthompsa * introduces a 50 ms delay: 3130203134Sthompsa */ 3131203134Sthompsa usbd_xfer_set_stall(xfer); 3132203134Sthompsa goto tr_setup; 3133203134Sthompsa } 3134203134Sthompsa break; 3135203134Sthompsa } 3136203134Sthompsa} 3137203134Sthompsa 3138203134Sthompsastatic void 3139203134Sthompsarun_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error) 3140203134Sthompsa{ 3141203134Sthompsa run_bulk_tx_callbackN(xfer, error, 0); 3142203134Sthompsa} 3143203134Sthompsa 3144203134Sthompsastatic void 3145203134Sthompsarun_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error) 3146203134Sthompsa{ 3147203134Sthompsa run_bulk_tx_callbackN(xfer, error, 1); 3148203134Sthompsa} 3149203134Sthompsa 3150203134Sthompsastatic void 3151203134Sthompsarun_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error) 3152203134Sthompsa{ 3153203134Sthompsa run_bulk_tx_callbackN(xfer, error, 2); 3154203134Sthompsa} 3155203134Sthompsa 3156203134Sthompsastatic void 3157203134Sthompsarun_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error) 3158203134Sthompsa{ 3159203134Sthompsa run_bulk_tx_callbackN(xfer, error, 3); 3160203134Sthompsa} 3161203134Sthompsa 3162203134Sthompsastatic void 3163203134Sthompsarun_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error) 3164203134Sthompsa{ 3165203134Sthompsa run_bulk_tx_callbackN(xfer, error, 4); 3166203134Sthompsa} 3167203134Sthompsa 3168203134Sthompsastatic void 3169203134Sthompsarun_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error) 3170203134Sthompsa{ 3171203134Sthompsa run_bulk_tx_callbackN(xfer, error, 5); 3172203134Sthompsa} 3173203134Sthompsa 3174203134Sthompsastatic void 3175208019Sthompsarun_set_tx_desc(struct run_softc *sc, struct run_tx_data *data) 3176203134Sthompsa{ 3177203134Sthompsa struct mbuf *m = data->m; 3178287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3179208019Sthompsa struct ieee80211vap *vap = data->ni->ni_vap; 3180203134Sthompsa struct ieee80211_frame *wh; 3181203134Sthompsa struct rt2870_txd *txd; 3182203134Sthompsa struct rt2860_txwi *txwi; 3183259032Skevlo uint16_t xferlen, txwisize; 3184208019Sthompsa uint16_t mcs; 3185203134Sthompsa uint8_t ridx = data->ridx; 3186208019Sthompsa uint8_t pad; 3187203134Sthompsa 3188203134Sthompsa /* get MCS code from rate index */ 3189208019Sthompsa mcs = rt2860_rates[ridx].mcs; 3190203134Sthompsa 3191259032Skevlo txwisize = (sc->mac_ver == 0x5592) ? 3192259032Skevlo sizeof(*txwi) + sizeof(uint32_t) : sizeof(*txwi); 3193259032Skevlo xferlen = txwisize + m->m_pkthdr.len; 3194203134Sthompsa 3195203134Sthompsa /* roundup to 32-bit alignment */ 3196203134Sthompsa xferlen = (xferlen + 3) & ~3; 3197203134Sthompsa 3198203134Sthompsa txd = (struct rt2870_txd *)&data->desc; 3199203134Sthompsa txd->len = htole16(xferlen); 3200203134Sthompsa 3201208019Sthompsa wh = mtod(m, struct ieee80211_frame *); 3202208019Sthompsa 3203208019Sthompsa /* 3204208019Sthompsa * Ether both are true or both are false, the header 3205208019Sthompsa * are nicely aligned to 32-bit. So, no L2 padding. 3206208019Sthompsa */ 3207208019Sthompsa if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh)) 3208208019Sthompsa pad = 0; 3209208019Sthompsa else 3210208019Sthompsa pad = 2; 3211208019Sthompsa 3212203134Sthompsa /* setup TX Wireless Information */ 3213203134Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3214203134Sthompsa txwi->len = htole16(m->m_pkthdr.len - pad); 3215203134Sthompsa if (rt2860_rates[ridx].phy == IEEE80211_T_DS) { 3216270192Skevlo mcs |= RT2860_PHY_CCK; 3217203134Sthompsa if (ridx != RT2860_RIDX_CCK1 && 3218203134Sthompsa (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 3219203134Sthompsa mcs |= RT2860_PHY_SHPRE; 3220203134Sthompsa } else 3221270192Skevlo mcs |= RT2860_PHY_OFDM; 3222270192Skevlo txwi->phy = htole16(mcs); 3223203134Sthompsa 3224203134Sthompsa /* check if RTS/CTS or CTS-to-self protection is required */ 3225203134Sthompsa if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 3226203134Sthompsa (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold || 3227203134Sthompsa ((ic->ic_flags & IEEE80211_F_USEPROT) && 3228203134Sthompsa rt2860_rates[ridx].phy == IEEE80211_T_OFDM))) 3229208019Sthompsa txwi->txop |= RT2860_TX_TXOP_HT; 3230203134Sthompsa else 3231208019Sthompsa txwi->txop |= RT2860_TX_TXOP_BACKOFF; 3232209144Sthompsa 3233209917Sthompsa if (vap->iv_opmode != IEEE80211_M_STA && !IEEE80211_QOS_HAS_SEQ(wh)) 3234209144Sthompsa txwi->xflags |= RT2860_TX_NSEQ; 3235203134Sthompsa} 3236203134Sthompsa 3237203134Sthompsa/* This function must be called locked */ 3238203134Sthompsastatic int 3239203134Sthompsarun_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) 3240203134Sthompsa{ 3241287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3242208019Sthompsa struct ieee80211vap *vap = ni->ni_vap; 3243203134Sthompsa struct ieee80211_frame *wh; 3244208019Sthompsa struct ieee80211_channel *chan; 3245203134Sthompsa const struct ieee80211_txparam *tp; 3246287552Skevlo struct run_node *rn = RUN_NODE(ni); 3247203134Sthompsa struct run_tx_data *data; 3248208019Sthompsa struct rt2870_txd *txd; 3249208019Sthompsa struct rt2860_txwi *txwi; 3250203134Sthompsa uint16_t qos; 3251203134Sthompsa uint16_t dur; 3252208019Sthompsa uint16_t qid; 3253203134Sthompsa uint8_t type; 3254203134Sthompsa uint8_t tid; 3255208019Sthompsa uint8_t ridx; 3256208019Sthompsa uint8_t ctl_ridx; 3257203134Sthompsa uint8_t qflags; 3258203134Sthompsa uint8_t xflags = 0; 3259203134Sthompsa int hasqos; 3260203134Sthompsa 3261203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3262203134Sthompsa 3263203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3264203134Sthompsa 3265203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3266203134Sthompsa 3267203134Sthompsa /* 3268203134Sthompsa * There are 7 bulk endpoints: 1 for RX 3269203134Sthompsa * and 6 for TX (4 EDCAs + HCCA + Prio). 3270203134Sthompsa * Update 03-14-2009: some devices like the Planex GW-US300MiniS 3271203134Sthompsa * seem to have only 4 TX bulk endpoints (Fukaumi Naoki). 3272203134Sthompsa */ 3273203134Sthompsa if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) { 3274203134Sthompsa uint8_t *frm; 3275203134Sthompsa 3276203134Sthompsa if(IEEE80211_HAS_ADDR4(wh)) 3277203134Sthompsa frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos; 3278203134Sthompsa else 3279203134Sthompsa frm =((struct ieee80211_qosframe *)wh)->i_qos; 3280203134Sthompsa 3281203134Sthompsa qos = le16toh(*(const uint16_t *)frm); 3282203134Sthompsa tid = qos & IEEE80211_QOS_TID; 3283203134Sthompsa qid = TID_TO_WME_AC(tid); 3284203134Sthompsa } else { 3285203134Sthompsa qos = 0; 3286203134Sthompsa tid = 0; 3287203134Sthompsa qid = WME_AC_BE; 3288203134Sthompsa } 3289203134Sthompsa qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA; 3290203134Sthompsa 3291203134Sthompsa DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n", 3292203134Sthompsa qos, qid, tid, qflags); 3293203134Sthompsa 3294208019Sthompsa chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan; 3295208019Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(chan)]; 3296203134Sthompsa 3297203134Sthompsa /* pickup a rate index */ 3298203134Sthompsa if (IEEE80211_IS_MULTICAST(wh->i_addr1) || 3299270192Skevlo type != IEEE80211_FC0_TYPE_DATA || m->m_flags & M_EAPOL) { 3300203134Sthompsa ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? 3301203134Sthompsa RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; 3302203134Sthompsa ctl_ridx = rt2860_rates[ridx].ctl_ridx; 3303203134Sthompsa } else { 3304208019Sthompsa if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) 3305208019Sthompsa ridx = rn->fix_ridx; 3306208019Sthompsa else 3307208019Sthompsa ridx = rn->amrr_ridx; 3308203134Sthompsa ctl_ridx = rt2860_rates[ridx].ctl_ridx; 3309203134Sthompsa } 3310203134Sthompsa 3311203134Sthompsa if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 3312203134Sthompsa (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) != 3313203134Sthompsa IEEE80211_QOS_ACKPOLICY_NOACK)) { 3314209144Sthompsa xflags |= RT2860_TX_ACK; 3315203134Sthompsa if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 3316208019Sthompsa dur = rt2860_rates[ctl_ridx].sp_ack_dur; 3317203134Sthompsa else 3318208019Sthompsa dur = rt2860_rates[ctl_ridx].lp_ack_dur; 3319258919Shselasky USETW(wh->i_dur, dur); 3320203134Sthompsa } 3321203134Sthompsa 3322203134Sthompsa /* reserve slots for mgmt packets, just in case */ 3323203134Sthompsa if (sc->sc_epq[qid].tx_nfree < 3) { 3324203134Sthompsa DPRINTFN(10, "tx ring %d is full\n", qid); 3325203134Sthompsa return (-1); 3326203134Sthompsa } 3327203134Sthompsa 3328203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh); 3329203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next); 3330203134Sthompsa sc->sc_epq[qid].tx_nfree--; 3331203134Sthompsa 3332208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3333208019Sthompsa txd->flags = qflags; 3334208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3335208019Sthompsa txwi->xflags = xflags; 3336259032Skevlo if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 3337245047Shselasky txwi->wcid = 0; 3338259032Skevlo else 3339245047Shselasky txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 3340245047Shselasky 1 : RUN_AID2WCID(ni->ni_associd); 3341259032Skevlo 3342208019Sthompsa /* clear leftover garbage bits */ 3343208019Sthompsa txwi->flags = 0; 3344208019Sthompsa txwi->txop = 0; 3345208019Sthompsa 3346203134Sthompsa data->m = m; 3347203134Sthompsa data->ni = ni; 3348203134Sthompsa data->ridx = ridx; 3349203134Sthompsa 3350208019Sthompsa run_set_tx_desc(sc, data); 3351203134Sthompsa 3352208019Sthompsa /* 3353208019Sthompsa * The chip keeps track of 2 kind of Tx stats, 3354208019Sthompsa * * TX_STAT_FIFO, for per WCID stats, and 3355208019Sthompsa * * TX_STA_CNT0 for all-TX-in-one stats. 3356208019Sthompsa * 3357208019Sthompsa * To use FIFO stats, we need to store MCS into the driver-private 3358208019Sthompsa * PacketID field. So that, we can tell whose stats when we read them. 3359208019Sthompsa * We add 1 to the MCS because setting the PacketID field to 0 means 3360208019Sthompsa * that we don't want feedback in TX_STAT_FIFO. 3361208019Sthompsa * And, that's what we want for STA mode, since TX_STA_CNT0 does the job. 3362208019Sthompsa * 3363208019Sthompsa * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx(). 3364208019Sthompsa */ 3365209917Sthompsa if (sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP || 3366209917Sthompsa vap->iv_opmode == IEEE80211_M_MBSS) { 3367208019Sthompsa uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf; 3368208019Sthompsa txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT); 3369208019Sthompsa 3370208019Sthompsa /* 3371208019Sthompsa * Unlike PCI based devices, we don't get any interrupt from 3372208019Sthompsa * USB devices, so we simulate FIFO-is-full interrupt here. 3373298932Spfg * Ralink recommends to drain FIFO stats every 100 ms, but 16 slots 3374208019Sthompsa * quickly get fulled. To prevent overflow, increment a counter on 3375208019Sthompsa * every FIFO stat request, so we know how many slots are left. 3376208019Sthompsa * We do this only in HOSTAP or multiple vap mode since FIFO stats 3377208019Sthompsa * are used only in those modes. 3378208019Sthompsa * We just drain stats. AMRR gets updated every 1 sec by 3379208019Sthompsa * run_ratectl_cb() via callout. 3380208019Sthompsa * Call it early. Otherwise overflow. 3381208019Sthompsa */ 3382209917Sthompsa if (sc->fifo_cnt++ == 10) { 3383208019Sthompsa /* 3384208019Sthompsa * With multiple vaps or if_bridge, if_start() is called 3385208019Sthompsa * with a non-sleepable lock, tcpinp. So, need to defer. 3386208019Sthompsa */ 3387208019Sthompsa uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 3388208019Sthompsa DPRINTFN(6, "cmdq_store=%d\n", i); 3389208019Sthompsa sc->cmdq[i].func = run_drain_fifo; 3390208019Sthompsa sc->cmdq[i].arg0 = sc; 3391208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 3392208019Sthompsa } 3393208019Sthompsa } 3394208019Sthompsa 3395203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next); 3396203134Sthompsa 3397203134Sthompsa usbd_transfer_start(sc->sc_xfer[qid]); 3398203134Sthompsa 3399258840Skevlo DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n", 3400259032Skevlo m->m_pkthdr.len + (int)(sizeof(struct rt2870_txd) + 3401259046Shselasky sizeof(struct rt2860_txwi)), rt2860_rates[ridx].rate, qid); 3402203134Sthompsa 3403203134Sthompsa return (0); 3404203134Sthompsa} 3405203134Sthompsa 3406203134Sthompsastatic int 3407203134Sthompsarun_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) 3408203134Sthompsa{ 3409287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3410287552Skevlo struct run_node *rn = RUN_NODE(ni); 3411203134Sthompsa struct run_tx_data *data; 3412203134Sthompsa struct ieee80211_frame *wh; 3413208019Sthompsa struct rt2870_txd *txd; 3414208019Sthompsa struct rt2860_txwi *txwi; 3415203134Sthompsa uint16_t dur; 3416208019Sthompsa uint8_t ridx = rn->mgt_ridx; 3417203134Sthompsa uint8_t type; 3418203134Sthompsa uint8_t xflags = 0; 3419208019Sthompsa uint8_t wflags = 0; 3420203134Sthompsa 3421203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3422203134Sthompsa 3423203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3424203134Sthompsa 3425203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3426203134Sthompsa 3427208019Sthompsa /* tell hardware to add timestamp for probe responses */ 3428208019Sthompsa if ((wh->i_fc[0] & 3429208019Sthompsa (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == 3430208019Sthompsa (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) 3431208019Sthompsa wflags |= RT2860_TX_TS; 3432208019Sthompsa else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 3433203134Sthompsa xflags |= RT2860_TX_ACK; 3434203134Sthompsa 3435208019Sthompsa dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate, 3436203134Sthompsa ic->ic_flags & IEEE80211_F_SHPREAMBLE); 3437258919Shselasky USETW(wh->i_dur, dur); 3438203134Sthompsa } 3439203134Sthompsa 3440287197Sglebius if (sc->sc_epq[0].tx_nfree == 0) 3441203134Sthompsa /* let caller free mbuf */ 3442203134Sthompsa return (EIO); 3443203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3444203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3445203134Sthompsa sc->sc_epq[0].tx_nfree--; 3446203134Sthompsa 3447208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3448208019Sthompsa txd->flags = RT2860_TX_QSEL_EDCA; 3449208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3450208019Sthompsa txwi->wcid = 0xff; 3451208019Sthompsa txwi->flags = wflags; 3452208019Sthompsa txwi->xflags = xflags; 3453208019Sthompsa txwi->txop = 0; /* clear leftover garbage bits */ 3454208019Sthompsa 3455203134Sthompsa data->m = m; 3456203134Sthompsa data->ni = ni; 3457203134Sthompsa data->ridx = ridx; 3458203134Sthompsa 3459208019Sthompsa run_set_tx_desc(sc, data); 3460203134Sthompsa 3461203134Sthompsa DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len + 3462258840Skevlo (int)(sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi)), 3463208019Sthompsa rt2860_rates[ridx].rate); 3464203134Sthompsa 3465203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3466203134Sthompsa 3467203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 3468203134Sthompsa 3469203134Sthompsa return (0); 3470203134Sthompsa} 3471203134Sthompsa 3472203134Sthompsastatic int 3473203134Sthompsarun_sendprot(struct run_softc *sc, 3474203134Sthompsa const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) 3475203134Sthompsa{ 3476203134Sthompsa struct ieee80211com *ic = ni->ni_ic; 3477203134Sthompsa struct ieee80211_frame *wh; 3478203134Sthompsa struct run_tx_data *data; 3479208019Sthompsa struct rt2870_txd *txd; 3480208019Sthompsa struct rt2860_txwi *txwi; 3481203134Sthompsa struct mbuf *mprot; 3482203134Sthompsa int ridx; 3483203134Sthompsa int protrate; 3484203134Sthompsa int ackrate; 3485203134Sthompsa int pktlen; 3486203134Sthompsa int isshort; 3487203134Sthompsa uint16_t dur; 3488203134Sthompsa uint8_t type; 3489208019Sthompsa uint8_t wflags = 0; 3490208019Sthompsa uint8_t xflags = 0; 3491203134Sthompsa 3492203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3493203134Sthompsa 3494203134Sthompsa KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, 3495203134Sthompsa ("protection %d", prot)); 3496203134Sthompsa 3497203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3498203134Sthompsa pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; 3499203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3500203134Sthompsa 3501203134Sthompsa protrate = ieee80211_ctl_rate(ic->ic_rt, rate); 3502203134Sthompsa ackrate = ieee80211_ack_rate(ic->ic_rt, rate); 3503203134Sthompsa 3504203134Sthompsa isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; 3505209189Sjkim dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort) 3506203134Sthompsa + ieee80211_ack_duration(ic->ic_rt, rate, isshort); 3507203134Sthompsa wflags = RT2860_TX_FRAG; 3508203134Sthompsa 3509203134Sthompsa /* check that there are free slots before allocating the mbuf */ 3510287197Sglebius if (sc->sc_epq[0].tx_nfree == 0) 3511203134Sthompsa /* let caller free mbuf */ 3512203134Sthompsa return (ENOBUFS); 3513203134Sthompsa 3514203134Sthompsa if (prot == IEEE80211_PROT_RTSCTS) { 3515203134Sthompsa /* NB: CTS is the same size as an ACK */ 3516203134Sthompsa dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); 3517208019Sthompsa xflags |= RT2860_TX_ACK; 3518203134Sthompsa mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); 3519203134Sthompsa } else { 3520203134Sthompsa mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); 3521203134Sthompsa } 3522203134Sthompsa if (mprot == NULL) { 3523287197Sglebius if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); 3524203134Sthompsa DPRINTF("could not allocate mbuf\n"); 3525203134Sthompsa return (ENOBUFS); 3526203134Sthompsa } 3527203134Sthompsa 3528203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3529203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3530203134Sthompsa sc->sc_epq[0].tx_nfree--; 3531203134Sthompsa 3532208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3533208019Sthompsa txd->flags = RT2860_TX_QSEL_EDCA; 3534208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3535208019Sthompsa txwi->wcid = 0xff; 3536208019Sthompsa txwi->flags = wflags; 3537208019Sthompsa txwi->xflags = xflags; 3538208019Sthompsa txwi->txop = 0; /* clear leftover garbage bits */ 3539208019Sthompsa 3540203134Sthompsa data->m = mprot; 3541203134Sthompsa data->ni = ieee80211_ref_node(ni); 3542203134Sthompsa 3543203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 3544203134Sthompsa if (rt2860_rates[ridx].rate == protrate) 3545203134Sthompsa break; 3546203134Sthompsa data->ridx = ridx; 3547203134Sthompsa 3548208019Sthompsa run_set_tx_desc(sc, data); 3549203134Sthompsa 3550203134Sthompsa DPRINTFN(1, "sending prot len=%u rate=%u\n", 3551203134Sthompsa m->m_pkthdr.len, rate); 3552203134Sthompsa 3553203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3554203134Sthompsa 3555203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 3556203134Sthompsa 3557203134Sthompsa return (0); 3558203134Sthompsa} 3559203134Sthompsa 3560203134Sthompsastatic int 3561203134Sthompsarun_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, 3562203134Sthompsa const struct ieee80211_bpf_params *params) 3563203134Sthompsa{ 3564203134Sthompsa struct ieee80211com *ic = ni->ni_ic; 3565203134Sthompsa struct ieee80211_frame *wh; 3566203134Sthompsa struct run_tx_data *data; 3567208019Sthompsa struct rt2870_txd *txd; 3568208019Sthompsa struct rt2860_txwi *txwi; 3569203134Sthompsa uint8_t type; 3570208019Sthompsa uint8_t ridx; 3571208019Sthompsa uint8_t rate; 3572208019Sthompsa uint8_t opflags = 0; 3573208019Sthompsa uint8_t xflags = 0; 3574203134Sthompsa int error; 3575203134Sthompsa 3576203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3577203134Sthompsa 3578203134Sthompsa KASSERT(params != NULL, ("no raw xmit params")); 3579203134Sthompsa 3580203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3581203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3582203134Sthompsa 3583203134Sthompsa rate = params->ibp_rate0; 3584203134Sthompsa if (!ieee80211_isratevalid(ic->ic_rt, rate)) { 3585203134Sthompsa /* let caller free mbuf */ 3586203134Sthompsa return (EINVAL); 3587203134Sthompsa } 3588203134Sthompsa 3589203134Sthompsa if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) 3590208019Sthompsa xflags |= RT2860_TX_ACK; 3591203134Sthompsa if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { 3592203134Sthompsa error = run_sendprot(sc, m, ni, 3593203134Sthompsa params->ibp_flags & IEEE80211_BPF_RTS ? 3594203134Sthompsa IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, 3595203134Sthompsa rate); 3596203134Sthompsa if (error) { 3597203134Sthompsa /* let caller free mbuf */ 3598209917Sthompsa return error; 3599203134Sthompsa } 3600203134Sthompsa opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS; 3601203134Sthompsa } 3602203134Sthompsa 3603203134Sthompsa if (sc->sc_epq[0].tx_nfree == 0) { 3604203134Sthompsa /* let caller free mbuf */ 3605203134Sthompsa DPRINTF("sending raw frame, but tx ring is full\n"); 3606203134Sthompsa return (EIO); 3607203134Sthompsa } 3608203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3609203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3610203134Sthompsa sc->sc_epq[0].tx_nfree--; 3611203134Sthompsa 3612208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3613208019Sthompsa txd->flags = RT2860_TX_QSEL_EDCA; 3614208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3615208019Sthompsa txwi->wcid = 0xff; 3616208019Sthompsa txwi->xflags = xflags; 3617208019Sthompsa txwi->txop = opflags; 3618208019Sthompsa txwi->flags = 0; /* clear leftover garbage bits */ 3619208019Sthompsa 3620203134Sthompsa data->m = m; 3621203134Sthompsa data->ni = ni; 3622203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 3623203134Sthompsa if (rt2860_rates[ridx].rate == rate) 3624203134Sthompsa break; 3625203134Sthompsa data->ridx = ridx; 3626203134Sthompsa 3627208019Sthompsa run_set_tx_desc(sc, data); 3628203134Sthompsa 3629203134Sthompsa DPRINTFN(10, "sending raw frame len=%u rate=%u\n", 3630203134Sthompsa m->m_pkthdr.len, rate); 3631203134Sthompsa 3632203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3633203134Sthompsa 3634203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 3635203134Sthompsa 3636209917Sthompsa return (0); 3637203134Sthompsa} 3638203134Sthompsa 3639203134Sthompsastatic int 3640203134Sthompsarun_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 3641203134Sthompsa const struct ieee80211_bpf_params *params) 3642203134Sthompsa{ 3643286950Sadrian struct run_softc *sc = ni->ni_ic->ic_softc; 3644208019Sthompsa int error = 0; 3645208019Sthompsa 3646203134Sthompsa RUN_LOCK(sc); 3647203134Sthompsa 3648203134Sthompsa /* prevent management frames from being sent if we're not ready */ 3649287197Sglebius if (!(sc->sc_flags & RUN_RUNNING)) { 3650287197Sglebius error = ENETDOWN; 3651208019Sthompsa goto done; 3652203134Sthompsa } 3653203134Sthompsa 3654203134Sthompsa if (params == NULL) { 3655203134Sthompsa /* tx mgt packet */ 3656209917Sthompsa if ((error = run_tx_mgt(sc, m, ni)) != 0) { 3657203134Sthompsa DPRINTF("mgt tx failed\n"); 3658208019Sthompsa goto done; 3659203134Sthompsa } 3660203134Sthompsa } else { 3661203134Sthompsa /* tx raw packet with param */ 3662209917Sthompsa if ((error = run_tx_param(sc, m, ni, params)) != 0) { 3663203134Sthompsa DPRINTF("tx with param failed\n"); 3664208019Sthompsa goto done; 3665203134Sthompsa } 3666203134Sthompsa } 3667203134Sthompsa 3668208019Sthompsadone: 3669203134Sthompsa RUN_UNLOCK(sc); 3670203134Sthompsa 3671209917Sthompsa if (error != 0) { 3672208019Sthompsa if(m != NULL) 3673208019Sthompsa m_freem(m); 3674208019Sthompsa } 3675203134Sthompsa 3676203134Sthompsa return (error); 3677203134Sthompsa} 3678203134Sthompsa 3679287197Sglebiusstatic int 3680287197Sglebiusrun_transmit(struct ieee80211com *ic, struct mbuf *m) 3681287197Sglebius{ 3682287197Sglebius struct run_softc *sc = ic->ic_softc; 3683287197Sglebius int error; 3684287197Sglebius 3685287197Sglebius RUN_LOCK(sc); 3686287197Sglebius if ((sc->sc_flags & RUN_RUNNING) == 0) { 3687287197Sglebius RUN_UNLOCK(sc); 3688287197Sglebius return (ENXIO); 3689287197Sglebius } 3690287197Sglebius error = mbufq_enqueue(&sc->sc_snd, m); 3691287197Sglebius if (error) { 3692287197Sglebius RUN_UNLOCK(sc); 3693287197Sglebius return (error); 3694287197Sglebius } 3695287197Sglebius run_start(sc); 3696287197Sglebius RUN_UNLOCK(sc); 3697287197Sglebius 3698287197Sglebius return (0); 3699287197Sglebius} 3700287197Sglebius 3701203134Sthompsastatic void 3702287197Sglebiusrun_start(struct run_softc *sc) 3703203134Sthompsa{ 3704203134Sthompsa struct ieee80211_node *ni; 3705203134Sthompsa struct mbuf *m; 3706203134Sthompsa 3707287197Sglebius RUN_LOCK_ASSERT(sc, MA_OWNED); 3708203134Sthompsa 3709287197Sglebius if ((sc->sc_flags & RUN_RUNNING) == 0) 3710203134Sthompsa return; 3711203134Sthompsa 3712287197Sglebius while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { 3713203134Sthompsa ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 3714203134Sthompsa if (run_tx(sc, m, ni) != 0) { 3715287197Sglebius mbufq_prepend(&sc->sc_snd, m); 3716203134Sthompsa break; 3717203134Sthompsa } 3718203134Sthompsa } 3719203134Sthompsa} 3720203134Sthompsa 3721287197Sglebiusstatic void 3722287197Sglebiusrun_parent(struct ieee80211com *ic) 3723203134Sthompsa{ 3724286950Sadrian struct run_softc *sc = ic->ic_softc; 3725208019Sthompsa int startall = 0; 3726203134Sthompsa 3727246614Shselasky RUN_LOCK(sc); 3728287197Sglebius if (sc->sc_detached) { 3729203134Sthompsa RUN_UNLOCK(sc); 3730287197Sglebius return; 3731203134Sthompsa } 3732203134Sthompsa 3733287197Sglebius if (ic->ic_nrunning > 0) { 3734287197Sglebius if (!(sc->sc_flags & RUN_RUNNING)) { 3735287197Sglebius startall = 1; 3736287197Sglebius run_init_locked(sc); 3737287197Sglebius } else 3738287197Sglebius run_update_promisc_locked(sc); 3739287197Sglebius } else if ((sc->sc_flags & RUN_RUNNING) && sc->rvp_cnt <= 1) 3740287197Sglebius run_stop(sc); 3741287197Sglebius RUN_UNLOCK(sc); 3742287197Sglebius if (startall) 3743287197Sglebius ieee80211_start_all(ic); 3744203134Sthompsa} 3745203134Sthompsa 3746203134Sthompsastatic void 3747259544Skevlorun_iq_calib(struct run_softc *sc, u_int chan) 3748259544Skevlo{ 3749259544Skevlo uint16_t val; 3750259544Skevlo 3751259544Skevlo /* Tx0 IQ gain. */ 3752259544Skevlo run_bbp_write(sc, 158, 0x2c); 3753259544Skevlo if (chan <= 14) 3754259544Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX0_2GHZ, &val, 1); 3755259544Skevlo else if (chan <= 64) { 3756259544Skevlo run_efuse_read(sc, 3757259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5GHZ, 3758259544Skevlo &val, 1); 3759259544Skevlo } else if (chan <= 138) { 3760259544Skevlo run_efuse_read(sc, 3761259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5GHZ, 3762259544Skevlo &val, 1); 3763259544Skevlo } else if (chan <= 165) { 3764259544Skevlo run_efuse_read(sc, 3765259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5GHZ, 3766259544Skevlo &val, 1); 3767259544Skevlo } else 3768259544Skevlo val = 0; 3769259547Skevlo run_bbp_write(sc, 159, val); 3770259544Skevlo 3771259544Skevlo /* Tx0 IQ phase. */ 3772259544Skevlo run_bbp_write(sc, 158, 0x2d); 3773259544Skevlo if (chan <= 14) { 3774259544Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX0_2GHZ, 3775259544Skevlo &val, 1); 3776259544Skevlo } else if (chan <= 64) { 3777259544Skevlo run_efuse_read(sc, 3778259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5GHZ, 3779259544Skevlo &val, 1); 3780259544Skevlo } else if (chan <= 138) { 3781259544Skevlo run_efuse_read(sc, 3782259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5GHZ, 3783259544Skevlo &val, 1); 3784259544Skevlo } else if (chan <= 165) { 3785259544Skevlo run_efuse_read(sc, 3786259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5GHZ, 3787259544Skevlo &val, 1); 3788259544Skevlo } else 3789259544Skevlo val = 0; 3790259547Skevlo run_bbp_write(sc, 159, val); 3791259544Skevlo 3792259544Skevlo /* Tx1 IQ gain. */ 3793259544Skevlo run_bbp_write(sc, 158, 0x4a); 3794259544Skevlo if (chan <= 14) { 3795259544Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX1_2GHZ, 3796259544Skevlo &val, 1); 3797259544Skevlo } else if (chan <= 64) { 3798259544Skevlo run_efuse_read(sc, 3799259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5GHZ, 3800259544Skevlo &val, 1); 3801259544Skevlo } else if (chan <= 138) { 3802259544Skevlo run_efuse_read(sc, 3803259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5GHZ, 3804259544Skevlo &val, 1); 3805259544Skevlo } else if (chan <= 165) { 3806259544Skevlo run_efuse_read(sc, 3807259544Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5GHZ, 3808259544Skevlo &val, 1); 3809259544Skevlo } else 3810259544Skevlo val = 0; 3811259547Skevlo run_bbp_write(sc, 159, val); 3812259544Skevlo 3813259544Skevlo /* Tx1 IQ phase. */ 3814259544Skevlo run_bbp_write(sc, 158, 0x4b); 3815259544Skevlo if (chan <= 14) { 3816259544Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX1_2GHZ, 3817259544Skevlo &val, 1); 3818259544Skevlo } else if (chan <= 64) { 3819259544Skevlo run_efuse_read(sc, 3820259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5GHZ, 3821259544Skevlo &val, 1); 3822259544Skevlo } else if (chan <= 138) { 3823259544Skevlo run_efuse_read(sc, 3824259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5GHZ, 3825259544Skevlo &val, 1); 3826259544Skevlo } else if (chan <= 165) { 3827259544Skevlo run_efuse_read(sc, 3828259544Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5GHZ, 3829259544Skevlo &val, 1); 3830259544Skevlo } else 3831259544Skevlo val = 0; 3832259547Skevlo run_bbp_write(sc, 159, val); 3833259544Skevlo 3834259544Skevlo /* RF IQ compensation control. */ 3835259544Skevlo run_bbp_write(sc, 158, 0x04); 3836259544Skevlo run_efuse_read(sc, RT5390_EEPROM_RF_IQ_COMPENSATION_CTL, 3837259544Skevlo &val, 1); 3838259547Skevlo run_bbp_write(sc, 159, val); 3839259544Skevlo 3840259544Skevlo /* RF IQ imbalance compensation control. */ 3841259544Skevlo run_bbp_write(sc, 158, 0x03); 3842259544Skevlo run_efuse_read(sc, 3843259544Skevlo RT5390_EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CTL, &val, 1); 3844259547Skevlo run_bbp_write(sc, 159, val); 3845259544Skevlo} 3846259544Skevlo 3847259544Skevlostatic void 3848205042Sthompsarun_set_agc(struct run_softc *sc, uint8_t agc) 3849205042Sthompsa{ 3850205042Sthompsa uint8_t bbp; 3851205042Sthompsa 3852205042Sthompsa if (sc->mac_ver == 0x3572) { 3853205042Sthompsa run_bbp_read(sc, 27, &bbp); 3854205042Sthompsa bbp &= ~(0x3 << 5); 3855205042Sthompsa run_bbp_write(sc, 27, bbp | 0 << 5); /* select Rx0 */ 3856205042Sthompsa run_bbp_write(sc, 66, agc); 3857205042Sthompsa run_bbp_write(sc, 27, bbp | 1 << 5); /* select Rx1 */ 3858205042Sthompsa run_bbp_write(sc, 66, agc); 3859205042Sthompsa } else 3860205042Sthompsa run_bbp_write(sc, 66, agc); 3861205042Sthompsa} 3862205042Sthompsa 3863205042Sthompsastatic void 3864203134Sthompsarun_select_chan_group(struct run_softc *sc, int group) 3865203134Sthompsa{ 3866203134Sthompsa uint32_t tmp; 3867205042Sthompsa uint8_t agc; 3868203134Sthompsa 3869203134Sthompsa run_bbp_write(sc, 62, 0x37 - sc->lna[group]); 3870203134Sthompsa run_bbp_write(sc, 63, 0x37 - sc->lna[group]); 3871203134Sthompsa run_bbp_write(sc, 64, 0x37 - sc->lna[group]); 3872258082Skevlo if (sc->mac_ver < 0x3572) 3873257955Skevlo run_bbp_write(sc, 86, 0x00); 3874203134Sthompsa 3875260219Skevlo if (sc->mac_ver == 0x3593) { 3876260219Skevlo run_bbp_write(sc, 77, 0x98); 3877260219Skevlo run_bbp_write(sc, 83, (group == 0) ? 0x8a : 0x9a); 3878260219Skevlo } 3879260219Skevlo 3880203134Sthompsa if (group == 0) { 3881203134Sthompsa if (sc->ext_2ghz_lna) { 3882257955Skevlo if (sc->mac_ver >= 0x5390) 3883257955Skevlo run_bbp_write(sc, 75, 0x52); 3884257955Skevlo else { 3885257955Skevlo run_bbp_write(sc, 82, 0x62); 3886257955Skevlo run_bbp_write(sc, 75, 0x46); 3887257955Skevlo } 3888203134Sthompsa } else { 3889259032Skevlo if (sc->mac_ver == 0x5592) { 3890259032Skevlo run_bbp_write(sc, 79, 0x1c); 3891259032Skevlo run_bbp_write(sc, 80, 0x0e); 3892259032Skevlo run_bbp_write(sc, 81, 0x3a); 3893259032Skevlo run_bbp_write(sc, 82, 0x62); 3894259032Skevlo 3895259032Skevlo run_bbp_write(sc, 195, 0x80); 3896259032Skevlo run_bbp_write(sc, 196, 0xe0); 3897259032Skevlo run_bbp_write(sc, 195, 0x81); 3898259032Skevlo run_bbp_write(sc, 196, 0x1f); 3899259032Skevlo run_bbp_write(sc, 195, 0x82); 3900259032Skevlo run_bbp_write(sc, 196, 0x38); 3901259032Skevlo run_bbp_write(sc, 195, 0x83); 3902259032Skevlo run_bbp_write(sc, 196, 0x32); 3903259032Skevlo run_bbp_write(sc, 195, 0x85); 3904259032Skevlo run_bbp_write(sc, 196, 0x28); 3905259032Skevlo run_bbp_write(sc, 195, 0x86); 3906259032Skevlo run_bbp_write(sc, 196, 0x19); 3907259032Skevlo } else if (sc->mac_ver >= 0x5390) 3908257955Skevlo run_bbp_write(sc, 75, 0x50); 3909257955Skevlo else { 3910260219Skevlo run_bbp_write(sc, 82, 3911260219Skevlo (sc->mac_ver == 0x3593) ? 0x62 : 0x84); 3912257955Skevlo run_bbp_write(sc, 75, 0x50); 3913257955Skevlo } 3914203134Sthompsa } 3915203134Sthompsa } else { 3916259032Skevlo if (sc->mac_ver == 0x5592) { 3917259032Skevlo run_bbp_write(sc, 79, 0x18); 3918259032Skevlo run_bbp_write(sc, 80, 0x08); 3919259032Skevlo run_bbp_write(sc, 81, 0x38); 3920259032Skevlo run_bbp_write(sc, 82, 0x92); 3921259032Skevlo 3922259032Skevlo run_bbp_write(sc, 195, 0x80); 3923259032Skevlo run_bbp_write(sc, 196, 0xf0); 3924259032Skevlo run_bbp_write(sc, 195, 0x81); 3925259032Skevlo run_bbp_write(sc, 196, 0x1e); 3926259032Skevlo run_bbp_write(sc, 195, 0x82); 3927259032Skevlo run_bbp_write(sc, 196, 0x28); 3928259032Skevlo run_bbp_write(sc, 195, 0x83); 3929259032Skevlo run_bbp_write(sc, 196, 0x20); 3930259032Skevlo run_bbp_write(sc, 195, 0x85); 3931259032Skevlo run_bbp_write(sc, 196, 0x7f); 3932259032Skevlo run_bbp_write(sc, 195, 0x86); 3933259032Skevlo run_bbp_write(sc, 196, 0x7f); 3934259032Skevlo } else if (sc->mac_ver == 0x3572) 3935205042Sthompsa run_bbp_write(sc, 82, 0x94); 3936205042Sthompsa else 3937260219Skevlo run_bbp_write(sc, 82, 3938260219Skevlo (sc->mac_ver == 0x3593) ? 0x82 : 0xf2); 3939205042Sthompsa if (sc->ext_5ghz_lna) 3940203134Sthompsa run_bbp_write(sc, 75, 0x46); 3941205042Sthompsa else 3942203134Sthompsa run_bbp_write(sc, 75, 0x50); 3943203134Sthompsa } 3944203134Sthompsa 3945203134Sthompsa run_read(sc, RT2860_TX_BAND_CFG, &tmp); 3946203134Sthompsa tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P); 3947203134Sthompsa tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P; 3948203134Sthompsa run_write(sc, RT2860_TX_BAND_CFG, tmp); 3949203134Sthompsa 3950203134Sthompsa /* enable appropriate Power Amplifiers and Low Noise Amplifiers */ 3951208019Sthompsa tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN; 3952260219Skevlo if (sc->mac_ver == 0x3593) 3953260219Skevlo tmp |= 1 << 29 | 1 << 28; 3954208019Sthompsa if (sc->nrxchains > 1) 3955208019Sthompsa tmp |= RT2860_LNA_PE1_EN; 3956203134Sthompsa if (group == 0) { /* 2GHz */ 3957208019Sthompsa tmp |= RT2860_PA_PE_G0_EN; 3958203134Sthompsa if (sc->ntxchains > 1) 3959203134Sthompsa tmp |= RT2860_PA_PE_G1_EN; 3960260219Skevlo if (sc->mac_ver == 0x3593) { 3961260219Skevlo if (sc->ntxchains > 2) 3962260219Skevlo tmp |= 1 << 25; 3963260219Skevlo } 3964203134Sthompsa } else { /* 5GHz */ 3965208019Sthompsa tmp |= RT2860_PA_PE_A0_EN; 3966203134Sthompsa if (sc->ntxchains > 1) 3967203134Sthompsa tmp |= RT2860_PA_PE_A1_EN; 3968203134Sthompsa } 3969205042Sthompsa if (sc->mac_ver == 0x3572) { 3970205042Sthompsa run_rt3070_rf_write(sc, 8, 0x00); 3971205042Sthompsa run_write(sc, RT2860_TX_PIN_CFG, tmp); 3972205042Sthompsa run_rt3070_rf_write(sc, 8, 0x80); 3973205042Sthompsa } else 3974205042Sthompsa run_write(sc, RT2860_TX_PIN_CFG, tmp); 3975203134Sthompsa 3976259032Skevlo if (sc->mac_ver == 0x5592) { 3977259032Skevlo run_bbp_write(sc, 195, 0x8d); 3978259032Skevlo run_bbp_write(sc, 196, 0x1a); 3979259032Skevlo } 3980259032Skevlo 3981260219Skevlo if (sc->mac_ver == 0x3593) { 3982260219Skevlo run_read(sc, RT2860_GPIO_CTRL, &tmp); 3983260219Skevlo tmp &= ~0x01010000; 3984260219Skevlo if (group == 0) 3985260219Skevlo tmp |= 0x00010000; 3986260219Skevlo tmp = (tmp & ~0x00009090) | 0x00000090; 3987260219Skevlo run_write(sc, RT2860_GPIO_CTRL, tmp); 3988260219Skevlo } 3989260219Skevlo 3990203134Sthompsa /* set initial AGC value */ 3991205042Sthompsa if (group == 0) { /* 2GHz band */ 3992205042Sthompsa if (sc->mac_ver >= 0x3070) 3993205042Sthompsa agc = 0x1c + sc->lna[0] * 2; 3994205042Sthompsa else 3995205042Sthompsa agc = 0x2e + sc->lna[0]; 3996205042Sthompsa } else { /* 5GHz band */ 3997259032Skevlo if (sc->mac_ver == 0x5592) 3998259032Skevlo agc = 0x24 + sc->lna[group] * 2; 3999260219Skevlo else if (sc->mac_ver == 0x3572 || sc->mac_ver == 0x3593) 4000205042Sthompsa agc = 0x22 + (sc->lna[group] * 5) / 3; 4001205042Sthompsa else 4002205042Sthompsa agc = 0x32 + (sc->lna[group] * 5) / 3; 4003205042Sthompsa } 4004205042Sthompsa run_set_agc(sc, agc); 4005203134Sthompsa} 4006203134Sthompsa 4007203134Sthompsastatic void 4008257429Shselaskyrun_rt2870_set_chan(struct run_softc *sc, u_int chan) 4009203134Sthompsa{ 4010203134Sthompsa const struct rfprog *rfprog = rt2860_rf2850; 4011203134Sthompsa uint32_t r2, r3, r4; 4012203134Sthompsa int8_t txpow1, txpow2; 4013203134Sthompsa int i; 4014203134Sthompsa 4015203134Sthompsa /* find the settings for this channel (we know it exists) */ 4016203134Sthompsa for (i = 0; rfprog[i].chan != chan; i++); 4017203134Sthompsa 4018203134Sthompsa r2 = rfprog[i].r2; 4019203134Sthompsa if (sc->ntxchains == 1) 4020258732Skevlo r2 |= 1 << 14; /* 1T: disable Tx chain 2 */ 4021203134Sthompsa if (sc->nrxchains == 1) 4022258732Skevlo r2 |= 1 << 17 | 1 << 6; /* 1R: disable Rx chains 2 & 3 */ 4023203134Sthompsa else if (sc->nrxchains == 2) 4024258732Skevlo r2 |= 1 << 6; /* 2R: disable Rx chain 3 */ 4025203134Sthompsa 4026203134Sthompsa /* use Tx power values from EEPROM */ 4027203134Sthompsa txpow1 = sc->txpow1[i]; 4028203134Sthompsa txpow2 = sc->txpow2[i]; 4029258732Skevlo 4030258732Skevlo /* Initialize RF R3 and R4. */ 4031258732Skevlo r3 = rfprog[i].r3 & 0xffffc1ff; 4032258732Skevlo r4 = (rfprog[i].r4 & ~(0x001f87c0)) | (sc->freq << 15); 4033203134Sthompsa if (chan > 14) { 4034258732Skevlo if (txpow1 >= 0) { 4035258732Skevlo txpow1 = (txpow1 > 0xf) ? (0xf) : (txpow1); 4036258732Skevlo r3 |= (txpow1 << 10) | (1 << 9); 4037258732Skevlo } else { 4038258732Skevlo txpow1 += 7; 4039258732Skevlo 4040258732Skevlo /* txpow1 is not possible larger than 15. */ 4041258732Skevlo r3 |= (txpow1 << 10); 4042258732Skevlo } 4043258732Skevlo if (txpow2 >= 0) { 4044258732Skevlo txpow2 = (txpow2 > 0xf) ? (0xf) : (txpow2); 4045258921Shselasky r4 |= (txpow2 << 7) | (1 << 6); 4046258732Skevlo } else { 4047258732Skevlo txpow2 += 7; 4048258732Skevlo r4 |= (txpow2 << 7); 4049258732Skevlo } 4050258732Skevlo } else { 4051258732Skevlo /* Set Tx0 power. */ 4052258732Skevlo r3 |= (txpow1 << 9); 4053258732Skevlo 4054258732Skevlo /* Set frequency offset and Tx1 power. */ 4055258732Skevlo r4 |= (txpow2 << 6); 4056203134Sthompsa } 4057203134Sthompsa 4058258733Skevlo run_rt2870_rf_write(sc, rfprog[i].r1); 4059258733Skevlo run_rt2870_rf_write(sc, r2); 4060258733Skevlo run_rt2870_rf_write(sc, r3 & ~(1 << 2)); 4061258733Skevlo run_rt2870_rf_write(sc, r4); 4062203134Sthompsa 4063203134Sthompsa run_delay(sc, 10); 4064203134Sthompsa 4065258733Skevlo run_rt2870_rf_write(sc, rfprog[i].r1); 4066258733Skevlo run_rt2870_rf_write(sc, r2); 4067258733Skevlo run_rt2870_rf_write(sc, r3 | (1 << 2)); 4068258733Skevlo run_rt2870_rf_write(sc, r4); 4069203134Sthompsa 4070203134Sthompsa run_delay(sc, 10); 4071203134Sthompsa 4072258733Skevlo run_rt2870_rf_write(sc, rfprog[i].r1); 4073258733Skevlo run_rt2870_rf_write(sc, r2); 4074258733Skevlo run_rt2870_rf_write(sc, r3 & ~(1 << 2)); 4075258733Skevlo run_rt2870_rf_write(sc, r4); 4076203134Sthompsa} 4077203134Sthompsa 4078203134Sthompsastatic void 4079257429Shselaskyrun_rt3070_set_chan(struct run_softc *sc, u_int chan) 4080203134Sthompsa{ 4081203134Sthompsa int8_t txpow1, txpow2; 4082203134Sthompsa uint8_t rf; 4083205042Sthompsa int i; 4084203134Sthompsa 4085205042Sthompsa /* find the settings for this channel (we know it exists) */ 4086205042Sthompsa for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4087205042Sthompsa 4088203134Sthompsa /* use Tx power values from EEPROM */ 4089205042Sthompsa txpow1 = sc->txpow1[i]; 4090205042Sthompsa txpow2 = sc->txpow2[i]; 4091203134Sthompsa 4092205042Sthompsa run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n); 4093256720Skevlo 4094256720Skevlo /* RT3370/RT3390: RF R3 [7:4] is not reserved bits. */ 4095256720Skevlo run_rt3070_rf_read(sc, 3, &rf); 4096256720Skevlo rf = (rf & ~0x0f) | rt3070_freqs[i].k; 4097256720Skevlo run_rt3070_rf_write(sc, 3, rf); 4098256720Skevlo 4099203134Sthompsa run_rt3070_rf_read(sc, 6, &rf); 4100205042Sthompsa rf = (rf & ~0x03) | rt3070_freqs[i].r; 4101203134Sthompsa run_rt3070_rf_write(sc, 6, rf); 4102203134Sthompsa 4103203134Sthompsa /* set Tx0 power */ 4104203134Sthompsa run_rt3070_rf_read(sc, 12, &rf); 4105203134Sthompsa rf = (rf & ~0x1f) | txpow1; 4106203134Sthompsa run_rt3070_rf_write(sc, 12, rf); 4107203134Sthompsa 4108203134Sthompsa /* set Tx1 power */ 4109203134Sthompsa run_rt3070_rf_read(sc, 13, &rf); 4110203134Sthompsa rf = (rf & ~0x1f) | txpow2; 4111203134Sthompsa run_rt3070_rf_write(sc, 13, rf); 4112203134Sthompsa 4113203134Sthompsa run_rt3070_rf_read(sc, 1, &rf); 4114203134Sthompsa rf &= ~0xfc; 4115203134Sthompsa if (sc->ntxchains == 1) 4116203134Sthompsa rf |= 1 << 7 | 1 << 5; /* 1T: disable Tx chains 2 & 3 */ 4117203134Sthompsa else if (sc->ntxchains == 2) 4118203134Sthompsa rf |= 1 << 7; /* 2T: disable Tx chain 3 */ 4119203134Sthompsa if (sc->nrxchains == 1) 4120203134Sthompsa rf |= 1 << 6 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 4121203134Sthompsa else if (sc->nrxchains == 2) 4122203134Sthompsa rf |= 1 << 6; /* 2R: disable Rx chain 3 */ 4123203134Sthompsa run_rt3070_rf_write(sc, 1, rf); 4124203134Sthompsa 4125203134Sthompsa /* set RF offset */ 4126203134Sthompsa run_rt3070_rf_read(sc, 23, &rf); 4127203134Sthompsa rf = (rf & ~0x7f) | sc->freq; 4128203134Sthompsa run_rt3070_rf_write(sc, 23, rf); 4129203134Sthompsa 4130203134Sthompsa /* program RF filter */ 4131205042Sthompsa run_rt3070_rf_read(sc, 24, &rf); /* Tx */ 4132205042Sthompsa rf = (rf & ~0x3f) | sc->rf24_20mhz; 4133205042Sthompsa run_rt3070_rf_write(sc, 24, rf); 4134205042Sthompsa run_rt3070_rf_read(sc, 31, &rf); /* Rx */ 4135205042Sthompsa rf = (rf & ~0x3f) | sc->rf24_20mhz; 4136205042Sthompsa run_rt3070_rf_write(sc, 31, rf); 4137203134Sthompsa 4138203134Sthompsa /* enable RF tuning */ 4139203134Sthompsa run_rt3070_rf_read(sc, 7, &rf); 4140203134Sthompsa run_rt3070_rf_write(sc, 7, rf | 0x01); 4141203134Sthompsa} 4142203134Sthompsa 4143203134Sthompsastatic void 4144205042Sthompsarun_rt3572_set_chan(struct run_softc *sc, u_int chan) 4145205042Sthompsa{ 4146205042Sthompsa int8_t txpow1, txpow2; 4147205042Sthompsa uint32_t tmp; 4148205042Sthompsa uint8_t rf; 4149205042Sthompsa int i; 4150205042Sthompsa 4151205042Sthompsa /* find the settings for this channel (we know it exists) */ 4152205042Sthompsa for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4153205042Sthompsa 4154205042Sthompsa /* use Tx power values from EEPROM */ 4155205042Sthompsa txpow1 = sc->txpow1[i]; 4156205042Sthompsa txpow2 = sc->txpow2[i]; 4157205042Sthompsa 4158205042Sthompsa if (chan <= 14) { 4159205042Sthompsa run_bbp_write(sc, 25, sc->bbp25); 4160205042Sthompsa run_bbp_write(sc, 26, sc->bbp26); 4161205042Sthompsa } else { 4162205042Sthompsa /* enable IQ phase correction */ 4163205042Sthompsa run_bbp_write(sc, 25, 0x09); 4164205042Sthompsa run_bbp_write(sc, 26, 0xff); 4165205042Sthompsa } 4166205042Sthompsa 4167205042Sthompsa run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n); 4168205042Sthompsa run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k); 4169205042Sthompsa run_rt3070_rf_read(sc, 6, &rf); 4170205042Sthompsa rf = (rf & ~0x0f) | rt3070_freqs[i].r; 4171205042Sthompsa rf |= (chan <= 14) ? 0x08 : 0x04; 4172205042Sthompsa run_rt3070_rf_write(sc, 6, rf); 4173205042Sthompsa 4174205042Sthompsa /* set PLL mode */ 4175205042Sthompsa run_rt3070_rf_read(sc, 5, &rf); 4176205042Sthompsa rf &= ~(0x08 | 0x04); 4177205042Sthompsa rf |= (chan <= 14) ? 0x04 : 0x08; 4178205042Sthompsa run_rt3070_rf_write(sc, 5, rf); 4179205042Sthompsa 4180205042Sthompsa /* set Tx power for chain 0 */ 4181205042Sthompsa if (chan <= 14) 4182205042Sthompsa rf = 0x60 | txpow1; 4183205042Sthompsa else 4184205042Sthompsa rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3); 4185205042Sthompsa run_rt3070_rf_write(sc, 12, rf); 4186205042Sthompsa 4187205042Sthompsa /* set Tx power for chain 1 */ 4188205042Sthompsa if (chan <= 14) 4189205042Sthompsa rf = 0x60 | txpow2; 4190205042Sthompsa else 4191205042Sthompsa rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3); 4192205042Sthompsa run_rt3070_rf_write(sc, 13, rf); 4193205042Sthompsa 4194205042Sthompsa /* set Tx/Rx streams */ 4195205042Sthompsa run_rt3070_rf_read(sc, 1, &rf); 4196205042Sthompsa rf &= ~0xfc; 4197205042Sthompsa if (sc->ntxchains == 1) 4198205042Sthompsa rf |= 1 << 7 | 1 << 5; /* 1T: disable Tx chains 2 & 3 */ 4199205042Sthompsa else if (sc->ntxchains == 2) 4200205042Sthompsa rf |= 1 << 7; /* 2T: disable Tx chain 3 */ 4201205042Sthompsa if (sc->nrxchains == 1) 4202205042Sthompsa rf |= 1 << 6 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 4203205042Sthompsa else if (sc->nrxchains == 2) 4204205042Sthompsa rf |= 1 << 6; /* 2R: disable Rx chain 3 */ 4205205042Sthompsa run_rt3070_rf_write(sc, 1, rf); 4206205042Sthompsa 4207205042Sthompsa /* set RF offset */ 4208205042Sthompsa run_rt3070_rf_read(sc, 23, &rf); 4209205042Sthompsa rf = (rf & ~0x7f) | sc->freq; 4210205042Sthompsa run_rt3070_rf_write(sc, 23, rf); 4211205042Sthompsa 4212205042Sthompsa /* program RF filter */ 4213205042Sthompsa rf = sc->rf24_20mhz; 4214205042Sthompsa run_rt3070_rf_write(sc, 24, rf); /* Tx */ 4215205042Sthompsa run_rt3070_rf_write(sc, 31, rf); /* Rx */ 4216205042Sthompsa 4217205042Sthompsa /* enable RF tuning */ 4218205042Sthompsa run_rt3070_rf_read(sc, 7, &rf); 4219205042Sthompsa rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14); 4220205042Sthompsa run_rt3070_rf_write(sc, 7, rf); 4221205042Sthompsa 4222205042Sthompsa /* TSSI */ 4223205042Sthompsa rf = (chan <= 14) ? 0xc3 : 0xc0; 4224205042Sthompsa run_rt3070_rf_write(sc, 9, rf); 4225205042Sthompsa 4226205042Sthompsa /* set loop filter 1 */ 4227205042Sthompsa run_rt3070_rf_write(sc, 10, 0xf1); 4228205042Sthompsa /* set loop filter 2 */ 4229205042Sthompsa run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00); 4230205042Sthompsa 4231205042Sthompsa /* set tx_mx2_ic */ 4232205042Sthompsa run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43); 4233205042Sthompsa /* set tx_mx1_ic */ 4234205042Sthompsa if (chan <= 14) 4235205042Sthompsa rf = 0x48 | sc->txmixgain_2ghz; 4236205042Sthompsa else 4237205042Sthompsa rf = 0x78 | sc->txmixgain_5ghz; 4238205042Sthompsa run_rt3070_rf_write(sc, 16, rf); 4239205042Sthompsa 4240205042Sthompsa /* set tx_lo1 */ 4241205042Sthompsa run_rt3070_rf_write(sc, 17, 0x23); 4242205042Sthompsa /* set tx_lo2 */ 4243205042Sthompsa if (chan <= 14) 4244205042Sthompsa rf = 0x93; 4245205042Sthompsa else if (chan <= 64) 4246205042Sthompsa rf = 0xb7; 4247205042Sthompsa else if (chan <= 128) 4248205042Sthompsa rf = 0x74; 4249205042Sthompsa else 4250205042Sthompsa rf = 0x72; 4251205042Sthompsa run_rt3070_rf_write(sc, 19, rf); 4252205042Sthompsa 4253205042Sthompsa /* set rx_lo1 */ 4254205042Sthompsa if (chan <= 14) 4255205042Sthompsa rf = 0xb3; 4256205042Sthompsa else if (chan <= 64) 4257205042Sthompsa rf = 0xf6; 4258205042Sthompsa else if (chan <= 128) 4259205042Sthompsa rf = 0xf4; 4260205042Sthompsa else 4261205042Sthompsa rf = 0xf3; 4262205042Sthompsa run_rt3070_rf_write(sc, 20, rf); 4263205042Sthompsa 4264205042Sthompsa /* set pfd_delay */ 4265205042Sthompsa if (chan <= 14) 4266205042Sthompsa rf = 0x15; 4267205042Sthompsa else if (chan <= 64) 4268205042Sthompsa rf = 0x3d; 4269205042Sthompsa else 4270205042Sthompsa rf = 0x01; 4271205042Sthompsa run_rt3070_rf_write(sc, 25, rf); 4272205042Sthompsa 4273205042Sthompsa /* set rx_lo2 */ 4274205042Sthompsa run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87); 4275205042Sthompsa /* set ldo_rf_vc */ 4276205042Sthompsa run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01); 4277205042Sthompsa /* set drv_cc */ 4278205042Sthompsa run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f); 4279205042Sthompsa 4280205042Sthompsa run_read(sc, RT2860_GPIO_CTRL, &tmp); 4281205042Sthompsa tmp &= ~0x8080; 4282205042Sthompsa if (chan <= 14) 4283205042Sthompsa tmp |= 0x80; 4284205042Sthompsa run_write(sc, RT2860_GPIO_CTRL, tmp); 4285205042Sthompsa 4286205042Sthompsa /* enable RF tuning */ 4287205042Sthompsa run_rt3070_rf_read(sc, 7, &rf); 4288205042Sthompsa run_rt3070_rf_write(sc, 7, rf | 0x01); 4289205042Sthompsa 4290205042Sthompsa run_delay(sc, 2); 4291205042Sthompsa} 4292205042Sthompsa 4293205042Sthompsastatic void 4294260219Skevlorun_rt3593_set_chan(struct run_softc *sc, u_int chan) 4295260219Skevlo{ 4296260219Skevlo int8_t txpow1, txpow2, txpow3; 4297260219Skevlo uint8_t h20mhz, rf; 4298260219Skevlo int i; 4299260219Skevlo 4300260219Skevlo /* find the settings for this channel (we know it exists) */ 4301260219Skevlo for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4302260219Skevlo 4303260219Skevlo /* use Tx power values from EEPROM */ 4304260219Skevlo txpow1 = sc->txpow1[i]; 4305260219Skevlo txpow2 = sc->txpow2[i]; 4306260219Skevlo txpow3 = (sc->ntxchains == 3) ? sc->txpow3[i] : 0; 4307260219Skevlo 4308260219Skevlo if (chan <= 14) { 4309260219Skevlo run_bbp_write(sc, 25, sc->bbp25); 4310260219Skevlo run_bbp_write(sc, 26, sc->bbp26); 4311260219Skevlo } else { 4312260219Skevlo /* Enable IQ phase correction. */ 4313260219Skevlo run_bbp_write(sc, 25, 0x09); 4314260219Skevlo run_bbp_write(sc, 26, 0xff); 4315260219Skevlo } 4316260219Skevlo 4317260219Skevlo run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n); 4318260219Skevlo run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f); 4319260219Skevlo run_rt3070_rf_read(sc, 11, &rf); 4320260219Skevlo rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03); 4321260219Skevlo run_rt3070_rf_write(sc, 11, rf); 4322260219Skevlo 4323260219Skevlo /* Set pll_idoh. */ 4324260219Skevlo run_rt3070_rf_read(sc, 11, &rf); 4325260219Skevlo rf &= ~0x4c; 4326260219Skevlo rf |= (chan <= 14) ? 0x44 : 0x48; 4327260219Skevlo run_rt3070_rf_write(sc, 11, rf); 4328260219Skevlo 4329260219Skevlo if (chan <= 14) 4330260219Skevlo rf = txpow1 & 0x1f; 4331260219Skevlo else 4332260219Skevlo rf = 0x40 | ((txpow1 & 0x18) << 1) | (txpow1 & 0x07); 4333260219Skevlo run_rt3070_rf_write(sc, 53, rf); 4334260219Skevlo 4335260219Skevlo if (chan <= 14) 4336260219Skevlo rf = txpow2 & 0x1f; 4337260219Skevlo else 4338260219Skevlo rf = 0x40 | ((txpow2 & 0x18) << 1) | (txpow2 & 0x07); 4339260219Skevlo run_rt3070_rf_write(sc, 55, rf); 4340260219Skevlo 4341260219Skevlo if (chan <= 14) 4342260219Skevlo rf = txpow3 & 0x1f; 4343260219Skevlo else 4344260219Skevlo rf = 0x40 | ((txpow3 & 0x18) << 1) | (txpow3 & 0x07); 4345260219Skevlo run_rt3070_rf_write(sc, 54, rf); 4346260219Skevlo 4347260219Skevlo rf = RT3070_RF_BLOCK | RT3070_PLL_PD; 4348260219Skevlo if (sc->ntxchains == 3) 4349260219Skevlo rf |= RT3070_TX0_PD | RT3070_TX1_PD | RT3070_TX2_PD; 4350260219Skevlo else 4351260219Skevlo rf |= RT3070_TX0_PD | RT3070_TX1_PD; 4352260219Skevlo rf |= RT3070_RX0_PD | RT3070_RX1_PD | RT3070_RX2_PD; 4353260219Skevlo run_rt3070_rf_write(sc, 1, rf); 4354260219Skevlo 4355260219Skevlo run_adjust_freq_offset(sc); 4356260219Skevlo 4357260219Skevlo run_rt3070_rf_write(sc, 31, (chan <= 14) ? 0xa0 : 0x80); 4358260219Skevlo 4359260219Skevlo h20mhz = (sc->rf24_20mhz & 0x20) >> 5; 4360260219Skevlo run_rt3070_rf_read(sc, 30, &rf); 4361260219Skevlo rf = (rf & ~0x06) | (h20mhz << 1) | (h20mhz << 2); 4362260219Skevlo run_rt3070_rf_write(sc, 30, rf); 4363260219Skevlo 4364260219Skevlo run_rt3070_rf_read(sc, 36, &rf); 4365260219Skevlo if (chan <= 14) 4366260219Skevlo rf |= 0x80; 4367260219Skevlo else 4368260219Skevlo rf &= ~0x80; 4369260219Skevlo run_rt3070_rf_write(sc, 36, rf); 4370260219Skevlo 4371260219Skevlo /* Set vcolo_bs. */ 4372260219Skevlo run_rt3070_rf_write(sc, 34, (chan <= 14) ? 0x3c : 0x20); 4373260219Skevlo /* Set pfd_delay. */ 4374260219Skevlo run_rt3070_rf_write(sc, 12, (chan <= 14) ? 0x1a : 0x12); 4375260219Skevlo 4376260219Skevlo /* Set vco bias current control. */ 4377260219Skevlo run_rt3070_rf_read(sc, 6, &rf); 4378260219Skevlo rf &= ~0xc0; 4379260219Skevlo if (chan <= 14) 4380260219Skevlo rf |= 0x40; 4381260219Skevlo else if (chan <= 128) 4382260219Skevlo rf |= 0x80; 4383260219Skevlo else 4384260219Skevlo rf |= 0x40; 4385260219Skevlo run_rt3070_rf_write(sc, 6, rf); 4386260219Skevlo 4387260219Skevlo run_rt3070_rf_read(sc, 30, &rf); 4388260219Skevlo rf = (rf & ~0x18) | 0x10; 4389260219Skevlo run_rt3070_rf_write(sc, 30, rf); 4390260219Skevlo 4391260219Skevlo run_rt3070_rf_write(sc, 10, (chan <= 14) ? 0xd3 : 0xd8); 4392260219Skevlo run_rt3070_rf_write(sc, 13, (chan <= 14) ? 0x12 : 0x23); 4393260219Skevlo 4394260219Skevlo run_rt3070_rf_read(sc, 51, &rf); 4395260219Skevlo rf = (rf & ~0x03) | 0x01; 4396260219Skevlo run_rt3070_rf_write(sc, 51, rf); 4397260219Skevlo /* Set tx_mx1_cc. */ 4398260219Skevlo run_rt3070_rf_read(sc, 51, &rf); 4399260219Skevlo rf &= ~0x1c; 4400260219Skevlo rf |= (chan <= 14) ? 0x14 : 0x10; 4401260219Skevlo run_rt3070_rf_write(sc, 51, rf); 4402260219Skevlo /* Set tx_mx1_ic. */ 4403260219Skevlo run_rt3070_rf_read(sc, 51, &rf); 4404260219Skevlo rf &= ~0xe0; 4405260219Skevlo rf |= (chan <= 14) ? 0x60 : 0x40; 4406260219Skevlo run_rt3070_rf_write(sc, 51, rf); 4407260219Skevlo /* Set tx_lo1_ic. */ 4408260219Skevlo run_rt3070_rf_read(sc, 49, &rf); 4409260219Skevlo rf &= ~0x1c; 4410260219Skevlo rf |= (chan <= 14) ? 0x0c : 0x08; 4411260219Skevlo run_rt3070_rf_write(sc, 49, rf); 4412260219Skevlo /* Set tx_lo1_en. */ 4413260219Skevlo run_rt3070_rf_read(sc, 50, &rf); 4414260219Skevlo run_rt3070_rf_write(sc, 50, rf & ~0x20); 4415260219Skevlo /* Set drv_cc. */ 4416260219Skevlo run_rt3070_rf_read(sc, 57, &rf); 4417260219Skevlo rf &= ~0xfc; 4418260219Skevlo rf |= (chan <= 14) ? 0x6c : 0x3c; 4419260219Skevlo run_rt3070_rf_write(sc, 57, rf); 4420260219Skevlo /* Set rx_mix1_ic, rxa_lnactr, lna_vc, lna_inbias_en and lna_en. */ 4421260219Skevlo run_rt3070_rf_write(sc, 44, (chan <= 14) ? 0x93 : 0x9b); 4422260219Skevlo /* Set drv_gnd_a, tx_vga_cc_a and tx_mx2_gain. */ 4423260219Skevlo run_rt3070_rf_write(sc, 52, (chan <= 14) ? 0x45 : 0x05); 4424260219Skevlo /* Enable VCO calibration. */ 4425260219Skevlo run_rt3070_rf_read(sc, 3, &rf); 4426260219Skevlo rf &= ~RT5390_VCOCAL; 4427260219Skevlo rf |= (chan <= 14) ? RT5390_VCOCAL : 0xbe; 4428260219Skevlo run_rt3070_rf_write(sc, 3, rf); 4429260219Skevlo 4430260219Skevlo if (chan <= 14) 4431260219Skevlo rf = 0x23; 4432260219Skevlo else if (chan <= 64) 4433260219Skevlo rf = 0x36; 4434260219Skevlo else if (chan <= 128) 4435260219Skevlo rf = 0x32; 4436260219Skevlo else 4437260219Skevlo rf = 0x30; 4438260219Skevlo run_rt3070_rf_write(sc, 39, rf); 4439260219Skevlo if (chan <= 14) 4440260219Skevlo rf = 0xbb; 4441260219Skevlo else if (chan <= 64) 4442260219Skevlo rf = 0xeb; 4443260219Skevlo else if (chan <= 128) 4444260219Skevlo rf = 0xb3; 4445260219Skevlo else 4446260219Skevlo rf = 0x9b; 4447260219Skevlo run_rt3070_rf_write(sc, 45, rf); 4448260219Skevlo 4449260219Skevlo /* Set FEQ/AEQ control. */ 4450260219Skevlo run_bbp_write(sc, 105, 0x34); 4451260219Skevlo} 4452260219Skevlo 4453260219Skevlostatic void 4454257955Skevlorun_rt5390_set_chan(struct run_softc *sc, u_int chan) 4455257955Skevlo{ 4456257955Skevlo int8_t txpow1, txpow2; 4457257955Skevlo uint8_t rf; 4458257955Skevlo int i; 4459257955Skevlo 4460257955Skevlo /* find the settings for this channel (we know it exists) */ 4461257955Skevlo for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4462257955Skevlo 4463257955Skevlo /* use Tx power values from EEPROM */ 4464257955Skevlo txpow1 = sc->txpow1[i]; 4465257955Skevlo txpow2 = sc->txpow2[i]; 4466257955Skevlo 4467257955Skevlo run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n); 4468257955Skevlo run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f); 4469257955Skevlo run_rt3070_rf_read(sc, 11, &rf); 4470257955Skevlo rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03); 4471257955Skevlo run_rt3070_rf_write(sc, 11, rf); 4472257955Skevlo 4473257955Skevlo run_rt3070_rf_read(sc, 49, &rf); 4474257955Skevlo rf = (rf & ~0x3f) | (txpow1 & 0x3f); 4475257955Skevlo /* The valid range of the RF R49 is 0x00 to 0x27. */ 4476257955Skevlo if ((rf & 0x3f) > 0x27) 4477257955Skevlo rf = (rf & ~0x3f) | 0x27; 4478257955Skevlo run_rt3070_rf_write(sc, 49, rf); 4479257955Skevlo 4480257955Skevlo if (sc->mac_ver == 0x5392) { 4481257955Skevlo run_rt3070_rf_read(sc, 50, &rf); 4482257955Skevlo rf = (rf & ~0x3f) | (txpow2 & 0x3f); 4483257955Skevlo /* The valid range of the RF R50 is 0x00 to 0x27. */ 4484257955Skevlo if ((rf & 0x3f) > 0x27) 4485257955Skevlo rf = (rf & ~0x3f) | 0x27; 4486257955Skevlo run_rt3070_rf_write(sc, 50, rf); 4487257955Skevlo } 4488257955Skevlo 4489257955Skevlo run_rt3070_rf_read(sc, 1, &rf); 4490257955Skevlo rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD; 4491257955Skevlo if (sc->mac_ver == 0x5392) 4492257955Skevlo rf |= RT3070_RX1_PD | RT3070_TX1_PD; 4493257955Skevlo run_rt3070_rf_write(sc, 1, rf); 4494257955Skevlo 4495257955Skevlo if (sc->mac_ver != 0x5392) { 4496257955Skevlo run_rt3070_rf_read(sc, 2, &rf); 4497257955Skevlo rf |= 0x80; 4498257955Skevlo run_rt3070_rf_write(sc, 2, rf); 4499257955Skevlo run_delay(sc, 10); 4500257955Skevlo rf &= 0x7f; 4501257955Skevlo run_rt3070_rf_write(sc, 2, rf); 4502257955Skevlo } 4503257955Skevlo 4504257955Skevlo run_adjust_freq_offset(sc); 4505257955Skevlo 4506257955Skevlo if (sc->mac_ver == 0x5392) { 4507257955Skevlo /* Fix for RT5392C. */ 4508257955Skevlo if (sc->mac_rev >= 0x0223) { 4509259030Skevlo if (chan <= 4) 4510257955Skevlo rf = 0x0f; 4511259030Skevlo else if (chan >= 5 && chan <= 7) 4512257955Skevlo rf = 0x0e; 4513259030Skevlo else 4514257955Skevlo rf = 0x0d; 4515257955Skevlo run_rt3070_rf_write(sc, 23, rf); 4516257955Skevlo 4517259030Skevlo if (chan <= 4) 4518257955Skevlo rf = 0x0c; 4519257955Skevlo else if (chan == 5) 4520257955Skevlo rf = 0x0b; 4521259030Skevlo else if (chan >= 6 && chan <= 7) 4522257955Skevlo rf = 0x0a; 4523259030Skevlo else if (chan >= 8 && chan <= 10) 4524257955Skevlo rf = 0x09; 4525259030Skevlo else 4526257955Skevlo rf = 0x08; 4527257955Skevlo run_rt3070_rf_write(sc, 59, rf); 4528257955Skevlo } else { 4529259030Skevlo if (chan <= 11) 4530257955Skevlo rf = 0x0f; 4531259030Skevlo else 4532257955Skevlo rf = 0x0b; 4533257955Skevlo run_rt3070_rf_write(sc, 59, rf); 4534257955Skevlo } 4535257955Skevlo } else { 4536257955Skevlo /* Fix for RT5390F. */ 4537257955Skevlo if (sc->mac_rev >= 0x0502) { 4538259030Skevlo if (chan <= 11) 4539257955Skevlo rf = 0x43; 4540259030Skevlo else 4541257955Skevlo rf = 0x23; 4542257955Skevlo run_rt3070_rf_write(sc, 55, rf); 4543257955Skevlo 4544259030Skevlo if (chan <= 11) 4545257955Skevlo rf = 0x0f; 4546257955Skevlo else if (chan == 12) 4547257955Skevlo rf = 0x0d; 4548259030Skevlo else 4549257955Skevlo rf = 0x0b; 4550257955Skevlo run_rt3070_rf_write(sc, 59, rf); 4551257955Skevlo } else { 4552257955Skevlo run_rt3070_rf_write(sc, 55, 0x44); 4553257955Skevlo run_rt3070_rf_write(sc, 59, 0x8f); 4554257955Skevlo } 4555257955Skevlo } 4556257955Skevlo 4557257955Skevlo /* Enable VCO calibration. */ 4558257955Skevlo run_rt3070_rf_read(sc, 3, &rf); 4559257955Skevlo rf |= RT5390_VCOCAL; 4560257955Skevlo run_rt3070_rf_write(sc, 3, rf); 4561257955Skevlo} 4562257955Skevlo 4563257955Skevlostatic void 4564259032Skevlorun_rt5592_set_chan(struct run_softc *sc, u_int chan) 4565259032Skevlo{ 4566259032Skevlo const struct rt5592_freqs *freqs; 4567259032Skevlo uint32_t tmp; 4568259032Skevlo uint8_t reg, rf, txpow_bound; 4569259032Skevlo int8_t txpow1, txpow2; 4570259032Skevlo int i; 4571259032Skevlo 4572259032Skevlo run_read(sc, RT5592_DEBUG_INDEX, &tmp); 4573259032Skevlo freqs = (tmp & RT5592_SEL_XTAL) ? 4574259032Skevlo rt5592_freqs_40mhz : rt5592_freqs_20mhz; 4575259032Skevlo 4576259032Skevlo /* find the settings for this channel (we know it exists) */ 4577259032Skevlo for (i = 0; rt2860_rf2850[i].chan != chan; i++, freqs++); 4578259032Skevlo 4579259032Skevlo /* use Tx power values from EEPROM */ 4580259032Skevlo txpow1 = sc->txpow1[i]; 4581259032Skevlo txpow2 = sc->txpow2[i]; 4582259032Skevlo 4583259032Skevlo run_read(sc, RT3070_LDO_CFG0, &tmp); 4584259032Skevlo tmp &= ~0x1c000000; 4585259032Skevlo if (chan > 14) 4586259032Skevlo tmp |= 0x14000000; 4587259032Skevlo run_write(sc, RT3070_LDO_CFG0, tmp); 4588259032Skevlo 4589259032Skevlo /* N setting. */ 4590259032Skevlo run_rt3070_rf_write(sc, 8, freqs->n & 0xff); 4591259032Skevlo run_rt3070_rf_read(sc, 9, &rf); 4592259032Skevlo rf &= ~(1 << 4); 4593259032Skevlo rf |= ((freqs->n & 0x0100) >> 8) << 4; 4594259032Skevlo run_rt3070_rf_write(sc, 9, rf); 4595259032Skevlo 4596259032Skevlo /* K setting. */ 4597259032Skevlo run_rt3070_rf_read(sc, 9, &rf); 4598259032Skevlo rf &= ~0x0f; 4599259032Skevlo rf |= (freqs->k & 0x0f); 4600259032Skevlo run_rt3070_rf_write(sc, 9, rf); 4601259032Skevlo 4602259032Skevlo /* Mode setting. */ 4603259032Skevlo run_rt3070_rf_read(sc, 11, &rf); 4604259032Skevlo rf &= ~0x0c; 4605259032Skevlo rf |= ((freqs->m - 0x8) & 0x3) << 2; 4606259032Skevlo run_rt3070_rf_write(sc, 11, rf); 4607259032Skevlo run_rt3070_rf_read(sc, 9, &rf); 4608259032Skevlo rf &= ~(1 << 7); 4609259032Skevlo rf |= (((freqs->m - 0x8) & 0x4) >> 2) << 7; 4610259032Skevlo run_rt3070_rf_write(sc, 9, rf); 4611259032Skevlo 4612259032Skevlo /* R setting. */ 4613259032Skevlo run_rt3070_rf_read(sc, 11, &rf); 4614259032Skevlo rf &= ~0x03; 4615259032Skevlo rf |= (freqs->r - 0x1); 4616259032Skevlo run_rt3070_rf_write(sc, 11, rf); 4617259032Skevlo 4618259032Skevlo if (chan <= 14) { 4619259032Skevlo /* Initialize RF registers for 2GHZ. */ 4620259032Skevlo for (i = 0; i < nitems(rt5592_2ghz_def_rf); i++) { 4621259032Skevlo run_rt3070_rf_write(sc, rt5592_2ghz_def_rf[i].reg, 4622259032Skevlo rt5592_2ghz_def_rf[i].val); 4623259032Skevlo } 4624259032Skevlo 4625259032Skevlo rf = (chan <= 10) ? 0x07 : 0x06; 4626259032Skevlo run_rt3070_rf_write(sc, 23, rf); 4627259032Skevlo run_rt3070_rf_write(sc, 59, rf); 4628259032Skevlo 4629259032Skevlo run_rt3070_rf_write(sc, 55, 0x43); 4630259032Skevlo 4631259032Skevlo /* 4632259032Skevlo * RF R49/R50 Tx power ALC code. 4633259032Skevlo * G-band bit<7:6>=1:0, bit<5:0> range from 0x0 ~ 0x27. 4634259032Skevlo */ 4635259032Skevlo reg = 2; 4636259032Skevlo txpow_bound = 0x27; 4637259032Skevlo } else { 4638259032Skevlo /* Initialize RF registers for 5GHZ. */ 4639259032Skevlo for (i = 0; i < nitems(rt5592_5ghz_def_rf); i++) { 4640259032Skevlo run_rt3070_rf_write(sc, rt5592_5ghz_def_rf[i].reg, 4641259032Skevlo rt5592_5ghz_def_rf[i].val); 4642259032Skevlo } 4643259032Skevlo for (i = 0; i < nitems(rt5592_chan_5ghz); i++) { 4644259032Skevlo if (chan >= rt5592_chan_5ghz[i].firstchan && 4645259032Skevlo chan <= rt5592_chan_5ghz[i].lastchan) { 4646259032Skevlo run_rt3070_rf_write(sc, rt5592_chan_5ghz[i].reg, 4647259032Skevlo rt5592_chan_5ghz[i].val); 4648259032Skevlo } 4649259032Skevlo } 4650259032Skevlo 4651259032Skevlo /* 4652259032Skevlo * RF R49/R50 Tx power ALC code. 4653259032Skevlo * A-band bit<7:6>=1:1, bit<5:0> range from 0x0 ~ 0x2b. 4654259032Skevlo */ 4655259032Skevlo reg = 3; 4656259032Skevlo txpow_bound = 0x2b; 4657259032Skevlo } 4658259032Skevlo 4659259032Skevlo /* RF R49 ch0 Tx power ALC code. */ 4660259032Skevlo run_rt3070_rf_read(sc, 49, &rf); 4661259032Skevlo rf &= ~0xc0; 4662259032Skevlo rf |= (reg << 6); 4663259032Skevlo rf = (rf & ~0x3f) | (txpow1 & 0x3f); 4664259032Skevlo if ((rf & 0x3f) > txpow_bound) 4665259032Skevlo rf = (rf & ~0x3f) | txpow_bound; 4666259032Skevlo run_rt3070_rf_write(sc, 49, rf); 4667259032Skevlo 4668259032Skevlo /* RF R50 ch1 Tx power ALC code. */ 4669259032Skevlo run_rt3070_rf_read(sc, 50, &rf); 4670259032Skevlo rf &= ~(1 << 7 | 1 << 6); 4671259032Skevlo rf |= (reg << 6); 4672259032Skevlo rf = (rf & ~0x3f) | (txpow2 & 0x3f); 4673259032Skevlo if ((rf & 0x3f) > txpow_bound) 4674259032Skevlo rf = (rf & ~0x3f) | txpow_bound; 4675259032Skevlo run_rt3070_rf_write(sc, 50, rf); 4676259032Skevlo 4677259032Skevlo /* Enable RF_BLOCK, PLL_PD, RX0_PD, and TX0_PD. */ 4678259032Skevlo run_rt3070_rf_read(sc, 1, &rf); 4679259032Skevlo rf |= (RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD); 4680259032Skevlo if (sc->ntxchains > 1) 4681259032Skevlo rf |= RT3070_TX1_PD; 4682259032Skevlo if (sc->nrxchains > 1) 4683259032Skevlo rf |= RT3070_RX1_PD; 4684259032Skevlo run_rt3070_rf_write(sc, 1, rf); 4685259032Skevlo 4686259032Skevlo run_rt3070_rf_write(sc, 6, 0xe4); 4687259032Skevlo 4688259032Skevlo run_rt3070_rf_write(sc, 30, 0x10); 4689259032Skevlo run_rt3070_rf_write(sc, 31, 0x80); 4690259032Skevlo run_rt3070_rf_write(sc, 32, 0x80); 4691259032Skevlo 4692259032Skevlo run_adjust_freq_offset(sc); 4693259032Skevlo 4694259032Skevlo /* Enable VCO calibration. */ 4695259032Skevlo run_rt3070_rf_read(sc, 3, &rf); 4696259032Skevlo rf |= RT5390_VCOCAL; 4697259032Skevlo run_rt3070_rf_write(sc, 3, rf); 4698259032Skevlo} 4699259032Skevlo 4700259032Skevlostatic void 4701203134Sthompsarun_set_rx_antenna(struct run_softc *sc, int aux) 4702203134Sthompsa{ 4703203134Sthompsa uint32_t tmp; 4704257955Skevlo uint8_t bbp152; 4705203134Sthompsa 4706203134Sthompsa if (aux) { 4707257955Skevlo if (sc->rf_rev == RT5390_RF_5370) { 4708257955Skevlo run_bbp_read(sc, 152, &bbp152); 4709257955Skevlo run_bbp_write(sc, 152, bbp152 & ~0x80); 4710259030Skevlo } else { 4711257955Skevlo run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0); 4712257955Skevlo run_read(sc, RT2860_GPIO_CTRL, &tmp); 4713257955Skevlo run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08); 4714257955Skevlo } 4715203134Sthompsa } else { 4716257955Skevlo if (sc->rf_rev == RT5390_RF_5370) { 4717257955Skevlo run_bbp_read(sc, 152, &bbp152); 4718257955Skevlo run_bbp_write(sc, 152, bbp152 | 0x80); 4719259030Skevlo } else { 4720257955Skevlo run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1); 4721257955Skevlo run_read(sc, RT2860_GPIO_CTRL, &tmp); 4722257955Skevlo run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808); 4723257955Skevlo } 4724203134Sthompsa } 4725203134Sthompsa} 4726203134Sthompsa 4727203134Sthompsastatic int 4728203134Sthompsarun_set_chan(struct run_softc *sc, struct ieee80211_channel *c) 4729203134Sthompsa{ 4730287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 4731257429Shselasky u_int chan, group; 4732203134Sthompsa 4733203134Sthompsa chan = ieee80211_chan2ieee(ic, c); 4734203134Sthompsa if (chan == 0 || chan == IEEE80211_CHAN_ANY) 4735209917Sthompsa return (EINVAL); 4736203134Sthompsa 4737259032Skevlo if (sc->mac_ver == 0x5592) 4738259032Skevlo run_rt5592_set_chan(sc, chan); 4739259032Skevlo else if (sc->mac_ver >= 0x5390) 4740257955Skevlo run_rt5390_set_chan(sc, chan); 4741260219Skevlo else if (sc->mac_ver == 0x3593) 4742260219Skevlo run_rt3593_set_chan(sc, chan); 4743257955Skevlo else if (sc->mac_ver == 0x3572) 4744205042Sthompsa run_rt3572_set_chan(sc, chan); 4745205042Sthompsa else if (sc->mac_ver >= 0x3070) 4746203134Sthompsa run_rt3070_set_chan(sc, chan); 4747203134Sthompsa else 4748203134Sthompsa run_rt2870_set_chan(sc, chan); 4749203134Sthompsa 4750203134Sthompsa /* determine channel group */ 4751203134Sthompsa if (chan <= 14) 4752203134Sthompsa group = 0; 4753203134Sthompsa else if (chan <= 64) 4754203134Sthompsa group = 1; 4755203134Sthompsa else if (chan <= 128) 4756203134Sthompsa group = 2; 4757203134Sthompsa else 4758203134Sthompsa group = 3; 4759203134Sthompsa 4760203134Sthompsa /* XXX necessary only when group has changed! */ 4761203134Sthompsa run_select_chan_group(sc, group); 4762203134Sthompsa 4763203134Sthompsa run_delay(sc, 10); 4764203134Sthompsa 4765259545Skevlo /* Perform IQ calibration. */ 4766259544Skevlo if (sc->mac_ver >= 0x5392) 4767259544Skevlo run_iq_calib(sc, chan); 4768259544Skevlo 4769209917Sthompsa return (0); 4770203134Sthompsa} 4771203134Sthompsa 4772203134Sthompsastatic void 4773203134Sthompsarun_set_channel(struct ieee80211com *ic) 4774203134Sthompsa{ 4775286950Sadrian struct run_softc *sc = ic->ic_softc; 4776203134Sthompsa 4777203134Sthompsa RUN_LOCK(sc); 4778203134Sthompsa run_set_chan(sc, ic->ic_curchan); 4779203134Sthompsa RUN_UNLOCK(sc); 4780203134Sthompsa 4781203134Sthompsa return; 4782203134Sthompsa} 4783203134Sthompsa 4784203134Sthompsastatic void 4785300748Savosrun_getradiocaps(struct ieee80211com *ic, 4786300748Savos int maxchans, int *nchans, struct ieee80211_channel chans[]) 4787300748Savos{ 4788300748Savos struct run_softc *sc = ic->ic_softc; 4789300748Savos uint8_t bands[IEEE80211_MODE_BYTES]; 4790300748Savos 4791300748Savos memset(bands, 0, sizeof(bands)); 4792300748Savos setbit(bands, IEEE80211_MODE_11B); 4793300748Savos setbit(bands, IEEE80211_MODE_11G); 4794300748Savos ieee80211_add_channel_list_2ghz(chans, maxchans, nchans, 4795300748Savos run_chan_2ghz, nitems(run_chan_2ghz), bands, 0); 4796300748Savos 4797300748Savos if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850 || 4798300748Savos sc->rf_rev == RT3070_RF_3052 || sc->rf_rev == RT3593_RF_3053 || 4799300748Savos sc->rf_rev == RT5592_RF_5592) { 4800300748Savos setbit(bands, IEEE80211_MODE_11A); 4801300748Savos ieee80211_add_channel_list_5ghz(chans, maxchans, nchans, 4802300748Savos run_chan_5ghz, nitems(run_chan_5ghz), bands, 0); 4803300748Savos } 4804300748Savos} 4805300748Savos 4806300748Savosstatic void 4807203134Sthompsarun_scan_start(struct ieee80211com *ic) 4808203134Sthompsa{ 4809286950Sadrian struct run_softc *sc = ic->ic_softc; 4810203134Sthompsa uint32_t tmp; 4811203134Sthompsa 4812203134Sthompsa RUN_LOCK(sc); 4813203134Sthompsa 4814203134Sthompsa /* abort TSF synchronization */ 4815203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 4816203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, 4817203134Sthompsa tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 4818203134Sthompsa RT2860_TBTT_TIMER_EN)); 4819287197Sglebius run_set_bssid(sc, ieee80211broadcastaddr); 4820203134Sthompsa 4821203134Sthompsa RUN_UNLOCK(sc); 4822203134Sthompsa 4823203134Sthompsa return; 4824203134Sthompsa} 4825203134Sthompsa 4826203134Sthompsastatic void 4827203134Sthompsarun_scan_end(struct ieee80211com *ic) 4828203134Sthompsa{ 4829286950Sadrian struct run_softc *sc = ic->ic_softc; 4830203134Sthompsa 4831203134Sthompsa RUN_LOCK(sc); 4832203134Sthompsa 4833203134Sthompsa run_enable_tsf_sync(sc); 4834296356Savos run_set_bssid(sc, sc->sc_bssid); 4835203134Sthompsa 4836203134Sthompsa RUN_UNLOCK(sc); 4837203134Sthompsa 4838203134Sthompsa return; 4839203134Sthompsa} 4840203134Sthompsa 4841208019Sthompsa/* 4842208019Sthompsa * Could be called from ieee80211_node_timeout() 4843208019Sthompsa * (non-sleepable thread) 4844208019Sthompsa */ 4845208019Sthompsastatic void 4846208019Sthompsarun_update_beacon(struct ieee80211vap *vap, int item) 4847203134Sthompsa{ 4848208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 4849288095Sadrian struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; 4850288095Sadrian struct ieee80211_node *ni = vap->iv_bss; 4851286950Sadrian struct run_softc *sc = ic->ic_softc; 4852218492Sbschmidt struct run_vap *rvp = RUN_VAP(vap); 4853218492Sbschmidt int mcast = 0; 4854208019Sthompsa uint32_t i; 4855208019Sthompsa 4856218492Sbschmidt switch (item) { 4857218492Sbschmidt case IEEE80211_BEACON_ERP: 4858283540Sglebius run_updateslot(ic); 4859218492Sbschmidt break; 4860218492Sbschmidt case IEEE80211_BEACON_HTINFO: 4861218492Sbschmidt run_updateprot(ic); 4862218492Sbschmidt break; 4863218492Sbschmidt case IEEE80211_BEACON_TIM: 4864218492Sbschmidt mcast = 1; /*TODO*/ 4865218492Sbschmidt break; 4866218492Sbschmidt default: 4867218492Sbschmidt break; 4868218492Sbschmidt } 4869218492Sbschmidt 4870288095Sadrian setbit(bo->bo_flags, item); 4871273448Skevlo if (rvp->beacon_mbuf == NULL) { 4872288636Sadrian rvp->beacon_mbuf = ieee80211_beacon_alloc(ni); 4873273448Skevlo if (rvp->beacon_mbuf == NULL) 4874273448Skevlo return; 4875273448Skevlo } 4876288636Sadrian ieee80211_beacon_update(ni, rvp->beacon_mbuf, mcast); 4877218492Sbschmidt 4878208019Sthompsa i = RUN_CMDQ_GET(&sc->cmdq_store); 4879208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 4880208019Sthompsa sc->cmdq[i].func = run_update_beacon_cb; 4881208019Sthompsa sc->cmdq[i].arg0 = vap; 4882208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 4883208019Sthompsa 4884208019Sthompsa return; 4885203134Sthompsa} 4886203134Sthompsa 4887203134Sthompsastatic void 4888208019Sthompsarun_update_beacon_cb(void *arg) 4889203134Sthompsa{ 4890208019Sthompsa struct ieee80211vap *vap = arg; 4891288095Sadrian struct ieee80211_node *ni = vap->iv_bss; 4892218492Sbschmidt struct run_vap *rvp = RUN_VAP(vap); 4893203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 4894286950Sadrian struct run_softc *sc = ic->ic_softc; 4895203134Sthompsa struct rt2860_txwi txwi; 4896203134Sthompsa struct mbuf *m; 4897259032Skevlo uint16_t txwisize; 4898208019Sthompsa uint8_t ridx; 4899203134Sthompsa 4900288095Sadrian if (ni->ni_chan == IEEE80211_CHAN_ANYC) 4901208019Sthompsa return; 4902236439Shselasky if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) 4903236439Shselasky return; 4904208019Sthompsa 4905218492Sbschmidt /* 4906218492Sbschmidt * No need to call ieee80211_beacon_update(), run_update_beacon() 4907298932Spfg * is taking care of appropriate calls. 4908218492Sbschmidt */ 4909218492Sbschmidt if (rvp->beacon_mbuf == NULL) { 4910288636Sadrian rvp->beacon_mbuf = ieee80211_beacon_alloc(ni); 4911218492Sbschmidt if (rvp->beacon_mbuf == NULL) 4912218492Sbschmidt return; 4913218492Sbschmidt } 4914218492Sbschmidt m = rvp->beacon_mbuf; 4915203134Sthompsa 4916259032Skevlo memset(&txwi, 0, sizeof(txwi)); 4917203134Sthompsa txwi.wcid = 0xff; 4918203134Sthompsa txwi.len = htole16(m->m_pkthdr.len); 4919259032Skevlo 4920203134Sthompsa /* send beacons at the lowest available rate */ 4921208019Sthompsa ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? 4922208019Sthompsa RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; 4923208019Sthompsa txwi.phy = htole16(rt2860_rates[ridx].mcs); 4924208019Sthompsa if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM) 4925259032Skevlo txwi.phy |= htole16(RT2860_PHY_OFDM); 4926203134Sthompsa txwi.txop = RT2860_TX_TXOP_HT; 4927203134Sthompsa txwi.flags = RT2860_TX_TS; 4928209144Sthompsa txwi.xflags = RT2860_TX_NSEQ; 4929203134Sthompsa 4930259032Skevlo txwisize = (sc->mac_ver == 0x5592) ? 4931259032Skevlo sizeof(txwi) + sizeof(uint32_t) : sizeof(txwi); 4932259032Skevlo run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id), (uint8_t *)&txwi, 4933259032Skevlo txwisize); 4934259032Skevlo run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id) + txwisize, 4935259032Skevlo mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1); 4936203134Sthompsa} 4937203134Sthompsa 4938203134Sthompsastatic void 4939203134Sthompsarun_updateprot(struct ieee80211com *ic) 4940203134Sthompsa{ 4941286950Sadrian struct run_softc *sc = ic->ic_softc; 4942218492Sbschmidt uint32_t i; 4943218492Sbschmidt 4944218492Sbschmidt i = RUN_CMDQ_GET(&sc->cmdq_store); 4945218492Sbschmidt DPRINTF("cmdq_store=%d\n", i); 4946218492Sbschmidt sc->cmdq[i].func = run_updateprot_cb; 4947218492Sbschmidt sc->cmdq[i].arg0 = ic; 4948218492Sbschmidt ieee80211_runtask(ic, &sc->cmdq_task); 4949218492Sbschmidt} 4950218492Sbschmidt 4951218492Sbschmidtstatic void 4952218492Sbschmidtrun_updateprot_cb(void *arg) 4953218492Sbschmidt{ 4954218492Sbschmidt struct ieee80211com *ic = arg; 4955286950Sadrian struct run_softc *sc = ic->ic_softc; 4956203134Sthompsa uint32_t tmp; 4957203134Sthompsa 4958203134Sthompsa tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL; 4959203134Sthompsa /* setup protection frame rate (MCS code) */ 4960203134Sthompsa tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ? 4961270192Skevlo rt2860_rates[RT2860_RIDX_OFDM6].mcs | RT2860_PHY_OFDM : 4962203134Sthompsa rt2860_rates[RT2860_RIDX_CCK11].mcs; 4963203134Sthompsa 4964203134Sthompsa /* CCK frames don't require protection */ 4965203134Sthompsa run_write(sc, RT2860_CCK_PROT_CFG, tmp); 4966203134Sthompsa if (ic->ic_flags & IEEE80211_F_USEPROT) { 4967203134Sthompsa if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) 4968203134Sthompsa tmp |= RT2860_PROT_CTRL_RTS_CTS; 4969203134Sthompsa else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) 4970203134Sthompsa tmp |= RT2860_PROT_CTRL_CTS; 4971203134Sthompsa } 4972203134Sthompsa run_write(sc, RT2860_OFDM_PROT_CFG, tmp); 4973203134Sthompsa} 4974203134Sthompsa 4975203134Sthompsastatic void 4976208019Sthompsarun_usb_timeout_cb(void *arg) 4977203134Sthompsa{ 4978208019Sthompsa struct ieee80211vap *vap = arg; 4979286950Sadrian struct run_softc *sc = vap->iv_ic->ic_softc; 4980203134Sthompsa 4981208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 4982203134Sthompsa 4983203134Sthompsa if(vap->iv_state == IEEE80211_S_RUN && 4984203134Sthompsa vap->iv_opmode != IEEE80211_M_STA) 4985203134Sthompsa run_reset_livelock(sc); 4986209917Sthompsa else if (vap->iv_state == IEEE80211_S_SCAN) { 4987203134Sthompsa DPRINTF("timeout caused by scan\n"); 4988203134Sthompsa /* cancel bgscan */ 4989203134Sthompsa ieee80211_cancel_scan(vap); 4990203134Sthompsa } else 4991203134Sthompsa DPRINTF("timeout by unknown cause\n"); 4992203134Sthompsa} 4993203134Sthompsa 4994203134Sthompsastatic void 4995203134Sthompsarun_reset_livelock(struct run_softc *sc) 4996203134Sthompsa{ 4997203134Sthompsa uint32_t tmp; 4998203134Sthompsa 4999208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 5000208019Sthompsa 5001203134Sthompsa /* 5002203134Sthompsa * In IBSS or HostAP modes (when the hardware sends beacons), the MAC 5003203134Sthompsa * can run into a livelock and start sending CTS-to-self frames like 5004203134Sthompsa * crazy if protection is enabled. Reset MAC/BBP for a while 5005203134Sthompsa */ 5006203134Sthompsa run_read(sc, RT2860_DEBUG, &tmp); 5007208019Sthompsa DPRINTFN(3, "debug reg %08x\n", tmp); 5008209917Sthompsa if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) { 5009203134Sthompsa DPRINTF("CTS-to-self livelock detected\n"); 5010203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST); 5011203134Sthompsa run_delay(sc, 1); 5012203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 5013203134Sthompsa RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 5014203134Sthompsa } 5015203134Sthompsa} 5016203134Sthompsa 5017203134Sthompsastatic void 5018283540Sglebiusrun_update_promisc_locked(struct run_softc *sc) 5019203134Sthompsa{ 5020203134Sthompsa uint32_t tmp; 5021203134Sthompsa 5022203134Sthompsa run_read(sc, RT2860_RX_FILTR_CFG, &tmp); 5023203134Sthompsa 5024203134Sthompsa tmp |= RT2860_DROP_UC_NOME; 5025287197Sglebius if (sc->sc_ic.ic_promisc > 0) 5026203134Sthompsa tmp &= ~RT2860_DROP_UC_NOME; 5027203134Sthompsa 5028203134Sthompsa run_write(sc, RT2860_RX_FILTR_CFG, tmp); 5029203134Sthompsa 5030287197Sglebius DPRINTF("%s promiscuous mode\n", (sc->sc_ic.ic_promisc > 0) ? 5031203134Sthompsa "entering" : "leaving"); 5032203134Sthompsa} 5033203134Sthompsa 5034203134Sthompsastatic void 5035283540Sglebiusrun_update_promisc(struct ieee80211com *ic) 5036203134Sthompsa{ 5037283540Sglebius struct run_softc *sc = ic->ic_softc; 5038203134Sthompsa 5039287197Sglebius if ((sc->sc_flags & RUN_RUNNING) == 0) 5040203134Sthompsa return; 5041203134Sthompsa 5042203134Sthompsa RUN_LOCK(sc); 5043283540Sglebius run_update_promisc_locked(sc); 5044203134Sthompsa RUN_UNLOCK(sc); 5045203134Sthompsa} 5046203134Sthompsa 5047203134Sthompsastatic void 5048203134Sthompsarun_enable_tsf_sync(struct run_softc *sc) 5049203134Sthompsa{ 5050287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 5051203134Sthompsa struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 5052203134Sthompsa uint32_t tmp; 5053203134Sthompsa 5054257955Skevlo DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id, 5055257955Skevlo ic->ic_opmode); 5056208019Sthompsa 5057203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 5058203134Sthompsa tmp &= ~0x1fffff; 5059203134Sthompsa tmp |= vap->iv_bss->ni_intval * 16; 5060203134Sthompsa tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN; 5061203134Sthompsa 5062208019Sthompsa if (ic->ic_opmode == IEEE80211_M_STA) { 5063203134Sthompsa /* 5064203134Sthompsa * Local TSF is always updated with remote TSF on beacon 5065203134Sthompsa * reception. 5066203134Sthompsa */ 5067203134Sthompsa tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT; 5068208019Sthompsa } else if (ic->ic_opmode == IEEE80211_M_IBSS) { 5069203134Sthompsa tmp |= RT2860_BCN_TX_EN; 5070203134Sthompsa /* 5071203134Sthompsa * Local TSF is updated with remote TSF on beacon reception 5072203134Sthompsa * only if the remote TSF is greater than local TSF. 5073203134Sthompsa */ 5074203134Sthompsa tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT; 5075208019Sthompsa } else if (ic->ic_opmode == IEEE80211_M_HOSTAP || 5076208019Sthompsa ic->ic_opmode == IEEE80211_M_MBSS) { 5077203134Sthompsa tmp |= RT2860_BCN_TX_EN; 5078203134Sthompsa /* SYNC with nobody */ 5079203134Sthompsa tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT; 5080208019Sthompsa } else { 5081203134Sthompsa DPRINTF("Enabling TSF failed. undefined opmode\n"); 5082208019Sthompsa return; 5083208019Sthompsa } 5084203134Sthompsa 5085203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, tmp); 5086203134Sthompsa} 5087203134Sthompsa 5088203134Sthompsastatic void 5089287555Skevlorun_enable_tsf(struct run_softc *sc) 5090287555Skevlo{ 5091287555Skevlo uint32_t tmp; 5092287555Skevlo 5093287555Skevlo if (run_read(sc, RT2860_BCN_TIME_CFG, &tmp) == 0) { 5094287555Skevlo tmp &= ~(RT2860_BCN_TX_EN | RT2860_TBTT_TIMER_EN); 5095287555Skevlo tmp |= RT2860_TSF_TIMER_EN; 5096287555Skevlo run_write(sc, RT2860_BCN_TIME_CFG, tmp); 5097287555Skevlo } 5098287555Skevlo} 5099287555Skevlo 5100287555Skevlostatic void 5101287554Skevlorun_get_tsf(struct run_softc *sc, uint64_t *buf) 5102287554Skevlo{ 5103287554Skevlo run_read_region_1(sc, RT2860_TSF_TIMER_DW0, (uint8_t *)buf, 5104287554Skevlo sizeof(*buf)); 5105287554Skevlo} 5106287554Skevlo 5107287554Skevlostatic void 5108203134Sthompsarun_enable_mrr(struct run_softc *sc) 5109203134Sthompsa{ 5110259546Skevlo#define CCK(mcs) (mcs) 5111259546Skevlo#define OFDM(mcs) (1 << 3 | (mcs)) 5112203134Sthompsa run_write(sc, RT2860_LG_FBK_CFG0, 5113203134Sthompsa OFDM(6) << 28 | /* 54->48 */ 5114203134Sthompsa OFDM(5) << 24 | /* 48->36 */ 5115203134Sthompsa OFDM(4) << 20 | /* 36->24 */ 5116203134Sthompsa OFDM(3) << 16 | /* 24->18 */ 5117203134Sthompsa OFDM(2) << 12 | /* 18->12 */ 5118203134Sthompsa OFDM(1) << 8 | /* 12-> 9 */ 5119203134Sthompsa OFDM(0) << 4 | /* 9-> 6 */ 5120203134Sthompsa OFDM(0)); /* 6-> 6 */ 5121203134Sthompsa 5122203134Sthompsa run_write(sc, RT2860_LG_FBK_CFG1, 5123203134Sthompsa CCK(2) << 12 | /* 11->5.5 */ 5124203134Sthompsa CCK(1) << 8 | /* 5.5-> 2 */ 5125203134Sthompsa CCK(0) << 4 | /* 2-> 1 */ 5126203134Sthompsa CCK(0)); /* 1-> 1 */ 5127203134Sthompsa#undef OFDM 5128203134Sthompsa#undef CCK 5129203134Sthompsa} 5130203134Sthompsa 5131203134Sthompsastatic void 5132203134Sthompsarun_set_txpreamble(struct run_softc *sc) 5133203134Sthompsa{ 5134287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 5135203134Sthompsa uint32_t tmp; 5136203134Sthompsa 5137203134Sthompsa run_read(sc, RT2860_AUTO_RSP_CFG, &tmp); 5138203134Sthompsa if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 5139203134Sthompsa tmp |= RT2860_CCK_SHORT_EN; 5140203134Sthompsa else 5141203134Sthompsa tmp &= ~RT2860_CCK_SHORT_EN; 5142203134Sthompsa run_write(sc, RT2860_AUTO_RSP_CFG, tmp); 5143203134Sthompsa} 5144203134Sthompsa 5145203134Sthompsastatic void 5146203134Sthompsarun_set_basicrates(struct run_softc *sc) 5147203134Sthompsa{ 5148287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 5149203134Sthompsa 5150203134Sthompsa /* set basic rates mask */ 5151203134Sthompsa if (ic->ic_curmode == IEEE80211_MODE_11B) 5152203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003); 5153203134Sthompsa else if (ic->ic_curmode == IEEE80211_MODE_11A) 5154203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150); 5155203134Sthompsa else /* 11g */ 5156203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f); 5157203134Sthompsa} 5158203134Sthompsa 5159203134Sthompsastatic void 5160203134Sthompsarun_set_leds(struct run_softc *sc, uint16_t which) 5161203134Sthompsa{ 5162203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS, 5163203134Sthompsa which | (sc->leds & 0x7f)); 5164203134Sthompsa} 5165203134Sthompsa 5166203134Sthompsastatic void 5167203134Sthompsarun_set_bssid(struct run_softc *sc, const uint8_t *bssid) 5168203134Sthompsa{ 5169203134Sthompsa run_write(sc, RT2860_MAC_BSSID_DW0, 5170203134Sthompsa bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24); 5171203134Sthompsa run_write(sc, RT2860_MAC_BSSID_DW1, 5172203134Sthompsa bssid[4] | bssid[5] << 8); 5173203134Sthompsa} 5174203134Sthompsa 5175203134Sthompsastatic void 5176203134Sthompsarun_set_macaddr(struct run_softc *sc, const uint8_t *addr) 5177203134Sthompsa{ 5178203134Sthompsa run_write(sc, RT2860_MAC_ADDR_DW0, 5179203134Sthompsa addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24); 5180203134Sthompsa run_write(sc, RT2860_MAC_ADDR_DW1, 5181203134Sthompsa addr[4] | addr[5] << 8 | 0xff << 16); 5182203134Sthompsa} 5183203134Sthompsa 5184203134Sthompsastatic void 5185283540Sglebiusrun_updateslot(struct ieee80211com *ic) 5186203134Sthompsa{ 5187283540Sglebius struct run_softc *sc = ic->ic_softc; 5188218492Sbschmidt uint32_t i; 5189218492Sbschmidt 5190218492Sbschmidt i = RUN_CMDQ_GET(&sc->cmdq_store); 5191218492Sbschmidt DPRINTF("cmdq_store=%d\n", i); 5192218492Sbschmidt sc->cmdq[i].func = run_updateslot_cb; 5193287197Sglebius sc->cmdq[i].arg0 = ic; 5194218492Sbschmidt ieee80211_runtask(ic, &sc->cmdq_task); 5195218492Sbschmidt 5196218492Sbschmidt return; 5197218492Sbschmidt} 5198218492Sbschmidt 5199218492Sbschmidt/* ARGSUSED */ 5200218492Sbschmidtstatic void 5201218492Sbschmidtrun_updateslot_cb(void *arg) 5202218492Sbschmidt{ 5203287197Sglebius struct ieee80211com *ic = arg; 5204286950Sadrian struct run_softc *sc = ic->ic_softc; 5205203134Sthompsa uint32_t tmp; 5206203134Sthompsa 5207203134Sthompsa run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp); 5208203134Sthompsa tmp &= ~0xff; 5209292165Savos tmp |= IEEE80211_GET_SLOTTIME(ic); 5210203134Sthompsa run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp); 5211203134Sthompsa} 5212203134Sthompsa 5213208019Sthompsastatic void 5214283540Sglebiusrun_update_mcast(struct ieee80211com *ic) 5215208019Sthompsa{ 5216208019Sthompsa} 5217208019Sthompsa 5218203134Sthompsastatic int8_t 5219203134Sthompsarun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain) 5220203134Sthompsa{ 5221287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 5222203134Sthompsa struct ieee80211_channel *c = ic->ic_curchan; 5223203134Sthompsa int delta; 5224203134Sthompsa 5225203134Sthompsa if (IEEE80211_IS_CHAN_5GHZ(c)) { 5226257429Shselasky u_int chan = ieee80211_chan2ieee(ic, c); 5227203134Sthompsa delta = sc->rssi_5ghz[rxchain]; 5228203134Sthompsa 5229203134Sthompsa /* determine channel group */ 5230203134Sthompsa if (chan <= 64) 5231203134Sthompsa delta -= sc->lna[1]; 5232203134Sthompsa else if (chan <= 128) 5233203134Sthompsa delta -= sc->lna[2]; 5234203134Sthompsa else 5235203134Sthompsa delta -= sc->lna[3]; 5236203134Sthompsa } else 5237203134Sthompsa delta = sc->rssi_2ghz[rxchain] - sc->lna[0]; 5238203134Sthompsa 5239209917Sthompsa return (-12 - delta - rssi); 5240203134Sthompsa} 5241203134Sthompsa 5242257955Skevlostatic void 5243257955Skevlorun_rt5390_bbp_init(struct run_softc *sc) 5244257955Skevlo{ 5245299176Spfg u_int i; 5246259032Skevlo uint8_t bbp; 5247257955Skevlo 5248259032Skevlo /* Apply maximum likelihood detection for 2 stream case. */ 5249259032Skevlo run_bbp_read(sc, 105, &bbp); 5250259032Skevlo if (sc->nrxchains > 1) 5251259032Skevlo run_bbp_write(sc, 105, bbp | RT5390_MLD); 5252259032Skevlo 5253257955Skevlo /* Avoid data lost and CRC error. */ 5254259032Skevlo run_bbp_read(sc, 4, &bbp); 5255259031Skevlo run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 5256257955Skevlo 5257259032Skevlo if (sc->mac_ver == 0x5592) { 5258259032Skevlo for (i = 0; i < nitems(rt5592_def_bbp); i++) { 5259259032Skevlo run_bbp_write(sc, rt5592_def_bbp[i].reg, 5260259032Skevlo rt5592_def_bbp[i].val); 5261259032Skevlo } 5262259032Skevlo for (i = 0; i < nitems(rt5592_bbp_r196); i++) { 5263259032Skevlo run_bbp_write(sc, 195, i + 0x80); 5264259032Skevlo run_bbp_write(sc, 196, rt5592_bbp_r196[i]); 5265259032Skevlo } 5266259032Skevlo } else { 5267259032Skevlo for (i = 0; i < nitems(rt5390_def_bbp); i++) { 5268259032Skevlo run_bbp_write(sc, rt5390_def_bbp[i].reg, 5269259032Skevlo rt5390_def_bbp[i].val); 5270259032Skevlo } 5271257955Skevlo } 5272257955Skevlo if (sc->mac_ver == 0x5392) { 5273257955Skevlo run_bbp_write(sc, 88, 0x90); 5274257955Skevlo run_bbp_write(sc, 95, 0x9a); 5275257955Skevlo run_bbp_write(sc, 98, 0x12); 5276257955Skevlo run_bbp_write(sc, 106, 0x12); 5277257955Skevlo run_bbp_write(sc, 134, 0xd0); 5278257955Skevlo run_bbp_write(sc, 135, 0xf6); 5279257955Skevlo run_bbp_write(sc, 148, 0x84); 5280257955Skevlo } 5281257955Skevlo 5282259032Skevlo run_bbp_read(sc, 152, &bbp); 5283259032Skevlo run_bbp_write(sc, 152, bbp | 0x80); 5284259032Skevlo 5285259032Skevlo /* Fix BBP254 for RT5592C. */ 5286259032Skevlo if (sc->mac_ver == 0x5592 && sc->mac_rev >= 0x0221) { 5287259032Skevlo run_bbp_read(sc, 254, &bbp); 5288259032Skevlo run_bbp_write(sc, 254, bbp | 0x80); 5289259032Skevlo } 5290259032Skevlo 5291257955Skevlo /* Disable hardware antenna diversity. */ 5292257955Skevlo if (sc->mac_ver == 0x5390) 5293257955Skevlo run_bbp_write(sc, 154, 0); 5294259032Skevlo 5295259032Skevlo /* Initialize Rx CCK/OFDM frequency offset report. */ 5296259032Skevlo run_bbp_write(sc, 142, 1); 5297259032Skevlo run_bbp_write(sc, 143, 57); 5298257955Skevlo} 5299257955Skevlo 5300203134Sthompsastatic int 5301203134Sthompsarun_bbp_init(struct run_softc *sc) 5302203134Sthompsa{ 5303203134Sthompsa int i, error, ntries; 5304203134Sthompsa uint8_t bbp0; 5305203134Sthompsa 5306203134Sthompsa /* wait for BBP to wake up */ 5307203134Sthompsa for (ntries = 0; ntries < 20; ntries++) { 5308203134Sthompsa if ((error = run_bbp_read(sc, 0, &bbp0)) != 0) 5309203134Sthompsa return error; 5310203134Sthompsa if (bbp0 != 0 && bbp0 != 0xff) 5311203134Sthompsa break; 5312203134Sthompsa } 5313203134Sthompsa if (ntries == 20) 5314209917Sthompsa return (ETIMEDOUT); 5315203134Sthompsa 5316203134Sthompsa /* initialize BBP registers to default values */ 5317257955Skevlo if (sc->mac_ver >= 0x5390) 5318257955Skevlo run_rt5390_bbp_init(sc); 5319257955Skevlo else { 5320257955Skevlo for (i = 0; i < nitems(rt2860_def_bbp); i++) { 5321257955Skevlo run_bbp_write(sc, rt2860_def_bbp[i].reg, 5322257955Skevlo rt2860_def_bbp[i].val); 5323257955Skevlo } 5324203134Sthompsa } 5325203134Sthompsa 5326260219Skevlo if (sc->mac_ver == 0x3593) { 5327260219Skevlo run_bbp_write(sc, 79, 0x13); 5328260219Skevlo run_bbp_write(sc, 80, 0x05); 5329260219Skevlo run_bbp_write(sc, 81, 0x33); 5330260219Skevlo run_bbp_write(sc, 86, 0x46); 5331260219Skevlo run_bbp_write(sc, 137, 0x0f); 5332260219Skevlo } 5333260219Skevlo 5334203134Sthompsa /* fix BBP84 for RT2860E */ 5335205042Sthompsa if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101) 5336205042Sthompsa run_bbp_write(sc, 84, 0x19); 5337203134Sthompsa 5338260219Skevlo if (sc->mac_ver >= 0x3070 && (sc->mac_ver != 0x3593 && 5339260219Skevlo sc->mac_ver != 0x5592)) { 5340203134Sthompsa run_bbp_write(sc, 79, 0x13); 5341203134Sthompsa run_bbp_write(sc, 80, 0x05); 5342203134Sthompsa run_bbp_write(sc, 81, 0x33); 5343205042Sthompsa } else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) { 5344203134Sthompsa run_bbp_write(sc, 69, 0x16); 5345203134Sthompsa run_bbp_write(sc, 73, 0x12); 5346203134Sthompsa } 5347209917Sthompsa return (0); 5348203134Sthompsa} 5349203134Sthompsa 5350203134Sthompsastatic int 5351203134Sthompsarun_rt3070_rf_init(struct run_softc *sc) 5352203134Sthompsa{ 5353203134Sthompsa uint32_t tmp; 5354256722Skevlo uint8_t bbp4, mingain, rf, target; 5355299176Spfg u_int i; 5356203134Sthompsa 5357203134Sthompsa run_rt3070_rf_read(sc, 30, &rf); 5358203134Sthompsa /* toggle RF R30 bit 7 */ 5359203134Sthompsa run_rt3070_rf_write(sc, 30, rf | 0x80); 5360203134Sthompsa run_delay(sc, 10); 5361203134Sthompsa run_rt3070_rf_write(sc, 30, rf & ~0x80); 5362203134Sthompsa 5363203134Sthompsa /* initialize RF registers to default value */ 5364205042Sthompsa if (sc->mac_ver == 0x3572) { 5365257955Skevlo for (i = 0; i < nitems(rt3572_def_rf); i++) { 5366205042Sthompsa run_rt3070_rf_write(sc, rt3572_def_rf[i].reg, 5367205042Sthompsa rt3572_def_rf[i].val); 5368205042Sthompsa } 5369205042Sthompsa } else { 5370257955Skevlo for (i = 0; i < nitems(rt3070_def_rf); i++) { 5371205042Sthompsa run_rt3070_rf_write(sc, rt3070_def_rf[i].reg, 5372205042Sthompsa rt3070_def_rf[i].val); 5373205042Sthompsa } 5374203134Sthompsa } 5375205042Sthompsa 5376256721Skevlo if (sc->mac_ver == 0x3070 && sc->mac_rev < 0x0201) { 5377256721Skevlo /* 5378256721Skevlo * Change voltage from 1.2V to 1.35V for RT3070. 5379256721Skevlo * The DAC issue (RT3070_LDO_CFG0) has been fixed 5380256721Skevlo * in RT3070(F). 5381256721Skevlo */ 5382203134Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 5383203134Sthompsa tmp = (tmp & ~0x0f000000) | 0x0d000000; 5384203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5385203134Sthompsa 5386205042Sthompsa } else if (sc->mac_ver == 0x3071) { 5387203134Sthompsa run_rt3070_rf_read(sc, 6, &rf); 5388203134Sthompsa run_rt3070_rf_write(sc, 6, rf | 0x40); 5389203134Sthompsa run_rt3070_rf_write(sc, 31, 0x14); 5390203134Sthompsa 5391203134Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 5392203134Sthompsa tmp &= ~0x1f000000; 5393205042Sthompsa if (sc->mac_rev < 0x0211) 5394205042Sthompsa tmp |= 0x0d000000; /* 1.3V */ 5395203134Sthompsa else 5396205042Sthompsa tmp |= 0x01000000; /* 1.2V */ 5397203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5398203134Sthompsa 5399203134Sthompsa /* patch LNA_PE_G1 */ 5400203134Sthompsa run_read(sc, RT3070_GPIO_SWITCH, &tmp); 5401203134Sthompsa run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20); 5402208019Sthompsa 5403209917Sthompsa } else if (sc->mac_ver == 0x3572) { 5404205042Sthompsa run_rt3070_rf_read(sc, 6, &rf); 5405205042Sthompsa run_rt3070_rf_write(sc, 6, rf | 0x40); 5406205042Sthompsa 5407208019Sthompsa /* increase voltage from 1.2V to 1.35V */ 5408208019Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 5409208019Sthompsa tmp = (tmp & ~0x1f000000) | 0x0d000000; 5410208019Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5411203134Sthompsa 5412209917Sthompsa if (sc->mac_rev < 0x0211 || !sc->patch_dac) { 5413203134Sthompsa run_delay(sc, 1); /* wait for 1msec */ 5414205042Sthompsa /* decrease voltage back to 1.2V */ 5415203134Sthompsa tmp = (tmp & ~0x1f000000) | 0x01000000; 5416203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5417203134Sthompsa } 5418203134Sthompsa } 5419203134Sthompsa 5420203134Sthompsa /* select 20MHz bandwidth */ 5421203134Sthompsa run_rt3070_rf_read(sc, 31, &rf); 5422203134Sthompsa run_rt3070_rf_write(sc, 31, rf & ~0x20); 5423203134Sthompsa 5424203134Sthompsa /* calibrate filter for 20MHz bandwidth */ 5425203134Sthompsa sc->rf24_20mhz = 0x1f; /* default value */ 5426205042Sthompsa target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13; 5427205042Sthompsa run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz); 5428203134Sthompsa 5429203134Sthompsa /* select 40MHz bandwidth */ 5430203134Sthompsa run_bbp_read(sc, 4, &bbp4); 5431256721Skevlo run_bbp_write(sc, 4, (bbp4 & ~0x18) | 0x10); 5432205042Sthompsa run_rt3070_rf_read(sc, 31, &rf); 5433205042Sthompsa run_rt3070_rf_write(sc, 31, rf | 0x20); 5434203134Sthompsa 5435203134Sthompsa /* calibrate filter for 40MHz bandwidth */ 5436203134Sthompsa sc->rf24_40mhz = 0x2f; /* default value */ 5437205042Sthompsa target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15; 5438205042Sthompsa run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz); 5439203134Sthompsa 5440203134Sthompsa /* go back to 20MHz bandwidth */ 5441203134Sthompsa run_bbp_read(sc, 4, &bbp4); 5442203134Sthompsa run_bbp_write(sc, 4, bbp4 & ~0x18); 5443203134Sthompsa 5444205042Sthompsa if (sc->mac_ver == 0x3572) { 5445205042Sthompsa /* save default BBP registers 25 and 26 values */ 5446205042Sthompsa run_bbp_read(sc, 25, &sc->bbp25); 5447205042Sthompsa run_bbp_read(sc, 26, &sc->bbp26); 5448256721Skevlo } else if (sc->mac_rev < 0x0201 || sc->mac_rev < 0x0211) 5449203134Sthompsa run_rt3070_rf_write(sc, 27, 0x03); 5450203134Sthompsa 5451203134Sthompsa run_read(sc, RT3070_OPT_14, &tmp); 5452203134Sthompsa run_write(sc, RT3070_OPT_14, tmp | 1); 5453203134Sthompsa 5454205042Sthompsa if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) { 5455205042Sthompsa run_rt3070_rf_read(sc, 17, &rf); 5456205042Sthompsa rf &= ~RT3070_TX_LO1; 5457205042Sthompsa if ((sc->mac_ver == 0x3070 || 5458205042Sthompsa (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) && 5459205042Sthompsa !sc->ext_2ghz_lna) 5460205042Sthompsa rf |= 0x20; /* fix for long range Rx issue */ 5461256722Skevlo mingain = (sc->mac_ver == 0x3070) ? 1 : 2; 5462256722Skevlo if (sc->txmixgain_2ghz >= mingain) 5463205042Sthompsa rf = (rf & ~0x7) | sc->txmixgain_2ghz; 5464205042Sthompsa run_rt3070_rf_write(sc, 17, rf); 5465205042Sthompsa } 5466205042Sthompsa 5467270643Skevlo if (sc->mac_ver == 0x3071) { 5468203134Sthompsa run_rt3070_rf_read(sc, 1, &rf); 5469203134Sthompsa rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD); 5470203134Sthompsa rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD; 5471203134Sthompsa run_rt3070_rf_write(sc, 1, rf); 5472203134Sthompsa 5473203134Sthompsa run_rt3070_rf_read(sc, 15, &rf); 5474203134Sthompsa run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2); 5475203134Sthompsa 5476203134Sthompsa run_rt3070_rf_read(sc, 20, &rf); 5477203134Sthompsa run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1); 5478203134Sthompsa 5479203134Sthompsa run_rt3070_rf_read(sc, 21, &rf); 5480203134Sthompsa run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2); 5481205042Sthompsa } 5482203134Sthompsa 5483205042Sthompsa if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) { 5484205042Sthompsa /* fix Tx to Rx IQ glitch by raising RF voltage */ 5485203134Sthompsa run_rt3070_rf_read(sc, 27, &rf); 5486203134Sthompsa rf &= ~0x77; 5487205042Sthompsa if (sc->mac_rev < 0x0211) 5488203134Sthompsa rf |= 0x03; 5489203134Sthompsa run_rt3070_rf_write(sc, 27, rf); 5490203134Sthompsa } 5491209917Sthompsa return (0); 5492203134Sthompsa} 5493203134Sthompsa 5494257955Skevlostatic void 5495260219Skevlorun_rt3593_rf_init(struct run_softc *sc) 5496260219Skevlo{ 5497260219Skevlo uint32_t tmp; 5498260219Skevlo uint8_t rf; 5499299176Spfg u_int i; 5500260219Skevlo 5501260219Skevlo /* Disable the GPIO bits 4 and 7 for LNA PE control. */ 5502260219Skevlo run_read(sc, RT3070_GPIO_SWITCH, &tmp); 5503260219Skevlo tmp &= ~(1 << 4 | 1 << 7); 5504260219Skevlo run_write(sc, RT3070_GPIO_SWITCH, tmp); 5505260219Skevlo 5506260219Skevlo /* Initialize RF registers to default value. */ 5507260219Skevlo for (i = 0; i < nitems(rt3593_def_rf); i++) { 5508260219Skevlo run_rt3070_rf_write(sc, rt3593_def_rf[i].reg, 5509260219Skevlo rt3593_def_rf[i].val); 5510260219Skevlo } 5511260219Skevlo 5512260219Skevlo /* Toggle RF R2 to initiate calibration. */ 5513260219Skevlo run_rt3070_rf_write(sc, 2, RT5390_RESCAL); 5514260219Skevlo 5515260219Skevlo /* Initialize RF frequency offset. */ 5516260219Skevlo run_adjust_freq_offset(sc); 5517260219Skevlo 5518260219Skevlo run_rt3070_rf_read(sc, 18, &rf); 5519260219Skevlo run_rt3070_rf_write(sc, 18, rf | RT3593_AUTOTUNE_BYPASS); 5520260219Skevlo 5521260219Skevlo /* 5522260219Skevlo * Increase voltage from 1.2V to 1.35V, wait for 1 msec to 5523260219Skevlo * decrease voltage back to 1.2V. 5524260219Skevlo */ 5525260219Skevlo run_read(sc, RT3070_LDO_CFG0, &tmp); 5526260219Skevlo tmp = (tmp & ~0x1f000000) | 0x0d000000; 5527260219Skevlo run_write(sc, RT3070_LDO_CFG0, tmp); 5528260219Skevlo run_delay(sc, 1); 5529260219Skevlo tmp = (tmp & ~0x1f000000) | 0x01000000; 5530260219Skevlo run_write(sc, RT3070_LDO_CFG0, tmp); 5531260219Skevlo 5532260219Skevlo sc->rf24_20mhz = 0x1f; 5533260219Skevlo sc->rf24_40mhz = 0x2f; 5534260219Skevlo 5535260219Skevlo /* Save default BBP registers 25 and 26 values. */ 5536260219Skevlo run_bbp_read(sc, 25, &sc->bbp25); 5537260219Skevlo run_bbp_read(sc, 26, &sc->bbp26); 5538260219Skevlo 5539260219Skevlo run_read(sc, RT3070_OPT_14, &tmp); 5540260219Skevlo run_write(sc, RT3070_OPT_14, tmp | 1); 5541260219Skevlo} 5542260219Skevlo 5543260219Skevlostatic void 5544257955Skevlorun_rt5390_rf_init(struct run_softc *sc) 5545257955Skevlo{ 5546257955Skevlo uint32_t tmp; 5547257955Skevlo uint8_t rf; 5548299176Spfg u_int i; 5549257955Skevlo 5550259030Skevlo /* Toggle RF R2 to initiate calibration. */ 5551259030Skevlo if (sc->mac_ver == 0x5390) { 5552257955Skevlo run_rt3070_rf_read(sc, 2, &rf); 5553259031Skevlo run_rt3070_rf_write(sc, 2, rf | RT5390_RESCAL); 5554257955Skevlo run_delay(sc, 10); 5555259031Skevlo run_rt3070_rf_write(sc, 2, rf & ~RT5390_RESCAL); 5556259030Skevlo } else { 5557259031Skevlo run_rt3070_rf_write(sc, 2, RT5390_RESCAL); 5558259030Skevlo run_delay(sc, 10); 5559257955Skevlo } 5560257955Skevlo 5561257955Skevlo /* Initialize RF registers to default value. */ 5562259032Skevlo if (sc->mac_ver == 0x5592) { 5563259032Skevlo for (i = 0; i < nitems(rt5592_def_rf); i++) { 5564259032Skevlo run_rt3070_rf_write(sc, rt5592_def_rf[i].reg, 5565259032Skevlo rt5592_def_rf[i].val); 5566259032Skevlo } 5567259032Skevlo /* Initialize RF frequency offset. */ 5568259032Skevlo run_adjust_freq_offset(sc); 5569259032Skevlo } else if (sc->mac_ver == 0x5392) { 5570257955Skevlo for (i = 0; i < nitems(rt5392_def_rf); i++) { 5571257955Skevlo run_rt3070_rf_write(sc, rt5392_def_rf[i].reg, 5572257955Skevlo rt5392_def_rf[i].val); 5573257955Skevlo } 5574257955Skevlo if (sc->mac_rev >= 0x0223) { 5575257955Skevlo run_rt3070_rf_write(sc, 23, 0x0f); 5576257955Skevlo run_rt3070_rf_write(sc, 24, 0x3e); 5577257955Skevlo run_rt3070_rf_write(sc, 51, 0x32); 5578257955Skevlo run_rt3070_rf_write(sc, 53, 0x22); 5579257955Skevlo run_rt3070_rf_write(sc, 56, 0xc1); 5580257955Skevlo run_rt3070_rf_write(sc, 59, 0x0f); 5581257955Skevlo } 5582257955Skevlo } else { 5583257955Skevlo for (i = 0; i < nitems(rt5390_def_rf); i++) { 5584257955Skevlo run_rt3070_rf_write(sc, rt5390_def_rf[i].reg, 5585257955Skevlo rt5390_def_rf[i].val); 5586257955Skevlo } 5587257955Skevlo if (sc->mac_rev >= 0x0502) { 5588257955Skevlo run_rt3070_rf_write(sc, 6, 0xe0); 5589257955Skevlo run_rt3070_rf_write(sc, 25, 0x80); 5590257955Skevlo run_rt3070_rf_write(sc, 46, 0x73); 5591257955Skevlo run_rt3070_rf_write(sc, 53, 0x00); 5592257955Skevlo run_rt3070_rf_write(sc, 56, 0x42); 5593257955Skevlo run_rt3070_rf_write(sc, 61, 0xd1); 5594257955Skevlo } 5595257955Skevlo } 5596257955Skevlo 5597257955Skevlo sc->rf24_20mhz = 0x1f; /* default value */ 5598259032Skevlo sc->rf24_40mhz = (sc->mac_ver == 0x5592) ? 0 : 0x2f; 5599257955Skevlo 5600257955Skevlo if (sc->mac_rev < 0x0211) 5601257955Skevlo run_rt3070_rf_write(sc, 27, 0x3); 5602257955Skevlo 5603257955Skevlo run_read(sc, RT3070_OPT_14, &tmp); 5604257955Skevlo run_write(sc, RT3070_OPT_14, tmp | 1); 5605257955Skevlo} 5606257955Skevlo 5607203134Sthompsastatic int 5608203134Sthompsarun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target, 5609203134Sthompsa uint8_t *val) 5610203134Sthompsa{ 5611203134Sthompsa uint8_t rf22, rf24; 5612203134Sthompsa uint8_t bbp55_pb, bbp55_sb, delta; 5613203134Sthompsa int ntries; 5614203134Sthompsa 5615203134Sthompsa /* program filter */ 5616205042Sthompsa run_rt3070_rf_read(sc, 24, &rf24); 5617205042Sthompsa rf24 = (rf24 & 0xc0) | init; /* initial filter value */ 5618203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 5619203134Sthompsa 5620203134Sthompsa /* enable baseband loopback mode */ 5621203134Sthompsa run_rt3070_rf_read(sc, 22, &rf22); 5622203134Sthompsa run_rt3070_rf_write(sc, 22, rf22 | 0x01); 5623203134Sthompsa 5624203134Sthompsa /* set power and frequency of passband test tone */ 5625203134Sthompsa run_bbp_write(sc, 24, 0x00); 5626203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5627203134Sthompsa /* transmit test tone */ 5628203134Sthompsa run_bbp_write(sc, 25, 0x90); 5629203134Sthompsa run_delay(sc, 10); 5630203134Sthompsa /* read received power */ 5631203134Sthompsa run_bbp_read(sc, 55, &bbp55_pb); 5632203134Sthompsa if (bbp55_pb != 0) 5633203134Sthompsa break; 5634203134Sthompsa } 5635203134Sthompsa if (ntries == 100) 5636257955Skevlo return (ETIMEDOUT); 5637203134Sthompsa 5638203134Sthompsa /* set power and frequency of stopband test tone */ 5639203134Sthompsa run_bbp_write(sc, 24, 0x06); 5640203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5641203134Sthompsa /* transmit test tone */ 5642203134Sthompsa run_bbp_write(sc, 25, 0x90); 5643203134Sthompsa run_delay(sc, 10); 5644203134Sthompsa /* read received power */ 5645203134Sthompsa run_bbp_read(sc, 55, &bbp55_sb); 5646203134Sthompsa 5647203134Sthompsa delta = bbp55_pb - bbp55_sb; 5648203134Sthompsa if (delta > target) 5649203134Sthompsa break; 5650203134Sthompsa 5651203134Sthompsa /* reprogram filter */ 5652203134Sthompsa rf24++; 5653203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 5654203134Sthompsa } 5655203134Sthompsa if (ntries < 100) { 5656203134Sthompsa if (rf24 != init) 5657203134Sthompsa rf24--; /* backtrack */ 5658203134Sthompsa *val = rf24; 5659203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 5660203134Sthompsa } 5661203134Sthompsa 5662203134Sthompsa /* restore initial state */ 5663203134Sthompsa run_bbp_write(sc, 24, 0x00); 5664203134Sthompsa 5665203134Sthompsa /* disable baseband loopback mode */ 5666203134Sthompsa run_rt3070_rf_read(sc, 22, &rf22); 5667203134Sthompsa run_rt3070_rf_write(sc, 22, rf22 & ~0x01); 5668203134Sthompsa 5669209917Sthompsa return (0); 5670203134Sthompsa} 5671203134Sthompsa 5672205042Sthompsastatic void 5673205042Sthompsarun_rt3070_rf_setup(struct run_softc *sc) 5674205042Sthompsa{ 5675205042Sthompsa uint8_t bbp, rf; 5676205042Sthompsa int i; 5677205042Sthompsa 5678260219Skevlo if (sc->mac_ver == 0x3572) { 5679205042Sthompsa /* enable DC filter */ 5680205042Sthompsa if (sc->mac_rev >= 0x0201) 5681205042Sthompsa run_bbp_write(sc, 103, 0xc0); 5682205042Sthompsa 5683205042Sthompsa run_bbp_read(sc, 138, &bbp); 5684205042Sthompsa if (sc->ntxchains == 1) 5685205042Sthompsa bbp |= 0x20; /* turn off DAC1 */ 5686205042Sthompsa if (sc->nrxchains == 1) 5687205042Sthompsa bbp &= ~0x02; /* turn off ADC1 */ 5688205042Sthompsa run_bbp_write(sc, 138, bbp); 5689205042Sthompsa 5690205042Sthompsa if (sc->mac_rev >= 0x0211) { 5691205042Sthompsa /* improve power consumption */ 5692205042Sthompsa run_bbp_read(sc, 31, &bbp); 5693205042Sthompsa run_bbp_write(sc, 31, bbp & ~0x03); 5694205042Sthompsa } 5695205042Sthompsa 5696205042Sthompsa run_rt3070_rf_read(sc, 16, &rf); 5697205042Sthompsa rf = (rf & ~0x07) | sc->txmixgain_2ghz; 5698205042Sthompsa run_rt3070_rf_write(sc, 16, rf); 5699205042Sthompsa 5700205042Sthompsa } else if (sc->mac_ver == 0x3071) { 5701257409Skevlo if (sc->mac_rev >= 0x0211) { 5702257409Skevlo /* enable DC filter */ 5703205042Sthompsa run_bbp_write(sc, 103, 0xc0); 5704205042Sthompsa 5705257409Skevlo /* improve power consumption */ 5706257409Skevlo run_bbp_read(sc, 31, &bbp); 5707257409Skevlo run_bbp_write(sc, 31, bbp & ~0x03); 5708257409Skevlo } 5709257409Skevlo 5710205042Sthompsa run_bbp_read(sc, 138, &bbp); 5711205042Sthompsa if (sc->ntxchains == 1) 5712205042Sthompsa bbp |= 0x20; /* turn off DAC1 */ 5713205042Sthompsa if (sc->nrxchains == 1) 5714205042Sthompsa bbp &= ~0x02; /* turn off ADC1 */ 5715205042Sthompsa run_bbp_write(sc, 138, bbp); 5716205042Sthompsa 5717205042Sthompsa run_write(sc, RT2860_TX_SW_CFG1, 0); 5718205042Sthompsa if (sc->mac_rev < 0x0211) { 5719205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 5720205042Sthompsa sc->patch_dac ? 0x2c : 0x0f); 5721205042Sthompsa } else 5722205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0); 5723205042Sthompsa 5724205042Sthompsa } else if (sc->mac_ver == 0x3070) { 5725205042Sthompsa if (sc->mac_rev >= 0x0201) { 5726205042Sthompsa /* enable DC filter */ 5727205042Sthompsa run_bbp_write(sc, 103, 0xc0); 5728205042Sthompsa 5729205042Sthompsa /* improve power consumption */ 5730205042Sthompsa run_bbp_read(sc, 31, &bbp); 5731205042Sthompsa run_bbp_write(sc, 31, bbp & ~0x03); 5732205042Sthompsa } 5733205042Sthompsa 5734256955Skevlo if (sc->mac_rev < 0x0201) { 5735205042Sthompsa run_write(sc, RT2860_TX_SW_CFG1, 0); 5736205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0x2c); 5737205042Sthompsa } else 5738205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0); 5739205042Sthompsa } 5740205042Sthompsa 5741205042Sthompsa /* initialize RF registers from ROM for >=RT3071*/ 5742260219Skevlo if (sc->mac_ver >= 0x3071) { 5743205042Sthompsa for (i = 0; i < 10; i++) { 5744205042Sthompsa if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff) 5745205042Sthompsa continue; 5746205042Sthompsa run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val); 5747205042Sthompsa } 5748205042Sthompsa } 5749205042Sthompsa} 5750205042Sthompsa 5751260219Skevlostatic void 5752260219Skevlorun_rt3593_rf_setup(struct run_softc *sc) 5753260219Skevlo{ 5754260219Skevlo uint8_t bbp, rf; 5755260219Skevlo 5756260219Skevlo if (sc->mac_rev >= 0x0211) { 5757260219Skevlo /* Enable DC filter. */ 5758260219Skevlo run_bbp_write(sc, 103, 0xc0); 5759260219Skevlo } 5760260219Skevlo run_write(sc, RT2860_TX_SW_CFG1, 0); 5761260219Skevlo if (sc->mac_rev < 0x0211) { 5762260219Skevlo run_write(sc, RT2860_TX_SW_CFG2, 5763260219Skevlo sc->patch_dac ? 0x2c : 0x0f); 5764260219Skevlo } else 5765260219Skevlo run_write(sc, RT2860_TX_SW_CFG2, 0); 5766260219Skevlo 5767260219Skevlo run_rt3070_rf_read(sc, 50, &rf); 5768260219Skevlo run_rt3070_rf_write(sc, 50, rf & ~RT3593_TX_LO2); 5769260219Skevlo 5770260219Skevlo run_rt3070_rf_read(sc, 51, &rf); 5771260219Skevlo rf = (rf & ~(RT3593_TX_LO1 | 0x0c)) | 5772260219Skevlo ((sc->txmixgain_2ghz & 0x07) << 2); 5773260219Skevlo run_rt3070_rf_write(sc, 51, rf); 5774260219Skevlo 5775260219Skevlo run_rt3070_rf_read(sc, 38, &rf); 5776260219Skevlo run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1); 5777260219Skevlo 5778260219Skevlo run_rt3070_rf_read(sc, 39, &rf); 5779260219Skevlo run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2); 5780260219Skevlo 5781260219Skevlo run_rt3070_rf_read(sc, 1, &rf); 5782260219Skevlo run_rt3070_rf_write(sc, 1, rf & ~(RT3070_RF_BLOCK | RT3070_PLL_PD)); 5783260219Skevlo 5784260219Skevlo run_rt3070_rf_read(sc, 30, &rf); 5785260219Skevlo rf = (rf & ~0x18) | 0x10; 5786260219Skevlo run_rt3070_rf_write(sc, 30, rf); 5787260219Skevlo 5788260219Skevlo /* Apply maximum likelihood detection for 2 stream case. */ 5789260219Skevlo run_bbp_read(sc, 105, &bbp); 5790260219Skevlo if (sc->nrxchains > 1) 5791260219Skevlo run_bbp_write(sc, 105, bbp | RT5390_MLD); 5792260219Skevlo 5793260219Skevlo /* Avoid data lost and CRC error. */ 5794260219Skevlo run_bbp_read(sc, 4, &bbp); 5795260219Skevlo run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 5796260219Skevlo 5797260219Skevlo run_bbp_write(sc, 92, 0x02); 5798260219Skevlo run_bbp_write(sc, 82, 0x82); 5799260219Skevlo run_bbp_write(sc, 106, 0x05); 5800260219Skevlo run_bbp_write(sc, 104, 0x92); 5801260219Skevlo run_bbp_write(sc, 88, 0x90); 5802260219Skevlo run_bbp_write(sc, 148, 0xc8); 5803260219Skevlo run_bbp_write(sc, 47, 0x48); 5804260219Skevlo run_bbp_write(sc, 120, 0x50); 5805260219Skevlo 5806260219Skevlo run_bbp_write(sc, 163, 0x9d); 5807260219Skevlo 5808260219Skevlo /* SNR mapping. */ 5809260219Skevlo run_bbp_write(sc, 142, 0x06); 5810260219Skevlo run_bbp_write(sc, 143, 0xa0); 5811260219Skevlo run_bbp_write(sc, 142, 0x07); 5812260219Skevlo run_bbp_write(sc, 143, 0xa1); 5813260219Skevlo run_bbp_write(sc, 142, 0x08); 5814260219Skevlo run_bbp_write(sc, 143, 0xa2); 5815260219Skevlo 5816260219Skevlo run_bbp_write(sc, 31, 0x08); 5817260219Skevlo run_bbp_write(sc, 68, 0x0b); 5818260219Skevlo run_bbp_write(sc, 105, 0x04); 5819260219Skevlo} 5820260219Skevlo 5821260219Skevlostatic void 5822260219Skevlorun_rt5390_rf_setup(struct run_softc *sc) 5823260219Skevlo{ 5824260219Skevlo uint8_t bbp, rf; 5825260219Skevlo 5826260219Skevlo if (sc->mac_rev >= 0x0211) { 5827260219Skevlo /* Enable DC filter. */ 5828260219Skevlo run_bbp_write(sc, 103, 0xc0); 5829260219Skevlo 5830260219Skevlo if (sc->mac_ver != 0x5592) { 5831260219Skevlo /* Improve power consumption. */ 5832260219Skevlo run_bbp_read(sc, 31, &bbp); 5833260219Skevlo run_bbp_write(sc, 31, bbp & ~0x03); 5834260219Skevlo } 5835260219Skevlo } 5836260219Skevlo 5837260219Skevlo run_bbp_read(sc, 138, &bbp); 5838260219Skevlo if (sc->ntxchains == 1) 5839260219Skevlo bbp |= 0x20; /* turn off DAC1 */ 5840260219Skevlo if (sc->nrxchains == 1) 5841260219Skevlo bbp &= ~0x02; /* turn off ADC1 */ 5842260219Skevlo run_bbp_write(sc, 138, bbp); 5843260219Skevlo 5844260219Skevlo run_rt3070_rf_read(sc, 38, &rf); 5845260219Skevlo run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1); 5846260219Skevlo 5847260219Skevlo run_rt3070_rf_read(sc, 39, &rf); 5848260219Skevlo run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2); 5849260219Skevlo 5850260219Skevlo /* Avoid data lost and CRC error. */ 5851260219Skevlo run_bbp_read(sc, 4, &bbp); 5852260219Skevlo run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 5853260219Skevlo 5854260219Skevlo run_rt3070_rf_read(sc, 30, &rf); 5855260219Skevlo rf = (rf & ~0x18) | 0x10; 5856260219Skevlo run_rt3070_rf_write(sc, 30, rf); 5857260219Skevlo 5858260219Skevlo if (sc->mac_ver != 0x5592) { 5859260219Skevlo run_write(sc, RT2860_TX_SW_CFG1, 0); 5860260219Skevlo if (sc->mac_rev < 0x0211) { 5861260219Skevlo run_write(sc, RT2860_TX_SW_CFG2, 5862260219Skevlo sc->patch_dac ? 0x2c : 0x0f); 5863260219Skevlo } else 5864260219Skevlo run_write(sc, RT2860_TX_SW_CFG2, 0); 5865260219Skevlo } 5866260219Skevlo} 5867260219Skevlo 5868203134Sthompsastatic int 5869203134Sthompsarun_txrx_enable(struct run_softc *sc) 5870203134Sthompsa{ 5871287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 5872203134Sthompsa uint32_t tmp; 5873203134Sthompsa int error, ntries; 5874203134Sthompsa 5875203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN); 5876203134Sthompsa for (ntries = 0; ntries < 200; ntries++) { 5877203134Sthompsa if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0) 5878257955Skevlo return (error); 5879203134Sthompsa if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 5880203134Sthompsa break; 5881203134Sthompsa run_delay(sc, 50); 5882203134Sthompsa } 5883203134Sthompsa if (ntries == 200) 5884257955Skevlo return (ETIMEDOUT); 5885203134Sthompsa 5886203134Sthompsa run_delay(sc, 50); 5887203134Sthompsa 5888203134Sthompsa tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE; 5889203134Sthompsa run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 5890203134Sthompsa 5891203134Sthompsa /* enable Rx bulk aggregation (set timeout and limit) */ 5892203134Sthompsa tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN | 5893203134Sthompsa RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2); 5894203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, tmp); 5895203134Sthompsa 5896203134Sthompsa /* set Rx filter */ 5897203134Sthompsa tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR; 5898203134Sthompsa if (ic->ic_opmode != IEEE80211_M_MONITOR) { 5899203134Sthompsa tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL | 5900203134Sthompsa RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK | 5901203134Sthompsa RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV | 5902203134Sthompsa RT2860_DROP_CFACK | RT2860_DROP_CFEND; 5903203134Sthompsa if (ic->ic_opmode == IEEE80211_M_STA) 5904203134Sthompsa tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL; 5905203134Sthompsa } 5906203134Sthompsa run_write(sc, RT2860_RX_FILTR_CFG, tmp); 5907203134Sthompsa 5908203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 5909203134Sthompsa RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 5910203134Sthompsa 5911209917Sthompsa return (0); 5912203134Sthompsa} 5913203134Sthompsa 5914203134Sthompsastatic void 5915259030Skevlorun_adjust_freq_offset(struct run_softc *sc) 5916257955Skevlo{ 5917257955Skevlo uint8_t rf, tmp; 5918257955Skevlo 5919257955Skevlo run_rt3070_rf_read(sc, 17, &rf); 5920257955Skevlo tmp = rf; 5921257955Skevlo rf = (rf & ~0x7f) | (sc->freq & 0x7f); 5922257955Skevlo rf = MIN(rf, 0x5f); 5923257955Skevlo 5924257955Skevlo if (tmp != rf) 5925257955Skevlo run_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf); 5926257955Skevlo} 5927257955Skevlo 5928257955Skevlostatic void 5929203134Sthompsarun_init_locked(struct run_softc *sc) 5930203134Sthompsa{ 5931287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 5932287197Sglebius struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 5933203134Sthompsa uint32_t tmp; 5934203134Sthompsa uint8_t bbp1, bbp3; 5935203134Sthompsa int i; 5936203134Sthompsa int ridx; 5937203134Sthompsa int ntries; 5938203134Sthompsa 5939209917Sthompsa if (ic->ic_nrunning > 1) 5940208019Sthompsa return; 5941208019Sthompsa 5942203134Sthompsa run_stop(sc); 5943203134Sthompsa 5944233283Sbschmidt if (run_load_microcode(sc) != 0) { 5945233283Sbschmidt device_printf(sc->sc_dev, "could not load 8051 microcode\n"); 5946233283Sbschmidt goto fail; 5947233283Sbschmidt } 5948233283Sbschmidt 5949203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5950203134Sthompsa if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0) 5951203134Sthompsa goto fail; 5952203134Sthompsa if (tmp != 0 && tmp != 0xffffffff) 5953203134Sthompsa break; 5954203134Sthompsa run_delay(sc, 10); 5955203134Sthompsa } 5956203134Sthompsa if (ntries == 100) 5957203134Sthompsa goto fail; 5958203134Sthompsa 5959203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 5960203134Sthompsa run_setup_tx_list(sc, &sc->sc_epq[i]); 5961203134Sthompsa 5962287197Sglebius run_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); 5963203134Sthompsa 5964203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5965203134Sthompsa if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 5966203134Sthompsa goto fail; 5967203134Sthompsa if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 5968203134Sthompsa break; 5969203134Sthompsa run_delay(sc, 10); 5970203134Sthompsa } 5971203134Sthompsa if (ntries == 100) { 5972203138Sthompsa device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); 5973203134Sthompsa goto fail; 5974203134Sthompsa } 5975203134Sthompsa tmp &= 0xff0; 5976203134Sthompsa tmp |= RT2860_TX_WB_DDONE; 5977203134Sthompsa run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 5978203134Sthompsa 5979203134Sthompsa /* turn off PME_OEN to solve high-current issue */ 5980203134Sthompsa run_read(sc, RT2860_SYS_CTRL, &tmp); 5981203134Sthompsa run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN); 5982203134Sthompsa 5983203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 5984203134Sthompsa RT2860_BBP_HRST | RT2860_MAC_SRST); 5985203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, 0); 5986203134Sthompsa 5987203134Sthompsa if (run_reset(sc) != 0) { 5988203138Sthompsa device_printf(sc->sc_dev, "could not reset chipset\n"); 5989203134Sthompsa goto fail; 5990203134Sthompsa } 5991203134Sthompsa 5992203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 0); 5993203134Sthompsa 5994203134Sthompsa /* init Tx power for all Tx rates (from EEPROM) */ 5995203134Sthompsa for (ridx = 0; ridx < 5; ridx++) { 5996203134Sthompsa if (sc->txpow20mhz[ridx] == 0xffffffff) 5997203134Sthompsa continue; 5998203134Sthompsa run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]); 5999203134Sthompsa } 6000203134Sthompsa 6001257955Skevlo for (i = 0; i < nitems(rt2870_def_mac); i++) 6002203134Sthompsa run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val); 6003203134Sthompsa run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273); 6004203134Sthompsa run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344); 6005203134Sthompsa run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa); 6006203134Sthompsa 6007259030Skevlo if (sc->mac_ver >= 0x5390) { 6008259030Skevlo run_write(sc, RT2860_TX_SW_CFG0, 6009259030Skevlo 4 << RT2860_DLY_PAPE_EN_SHIFT | 4); 6010259030Skevlo if (sc->mac_ver >= 0x5392) { 6011259030Skevlo run_write(sc, RT2860_MAX_LEN_CFG, 0x00002fff); 6012259032Skevlo if (sc->mac_ver == 0x5592) { 6013259032Skevlo run_write(sc, RT2860_HT_FBK_CFG1, 0xedcba980); 6014259032Skevlo run_write(sc, RT2860_TXOP_HLDR_ET, 0x00000082); 6015259032Skevlo } else { 6016259032Skevlo run_write(sc, RT2860_HT_FBK_CFG1, 0xedcb4980); 6017259032Skevlo run_write(sc, RT2860_LG_FBK_CFG0, 0xedcba322); 6018259032Skevlo } 6019259030Skevlo } 6020260219Skevlo } else if (sc->mac_ver == 0x3593) { 6021260219Skevlo run_write(sc, RT2860_TX_SW_CFG0, 6022260219Skevlo 4 << RT2860_DLY_PAPE_EN_SHIFT | 2); 6023257955Skevlo } else if (sc->mac_ver >= 0x3070) { 6024203134Sthompsa /* set delay of PA_PE assertion to 1us (unit of 0.25us) */ 6025203134Sthompsa run_write(sc, RT2860_TX_SW_CFG0, 6026203134Sthompsa 4 << RT2860_DLY_PAPE_EN_SHIFT); 6027203134Sthompsa } 6028203134Sthompsa 6029203134Sthompsa /* wait while MAC is busy */ 6030203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 6031203134Sthompsa if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0) 6032203134Sthompsa goto fail; 6033203134Sthompsa if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY))) 6034203134Sthompsa break; 6035203134Sthompsa run_delay(sc, 10); 6036203134Sthompsa } 6037203134Sthompsa if (ntries == 100) 6038203134Sthompsa goto fail; 6039203134Sthompsa 6040203134Sthompsa /* clear Host to MCU mailbox */ 6041203134Sthompsa run_write(sc, RT2860_H2M_BBPAGENT, 0); 6042203134Sthompsa run_write(sc, RT2860_H2M_MAILBOX, 0); 6043203134Sthompsa run_delay(sc, 10); 6044203134Sthompsa 6045203134Sthompsa if (run_bbp_init(sc) != 0) { 6046203138Sthompsa device_printf(sc->sc_dev, "could not initialize BBP\n"); 6047203134Sthompsa goto fail; 6048203134Sthompsa } 6049203134Sthompsa 6050203134Sthompsa /* abort TSF synchronization */ 6051203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 6052203134Sthompsa tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 6053203134Sthompsa RT2860_TBTT_TIMER_EN); 6054203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, tmp); 6055203134Sthompsa 6056203134Sthompsa /* clear RX WCID search table */ 6057203134Sthompsa run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512); 6058203134Sthompsa /* clear WCID attribute table */ 6059203134Sthompsa run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32); 6060203134Sthompsa 6061209144Sthompsa /* hostapd sets a key before init. So, don't clear it. */ 6062209917Sthompsa if (sc->cmdq_key_set != RUN_CMDQ_GO) { 6063209144Sthompsa /* clear shared key table */ 6064209144Sthompsa run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32); 6065209144Sthompsa /* clear shared key mode */ 6066209144Sthompsa run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4); 6067209144Sthompsa } 6068209144Sthompsa 6069203134Sthompsa run_read(sc, RT2860_US_CYC_CNT, &tmp); 6070203134Sthompsa tmp = (tmp & ~0xff) | 0x1e; 6071203134Sthompsa run_write(sc, RT2860_US_CYC_CNT, tmp); 6072203134Sthompsa 6073205042Sthompsa if (sc->mac_rev != 0x0101) 6074203134Sthompsa run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f); 6075203134Sthompsa 6076203134Sthompsa run_write(sc, RT2860_WMM_TXOP0_CFG, 0); 6077203134Sthompsa run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96); 6078203134Sthompsa 6079203134Sthompsa /* write vendor-specific BBP values (from EEPROM) */ 6080260219Skevlo if (sc->mac_ver < 0x3593) { 6081257955Skevlo for (i = 0; i < 10; i++) { 6082257955Skevlo if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff) 6083257955Skevlo continue; 6084257955Skevlo run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val); 6085257955Skevlo } 6086203134Sthompsa } 6087203134Sthompsa 6088203134Sthompsa /* select Main antenna for 1T1R devices */ 6089257955Skevlo if (sc->rf_rev == RT3070_RF_3020 || sc->rf_rev == RT5390_RF_5370) 6090203134Sthompsa run_set_rx_antenna(sc, 0); 6091203134Sthompsa 6092203134Sthompsa /* send LEDs operating mode to microcontroller */ 6093203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]); 6094203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]); 6095203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]); 6096203134Sthompsa 6097257955Skevlo if (sc->mac_ver >= 0x5390) 6098257955Skevlo run_rt5390_rf_init(sc); 6099260219Skevlo else if (sc->mac_ver == 0x3593) 6100260219Skevlo run_rt3593_rf_init(sc); 6101257955Skevlo else if (sc->mac_ver >= 0x3070) 6102205042Sthompsa run_rt3070_rf_init(sc); 6103205042Sthompsa 6104203134Sthompsa /* disable non-existing Rx chains */ 6105203134Sthompsa run_bbp_read(sc, 3, &bbp3); 6106203134Sthompsa bbp3 &= ~(1 << 3 | 1 << 4); 6107203134Sthompsa if (sc->nrxchains == 2) 6108203134Sthompsa bbp3 |= 1 << 3; 6109203134Sthompsa else if (sc->nrxchains == 3) 6110203134Sthompsa bbp3 |= 1 << 4; 6111203134Sthompsa run_bbp_write(sc, 3, bbp3); 6112203134Sthompsa 6113203134Sthompsa /* disable non-existing Tx chains */ 6114203134Sthompsa run_bbp_read(sc, 1, &bbp1); 6115203134Sthompsa if (sc->ntxchains == 1) 6116203134Sthompsa bbp1 &= ~(1 << 3 | 1 << 4); 6117203134Sthompsa run_bbp_write(sc, 1, bbp1); 6118203134Sthompsa 6119260219Skevlo if (sc->mac_ver >= 0x5390) 6120260219Skevlo run_rt5390_rf_setup(sc); 6121260219Skevlo else if (sc->mac_ver == 0x3593) 6122260219Skevlo run_rt3593_rf_setup(sc); 6123260219Skevlo else if (sc->mac_ver >= 0x3070) 6124205042Sthompsa run_rt3070_rf_setup(sc); 6125203134Sthompsa 6126203134Sthompsa /* select default channel */ 6127203134Sthompsa run_set_chan(sc, ic->ic_curchan); 6128203134Sthompsa 6129203134Sthompsa /* setup initial protection mode */ 6130218492Sbschmidt run_updateprot_cb(ic); 6131203134Sthompsa 6132203134Sthompsa /* turn radio LED on */ 6133203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO); 6134203134Sthompsa 6135287197Sglebius sc->sc_flags |= RUN_RUNNING; 6136208019Sthompsa sc->cmdq_run = RUN_CMDQ_GO; 6137203134Sthompsa 6138209917Sthompsa for (i = 0; i != RUN_N_XFER; i++) 6139203134Sthompsa usbd_xfer_set_stall(sc->sc_xfer[i]); 6140203134Sthompsa 6141203134Sthompsa usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]); 6142203134Sthompsa 6143203134Sthompsa if (run_txrx_enable(sc) != 0) 6144203134Sthompsa goto fail; 6145203134Sthompsa 6146203134Sthompsa return; 6147203134Sthompsa 6148203134Sthompsafail: 6149203134Sthompsa run_stop(sc); 6150203134Sthompsa} 6151203134Sthompsa 6152203134Sthompsastatic void 6153203134Sthompsarun_stop(void *arg) 6154203134Sthompsa{ 6155203134Sthompsa struct run_softc *sc = (struct run_softc *)arg; 6156203134Sthompsa uint32_t tmp; 6157203134Sthompsa int i; 6158203134Sthompsa int ntries; 6159203134Sthompsa 6160203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 6161203134Sthompsa 6162287197Sglebius if (sc->sc_flags & RUN_RUNNING) 6163203134Sthompsa run_set_leds(sc, 0); /* turn all LEDs off */ 6164203134Sthompsa 6165287197Sglebius sc->sc_flags &= ~RUN_RUNNING; 6166203134Sthompsa 6167208019Sthompsa sc->ratectl_run = RUN_RATECTL_OFF; 6168209144Sthompsa sc->cmdq_run = sc->cmdq_key_set; 6169208019Sthompsa 6170203134Sthompsa RUN_UNLOCK(sc); 6171203134Sthompsa 6172203134Sthompsa for(i = 0; i < RUN_N_XFER; i++) 6173203134Sthompsa usbd_transfer_drain(sc->sc_xfer[i]); 6174203134Sthompsa 6175203134Sthompsa RUN_LOCK(sc); 6176203134Sthompsa 6177288649Sadrian run_drain_mbufq(sc); 6178288649Sadrian 6179209917Sthompsa if (sc->rx_m != NULL) { 6180203134Sthompsa m_free(sc->rx_m); 6181203134Sthompsa sc->rx_m = NULL; 6182203134Sthompsa } 6183203134Sthompsa 6184257955Skevlo /* Disable Tx/Rx DMA. */ 6185257955Skevlo if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 6186257955Skevlo return; 6187257955Skevlo tmp &= ~(RT2860_RX_DMA_EN | RT2860_TX_DMA_EN); 6188257955Skevlo run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 6189257955Skevlo 6190258643Shselasky for (ntries = 0; ntries < 100; ntries++) { 6191257955Skevlo if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 6192257955Skevlo return; 6193257955Skevlo if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 6194257955Skevlo break; 6195257955Skevlo run_delay(sc, 10); 6196257955Skevlo } 6197257955Skevlo if (ntries == 100) { 6198257955Skevlo device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); 6199257955Skevlo return; 6200257955Skevlo } 6201257955Skevlo 6202203134Sthompsa /* disable Tx/Rx */ 6203203134Sthompsa run_read(sc, RT2860_MAC_SYS_CTRL, &tmp); 6204203134Sthompsa tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 6205203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, tmp); 6206203134Sthompsa 6207203134Sthompsa /* wait for pending Tx to complete */ 6208203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 6209209917Sthompsa if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0) { 6210203134Sthompsa DPRINTF("Cannot read Tx queue count\n"); 6211203134Sthompsa break; 6212203134Sthompsa } 6213209917Sthompsa if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0) { 6214203134Sthompsa DPRINTF("All Tx cleared\n"); 6215203134Sthompsa break; 6216203134Sthompsa } 6217203134Sthompsa run_delay(sc, 10); 6218203134Sthompsa } 6219209917Sthompsa if (ntries >= 100) 6220203134Sthompsa DPRINTF("There are still pending Tx\n"); 6221203134Sthompsa run_delay(sc, 10); 6222203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, 0); 6223203134Sthompsa 6224203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST); 6225203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 0); 6226203134Sthompsa 6227203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 6228203134Sthompsa run_unsetup_tx_list(sc, &sc->sc_epq[i]); 6229203134Sthompsa} 6230203134Sthompsa 6231203134Sthompsastatic void 6232257429Shselaskyrun_delay(struct run_softc *sc, u_int ms) 6233203134Sthompsa{ 6234203134Sthompsa usb_pause_mtx(mtx_owned(&sc->sc_mtx) ? 6235203134Sthompsa &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms)); 6236203134Sthompsa} 6237203134Sthompsa 6238203134Sthompsastatic device_method_t run_methods[] = { 6239203134Sthompsa /* Device interface */ 6240203134Sthompsa DEVMETHOD(device_probe, run_match), 6241203134Sthompsa DEVMETHOD(device_attach, run_attach), 6242203134Sthompsa DEVMETHOD(device_detach, run_detach), 6243246614Shselasky DEVMETHOD_END 6244203134Sthompsa}; 6245203134Sthompsa 6246203134Sthompsastatic driver_t run_driver = { 6247233774Shselasky .name = "run", 6248233774Shselasky .methods = run_methods, 6249233774Shselasky .size = sizeof(struct run_softc) 6250203134Sthompsa}; 6251203134Sthompsa 6252203134Sthompsastatic devclass_t run_devclass; 6253203134Sthompsa 6254259812SkevloDRIVER_MODULE(run, uhub, run_driver, run_devclass, run_driver_loaded, NULL); 6255212122SthompsaMODULE_DEPEND(run, wlan, 1, 1, 1); 6256212122SthompsaMODULE_DEPEND(run, usb, 1, 1, 1); 6257212122SthompsaMODULE_DEPEND(run, firmware, 1, 1, 1); 6258212122SthompsaMODULE_VERSION(run, 1); 6259292080SimpUSB_PNP_HOST_INFO(run_devs); 6260