1203134Sthompsa/*- 2205042Sthompsa * Copyright (c) 2008,2010 Damien Bergamini <damien.bergamini@free.fr> 3205042Sthompsa * ported to FreeBSD by Akinori Furukoshi <moonlightakkiy@yahoo.ca> 4205042Sthompsa * USB Consulting, Hans Petter Selasky <hselasky@freebsd.org> 5261868Skevlo * Copyright (c) 2013-2014 Kevin Lo 6203134Sthompsa * 7203134Sthompsa * Permission to use, copy, modify, and distribute this software for any 8203134Sthompsa * purpose with or without fee is hereby granted, provided that the above 9203134Sthompsa * copyright notice and this permission notice appear in all copies. 10203134Sthompsa * 11203134Sthompsa * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12203134Sthompsa * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13203134Sthompsa * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14203134Sthompsa * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15203134Sthompsa * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16203134Sthompsa * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17203134Sthompsa * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18203134Sthompsa */ 19203134Sthompsa 20203134Sthompsa#include <sys/cdefs.h> 21203134Sthompsa__FBSDID("$FreeBSD: stable/10/sys/dev/usb/wlan/if_run.c 343821 2019-02-06 02:18:11Z avos $"); 22203134Sthompsa 23203134Sthompsa/*- 24259453Shselasky * Ralink Technology RT2700U/RT2800U/RT3000U/RT3900E chipset driver. 25203134Sthompsa * http://www.ralinktech.com/ 26203134Sthompsa */ 27203134Sthompsa 28203134Sthompsa#include <sys/param.h> 29203134Sthompsa#include <sys/sockio.h> 30203134Sthompsa#include <sys/sysctl.h> 31203134Sthompsa#include <sys/lock.h> 32203134Sthompsa#include <sys/mutex.h> 33203134Sthompsa#include <sys/mbuf.h> 34203134Sthompsa#include <sys/kernel.h> 35203134Sthompsa#include <sys/socket.h> 36203134Sthompsa#include <sys/systm.h> 37203134Sthompsa#include <sys/malloc.h> 38203134Sthompsa#include <sys/module.h> 39203134Sthompsa#include <sys/bus.h> 40203134Sthompsa#include <sys/endian.h> 41203134Sthompsa#include <sys/linker.h> 42203134Sthompsa#include <sys/firmware.h> 43203134Sthompsa#include <sys/kdb.h> 44203134Sthompsa 45203134Sthompsa#include <net/bpf.h> 46203134Sthompsa#include <net/if.h> 47203134Sthompsa#include <net/if_arp.h> 48203134Sthompsa#include <net/ethernet.h> 49203134Sthompsa#include <net/if_dl.h> 50203134Sthompsa#include <net/if_media.h> 51203134Sthompsa#include <net/if_types.h> 52203134Sthompsa 53203134Sthompsa#include <netinet/in.h> 54203134Sthompsa#include <netinet/in_systm.h> 55203134Sthompsa#include <netinet/in_var.h> 56203134Sthompsa#include <netinet/if_ether.h> 57203134Sthompsa#include <netinet/ip.h> 58203134Sthompsa 59203134Sthompsa#include <net80211/ieee80211_var.h> 60203134Sthompsa#include <net80211/ieee80211_regdomain.h> 61203134Sthompsa#include <net80211/ieee80211_radiotap.h> 62206358Srpaulo#include <net80211/ieee80211_ratectl.h> 63203134Sthompsa 64203134Sthompsa#include <dev/usb/usb.h> 65203134Sthompsa#include <dev/usb/usbdi.h> 66203134Sthompsa#include "usbdevs.h" 67203134Sthompsa 68261868Skevlo#define USB_DEBUG_VAR run_debug 69203134Sthompsa#include <dev/usb/usb_debug.h> 70261868Skevlo#include <dev/usb/usb_msctest.h> 71203134Sthompsa 72220235Skevlo#include <dev/usb/wlan/if_runreg.h> 73220235Skevlo#include <dev/usb/wlan/if_runvar.h> 74203134Sthompsa 75207077Sthompsa#ifdef USB_DEBUG 76261868Skevlo#define RUN_DEBUG 77203134Sthompsa#endif 78203134Sthompsa 79203134Sthompsa#ifdef RUN_DEBUG 80203134Sthompsaint run_debug = 0; 81227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, run, CTLFLAG_RW, 0, "USB run"); 82203134SthompsaSYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RW, &run_debug, 0, 83203134Sthompsa "run debug level"); 84203134Sthompsa#endif 85203134Sthompsa 86261868Skevlo#define IEEE80211_HAS_ADDR4(wh) \ 87203134Sthompsa (((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) 88203134Sthompsa 89208019Sthompsa/* 90208019Sthompsa * Because of LOR in run_key_delete(), use atomic instead. 91208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[]. 92208019Sthompsa */ 93261868Skevlo#define RUN_CMDQ_GET(c) (atomic_fetchadd_32((c), 1) & RUN_CMDQ_MASQ) 94208019Sthompsa 95223486Shselaskystatic const STRUCT_USB_HOST_ID run_devs[] = { 96261868Skevlo#define RUN_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } 97261868Skevlo#define RUN_DEV_EJECT(v,p) \ 98262604Skevlo { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RUN_EJECT) } 99262604Skevlo#define RUN_EJECT 1 100209918Sthompsa RUN_DEV(ABOCOM, RT2770), 101209918Sthompsa RUN_DEV(ABOCOM, RT2870), 102209918Sthompsa RUN_DEV(ABOCOM, RT3070), 103209918Sthompsa RUN_DEV(ABOCOM, RT3071), 104209918Sthompsa RUN_DEV(ABOCOM, RT3072), 105209918Sthompsa RUN_DEV(ABOCOM2, RT2870_1), 106209918Sthompsa RUN_DEV(ACCTON, RT2770), 107209918Sthompsa RUN_DEV(ACCTON, RT2870_1), 108209918Sthompsa RUN_DEV(ACCTON, RT2870_2), 109209918Sthompsa RUN_DEV(ACCTON, RT2870_3), 110209918Sthompsa RUN_DEV(ACCTON, RT2870_4), 111209918Sthompsa RUN_DEV(ACCTON, RT2870_5), 112209918Sthompsa RUN_DEV(ACCTON, RT3070), 113209918Sthompsa RUN_DEV(ACCTON, RT3070_1), 114209918Sthompsa RUN_DEV(ACCTON, RT3070_2), 115209918Sthompsa RUN_DEV(ACCTON, RT3070_3), 116209918Sthompsa RUN_DEV(ACCTON, RT3070_4), 117209918Sthompsa RUN_DEV(ACCTON, RT3070_5), 118209918Sthompsa RUN_DEV(AIRTIES, RT3070), 119209918Sthompsa RUN_DEV(ALLWIN, RT2070), 120209918Sthompsa RUN_DEV(ALLWIN, RT2770), 121209918Sthompsa RUN_DEV(ALLWIN, RT2870), 122209918Sthompsa RUN_DEV(ALLWIN, RT3070), 123209918Sthompsa RUN_DEV(ALLWIN, RT3071), 124209918Sthompsa RUN_DEV(ALLWIN, RT3072), 125209918Sthompsa RUN_DEV(ALLWIN, RT3572), 126209918Sthompsa RUN_DEV(AMIGO, RT2870_1), 127209918Sthompsa RUN_DEV(AMIGO, RT2870_2), 128209918Sthompsa RUN_DEV(AMIT, CGWLUSB2GNR), 129209918Sthompsa RUN_DEV(AMIT, RT2870_1), 130209918Sthompsa RUN_DEV(AMIT2, RT2870), 131209918Sthompsa RUN_DEV(ASUS, RT2870_1), 132209918Sthompsa RUN_DEV(ASUS, RT2870_2), 133209918Sthompsa RUN_DEV(ASUS, RT2870_3), 134209918Sthompsa RUN_DEV(ASUS, RT2870_4), 135209918Sthompsa RUN_DEV(ASUS, RT2870_5), 136209918Sthompsa RUN_DEV(ASUS, USBN13), 137209918Sthompsa RUN_DEV(ASUS, RT3070_1), 138261868Skevlo RUN_DEV(ASUS, USBN66), 139239358Shselasky RUN_DEV(ASUS, USB_N53), 140209918Sthompsa RUN_DEV(ASUS2, USBN11), 141209918Sthompsa RUN_DEV(AZUREWAVE, RT2870_1), 142209918Sthompsa RUN_DEV(AZUREWAVE, RT2870_2), 143209918Sthompsa RUN_DEV(AZUREWAVE, RT3070_1), 144209918Sthompsa RUN_DEV(AZUREWAVE, RT3070_2), 145209918Sthompsa RUN_DEV(AZUREWAVE, RT3070_3), 146261868Skevlo RUN_DEV(BELKIN, F9L1103), 147209918Sthompsa RUN_DEV(BELKIN, F5D8053V3), 148209918Sthompsa RUN_DEV(BELKIN, F5D8055), 149226534Shselasky RUN_DEV(BELKIN, F5D8055V2), 150209918Sthompsa RUN_DEV(BELKIN, F6D4050V1), 151257044Shselasky RUN_DEV(BELKIN, F6D4050V2), 152209918Sthompsa RUN_DEV(BELKIN, RT2870_1), 153209918Sthompsa RUN_DEV(BELKIN, RT2870_2), 154226534Shselasky RUN_DEV(CISCOLINKSYS, AE1000), 155209918Sthompsa RUN_DEV(CISCOLINKSYS2, RT3070), 156209918Sthompsa RUN_DEV(CISCOLINKSYS3, RT3070), 157209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_1), 158209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_2), 159209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_3), 160209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_4), 161209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_5), 162209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_6), 163209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_7), 164209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT2870_8), 165209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT3070_1), 166209918Sthompsa RUN_DEV(CONCEPTRONIC2, RT3070_2), 167209918Sthompsa RUN_DEV(CONCEPTRONIC2, VIGORN61), 168209918Sthompsa RUN_DEV(COREGA, CGWLUSB300GNM), 169209918Sthompsa RUN_DEV(COREGA, RT2870_1), 170209918Sthompsa RUN_DEV(COREGA, RT2870_2), 171209918Sthompsa RUN_DEV(COREGA, RT2870_3), 172209918Sthompsa RUN_DEV(COREGA, RT3070), 173209918Sthompsa RUN_DEV(CYBERTAN, RT2870), 174209918Sthompsa RUN_DEV(DLINK, RT2870), 175209918Sthompsa RUN_DEV(DLINK, RT3072), 176255238Sbr RUN_DEV(DLINK, DWA127), 177259453Shselasky RUN_DEV(DLINK, DWA140B3), 178259453Shselasky RUN_DEV(DLINK, DWA160B2), 179267263Skevlo RUN_DEV(DLINK, DWA140D1), 180261868Skevlo RUN_DEV(DLINK, DWA162), 181209918Sthompsa RUN_DEV(DLINK2, DWA130), 182209918Sthompsa RUN_DEV(DLINK2, RT2870_1), 183209918Sthompsa RUN_DEV(DLINK2, RT2870_2), 184209918Sthompsa RUN_DEV(DLINK2, RT3070_1), 185209918Sthompsa RUN_DEV(DLINK2, RT3070_2), 186209918Sthompsa RUN_DEV(DLINK2, RT3070_3), 187209918Sthompsa RUN_DEV(DLINK2, RT3070_4), 188209918Sthompsa RUN_DEV(DLINK2, RT3070_5), 189209918Sthompsa RUN_DEV(DLINK2, RT3072), 190209918Sthompsa RUN_DEV(DLINK2, RT3072_1), 191209918Sthompsa RUN_DEV(EDIMAX, EW7717), 192209918Sthompsa RUN_DEV(EDIMAX, EW7718), 193261868Skevlo RUN_DEV(EDIMAX, EW7733UND), 194209918Sthompsa RUN_DEV(EDIMAX, RT2870_1), 195209918Sthompsa RUN_DEV(ENCORE, RT3070_1), 196209918Sthompsa RUN_DEV(ENCORE, RT3070_2), 197209918Sthompsa RUN_DEV(ENCORE, RT3070_3), 198209918Sthompsa RUN_DEV(GIGABYTE, GNWB31N), 199209918Sthompsa RUN_DEV(GIGABYTE, GNWB32L), 200209918Sthompsa RUN_DEV(GIGABYTE, RT2870_1), 201209918Sthompsa RUN_DEV(GIGASET, RT3070_1), 202209918Sthompsa RUN_DEV(GIGASET, RT3070_2), 203209918Sthompsa RUN_DEV(GUILLEMOT, HWNU300), 204209918Sthompsa RUN_DEV(HAWKING, HWUN2), 205209918Sthompsa RUN_DEV(HAWKING, RT2870_1), 206209918Sthompsa RUN_DEV(HAWKING, RT2870_2), 207209918Sthompsa RUN_DEV(HAWKING, RT3070), 208209918Sthompsa RUN_DEV(IODATA, RT3072_1), 209209918Sthompsa RUN_DEV(IODATA, RT3072_2), 210209918Sthompsa RUN_DEV(IODATA, RT3072_3), 211209918Sthompsa RUN_DEV(IODATA, RT3072_4), 212209918Sthompsa RUN_DEV(LINKSYS4, RT3070), 213209918Sthompsa RUN_DEV(LINKSYS4, WUSB100), 214209918Sthompsa RUN_DEV(LINKSYS4, WUSB54GCV3), 215209918Sthompsa RUN_DEV(LINKSYS4, WUSB600N), 216209918Sthompsa RUN_DEV(LINKSYS4, WUSB600NV2), 217209918Sthompsa RUN_DEV(LOGITEC, RT2870_1), 218209918Sthompsa RUN_DEV(LOGITEC, RT2870_2), 219209918Sthompsa RUN_DEV(LOGITEC, RT2870_3), 220230333Shselasky RUN_DEV(LOGITEC, LANW300NU2), 221238274Shrs RUN_DEV(LOGITEC, LANW150NU2), 222248458Shselasky RUN_DEV(LOGITEC, LANW300NU2S), 223281878Skevlo RUN_DEV(MELCO, WLIUCG300HP), 224209918Sthompsa RUN_DEV(MELCO, RT2870_2), 225209918Sthompsa RUN_DEV(MELCO, WLIUCAG300N), 226209918Sthompsa RUN_DEV(MELCO, WLIUCG300N), 227219257Sdaichi RUN_DEV(MELCO, WLIUCG301N), 228209918Sthompsa RUN_DEV(MELCO, WLIUCGN), 229227781Shselasky RUN_DEV(MELCO, WLIUCGNM), 230281878Skevlo RUN_DEV(MELCO, WLIUCG300HPV1), 231238274Shrs RUN_DEV(MELCO, WLIUCGNM2), 232209918Sthompsa RUN_DEV(MOTOROLA4, RT2770), 233209918Sthompsa RUN_DEV(MOTOROLA4, RT3070), 234209918Sthompsa RUN_DEV(MSI, RT3070_1), 235209918Sthompsa RUN_DEV(MSI, RT3070_2), 236209918Sthompsa RUN_DEV(MSI, RT3070_3), 237209918Sthompsa RUN_DEV(MSI, RT3070_4), 238209918Sthompsa RUN_DEV(MSI, RT3070_5), 239209918Sthompsa RUN_DEV(MSI, RT3070_6), 240209918Sthompsa RUN_DEV(MSI, RT3070_7), 241209918Sthompsa RUN_DEV(MSI, RT3070_8), 242209918Sthompsa RUN_DEV(MSI, RT3070_9), 243209918Sthompsa RUN_DEV(MSI, RT3070_10), 244209918Sthompsa RUN_DEV(MSI, RT3070_11), 245292183Shselasky RUN_DEV(NETGEAR, WNDA4100), 246209918Sthompsa RUN_DEV(OVISLINK, RT3072), 247209918Sthompsa RUN_DEV(PARA, RT3070), 248209918Sthompsa RUN_DEV(PEGATRON, RT2870), 249209918Sthompsa RUN_DEV(PEGATRON, RT3070), 250209918Sthompsa RUN_DEV(PEGATRON, RT3070_2), 251209918Sthompsa RUN_DEV(PEGATRON, RT3070_3), 252209918Sthompsa RUN_DEV(PHILIPS, RT2870), 253209918Sthompsa RUN_DEV(PLANEX2, GWUS300MINIS), 254209918Sthompsa RUN_DEV(PLANEX2, GWUSMICRON), 255209918Sthompsa RUN_DEV(PLANEX2, RT2870), 256209918Sthompsa RUN_DEV(PLANEX2, RT3070), 257209918Sthompsa RUN_DEV(QCOM, RT2870), 258209918Sthompsa RUN_DEV(QUANTA, RT3070), 259209918Sthompsa RUN_DEV(RALINK, RT2070), 260209918Sthompsa RUN_DEV(RALINK, RT2770), 261209918Sthompsa RUN_DEV(RALINK, RT2870), 262209918Sthompsa RUN_DEV(RALINK, RT3070), 263209918Sthompsa RUN_DEV(RALINK, RT3071), 264209918Sthompsa RUN_DEV(RALINK, RT3072), 265209918Sthompsa RUN_DEV(RALINK, RT3370), 266209918Sthompsa RUN_DEV(RALINK, RT3572), 267261868Skevlo RUN_DEV(RALINK, RT3573), 268259453Shselasky RUN_DEV(RALINK, RT5370), 269259453Shselasky RUN_DEV(RALINK, RT5572), 270209918Sthompsa RUN_DEV(RALINK, RT8070), 271226534Shselasky RUN_DEV(SAMSUNG, WIS09ABGN), 272209918Sthompsa RUN_DEV(SAMSUNG2, RT2870_1), 273209918Sthompsa RUN_DEV(SENAO, RT2870_1), 274209918Sthompsa RUN_DEV(SENAO, RT2870_2), 275209918Sthompsa RUN_DEV(SENAO, RT2870_3), 276209918Sthompsa RUN_DEV(SENAO, RT2870_4), 277209918Sthompsa RUN_DEV(SENAO, RT3070), 278209918Sthompsa RUN_DEV(SENAO, RT3071), 279209918Sthompsa RUN_DEV(SENAO, RT3072_1), 280209918Sthompsa RUN_DEV(SENAO, RT3072_2), 281209918Sthompsa RUN_DEV(SENAO, RT3072_3), 282209918Sthompsa RUN_DEV(SENAO, RT3072_4), 283209918Sthompsa RUN_DEV(SENAO, RT3072_5), 284209918Sthompsa RUN_DEV(SITECOMEU, RT2770), 285209918Sthompsa RUN_DEV(SITECOMEU, RT2870_1), 286209918Sthompsa RUN_DEV(SITECOMEU, RT2870_2), 287209918Sthompsa RUN_DEV(SITECOMEU, RT2870_3), 288209918Sthompsa RUN_DEV(SITECOMEU, RT2870_4), 289209918Sthompsa RUN_DEV(SITECOMEU, RT3070), 290209918Sthompsa RUN_DEV(SITECOMEU, RT3070_2), 291209918Sthompsa RUN_DEV(SITECOMEU, RT3070_3), 292209918Sthompsa RUN_DEV(SITECOMEU, RT3070_4), 293209918Sthompsa RUN_DEV(SITECOMEU, RT3071), 294209918Sthompsa RUN_DEV(SITECOMEU, RT3072_1), 295209918Sthompsa RUN_DEV(SITECOMEU, RT3072_2), 296209918Sthompsa RUN_DEV(SITECOMEU, RT3072_3), 297209918Sthompsa RUN_DEV(SITECOMEU, RT3072_4), 298209918Sthompsa RUN_DEV(SITECOMEU, RT3072_5), 299209918Sthompsa RUN_DEV(SITECOMEU, RT3072_6), 300209918Sthompsa RUN_DEV(SITECOMEU, WL608), 301209918Sthompsa RUN_DEV(SPARKLAN, RT2870_1), 302209918Sthompsa RUN_DEV(SPARKLAN, RT3070), 303209918Sthompsa RUN_DEV(SWEEX2, LW153), 304209918Sthompsa RUN_DEV(SWEEX2, LW303), 305209918Sthompsa RUN_DEV(SWEEX2, LW313), 306209918Sthompsa RUN_DEV(TOSHIBA, RT3070), 307209918Sthompsa RUN_DEV(UMEDIA, RT2870_1), 308209918Sthompsa RUN_DEV(ZCOM, RT2870_1), 309209918Sthompsa RUN_DEV(ZCOM, RT2870_2), 310209918Sthompsa RUN_DEV(ZINWELL, RT2870_1), 311209918Sthompsa RUN_DEV(ZINWELL, RT2870_2), 312209918Sthompsa RUN_DEV(ZINWELL, RT3070), 313209918Sthompsa RUN_DEV(ZINWELL, RT3072_1), 314209918Sthompsa RUN_DEV(ZINWELL, RT3072_2), 315209918Sthompsa RUN_DEV(ZYXEL, RT2870_1), 316209918Sthompsa RUN_DEV(ZYXEL, RT2870_2), 317292183Shselasky RUN_DEV(ZYXEL, RT3070), 318262604Skevlo RUN_DEV_EJECT(ZYXEL, NWD2705), 319261868Skevlo RUN_DEV_EJECT(RALINK, RT_STOR), 320261868Skevlo#undef RUN_DEV_EJECT 321209918Sthompsa#undef RUN_DEV 322203134Sthompsa}; 323203134Sthompsa 324203134Sthompsastatic device_probe_t run_match; 325203134Sthompsastatic device_attach_t run_attach; 326203134Sthompsastatic device_detach_t run_detach; 327203134Sthompsa 328203134Sthompsastatic usb_callback_t run_bulk_rx_callback; 329203134Sthompsastatic usb_callback_t run_bulk_tx_callback0; 330203134Sthompsastatic usb_callback_t run_bulk_tx_callback1; 331203134Sthompsastatic usb_callback_t run_bulk_tx_callback2; 332203134Sthompsastatic usb_callback_t run_bulk_tx_callback3; 333203134Sthompsastatic usb_callback_t run_bulk_tx_callback4; 334203134Sthompsastatic usb_callback_t run_bulk_tx_callback5; 335203134Sthompsa 336261868Skevlostatic void run_autoinst(void *, struct usb_device *, 337261868Skevlo struct usb_attach_arg *); 338261868Skevlostatic int run_driver_loaded(struct module *, int, void *); 339203134Sthompsastatic void run_bulk_tx_callbackN(struct usb_xfer *xfer, 340259453Shselasky usb_error_t error, u_int index); 341203134Sthompsastatic struct ieee80211vap *run_vap_create(struct ieee80211com *, 342228621Sbschmidt const char [IFNAMSIZ], int, enum ieee80211_opmode, int, 343228621Sbschmidt const uint8_t [IEEE80211_ADDR_LEN], 344228621Sbschmidt const uint8_t [IEEE80211_ADDR_LEN]); 345203134Sthompsastatic void run_vap_delete(struct ieee80211vap *); 346208019Sthompsastatic void run_cmdq_cb(void *, int); 347203134Sthompsastatic void run_setup_tx_list(struct run_softc *, 348203134Sthompsa struct run_endpoint_queue *); 349203134Sthompsastatic void run_unsetup_tx_list(struct run_softc *, 350203134Sthompsa struct run_endpoint_queue *); 351203134Sthompsastatic int run_load_microcode(struct run_softc *); 352203134Sthompsastatic int run_reset(struct run_softc *); 353203134Sthompsastatic usb_error_t run_do_request(struct run_softc *, 354203134Sthompsa struct usb_device_request *, void *); 355203134Sthompsastatic int run_read(struct run_softc *, uint16_t, uint32_t *); 356203134Sthompsastatic int run_read_region_1(struct run_softc *, uint16_t, uint8_t *, int); 357203134Sthompsastatic int run_write_2(struct run_softc *, uint16_t, uint16_t); 358203134Sthompsastatic int run_write(struct run_softc *, uint16_t, uint32_t); 359203134Sthompsastatic int run_write_region_1(struct run_softc *, uint16_t, 360203134Sthompsa const uint8_t *, int); 361203134Sthompsastatic int run_set_region_4(struct run_softc *, uint16_t, uint32_t, int); 362261868Skevlostatic int run_efuse_read(struct run_softc *, uint16_t, uint16_t *, int); 363203134Sthompsastatic int run_efuse_read_2(struct run_softc *, uint16_t, uint16_t *); 364203134Sthompsastatic int run_eeprom_read_2(struct run_softc *, uint16_t, uint16_t *); 365259453Shselaskystatic int run_rt2870_rf_write(struct run_softc *, uint32_t); 366203134Sthompsastatic int run_rt3070_rf_read(struct run_softc *, uint8_t, uint8_t *); 367203134Sthompsastatic int run_rt3070_rf_write(struct run_softc *, uint8_t, uint8_t); 368203134Sthompsastatic int run_bbp_read(struct run_softc *, uint8_t, uint8_t *); 369203134Sthompsastatic int run_bbp_write(struct run_softc *, uint8_t, uint8_t); 370203134Sthompsastatic int run_mcu_cmd(struct run_softc *, uint8_t, uint16_t); 371259453Shselaskystatic const char *run_get_rf(uint16_t); 372261868Skevlostatic void run_rt3593_get_txpower(struct run_softc *); 373261868Skevlostatic void run_get_txpower(struct run_softc *); 374203134Sthompsastatic int run_read_eeprom(struct run_softc *); 375203134Sthompsastatic struct ieee80211_node *run_node_alloc(struct ieee80211vap *, 376203134Sthompsa const uint8_t mac[IEEE80211_ADDR_LEN]); 377203134Sthompsastatic int run_media_change(struct ifnet *); 378203134Sthompsastatic int run_newstate(struct ieee80211vap *, enum ieee80211_state, int); 379203134Sthompsastatic int run_wme_update(struct ieee80211com *); 380208019Sthompsastatic void run_wme_update_cb(void *); 381203134Sthompsastatic void run_key_update_begin(struct ieee80211vap *); 382203134Sthompsastatic void run_key_update_end(struct ieee80211vap *); 383208019Sthompsastatic void run_key_set_cb(void *); 384208019Sthompsastatic int run_key_set(struct ieee80211vap *, struct ieee80211_key *, 385259453Shselasky const uint8_t mac[IEEE80211_ADDR_LEN]); 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); 394203134Sthompsastatic void run_rx_frame(struct run_softc *, struct mbuf *, uint32_t); 395203134Sthompsastatic void run_tx_free(struct run_endpoint_queue *pq, 396203134Sthompsa struct run_tx_data *, int); 397208019Sthompsastatic void run_set_tx_desc(struct run_softc *, struct run_tx_data *); 398203134Sthompsastatic int run_tx(struct run_softc *, struct mbuf *, 399203134Sthompsa struct ieee80211_node *); 400203134Sthompsastatic int run_tx_mgt(struct run_softc *, struct mbuf *, 401203134Sthompsa struct ieee80211_node *); 402203134Sthompsastatic int run_sendprot(struct run_softc *, const struct mbuf *, 403203134Sthompsa struct ieee80211_node *, int, int); 404203134Sthompsastatic int run_tx_param(struct run_softc *, struct mbuf *, 405203134Sthompsa struct ieee80211_node *, 406203134Sthompsa const struct ieee80211_bpf_params *); 407203134Sthompsastatic int run_raw_xmit(struct ieee80211_node *, struct mbuf *, 408203134Sthompsa const struct ieee80211_bpf_params *); 409203134Sthompsastatic void run_start(struct ifnet *); 410203134Sthompsastatic int run_ioctl(struct ifnet *, u_long, caddr_t); 411261868Skevlostatic void run_iq_calib(struct run_softc *, u_int); 412205042Sthompsastatic void run_set_agc(struct run_softc *, uint8_t); 413203134Sthompsastatic void run_select_chan_group(struct run_softc *, int); 414203134Sthompsastatic void run_set_rx_antenna(struct run_softc *, int); 415203134Sthompsastatic void run_rt2870_set_chan(struct run_softc *, u_int); 416203134Sthompsastatic void run_rt3070_set_chan(struct run_softc *, u_int); 417205042Sthompsastatic void run_rt3572_set_chan(struct run_softc *, u_int); 418261868Skevlostatic void run_rt3593_set_chan(struct run_softc *, u_int); 419259453Shselaskystatic void run_rt5390_set_chan(struct run_softc *, u_int); 420259453Shselaskystatic void run_rt5592_set_chan(struct run_softc *, u_int); 421203134Sthompsastatic int run_set_chan(struct run_softc *, struct ieee80211_channel *); 422203134Sthompsastatic void run_set_channel(struct ieee80211com *); 423203134Sthompsastatic void run_scan_start(struct ieee80211com *); 424203134Sthompsastatic void run_scan_end(struct ieee80211com *); 425203134Sthompsastatic void run_update_beacon(struct ieee80211vap *, int); 426208019Sthompsastatic void run_update_beacon_cb(void *); 427203134Sthompsastatic void run_updateprot(struct ieee80211com *); 428218492Sbschmidtstatic void run_updateprot_cb(void *); 429208019Sthompsastatic void run_usb_timeout_cb(void *); 430203134Sthompsastatic void run_reset_livelock(struct run_softc *); 431203134Sthompsastatic void run_enable_tsf_sync(struct run_softc *); 432203134Sthompsastatic void run_enable_mrr(struct run_softc *); 433203134Sthompsastatic void run_set_txpreamble(struct run_softc *); 434203134Sthompsastatic void run_set_basicrates(struct run_softc *); 435203134Sthompsastatic void run_set_leds(struct run_softc *, uint16_t); 436203134Sthompsastatic void run_set_bssid(struct run_softc *, const uint8_t *); 437203134Sthompsastatic void run_set_macaddr(struct run_softc *, const uint8_t *); 438203134Sthompsastatic void run_updateslot(struct ifnet *); 439218492Sbschmidtstatic void run_updateslot_cb(void *); 440208019Sthompsastatic void run_update_mcast(struct ifnet *); 441203134Sthompsastatic int8_t run_rssi2dbm(struct run_softc *, uint8_t, uint8_t); 442203134Sthompsastatic void run_update_promisc_locked(struct ifnet *); 443203134Sthompsastatic void run_update_promisc(struct ifnet *); 444259453Shselaskystatic void run_rt5390_bbp_init(struct run_softc *); 445203134Sthompsastatic int run_bbp_init(struct run_softc *); 446203134Sthompsastatic int run_rt3070_rf_init(struct run_softc *); 447261868Skevlostatic void run_rt3593_rf_init(struct run_softc *); 448259453Shselaskystatic void run_rt5390_rf_init(struct run_softc *); 449203134Sthompsastatic int run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t, 450203134Sthompsa uint8_t *); 451205042Sthompsastatic void run_rt3070_rf_setup(struct run_softc *); 452261868Skevlostatic void run_rt3593_rf_setup(struct run_softc *); 453261868Skevlostatic void run_rt5390_rf_setup(struct run_softc *); 454203134Sthompsastatic int run_txrx_enable(struct run_softc *); 455259453Shselaskystatic void run_adjust_freq_offset(struct run_softc *); 456203134Sthompsastatic void run_init(void *); 457203134Sthompsastatic void run_init_locked(struct run_softc *); 458203134Sthompsastatic void run_stop(void *); 459259453Shselaskystatic void run_delay(struct run_softc *, u_int); 460203134Sthompsa 461261868Skevlostatic eventhandler_tag run_etag; 462261868Skevlo 463261868Skevlostatic const struct rt2860_rate { 464261868Skevlo uint8_t rate; 465261868Skevlo uint8_t mcs; 466261868Skevlo enum ieee80211_phytype phy; 467261868Skevlo uint8_t ctl_ridx; 468261868Skevlo uint16_t sp_ack_dur; 469261868Skevlo uint16_t lp_ack_dur; 470261868Skevlo} rt2860_rates[] = { 471261868Skevlo { 2, 0, IEEE80211_T_DS, 0, 314, 314 }, 472261868Skevlo { 4, 1, IEEE80211_T_DS, 1, 258, 162 }, 473261868Skevlo { 11, 2, IEEE80211_T_DS, 2, 223, 127 }, 474261868Skevlo { 22, 3, IEEE80211_T_DS, 3, 213, 117 }, 475261868Skevlo { 12, 0, IEEE80211_T_OFDM, 4, 60, 60 }, 476261868Skevlo { 18, 1, IEEE80211_T_OFDM, 4, 52, 52 }, 477261868Skevlo { 24, 2, IEEE80211_T_OFDM, 6, 48, 48 }, 478261868Skevlo { 36, 3, IEEE80211_T_OFDM, 6, 44, 44 }, 479261868Skevlo { 48, 4, IEEE80211_T_OFDM, 8, 44, 44 }, 480261868Skevlo { 72, 5, IEEE80211_T_OFDM, 8, 40, 40 }, 481261868Skevlo { 96, 6, IEEE80211_T_OFDM, 8, 40, 40 }, 482261868Skevlo { 108, 7, IEEE80211_T_OFDM, 8, 40, 40 } 483261868Skevlo}; 484261868Skevlo 485203134Sthompsastatic const struct { 486208019Sthompsa uint16_t reg; 487203134Sthompsa uint32_t val; 488203134Sthompsa} rt2870_def_mac[] = { 489203134Sthompsa RT2870_DEF_MAC 490203134Sthompsa}; 491203134Sthompsa 492203134Sthompsastatic const struct { 493203134Sthompsa uint8_t reg; 494203134Sthompsa uint8_t val; 495203134Sthompsa} rt2860_def_bbp[] = { 496203134Sthompsa RT2860_DEF_BBP 497259453Shselasky},rt5390_def_bbp[] = { 498259453Shselasky RT5390_DEF_BBP 499259453Shselasky},rt5592_def_bbp[] = { 500259453Shselasky RT5592_DEF_BBP 501203134Sthompsa}; 502203134Sthompsa 503259453Shselasky/* 504259453Shselasky * Default values for BBP register R196 for RT5592. 505259453Shselasky */ 506259453Shselaskystatic const uint8_t rt5592_bbp_r196[] = { 507259453Shselasky 0xe0, 0x1f, 0x38, 0x32, 0x08, 0x28, 0x19, 0x0a, 0xff, 0x00, 508259453Shselasky 0x16, 0x10, 0x10, 0x0b, 0x36, 0x2c, 0x26, 0x24, 0x42, 0x36, 509259453Shselasky 0x30, 0x2d, 0x4c, 0x46, 0x3d, 0x40, 0x3e, 0x42, 0x3d, 0x40, 510259453Shselasky 0x3c, 0x34, 0x2c, 0x2f, 0x3c, 0x35, 0x2e, 0x2a, 0x49, 0x41, 511259453Shselasky 0x36, 0x31, 0x30, 0x30, 0x0e, 0x0d, 0x28, 0x21, 0x1c, 0x16, 512259453Shselasky 0x50, 0x4a, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 513259453Shselasky 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 514259453Shselasky 0x00, 0x00, 0x7d, 0x14, 0x32, 0x2c, 0x36, 0x4c, 0x43, 0x2c, 515259453Shselasky 0x2e, 0x36, 0x30, 0x6e 516259453Shselasky}; 517259453Shselasky 518203134Sthompsastatic const struct rfprog { 519203134Sthompsa uint8_t chan; 520203134Sthompsa uint32_t r1, r2, r3, r4; 521203134Sthompsa} rt2860_rf2850[] = { 522203134Sthompsa RT2860_RF2850 523203134Sthompsa}; 524203134Sthompsa 525203134Sthompsastruct { 526203134Sthompsa uint8_t n, r, k; 527205042Sthompsa} rt3070_freqs[] = { 528205042Sthompsa RT3070_RF3052 529203134Sthompsa}; 530203134Sthompsa 531259453Shselaskystatic const struct rt5592_freqs { 532259453Shselasky uint16_t n; 533259453Shselasky uint8_t k, m, r; 534259453Shselasky} rt5592_freqs_20mhz[] = { 535259453Shselasky RT5592_RF5592_20MHZ 536259453Shselasky},rt5592_freqs_40mhz[] = { 537259453Shselasky RT5592_RF5592_40MHZ 538259453Shselasky}; 539259453Shselasky 540203134Sthompsastatic const struct { 541203134Sthompsa uint8_t reg; 542203134Sthompsa uint8_t val; 543203134Sthompsa} rt3070_def_rf[] = { 544203134Sthompsa RT3070_DEF_RF 545205042Sthompsa},rt3572_def_rf[] = { 546205042Sthompsa RT3572_DEF_RF 547261868Skevlo},rt3593_def_rf[] = { 548261868Skevlo RT3593_DEF_RF 549259453Shselasky},rt5390_def_rf[] = { 550259453Shselasky RT5390_DEF_RF 551259453Shselasky},rt5392_def_rf[] = { 552259453Shselasky RT5392_DEF_RF 553259453Shselasky},rt5592_def_rf[] = { 554259453Shselasky RT5592_DEF_RF 555259453Shselasky},rt5592_2ghz_def_rf[] = { 556259453Shselasky RT5592_2GHZ_DEF_RF 557259453Shselasky},rt5592_5ghz_def_rf[] = { 558259453Shselasky RT5592_5GHZ_DEF_RF 559203134Sthompsa}; 560203134Sthompsa 561259453Shselaskystatic const struct { 562259453Shselasky u_int firstchan; 563259453Shselasky u_int lastchan; 564259453Shselasky uint8_t reg; 565259453Shselasky uint8_t val; 566259453Shselasky} rt5592_chan_5ghz[] = { 567259453Shselasky RT5592_CHAN_5GHZ 568259453Shselasky}; 569259453Shselasky 570203134Sthompsastatic const struct usb_config run_config[RUN_N_XFER] = { 571203134Sthompsa [RUN_BULK_TX_BE] = { 572203134Sthompsa .type = UE_BULK, 573203134Sthompsa .endpoint = UE_ADDR_ANY, 574203134Sthompsa .ep_index = 0, 575203134Sthompsa .direction = UE_DIR_OUT, 576203134Sthompsa .bufsize = RUN_MAX_TXSZ, 577203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 578203134Sthompsa .callback = run_bulk_tx_callback0, 579203134Sthompsa .timeout = 5000, /* ms */ 580203134Sthompsa }, 581203134Sthompsa [RUN_BULK_TX_BK] = { 582203134Sthompsa .type = UE_BULK, 583203134Sthompsa .endpoint = UE_ADDR_ANY, 584203134Sthompsa .direction = UE_DIR_OUT, 585203134Sthompsa .ep_index = 1, 586203134Sthompsa .bufsize = RUN_MAX_TXSZ, 587203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 588203134Sthompsa .callback = run_bulk_tx_callback1, 589203134Sthompsa .timeout = 5000, /* ms */ 590203134Sthompsa }, 591203134Sthompsa [RUN_BULK_TX_VI] = { 592203134Sthompsa .type = UE_BULK, 593203134Sthompsa .endpoint = UE_ADDR_ANY, 594203134Sthompsa .direction = UE_DIR_OUT, 595203134Sthompsa .ep_index = 2, 596203134Sthompsa .bufsize = RUN_MAX_TXSZ, 597203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 598203134Sthompsa .callback = run_bulk_tx_callback2, 599203134Sthompsa .timeout = 5000, /* ms */ 600203134Sthompsa }, 601203134Sthompsa [RUN_BULK_TX_VO] = { 602203134Sthompsa .type = UE_BULK, 603203134Sthompsa .endpoint = UE_ADDR_ANY, 604203134Sthompsa .direction = UE_DIR_OUT, 605203134Sthompsa .ep_index = 3, 606203134Sthompsa .bufsize = RUN_MAX_TXSZ, 607203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 608203134Sthompsa .callback = run_bulk_tx_callback3, 609203134Sthompsa .timeout = 5000, /* ms */ 610203134Sthompsa }, 611203134Sthompsa [RUN_BULK_TX_HCCA] = { 612203134Sthompsa .type = UE_BULK, 613203134Sthompsa .endpoint = UE_ADDR_ANY, 614203134Sthompsa .direction = UE_DIR_OUT, 615203134Sthompsa .ep_index = 4, 616203134Sthompsa .bufsize = RUN_MAX_TXSZ, 617203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 618203134Sthompsa .callback = run_bulk_tx_callback4, 619203134Sthompsa .timeout = 5000, /* ms */ 620203134Sthompsa }, 621203134Sthompsa [RUN_BULK_TX_PRIO] = { 622203134Sthompsa .type = UE_BULK, 623203134Sthompsa .endpoint = UE_ADDR_ANY, 624203134Sthompsa .direction = UE_DIR_OUT, 625203134Sthompsa .ep_index = 5, 626203134Sthompsa .bufsize = RUN_MAX_TXSZ, 627203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 628203134Sthompsa .callback = run_bulk_tx_callback5, 629203134Sthompsa .timeout = 5000, /* ms */ 630203134Sthompsa }, 631203134Sthompsa [RUN_BULK_RX] = { 632203134Sthompsa .type = UE_BULK, 633203134Sthompsa .endpoint = UE_ADDR_ANY, 634203134Sthompsa .direction = UE_DIR_IN, 635203134Sthompsa .bufsize = RUN_MAX_RXSZ, 636203134Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 637203134Sthompsa .callback = run_bulk_rx_callback, 638203134Sthompsa } 639203134Sthompsa}; 640203134Sthompsa 641261868Skevlostatic void 642261868Skevlorun_autoinst(void *arg, struct usb_device *udev, 643261868Skevlo struct usb_attach_arg *uaa) 644261868Skevlo{ 645261868Skevlo struct usb_interface *iface; 646261868Skevlo struct usb_interface_descriptor *id; 647261868Skevlo 648261868Skevlo if (uaa->dev_state != UAA_DEV_READY) 649261868Skevlo return; 650261868Skevlo 651261868Skevlo iface = usbd_get_iface(udev, 0); 652261868Skevlo if (iface == NULL) 653261868Skevlo return; 654261868Skevlo id = iface->idesc; 655261868Skevlo if (id == NULL || id->bInterfaceClass != UICLASS_MASS) 656261868Skevlo return; 657261868Skevlo if (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa)) 658261868Skevlo return; 659261868Skevlo 660261868Skevlo if (usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT) == 0) 661261868Skevlo uaa->dev_state = UAA_DEV_EJECTING; 662261868Skevlo} 663261868Skevlo 664220235Skevlostatic int 665261868Skevlorun_driver_loaded(struct module *mod, int what, void *arg) 666261868Skevlo{ 667261868Skevlo switch (what) { 668261868Skevlo case MOD_LOAD: 669261868Skevlo run_etag = EVENTHANDLER_REGISTER(usb_dev_configured, 670261868Skevlo run_autoinst, NULL, EVENTHANDLER_PRI_ANY); 671261868Skevlo break; 672261868Skevlo case MOD_UNLOAD: 673261868Skevlo EVENTHANDLER_DEREGISTER(usb_dev_configured, run_etag); 674261868Skevlo break; 675261868Skevlo default: 676261868Skevlo return (EOPNOTSUPP); 677261868Skevlo } 678261868Skevlo return (0); 679261868Skevlo} 680261868Skevlo 681261868Skevlostatic int 682203134Sthompsarun_match(device_t self) 683203134Sthompsa{ 684203134Sthompsa struct usb_attach_arg *uaa = device_get_ivars(self); 685203134Sthompsa 686203134Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 687203134Sthompsa return (ENXIO); 688203134Sthompsa if (uaa->info.bConfigIndex != 0) 689203134Sthompsa return (ENXIO); 690203134Sthompsa if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX) 691203134Sthompsa return (ENXIO); 692203134Sthompsa 693203134Sthompsa return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa)); 694203134Sthompsa} 695203134Sthompsa 696203134Sthompsastatic int 697203134Sthompsarun_attach(device_t self) 698203134Sthompsa{ 699203134Sthompsa struct run_softc *sc = device_get_softc(self); 700203134Sthompsa struct usb_attach_arg *uaa = device_get_ivars(self); 701203134Sthompsa struct ieee80211com *ic; 702203134Sthompsa struct ifnet *ifp; 703205042Sthompsa uint32_t ver; 704259453Shselasky int ntries, error; 705203134Sthompsa uint8_t iface_index, bands; 706203134Sthompsa 707203134Sthompsa device_set_usb_desc(self); 708203134Sthompsa sc->sc_udev = uaa->device; 709203134Sthompsa sc->sc_dev = self; 710262604Skevlo if (USB_GET_DRIVER_INFO(uaa) != RUN_EJECT) 711262604Skevlo sc->sc_flags |= RUN_FLAG_FWLOAD_NEEDED; 712203134Sthompsa 713203134Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), 714203134Sthompsa MTX_NETWORK_LOCK, MTX_DEF); 715203134Sthompsa 716203134Sthompsa iface_index = RT2860_IFACE_INDEX; 717208019Sthompsa 718203134Sthompsa error = usbd_transfer_setup(uaa->device, &iface_index, 719203134Sthompsa sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx); 720203134Sthompsa if (error) { 721205042Sthompsa device_printf(self, "could not allocate USB transfers, " 722203134Sthompsa "err=%s\n", usbd_errstr(error)); 723203134Sthompsa goto detach; 724203134Sthompsa } 725203134Sthompsa 726203134Sthompsa RUN_LOCK(sc); 727203134Sthompsa 728203134Sthompsa /* wait for the chip to settle */ 729203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 730209917Sthompsa if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0) { 731203134Sthompsa RUN_UNLOCK(sc); 732203134Sthompsa goto detach; 733203134Sthompsa } 734205042Sthompsa if (ver != 0 && ver != 0xffffffff) 735203134Sthompsa break; 736203134Sthompsa run_delay(sc, 10); 737203134Sthompsa } 738203134Sthompsa if (ntries == 100) { 739203138Sthompsa device_printf(sc->sc_dev, 740203138Sthompsa "timeout waiting for NIC to initialize\n"); 741203134Sthompsa RUN_UNLOCK(sc); 742203134Sthompsa goto detach; 743203134Sthompsa } 744205042Sthompsa sc->mac_ver = ver >> 16; 745205042Sthompsa sc->mac_rev = ver & 0xffff; 746203134Sthompsa 747203134Sthompsa /* retrieve RF rev. no and various other things from EEPROM */ 748203134Sthompsa run_read_eeprom(sc); 749203134Sthompsa 750203138Sthompsa device_printf(sc->sc_dev, 751203138Sthompsa "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n", 752205042Sthompsa sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev), 753203138Sthompsa sc->ntxchains, sc->nrxchains, ether_sprintf(sc->sc_bssid)); 754203134Sthompsa 755203134Sthompsa RUN_UNLOCK(sc); 756203134Sthompsa 757203134Sthompsa ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); 758220235Skevlo if (ifp == NULL) { 759203138Sthompsa device_printf(sc->sc_dev, "can not if_alloc()\n"); 760203134Sthompsa goto detach; 761203134Sthompsa } 762203134Sthompsa ic = ifp->if_l2com; 763203134Sthompsa 764203134Sthompsa ifp->if_softc = sc; 765203134Sthompsa if_initname(ifp, "run", device_get_unit(sc->sc_dev)); 766203134Sthompsa ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 767203134Sthompsa ifp->if_init = run_init; 768203134Sthompsa ifp->if_ioctl = run_ioctl; 769203134Sthompsa ifp->if_start = run_start; 770207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 771207554Ssobomax ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 772203134Sthompsa IFQ_SET_READY(&ifp->if_snd); 773203134Sthompsa 774203134Sthompsa ic->ic_ifp = ifp; 775203134Sthompsa ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 776203134Sthompsa ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 777208019Sthompsa 778203134Sthompsa /* set device capabilities */ 779203134Sthompsa ic->ic_caps = 780203134Sthompsa IEEE80211_C_STA | /* station mode supported */ 781203134Sthompsa IEEE80211_C_MONITOR | /* monitor mode supported */ 782203134Sthompsa IEEE80211_C_IBSS | 783203134Sthompsa IEEE80211_C_HOSTAP | 784208019Sthompsa IEEE80211_C_WDS | /* 4-address traffic works */ 785208019Sthompsa IEEE80211_C_MBSS | 786203134Sthompsa IEEE80211_C_SHPREAMBLE | /* short preamble supported */ 787203134Sthompsa IEEE80211_C_SHSLOT | /* short slot time supported */ 788203134Sthompsa IEEE80211_C_WME | /* WME */ 789214894Sbschmidt IEEE80211_C_WPA; /* WPA1|WPA2(RSN) */ 790203134Sthompsa 791203134Sthompsa ic->ic_cryptocaps = 792203134Sthompsa IEEE80211_CRYPTO_WEP | 793203134Sthompsa IEEE80211_CRYPTO_AES_CCM | 794203134Sthompsa IEEE80211_CRYPTO_TKIPMIC | 795203134Sthompsa IEEE80211_CRYPTO_TKIP; 796203134Sthompsa 797203134Sthompsa ic->ic_flags |= IEEE80211_F_DATAPAD; 798203134Sthompsa ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; 799203134Sthompsa 800203134Sthompsa bands = 0; 801203134Sthompsa setbit(&bands, IEEE80211_MODE_11B); 802203134Sthompsa setbit(&bands, IEEE80211_MODE_11G); 803259453Shselasky if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850 || 804261868Skevlo sc->rf_rev == RT3070_RF_3052 || sc->rf_rev == RT3593_RF_3053 || 805261868Skevlo sc->rf_rev == RT5592_RF_5592) 806259453Shselasky setbit(&bands, IEEE80211_MODE_11A); 807203134Sthompsa ieee80211_init_channels(ic, NULL, &bands); 808203134Sthompsa 809203134Sthompsa ieee80211_ifattach(ic, sc->sc_bssid); 810203134Sthompsa 811203134Sthompsa ic->ic_scan_start = run_scan_start; 812203134Sthompsa ic->ic_scan_end = run_scan_end; 813203134Sthompsa ic->ic_set_channel = run_set_channel; 814203134Sthompsa ic->ic_node_alloc = run_node_alloc; 815203134Sthompsa ic->ic_newassoc = run_newassoc; 816218492Sbschmidt ic->ic_updateslot = run_updateslot; 817208019Sthompsa ic->ic_update_mcast = run_update_mcast; 818203134Sthompsa ic->ic_wme.wme_update = run_wme_update; 819203134Sthompsa ic->ic_raw_xmit = run_raw_xmit; 820203134Sthompsa ic->ic_update_promisc = run_update_promisc; 821203134Sthompsa 822203134Sthompsa ic->ic_vap_create = run_vap_create; 823203134Sthompsa ic->ic_vap_delete = run_vap_delete; 824203134Sthompsa 825203134Sthompsa ieee80211_radiotap_attach(ic, 826203134Sthompsa &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), 827203134Sthompsa RUN_TX_RADIOTAP_PRESENT, 828203134Sthompsa &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 829203134Sthompsa RUN_RX_RADIOTAP_PRESENT); 830203134Sthompsa 831208019Sthompsa TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc); 832208019Sthompsa TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc); 833259453Shselasky usb_callout_init_mtx(&sc->ratectl_ch, &sc->sc_mtx, 0); 834208019Sthompsa 835203134Sthompsa if (bootverbose) 836203134Sthompsa ieee80211_announce(ic); 837203134Sthompsa 838209917Sthompsa return (0); 839203134Sthompsa 840203134Sthompsadetach: 841203134Sthompsa run_detach(self); 842209917Sthompsa return (ENXIO); 843203134Sthompsa} 844203134Sthompsa 845203134Sthompsastatic int 846203134Sthompsarun_detach(device_t self) 847203134Sthompsa{ 848203134Sthompsa struct run_softc *sc = device_get_softc(self); 849203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 850203134Sthompsa struct ieee80211com *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]); 867203134Sthompsa RUN_UNLOCK(sc); 868203134Sthompsa 869203134Sthompsa if (ifp) { 870203134Sthompsa ic = ifp->if_l2com; 871208019Sthompsa /* drain tasks */ 872208019Sthompsa usb_callout_drain(&sc->ratectl_ch); 873208019Sthompsa ieee80211_draintask(ic, &sc->cmdq_task); 874208019Sthompsa ieee80211_draintask(ic, &sc->ratectl_task); 875203134Sthompsa ieee80211_ifdetach(ic); 876203134Sthompsa if_free(ifp); 877203134Sthompsa } 878203134Sthompsa 879203134Sthompsa mtx_destroy(&sc->sc_mtx); 880203134Sthompsa 881203134Sthompsa return (0); 882203134Sthompsa} 883203134Sthompsa 884203134Sthompsastatic struct ieee80211vap * 885228621Sbschmidtrun_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, 886228621Sbschmidt enum ieee80211_opmode opmode, int flags, 887203134Sthompsa const uint8_t bssid[IEEE80211_ADDR_LEN], 888203134Sthompsa const uint8_t mac[IEEE80211_ADDR_LEN]) 889203134Sthompsa{ 890208019Sthompsa struct ifnet *ifp = ic->ic_ifp; 891208019Sthompsa struct run_softc *sc = ifp->if_softc; 892203134Sthompsa struct run_vap *rvp; 893203134Sthompsa struct ieee80211vap *vap; 894208019Sthompsa int i; 895203134Sthompsa 896209917Sthompsa if (sc->rvp_cnt >= RUN_VAP_MAX) { 897208019Sthompsa if_printf(ifp, "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) { 923208019Sthompsa if_printf(ifp, "wds only supported in ap mode\n"); 924209917Sthompsa return (NULL); 925208019Sthompsa } 926208019Sthompsa break; 927208019Sthompsa default: 928208019Sthompsa if_printf(ifp, "unknown opmode %d\n", opmode); 929209917Sthompsa return (NULL); 930208019Sthompsa } 931208019Sthompsa 932208019Sthompsa rvp = (struct run_vap *) malloc(sizeof(struct run_vap), 933203134Sthompsa M_80211_VAP, M_NOWAIT | M_ZERO); 934203134Sthompsa if (rvp == NULL) 935209917Sthompsa return (NULL); 936203134Sthompsa vap = &rvp->vap; 937203134Sthompsa 938259453Shselasky if (ieee80211_vap_setup(ic, vap, name, unit, 939259453Shselasky opmode, flags, bssid, mac) != 0) { 940259453Shselasky /* out of memory */ 941259453Shselasky free(rvp, M_80211_VAP); 942259453Shselasky return (NULL); 943259453Shselasky } 944259453Shselasky 945203134Sthompsa vap->iv_key_update_begin = run_key_update_begin; 946203134Sthompsa vap->iv_key_update_end = run_key_update_end; 947203134Sthompsa vap->iv_update_beacon = run_update_beacon; 948208019Sthompsa vap->iv_max_aid = RT2870_WCID_MAX; 949208019Sthompsa /* 950208019Sthompsa * To delete the right key from h/w, we need wcid. 951208019Sthompsa * Luckily, there is unused space in ieee80211_key{}, wk_pad, 952208019Sthompsa * and matching wcid will be written into there. So, cast 953208019Sthompsa * some spells to remove 'const' from ieee80211_key{} 954208019Sthompsa */ 955208019Sthompsa vap->iv_key_delete = (void *)run_key_delete; 956208019Sthompsa vap->iv_key_set = (void *)run_key_set; 957203134Sthompsa 958203134Sthompsa /* override state transition machine */ 959203134Sthompsa rvp->newstate = vap->iv_newstate; 960203134Sthompsa vap->iv_newstate = run_newstate; 961203134Sthompsa 962206358Srpaulo ieee80211_ratectl_init(vap); 963206358Srpaulo ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */); 964203134Sthompsa 965203134Sthompsa /* complete setup */ 966203134Sthompsa ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status); 967208019Sthompsa 968208019Sthompsa /* make sure id is always unique */ 969209917Sthompsa for (i = 0; i < RUN_VAP_MAX; i++) { 970208019Sthompsa if((sc->rvp_bmap & 1 << i) == 0){ 971208019Sthompsa sc->rvp_bmap |= 1 << i; 972208019Sthompsa rvp->rvp_id = i; 973208019Sthompsa break; 974208019Sthompsa } 975208019Sthompsa } 976209917Sthompsa if (sc->rvp_cnt++ == 0) 977208019Sthompsa ic->ic_opmode = opmode; 978208019Sthompsa 979209917Sthompsa if (opmode == IEEE80211_M_HOSTAP) 980209144Sthompsa sc->cmdq_run = RUN_CMDQ_GO; 981209144Sthompsa 982208019Sthompsa DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n", 983208019Sthompsa rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt); 984208019Sthompsa 985209917Sthompsa return (vap); 986203134Sthompsa} 987203134Sthompsa 988203134Sthompsastatic void 989203134Sthompsarun_vap_delete(struct ieee80211vap *vap) 990203134Sthompsa{ 991203134Sthompsa struct run_vap *rvp = RUN_VAP(vap); 992203134Sthompsa struct ifnet *ifp; 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; 1001203134Sthompsa ifp = ic->ic_ifp; 1002203134Sthompsa 1003203134Sthompsa sc = ifp->if_softc; 1004203134Sthompsa 1005205042Sthompsa RUN_LOCK(sc); 1006208019Sthompsa 1007218492Sbschmidt m_freem(rvp->beacon_mbuf); 1008218492Sbschmidt rvp->beacon_mbuf = NULL; 1009218492Sbschmidt 1010208019Sthompsa rvp_id = rvp->rvp_id; 1011208019Sthompsa sc->ratectl_run &= ~(1 << rvp_id); 1012208019Sthompsa sc->rvp_bmap &= ~(1 << rvp_id); 1013208019Sthompsa run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128); 1014208019Sthompsa run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512); 1015208019Sthompsa --sc->rvp_cnt; 1016208019Sthompsa 1017208019Sthompsa DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n", 1018208019Sthompsa vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt); 1019208019Sthompsa 1020205042Sthompsa RUN_UNLOCK(sc); 1021203134Sthompsa 1022206358Srpaulo ieee80211_ratectl_deinit(vap); 1023203134Sthompsa ieee80211_vap_detach(vap); 1024203134Sthompsa free(rvp, M_80211_VAP); 1025203134Sthompsa} 1026203134Sthompsa 1027208019Sthompsa/* 1028208019Sthompsa * There are numbers of functions need to be called in context thread. 1029208019Sthompsa * Rather than creating taskqueue event for each of those functions, 1030208019Sthompsa * here is all-for-one taskqueue callback function. This function 1031208019Sthompsa * gurantees deferred functions are executed in the same order they 1032208019Sthompsa * were enqueued. 1033208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[]. 1034208019Sthompsa */ 1035203134Sthompsastatic void 1036208019Sthompsarun_cmdq_cb(void *arg, int pending) 1037208019Sthompsa{ 1038208019Sthompsa struct run_softc *sc = arg; 1039208019Sthompsa uint8_t i; 1040208019Sthompsa 1041208019Sthompsa /* call cmdq[].func locked */ 1042208019Sthompsa RUN_LOCK(sc); 1043209917Sthompsa for (i = sc->cmdq_exec; sc->cmdq[i].func && pending; 1044209917Sthompsa i = sc->cmdq_exec, pending--) { 1045208019Sthompsa DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending); 1046209917Sthompsa if (sc->cmdq_run == RUN_CMDQ_GO) { 1047208019Sthompsa /* 1048208019Sthompsa * If arg0 is NULL, callback func needs more 1049208019Sthompsa * than one arg. So, pass ptr to cmdq struct. 1050208019Sthompsa */ 1051209917Sthompsa if (sc->cmdq[i].arg0) 1052208019Sthompsa sc->cmdq[i].func(sc->cmdq[i].arg0); 1053208019Sthompsa else 1054208019Sthompsa sc->cmdq[i].func(&sc->cmdq[i]); 1055208019Sthompsa } 1056208019Sthompsa sc->cmdq[i].arg0 = NULL; 1057208019Sthompsa sc->cmdq[i].func = NULL; 1058208019Sthompsa sc->cmdq_exec++; 1059208019Sthompsa sc->cmdq_exec &= RUN_CMDQ_MASQ; 1060208019Sthompsa } 1061208019Sthompsa RUN_UNLOCK(sc); 1062208019Sthompsa} 1063208019Sthompsa 1064208019Sthompsastatic void 1065203134Sthompsarun_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq) 1066203134Sthompsa{ 1067203134Sthompsa struct run_tx_data *data; 1068203134Sthompsa 1069203134Sthompsa memset(pq, 0, sizeof(*pq)); 1070203134Sthompsa 1071203134Sthompsa STAILQ_INIT(&pq->tx_qh); 1072203134Sthompsa STAILQ_INIT(&pq->tx_fh); 1073203134Sthompsa 1074203134Sthompsa for (data = &pq->tx_data[0]; 1075203134Sthompsa data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) { 1076203134Sthompsa data->sc = sc; 1077203134Sthompsa STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); 1078203134Sthompsa } 1079203134Sthompsa pq->tx_nfree = RUN_TX_RING_COUNT; 1080203134Sthompsa} 1081203134Sthompsa 1082203134Sthompsastatic void 1083203134Sthompsarun_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq) 1084203134Sthompsa{ 1085203134Sthompsa struct run_tx_data *data; 1086203134Sthompsa 1087203134Sthompsa /* make sure any subsequent use of the queues will fail */ 1088203134Sthompsa pq->tx_nfree = 0; 1089203134Sthompsa STAILQ_INIT(&pq->tx_fh); 1090203134Sthompsa STAILQ_INIT(&pq->tx_qh); 1091203134Sthompsa 1092203134Sthompsa /* free up all node references and mbufs */ 1093203134Sthompsa for (data = &pq->tx_data[0]; 1094209917Sthompsa data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) { 1095203134Sthompsa if (data->m != NULL) { 1096203134Sthompsa m_freem(data->m); 1097203134Sthompsa data->m = NULL; 1098203134Sthompsa } 1099203134Sthompsa if (data->ni != NULL) { 1100203134Sthompsa ieee80211_free_node(data->ni); 1101203134Sthompsa data->ni = NULL; 1102203134Sthompsa } 1103203134Sthompsa } 1104203134Sthompsa} 1105203134Sthompsa 1106220235Skevlostatic int 1107203134Sthompsarun_load_microcode(struct run_softc *sc) 1108203134Sthompsa{ 1109203134Sthompsa usb_device_request_t req; 1110203137Sthompsa const struct firmware *fw; 1111203134Sthompsa const u_char *base; 1112203134Sthompsa uint32_t tmp; 1113203134Sthompsa int ntries, error; 1114203134Sthompsa const uint64_t *temp; 1115203134Sthompsa uint64_t bytes; 1116203134Sthompsa 1117205042Sthompsa RUN_UNLOCK(sc); 1118203137Sthompsa fw = firmware_get("runfw"); 1119205042Sthompsa RUN_LOCK(sc); 1120209917Sthompsa if (fw == NULL) { 1121203138Sthompsa device_printf(sc->sc_dev, 1122203138Sthompsa "failed loadfirmware of file %s\n", "runfw"); 1123203134Sthompsa return ENOENT; 1124203134Sthompsa } 1125203134Sthompsa 1126203137Sthompsa if (fw->datasize != 8192) { 1127203138Sthompsa device_printf(sc->sc_dev, 1128203138Sthompsa "invalid firmware size (should be 8KB)\n"); 1129203137Sthompsa error = EINVAL; 1130203137Sthompsa goto fail; 1131203134Sthompsa } 1132203134Sthompsa 1133203134Sthompsa /* 1134203134Sthompsa * RT3071/RT3072 use a different firmware 1135203134Sthompsa * run-rt2870 (8KB) contains both, 1136203134Sthompsa * first half (4KB) is for rt2870, 1137203134Sthompsa * last half is for rt3071. 1138203134Sthompsa */ 1139203137Sthompsa base = fw->data; 1140205042Sthompsa if ((sc->mac_ver) != 0x2860 && 1141205042Sthompsa (sc->mac_ver) != 0x2872 && 1142209917Sthompsa (sc->mac_ver) != 0x3070) { 1143203134Sthompsa base += 4096; 1144205042Sthompsa } 1145203134Sthompsa 1146203134Sthompsa /* cheap sanity check */ 1147203137Sthompsa temp = fw->data; 1148203134Sthompsa bytes = *temp; 1149259453Shselasky if (bytes != be64toh(0xffffff0210280210ULL)) { 1150203138Sthompsa device_printf(sc->sc_dev, "firmware checksum failed\n"); 1151203137Sthompsa error = EINVAL; 1152203137Sthompsa goto fail; 1153203137Sthompsa } 1154203134Sthompsa 1155203134Sthompsa /* write microcode image */ 1156262604Skevlo if (sc->sc_flags & RUN_FLAG_FWLOAD_NEEDED) { 1157261868Skevlo run_write_region_1(sc, RT2870_FW_BASE, base, 4096); 1158261868Skevlo run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff); 1159261868Skevlo run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff); 1160261868Skevlo } 1161203134Sthompsa 1162203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1163203134Sthompsa req.bRequest = RT2870_RESET; 1164203134Sthompsa USETW(req.wValue, 8); 1165203134Sthompsa USETW(req.wIndex, 0); 1166203134Sthompsa USETW(req.wLength, 0); 1167220235Skevlo if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)) 1168220235Skevlo != 0) { 1169203138Sthompsa device_printf(sc->sc_dev, "firmware reset failed\n"); 1170203137Sthompsa goto fail; 1171203137Sthompsa } 1172203134Sthompsa 1173203134Sthompsa run_delay(sc, 10); 1174203134Sthompsa 1175261868Skevlo run_write(sc, RT2860_H2M_BBPAGENT, 0); 1176203134Sthompsa run_write(sc, RT2860_H2M_MAILBOX, 0); 1177261868Skevlo run_write(sc, RT2860_H2M_INTSRC, 0); 1178205042Sthompsa if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0) 1179203137Sthompsa goto fail; 1180203134Sthompsa 1181203134Sthompsa /* wait until microcontroller is ready */ 1182203134Sthompsa for (ntries = 0; ntries < 1000; ntries++) { 1183261868Skevlo if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0) 1184203137Sthompsa goto fail; 1185203134Sthompsa if (tmp & RT2860_MCU_READY) 1186203134Sthompsa break; 1187203134Sthompsa run_delay(sc, 10); 1188203134Sthompsa } 1189203134Sthompsa if (ntries == 1000) { 1190203138Sthompsa device_printf(sc->sc_dev, 1191203138Sthompsa "timeout waiting for MCU to initialize\n"); 1192203137Sthompsa error = ETIMEDOUT; 1193203137Sthompsa goto fail; 1194203134Sthompsa } 1195233283Sbschmidt device_printf(sc->sc_dev, "firmware %s ver. %u.%u loaded\n", 1196233283Sbschmidt (base == fw->data) ? "RT2870" : "RT3071", 1197233283Sbschmidt *(base + 4092), *(base + 4093)); 1198203134Sthompsa 1199203137Sthompsafail: 1200203137Sthompsa firmware_put(fw, FIRMWARE_UNLOAD); 1201203137Sthompsa return (error); 1202203134Sthompsa} 1203203134Sthompsa 1204259453Shselaskystatic int 1205203134Sthompsarun_reset(struct run_softc *sc) 1206203134Sthompsa{ 1207203134Sthompsa usb_device_request_t req; 1208203134Sthompsa 1209203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1210203134Sthompsa req.bRequest = RT2870_RESET; 1211203134Sthompsa USETW(req.wValue, 1); 1212203134Sthompsa USETW(req.wIndex, 0); 1213203134Sthompsa USETW(req.wLength, 0); 1214209917Sthompsa return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)); 1215203134Sthompsa} 1216203134Sthompsa 1217203134Sthompsastatic usb_error_t 1218203134Sthompsarun_do_request(struct run_softc *sc, 1219203134Sthompsa struct usb_device_request *req, void *data) 1220203134Sthompsa{ 1221203134Sthompsa usb_error_t err; 1222203134Sthompsa int ntries = 10; 1223203134Sthompsa 1224203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 1225203134Sthompsa 1226203134Sthompsa while (ntries--) { 1227203134Sthompsa err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, 1228203134Sthompsa req, data, 0, NULL, 250 /* ms */); 1229203134Sthompsa if (err == 0) 1230203134Sthompsa break; 1231203134Sthompsa DPRINTFN(1, "Control request failed, %s (retrying)\n", 1232203134Sthompsa usbd_errstr(err)); 1233203134Sthompsa run_delay(sc, 10); 1234203134Sthompsa } 1235203134Sthompsa return (err); 1236203134Sthompsa} 1237203134Sthompsa 1238203134Sthompsastatic int 1239203134Sthompsarun_read(struct run_softc *sc, uint16_t reg, uint32_t *val) 1240203134Sthompsa{ 1241203134Sthompsa uint32_t tmp; 1242203134Sthompsa int error; 1243203134Sthompsa 1244203134Sthompsa error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp); 1245203134Sthompsa if (error == 0) 1246203134Sthompsa *val = le32toh(tmp); 1247203134Sthompsa else 1248203134Sthompsa *val = 0xffffffff; 1249209917Sthompsa return (error); 1250203134Sthompsa} 1251203134Sthompsa 1252203134Sthompsastatic int 1253203134Sthompsarun_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len) 1254203134Sthompsa{ 1255203134Sthompsa usb_device_request_t req; 1256203134Sthompsa 1257203134Sthompsa req.bmRequestType = UT_READ_VENDOR_DEVICE; 1258203134Sthompsa req.bRequest = RT2870_READ_REGION_1; 1259203134Sthompsa USETW(req.wValue, 0); 1260203134Sthompsa USETW(req.wIndex, reg); 1261203134Sthompsa USETW(req.wLength, len); 1262203134Sthompsa 1263209917Sthompsa return (run_do_request(sc, &req, buf)); 1264203134Sthompsa} 1265203134Sthompsa 1266203134Sthompsastatic int 1267203134Sthompsarun_write_2(struct run_softc *sc, uint16_t reg, uint16_t val) 1268203134Sthompsa{ 1269203134Sthompsa usb_device_request_t req; 1270203134Sthompsa 1271203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1272203134Sthompsa req.bRequest = RT2870_WRITE_2; 1273203134Sthompsa USETW(req.wValue, val); 1274203134Sthompsa USETW(req.wIndex, reg); 1275203134Sthompsa USETW(req.wLength, 0); 1276203134Sthompsa 1277209917Sthompsa return (run_do_request(sc, &req, NULL)); 1278203134Sthompsa} 1279203134Sthompsa 1280203134Sthompsastatic int 1281203134Sthompsarun_write(struct run_softc *sc, uint16_t reg, uint32_t val) 1282203134Sthompsa{ 1283203134Sthompsa int error; 1284203134Sthompsa 1285203134Sthompsa if ((error = run_write_2(sc, reg, val & 0xffff)) == 0) 1286203134Sthompsa error = run_write_2(sc, reg + 2, val >> 16); 1287209917Sthompsa return (error); 1288203134Sthompsa} 1289203134Sthompsa 1290203134Sthompsastatic int 1291203134Sthompsarun_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf, 1292203134Sthompsa int len) 1293203134Sthompsa{ 1294203134Sthompsa#if 1 1295203134Sthompsa int i, error = 0; 1296203134Sthompsa /* 1297203134Sthompsa * NB: the WRITE_REGION_1 command is not stable on RT2860. 1298203134Sthompsa * We thus issue multiple WRITE_2 commands instead. 1299203134Sthompsa */ 1300203134Sthompsa KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n")); 1301203134Sthompsa for (i = 0; i < len && error == 0; i += 2) 1302203134Sthompsa error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8); 1303209917Sthompsa return (error); 1304203134Sthompsa#else 1305203134Sthompsa usb_device_request_t req; 1306259453Shselasky int error = 0; 1307203134Sthompsa 1308259453Shselasky /* 1309259453Shselasky * NOTE: It appears the WRITE_REGION_1 command cannot be 1310259453Shselasky * passed a huge amount of data, which will crash the 1311259453Shselasky * firmware. Limit amount of data passed to 64-bytes at a 1312259453Shselasky * time. 1313259453Shselasky */ 1314259453Shselasky while (len > 0) { 1315259453Shselasky int delta = 64; 1316259453Shselasky if (delta > len) 1317259453Shselasky delta = len; 1318259453Shselasky 1319259453Shselasky req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1320259453Shselasky req.bRequest = RT2870_WRITE_REGION_1; 1321259453Shselasky USETW(req.wValue, 0); 1322259453Shselasky USETW(req.wIndex, reg); 1323259453Shselasky USETW(req.wLength, delta); 1324259453Shselasky error = run_do_request(sc, &req, __DECONST(uint8_t *, buf)); 1325259453Shselasky if (error != 0) 1326259453Shselasky break; 1327259453Shselasky reg += delta; 1328259453Shselasky buf += delta; 1329259453Shselasky len -= delta; 1330259453Shselasky } 1331259453Shselasky return (error); 1332203134Sthompsa#endif 1333203134Sthompsa} 1334203134Sthompsa 1335203134Sthompsastatic int 1336203134Sthompsarun_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len) 1337203134Sthompsa{ 1338203134Sthompsa int i, error = 0; 1339203134Sthompsa 1340203134Sthompsa KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n")); 1341203134Sthompsa for (i = 0; i < len && error == 0; i += 4) 1342203134Sthompsa error = run_write(sc, reg + i, val); 1343209917Sthompsa return (error); 1344203134Sthompsa} 1345203134Sthompsa 1346203134Sthompsastatic int 1347261868Skevlorun_efuse_read(struct run_softc *sc, uint16_t addr, uint16_t *val, int count) 1348203134Sthompsa{ 1349203134Sthompsa uint32_t tmp; 1350203134Sthompsa uint16_t reg; 1351203134Sthompsa int error, ntries; 1352203134Sthompsa 1353203134Sthompsa if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0) 1354209917Sthompsa return (error); 1355203134Sthompsa 1356261868Skevlo if (count == 2) 1357261868Skevlo addr *= 2; 1358203134Sthompsa /*- 1359203134Sthompsa * Read one 16-byte block into registers EFUSE_DATA[0-3]: 1360203134Sthompsa * DATA0: F E D C 1361203134Sthompsa * DATA1: B A 9 8 1362203134Sthompsa * DATA2: 7 6 5 4 1363203134Sthompsa * DATA3: 3 2 1 0 1364203134Sthompsa */ 1365203134Sthompsa tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK); 1366203134Sthompsa tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK; 1367203134Sthompsa run_write(sc, RT3070_EFUSE_CTRL, tmp); 1368203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1369203134Sthompsa if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0) 1370209917Sthompsa return (error); 1371203134Sthompsa if (!(tmp & RT3070_EFSROM_KICK)) 1372203134Sthompsa break; 1373203134Sthompsa run_delay(sc, 2); 1374203134Sthompsa } 1375203134Sthompsa if (ntries == 100) 1376209917Sthompsa return (ETIMEDOUT); 1377203134Sthompsa 1378203134Sthompsa if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) { 1379203134Sthompsa *val = 0xffff; /* address not found */ 1380209917Sthompsa return (0); 1381203134Sthompsa } 1382203134Sthompsa /* determine to which 32-bit register our 16-bit word belongs */ 1383203134Sthompsa reg = RT3070_EFUSE_DATA3 - (addr & 0xc); 1384203134Sthompsa if ((error = run_read(sc, reg, &tmp)) != 0) 1385209917Sthompsa return (error); 1386203134Sthompsa 1387261868Skevlo tmp >>= (8 * (addr & 0x3)); 1388261868Skevlo *val = (addr & 1) ? tmp >> 16 : tmp & 0xffff; 1389261868Skevlo 1390209917Sthompsa return (0); 1391203134Sthompsa} 1392203134Sthompsa 1393261868Skevlo/* Read 16-bit from eFUSE ROM for RT3xxx. */ 1394203134Sthompsastatic int 1395261868Skevlorun_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val) 1396261868Skevlo{ 1397261868Skevlo return (run_efuse_read(sc, addr, val, 2)); 1398261868Skevlo} 1399261868Skevlo 1400261868Skevlostatic int 1401203134Sthompsarun_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val) 1402203134Sthompsa{ 1403203134Sthompsa usb_device_request_t req; 1404203134Sthompsa uint16_t tmp; 1405203134Sthompsa int error; 1406203134Sthompsa 1407203134Sthompsa addr *= 2; 1408203134Sthompsa req.bmRequestType = UT_READ_VENDOR_DEVICE; 1409203134Sthompsa req.bRequest = RT2870_EEPROM_READ; 1410203134Sthompsa USETW(req.wValue, 0); 1411203134Sthompsa USETW(req.wIndex, addr); 1412261868Skevlo USETW(req.wLength, sizeof(tmp)); 1413203134Sthompsa 1414203134Sthompsa error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp); 1415203134Sthompsa if (error == 0) 1416203134Sthompsa *val = le16toh(tmp); 1417203134Sthompsa else 1418203134Sthompsa *val = 0xffff; 1419209917Sthompsa return (error); 1420203134Sthompsa} 1421203134Sthompsa 1422203134Sthompsastatic __inline int 1423203134Sthompsarun_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val) 1424203134Sthompsa{ 1425203134Sthompsa /* either eFUSE ROM or EEPROM */ 1426203134Sthompsa return sc->sc_srom_read(sc, addr, val); 1427203134Sthompsa} 1428203134Sthompsa 1429203134Sthompsastatic int 1430259453Shselaskyrun_rt2870_rf_write(struct run_softc *sc, uint32_t val) 1431203134Sthompsa{ 1432203134Sthompsa uint32_t tmp; 1433203134Sthompsa int error, ntries; 1434203134Sthompsa 1435203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1436203134Sthompsa if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0) 1437209917Sthompsa return (error); 1438203134Sthompsa if (!(tmp & RT2860_RF_REG_CTRL)) 1439203134Sthompsa break; 1440203134Sthompsa } 1441203134Sthompsa if (ntries == 10) 1442209917Sthompsa return (ETIMEDOUT); 1443203134Sthompsa 1444259453Shselasky return (run_write(sc, RT2860_RF_CSR_CFG0, val)); 1445203134Sthompsa} 1446203134Sthompsa 1447203134Sthompsastatic int 1448203134Sthompsarun_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val) 1449203134Sthompsa{ 1450203134Sthompsa uint32_t tmp; 1451203134Sthompsa int error, ntries; 1452203134Sthompsa 1453203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1454203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1455209917Sthompsa return (error); 1456203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1457203134Sthompsa break; 1458203134Sthompsa } 1459203134Sthompsa if (ntries == 100) 1460209917Sthompsa return (ETIMEDOUT); 1461203134Sthompsa 1462203134Sthompsa tmp = RT3070_RF_KICK | reg << 8; 1463203134Sthompsa if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0) 1464209917Sthompsa return (error); 1465203134Sthompsa 1466203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1467203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1468209917Sthompsa return (error); 1469203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1470203134Sthompsa break; 1471203134Sthompsa } 1472203134Sthompsa if (ntries == 100) 1473209917Sthompsa return (ETIMEDOUT); 1474203134Sthompsa 1475203134Sthompsa *val = tmp & 0xff; 1476209917Sthompsa return (0); 1477203134Sthompsa} 1478203134Sthompsa 1479203134Sthompsastatic int 1480203134Sthompsarun_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val) 1481203134Sthompsa{ 1482203134Sthompsa uint32_t tmp; 1483203134Sthompsa int error, ntries; 1484203134Sthompsa 1485203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1486203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1487209917Sthompsa return (error); 1488203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1489203134Sthompsa break; 1490203134Sthompsa } 1491203134Sthompsa if (ntries == 10) 1492209917Sthompsa return (ETIMEDOUT); 1493203134Sthompsa 1494203134Sthompsa tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val; 1495209917Sthompsa return (run_write(sc, RT3070_RF_CSR_CFG, tmp)); 1496203134Sthompsa} 1497203134Sthompsa 1498203134Sthompsastatic int 1499203134Sthompsarun_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val) 1500203134Sthompsa{ 1501203134Sthompsa uint32_t tmp; 1502203134Sthompsa int ntries, error; 1503203134Sthompsa 1504203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1505203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1506209917Sthompsa return (error); 1507203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1508203134Sthompsa break; 1509203134Sthompsa } 1510203134Sthompsa if (ntries == 10) 1511209917Sthompsa return (ETIMEDOUT); 1512203134Sthompsa 1513203134Sthompsa tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8; 1514203134Sthompsa if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0) 1515209917Sthompsa return (error); 1516203134Sthompsa 1517203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1518203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1519209917Sthompsa return (error); 1520203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1521203134Sthompsa break; 1522203134Sthompsa } 1523203134Sthompsa if (ntries == 10) 1524209917Sthompsa return (ETIMEDOUT); 1525203134Sthompsa 1526203134Sthompsa *val = tmp & 0xff; 1527209917Sthompsa return (0); 1528203134Sthompsa} 1529203134Sthompsa 1530203134Sthompsastatic int 1531203134Sthompsarun_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val) 1532203134Sthompsa{ 1533203134Sthompsa uint32_t tmp; 1534203134Sthompsa int ntries, error; 1535203134Sthompsa 1536203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1537203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1538209917Sthompsa return (error); 1539203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1540203134Sthompsa break; 1541203134Sthompsa } 1542203134Sthompsa if (ntries == 10) 1543209917Sthompsa return (ETIMEDOUT); 1544203134Sthompsa 1545203134Sthompsa tmp = RT2860_BBP_CSR_KICK | reg << 8 | val; 1546209917Sthompsa return (run_write(sc, RT2860_BBP_CSR_CFG, tmp)); 1547203134Sthompsa} 1548203134Sthompsa 1549203134Sthompsa/* 1550203134Sthompsa * Send a command to the 8051 microcontroller unit. 1551203134Sthompsa */ 1552203134Sthompsastatic int 1553203134Sthompsarun_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg) 1554203134Sthompsa{ 1555203134Sthompsa uint32_t tmp; 1556203134Sthompsa int error, ntries; 1557203134Sthompsa 1558203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1559203134Sthompsa if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0) 1560203134Sthompsa return error; 1561203134Sthompsa if (!(tmp & RT2860_H2M_BUSY)) 1562203134Sthompsa break; 1563203134Sthompsa } 1564203134Sthompsa if (ntries == 100) 1565203134Sthompsa return ETIMEDOUT; 1566203134Sthompsa 1567203134Sthompsa tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg; 1568203134Sthompsa if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0) 1569203134Sthompsa error = run_write(sc, RT2860_HOST_CMD, cmd); 1570209917Sthompsa return (error); 1571203134Sthompsa} 1572203134Sthompsa 1573203134Sthompsa/* 1574203134Sthompsa * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word. 1575203134Sthompsa * Used to adjust per-rate Tx power registers. 1576203134Sthompsa */ 1577203134Sthompsastatic __inline uint32_t 1578203134Sthompsab4inc(uint32_t b32, int8_t delta) 1579203134Sthompsa{ 1580203134Sthompsa int8_t i, b4; 1581203134Sthompsa 1582203134Sthompsa for (i = 0; i < 8; i++) { 1583203134Sthompsa b4 = b32 & 0xf; 1584203134Sthompsa b4 += delta; 1585203134Sthompsa if (b4 < 0) 1586203134Sthompsa b4 = 0; 1587203134Sthompsa else if (b4 > 0xf) 1588203134Sthompsa b4 = 0xf; 1589203134Sthompsa b32 = b32 >> 4 | b4 << 28; 1590203134Sthompsa } 1591209917Sthompsa return (b32); 1592203134Sthompsa} 1593203134Sthompsa 1594203134Sthompsastatic const char * 1595259453Shselaskyrun_get_rf(uint16_t rev) 1596203134Sthompsa{ 1597203134Sthompsa switch (rev) { 1598203134Sthompsa case RT2860_RF_2820: return "RT2820"; 1599203134Sthompsa case RT2860_RF_2850: return "RT2850"; 1600203134Sthompsa case RT2860_RF_2720: return "RT2720"; 1601203134Sthompsa case RT2860_RF_2750: return "RT2750"; 1602203134Sthompsa case RT3070_RF_3020: return "RT3020"; 1603203134Sthompsa case RT3070_RF_2020: return "RT2020"; 1604203134Sthompsa case RT3070_RF_3021: return "RT3021"; 1605203134Sthompsa case RT3070_RF_3022: return "RT3022"; 1606203134Sthompsa case RT3070_RF_3052: return "RT3052"; 1607261868Skevlo case RT3593_RF_3053: return "RT3053"; 1608259453Shselasky case RT5592_RF_5592: return "RT5592"; 1609259453Shselasky case RT5390_RF_5370: return "RT5370"; 1610259453Shselasky case RT5390_RF_5372: return "RT5372"; 1611203134Sthompsa } 1612209917Sthompsa return ("unknown"); 1613203134Sthompsa} 1614203134Sthompsa 1615261868Skevlostatic void 1616261868Skevlorun_rt3593_get_txpower(struct run_softc *sc) 1617261868Skevlo{ 1618261868Skevlo uint16_t addr, val; 1619261868Skevlo int i; 1620261868Skevlo 1621261868Skevlo /* Read power settings for 2GHz channels. */ 1622261868Skevlo for (i = 0; i < 14; i += 2) { 1623261868Skevlo addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE1 : 1624261868Skevlo RT2860_EEPROM_PWR2GHZ_BASE1; 1625261868Skevlo run_srom_read(sc, addr + i / 2, &val); 1626261868Skevlo sc->txpow1[i + 0] = (int8_t)(val & 0xff); 1627261868Skevlo sc->txpow1[i + 1] = (int8_t)(val >> 8); 1628261868Skevlo 1629261868Skevlo addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE2 : 1630261868Skevlo RT2860_EEPROM_PWR2GHZ_BASE2; 1631261868Skevlo run_srom_read(sc, addr + i / 2, &val); 1632261868Skevlo sc->txpow2[i + 0] = (int8_t)(val & 0xff); 1633261868Skevlo sc->txpow2[i + 1] = (int8_t)(val >> 8); 1634261868Skevlo 1635261868Skevlo if (sc->ntxchains == 3) { 1636261868Skevlo run_srom_read(sc, RT3593_EEPROM_PWR2GHZ_BASE3 + i / 2, 1637261868Skevlo &val); 1638261868Skevlo sc->txpow3[i + 0] = (int8_t)(val & 0xff); 1639261868Skevlo sc->txpow3[i + 1] = (int8_t)(val >> 8); 1640261868Skevlo } 1641261868Skevlo } 1642261868Skevlo /* Fix broken Tx power entries. */ 1643261868Skevlo for (i = 0; i < 14; i++) { 1644261868Skevlo if (sc->txpow1[i] > 31) 1645261868Skevlo sc->txpow1[i] = 5; 1646261868Skevlo if (sc->txpow2[i] > 31) 1647261868Skevlo sc->txpow2[i] = 5; 1648261868Skevlo if (sc->ntxchains == 3) { 1649261868Skevlo if (sc->txpow3[i] > 31) 1650261868Skevlo sc->txpow3[i] = 5; 1651261868Skevlo } 1652261868Skevlo } 1653261868Skevlo /* Read power settings for 5GHz channels. */ 1654261868Skevlo for (i = 0; i < 40; i += 2) { 1655261868Skevlo run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE1 + i / 2, &val); 1656261868Skevlo sc->txpow1[i + 14] = (int8_t)(val & 0xff); 1657261868Skevlo sc->txpow1[i + 15] = (int8_t)(val >> 8); 1658261868Skevlo 1659261868Skevlo run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE2 + i / 2, &val); 1660261868Skevlo sc->txpow2[i + 14] = (int8_t)(val & 0xff); 1661261868Skevlo sc->txpow2[i + 15] = (int8_t)(val >> 8); 1662261868Skevlo 1663261868Skevlo if (sc->ntxchains == 3) { 1664261868Skevlo run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE3 + i / 2, 1665261868Skevlo &val); 1666261868Skevlo sc->txpow3[i + 14] = (int8_t)(val & 0xff); 1667261868Skevlo sc->txpow3[i + 15] = (int8_t)(val >> 8); 1668261868Skevlo } 1669261868Skevlo } 1670261868Skevlo} 1671261868Skevlo 1672261868Skevlostatic void 1673261868Skevlorun_get_txpower(struct run_softc *sc) 1674261868Skevlo{ 1675261868Skevlo uint16_t val; 1676261868Skevlo int i; 1677261868Skevlo 1678261868Skevlo /* Read power settings for 2GHz channels. */ 1679261868Skevlo for (i = 0; i < 14; i += 2) { 1680261868Skevlo run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val); 1681261868Skevlo sc->txpow1[i + 0] = (int8_t)(val & 0xff); 1682261868Skevlo sc->txpow1[i + 1] = (int8_t)(val >> 8); 1683261868Skevlo 1684261868Skevlo if (sc->mac_ver != 0x5390) { 1685261868Skevlo run_srom_read(sc, 1686261868Skevlo RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val); 1687261868Skevlo sc->txpow2[i + 0] = (int8_t)(val & 0xff); 1688261868Skevlo sc->txpow2[i + 1] = (int8_t)(val >> 8); 1689261868Skevlo } 1690261868Skevlo } 1691261868Skevlo /* Fix broken Tx power entries. */ 1692261868Skevlo for (i = 0; i < 14; i++) { 1693261868Skevlo if (sc->mac_ver >= 0x5390) { 1694261868Skevlo if (sc->txpow1[i] < 0 || sc->txpow1[i] > 27) 1695261868Skevlo sc->txpow1[i] = 5; 1696261868Skevlo } else { 1697261868Skevlo if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31) 1698261868Skevlo sc->txpow1[i] = 5; 1699261868Skevlo } 1700261868Skevlo if (sc->mac_ver > 0x5390) { 1701261868Skevlo if (sc->txpow2[i] < 0 || sc->txpow2[i] > 27) 1702261868Skevlo sc->txpow2[i] = 5; 1703261868Skevlo } else if (sc->mac_ver < 0x5390) { 1704261868Skevlo if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31) 1705261868Skevlo sc->txpow2[i] = 5; 1706261868Skevlo } 1707261868Skevlo DPRINTF("chan %d: power1=%d, power2=%d\n", 1708261868Skevlo rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]); 1709261868Skevlo } 1710261868Skevlo /* Read power settings for 5GHz channels. */ 1711261868Skevlo for (i = 0; i < 40; i += 2) { 1712261868Skevlo run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val); 1713261868Skevlo sc->txpow1[i + 14] = (int8_t)(val & 0xff); 1714261868Skevlo sc->txpow1[i + 15] = (int8_t)(val >> 8); 1715261868Skevlo 1716261868Skevlo run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val); 1717261868Skevlo sc->txpow2[i + 14] = (int8_t)(val & 0xff); 1718261868Skevlo sc->txpow2[i + 15] = (int8_t)(val >> 8); 1719261868Skevlo } 1720261868Skevlo /* Fix broken Tx power entries. */ 1721261868Skevlo for (i = 0; i < 40; i++ ) { 1722261868Skevlo if (sc->mac_ver != 0x5592) { 1723261868Skevlo if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15) 1724261868Skevlo sc->txpow1[14 + i] = 5; 1725261868Skevlo if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15) 1726261868Skevlo sc->txpow2[14 + i] = 5; 1727261868Skevlo } 1728261868Skevlo DPRINTF("chan %d: power1=%d, power2=%d\n", 1729261868Skevlo rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i], 1730261868Skevlo sc->txpow2[14 + i]); 1731261868Skevlo } 1732261868Skevlo} 1733261868Skevlo 1734259453Shselaskystatic int 1735203134Sthompsarun_read_eeprom(struct run_softc *sc) 1736203134Sthompsa{ 1737203134Sthompsa int8_t delta_2ghz, delta_5ghz; 1738203134Sthompsa uint32_t tmp; 1739203134Sthompsa uint16_t val; 1740203134Sthompsa int ridx, ant, i; 1741203134Sthompsa 1742203134Sthompsa /* check whether the ROM is eFUSE ROM or EEPROM */ 1743203134Sthompsa sc->sc_srom_read = run_eeprom_read_2; 1744205042Sthompsa if (sc->mac_ver >= 0x3070) { 1745203134Sthompsa run_read(sc, RT3070_EFUSE_CTRL, &tmp); 1746203134Sthompsa DPRINTF("EFUSE_CTRL=0x%08x\n", tmp); 1747261868Skevlo if ((tmp & RT3070_SEL_EFUSE) || sc->mac_ver == 0x3593) 1748203134Sthompsa sc->sc_srom_read = run_efuse_read_2; 1749203134Sthompsa } 1750203134Sthompsa 1751203134Sthompsa /* read ROM version */ 1752203134Sthompsa run_srom_read(sc, RT2860_EEPROM_VERSION, &val); 1753203134Sthompsa DPRINTF("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8); 1754203134Sthompsa 1755203134Sthompsa /* read MAC address */ 1756203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC01, &val); 1757203134Sthompsa sc->sc_bssid[0] = val & 0xff; 1758203134Sthompsa sc->sc_bssid[1] = val >> 8; 1759203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC23, &val); 1760203134Sthompsa sc->sc_bssid[2] = val & 0xff; 1761203134Sthompsa sc->sc_bssid[3] = val >> 8; 1762203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC45, &val); 1763203134Sthompsa sc->sc_bssid[4] = val & 0xff; 1764203134Sthompsa sc->sc_bssid[5] = val >> 8; 1765203134Sthompsa 1766261868Skevlo if (sc->mac_ver < 0x3593) { 1767259453Shselasky /* read vender BBP settings */ 1768205042Sthompsa for (i = 0; i < 10; i++) { 1769259453Shselasky run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val); 1770259453Shselasky sc->bbp[i].val = val & 0xff; 1771259453Shselasky sc->bbp[i].reg = val >> 8; 1772259453Shselasky DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg, 1773259453Shselasky sc->bbp[i].val); 1774205042Sthompsa } 1775259453Shselasky if (sc->mac_ver >= 0x3071) { 1776259453Shselasky /* read vendor RF settings */ 1777259453Shselasky for (i = 0; i < 10; i++) { 1778259453Shselasky run_srom_read(sc, RT3071_EEPROM_RF_BASE + i, 1779259453Shselasky &val); 1780259453Shselasky sc->rf[i].val = val & 0xff; 1781259453Shselasky sc->rf[i].reg = val >> 8; 1782259453Shselasky DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg, 1783259453Shselasky sc->rf[i].val); 1784259453Shselasky } 1785259453Shselasky } 1786205042Sthompsa } 1787203134Sthompsa 1788203134Sthompsa /* read RF frequency offset from EEPROM */ 1789261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS : 1790261868Skevlo RT3593_EEPROM_FREQ, &val); 1791203134Sthompsa sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0; 1792203134Sthompsa DPRINTF("EEPROM freq offset %d\n", sc->freq & 0xff); 1793203134Sthompsa 1794261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS : 1795261868Skevlo RT3593_EEPROM_FREQ_LEDS, &val); 1796205042Sthompsa if (val >> 8 != 0xff) { 1797203134Sthompsa /* read LEDs operating mode */ 1798205042Sthompsa sc->leds = val >> 8; 1799261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED1 : 1800261868Skevlo RT3593_EEPROM_LED1, &sc->led[0]); 1801261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED2 : 1802261868Skevlo RT3593_EEPROM_LED2, &sc->led[1]); 1803261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED3 : 1804261868Skevlo RT3593_EEPROM_LED3, &sc->led[2]); 1805203134Sthompsa } else { 1806203134Sthompsa /* broken EEPROM, use default settings */ 1807203134Sthompsa sc->leds = 0x01; 1808203134Sthompsa sc->led[0] = 0x5555; 1809203134Sthompsa sc->led[1] = 0x2221; 1810203134Sthompsa sc->led[2] = 0x5627; /* differs from RT2860 */ 1811203134Sthompsa } 1812203134Sthompsa DPRINTF("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n", 1813203134Sthompsa sc->leds, sc->led[0], sc->led[1], sc->led[2]); 1814203134Sthompsa 1815203134Sthompsa /* read RF information */ 1816259453Shselasky if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) 1817259453Shselasky run_srom_read(sc, 0x00, &val); 1818259453Shselasky else 1819259453Shselasky run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val); 1820259453Shselasky 1821203134Sthompsa if (val == 0xffff) { 1822261868Skevlo device_printf(sc->sc_dev, 1823261868Skevlo "invalid EEPROM antenna info, using default\n"); 1824203134Sthompsa DPRINTF("invalid EEPROM antenna info, using default\n"); 1825205042Sthompsa if (sc->mac_ver == 0x3572) { 1826205042Sthompsa /* default to RF3052 2T2R */ 1827205042Sthompsa sc->rf_rev = RT3070_RF_3052; 1828205042Sthompsa sc->ntxchains = 2; 1829205042Sthompsa sc->nrxchains = 2; 1830205042Sthompsa } else if (sc->mac_ver >= 0x3070) { 1831203134Sthompsa /* default to RF3020 1T1R */ 1832203134Sthompsa sc->rf_rev = RT3070_RF_3020; 1833203134Sthompsa sc->ntxchains = 1; 1834203134Sthompsa sc->nrxchains = 1; 1835203134Sthompsa } else { 1836203134Sthompsa /* default to RF2820 1T2R */ 1837203134Sthompsa sc->rf_rev = RT2860_RF_2820; 1838203134Sthompsa sc->ntxchains = 1; 1839203134Sthompsa sc->nrxchains = 2; 1840203134Sthompsa } 1841203134Sthompsa } else { 1842259453Shselasky if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) { 1843259453Shselasky sc->rf_rev = val; 1844259453Shselasky run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val); 1845259453Shselasky } else 1846259453Shselasky sc->rf_rev = (val >> 8) & 0xf; 1847203134Sthompsa sc->ntxchains = (val >> 4) & 0xf; 1848203134Sthompsa sc->nrxchains = val & 0xf; 1849203134Sthompsa } 1850259453Shselasky DPRINTF("EEPROM RF rev=0x%04x chains=%dT%dR\n", 1851203134Sthompsa sc->rf_rev, sc->ntxchains, sc->nrxchains); 1852203134Sthompsa 1853208019Sthompsa /* check if RF supports automatic Tx access gain control */ 1854203134Sthompsa run_srom_read(sc, RT2860_EEPROM_CONFIG, &val); 1855203134Sthompsa DPRINTF("EEPROM CFG 0x%04x\n", val); 1856205042Sthompsa /* check if driver should patch the DAC issue */ 1857205042Sthompsa if ((val >> 8) != 0xff) 1858205042Sthompsa sc->patch_dac = (val >> 15) & 1; 1859203134Sthompsa if ((val & 0xff) != 0xff) { 1860203134Sthompsa sc->ext_5ghz_lna = (val >> 3) & 1; 1861203134Sthompsa sc->ext_2ghz_lna = (val >> 2) & 1; 1862205042Sthompsa /* check if RF supports automatic Tx access gain control */ 1863203134Sthompsa sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1; 1864205042Sthompsa /* check if we have a hardware radio switch */ 1865205042Sthompsa sc->rfswitch = val & 1; 1866203134Sthompsa } 1867203134Sthompsa 1868261868Skevlo /* Read Tx power settings. */ 1869261868Skevlo if (sc->mac_ver == 0x3593) 1870261868Skevlo run_rt3593_get_txpower(sc); 1871261868Skevlo else 1872261868Skevlo run_get_txpower(sc); 1873203134Sthompsa 1874203134Sthompsa /* read Tx power compensation for each Tx rate */ 1875203134Sthompsa run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val); 1876203134Sthompsa delta_2ghz = delta_5ghz = 0; 1877203134Sthompsa if ((val & 0xff) != 0xff && (val & 0x80)) { 1878203134Sthompsa delta_2ghz = val & 0xf; 1879203134Sthompsa if (!(val & 0x40)) /* negative number */ 1880203134Sthompsa delta_2ghz = -delta_2ghz; 1881203134Sthompsa } 1882203134Sthompsa val >>= 8; 1883203134Sthompsa if ((val & 0xff) != 0xff && (val & 0x80)) { 1884203134Sthompsa delta_5ghz = val & 0xf; 1885203134Sthompsa if (!(val & 0x40)) /* negative number */ 1886203134Sthompsa delta_5ghz = -delta_5ghz; 1887203134Sthompsa } 1888203134Sthompsa DPRINTF("power compensation=%d (2GHz), %d (5GHz)\n", 1889203134Sthompsa delta_2ghz, delta_5ghz); 1890203134Sthompsa 1891203134Sthompsa for (ridx = 0; ridx < 5; ridx++) { 1892203134Sthompsa uint32_t reg; 1893203134Sthompsa 1894208019Sthompsa run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val); 1895208019Sthompsa reg = val; 1896208019Sthompsa run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val); 1897208019Sthompsa reg |= (uint32_t)val << 16; 1898203134Sthompsa 1899203134Sthompsa sc->txpow20mhz[ridx] = reg; 1900203134Sthompsa sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz); 1901203134Sthompsa sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz); 1902203134Sthompsa 1903203134Sthompsa DPRINTF("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, " 1904203134Sthompsa "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx], 1905203134Sthompsa sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]); 1906203134Sthompsa } 1907203134Sthompsa 1908261868Skevlo /* Read RSSI offsets and LNA gains from EEPROM. */ 1909261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_2GHZ : 1910261868Skevlo RT3593_EEPROM_RSSI1_2GHZ, &val); 1911203134Sthompsa sc->rssi_2ghz[0] = val & 0xff; /* Ant A */ 1912203134Sthompsa sc->rssi_2ghz[1] = val >> 8; /* Ant B */ 1913261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_2GHZ : 1914261868Skevlo RT3593_EEPROM_RSSI2_2GHZ, &val); 1915205042Sthompsa if (sc->mac_ver >= 0x3070) { 1916261868Skevlo if (sc->mac_ver == 0x3593) { 1917261868Skevlo sc->txmixgain_2ghz = 0; 1918261868Skevlo sc->rssi_2ghz[2] = val & 0xff; /* Ant C */ 1919261868Skevlo } else { 1920261868Skevlo /* 1921261868Skevlo * On RT3070 chips (limited to 2 Rx chains), this ROM 1922261868Skevlo * field contains the Tx mixer gain for the 2GHz band. 1923261868Skevlo */ 1924261868Skevlo if ((val & 0xff) != 0xff) 1925261868Skevlo sc->txmixgain_2ghz = val & 0x7; 1926261868Skevlo } 1927205042Sthompsa DPRINTF("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz); 1928205042Sthompsa } else 1929205042Sthompsa sc->rssi_2ghz[2] = val & 0xff; /* Ant C */ 1930261868Skevlo if (sc->mac_ver == 0x3593) 1931261868Skevlo run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val); 1932203134Sthompsa sc->lna[2] = val >> 8; /* channel group 2 */ 1933203134Sthompsa 1934261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_5GHZ : 1935261868Skevlo RT3593_EEPROM_RSSI1_5GHZ, &val); 1936203134Sthompsa sc->rssi_5ghz[0] = val & 0xff; /* Ant A */ 1937203134Sthompsa sc->rssi_5ghz[1] = val >> 8; /* Ant B */ 1938261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_5GHZ : 1939261868Skevlo RT3593_EEPROM_RSSI2_5GHZ, &val); 1940205042Sthompsa if (sc->mac_ver == 0x3572) { 1941205042Sthompsa /* 1942205042Sthompsa * On RT3572 chips (limited to 2 Rx chains), this ROM 1943205042Sthompsa * field contains the Tx mixer gain for the 5GHz band. 1944205042Sthompsa */ 1945205042Sthompsa if ((val & 0xff) != 0xff) 1946205042Sthompsa sc->txmixgain_5ghz = val & 0x7; 1947205042Sthompsa DPRINTF("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz); 1948205042Sthompsa } else 1949205042Sthompsa sc->rssi_5ghz[2] = val & 0xff; /* Ant C */ 1950261868Skevlo if (sc->mac_ver == 0x3593) { 1951261868Skevlo sc->txmixgain_5ghz = 0; 1952261868Skevlo run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val); 1953261868Skevlo } 1954203134Sthompsa sc->lna[3] = val >> 8; /* channel group 3 */ 1955203134Sthompsa 1956261868Skevlo run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LNA : 1957261868Skevlo RT3593_EEPROM_LNA, &val); 1958203134Sthompsa sc->lna[0] = val & 0xff; /* channel group 0 */ 1959203134Sthompsa sc->lna[1] = val >> 8; /* channel group 1 */ 1960203134Sthompsa 1961203134Sthompsa /* fix broken 5GHz LNA entries */ 1962203134Sthompsa if (sc->lna[2] == 0 || sc->lna[2] == 0xff) { 1963203134Sthompsa DPRINTF("invalid LNA for channel group %d\n", 2); 1964203134Sthompsa sc->lna[2] = sc->lna[1]; 1965203134Sthompsa } 1966203134Sthompsa if (sc->lna[3] == 0 || sc->lna[3] == 0xff) { 1967203134Sthompsa DPRINTF("invalid LNA for channel group %d\n", 3); 1968203134Sthompsa sc->lna[3] = sc->lna[1]; 1969203134Sthompsa } 1970203134Sthompsa 1971203134Sthompsa /* fix broken RSSI offset entries */ 1972203134Sthompsa for (ant = 0; ant < 3; ant++) { 1973203134Sthompsa if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) { 1974203134Sthompsa DPRINTF("invalid RSSI%d offset: %d (2GHz)\n", 1975203134Sthompsa ant + 1, sc->rssi_2ghz[ant]); 1976203134Sthompsa sc->rssi_2ghz[ant] = 0; 1977203134Sthompsa } 1978203134Sthompsa if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) { 1979203134Sthompsa DPRINTF("invalid RSSI%d offset: %d (5GHz)\n", 1980203134Sthompsa ant + 1, sc->rssi_5ghz[ant]); 1981203134Sthompsa sc->rssi_5ghz[ant] = 0; 1982203134Sthompsa } 1983203134Sthompsa } 1984209917Sthompsa return (0); 1985203134Sthompsa} 1986203134Sthompsa 1987218676Shselaskystatic struct ieee80211_node * 1988203134Sthompsarun_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) 1989203134Sthompsa{ 1990343821Savos return malloc(sizeof (struct run_node), M_80211_NODE, 1991343821Savos M_NOWAIT | M_ZERO); 1992203134Sthompsa} 1993203134Sthompsa 1994203134Sthompsastatic int 1995203134Sthompsarun_media_change(struct ifnet *ifp) 1996203134Sthompsa{ 1997208019Sthompsa struct ieee80211vap *vap = ifp->if_softc; 1998208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 1999203134Sthompsa const struct ieee80211_txparam *tp; 2000208019Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2001203134Sthompsa uint8_t rate, ridx; 2002203134Sthompsa int error; 2003203134Sthompsa 2004203134Sthompsa RUN_LOCK(sc); 2005203134Sthompsa 2006203134Sthompsa error = ieee80211_media_change(ifp); 2007209917Sthompsa if (error != ENETRESET) { 2008203134Sthompsa RUN_UNLOCK(sc); 2009209917Sthompsa return (error); 2010208019Sthompsa } 2011203134Sthompsa 2012203134Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 2013203134Sthompsa if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 2014212127Sthompsa struct ieee80211_node *ni; 2015212127Sthompsa struct run_node *rn; 2016212127Sthompsa 2017203134Sthompsa rate = ic->ic_sup_rates[ic->ic_curmode]. 2018203134Sthompsa rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL; 2019203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2020203134Sthompsa if (rt2860_rates[ridx].rate == rate) 2021203134Sthompsa break; 2022212127Sthompsa ni = ieee80211_ref_node(vap->iv_bss); 2023212127Sthompsa rn = (struct run_node *)ni; 2024208019Sthompsa rn->fix_ridx = ridx; 2025208019Sthompsa DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx); 2026212127Sthompsa ieee80211_free_node(ni); 2027203134Sthompsa } 2028203134Sthompsa 2029208019Sthompsa#if 0 2030203134Sthompsa if ((ifp->if_flags & IFF_UP) && 2031203134Sthompsa (ifp->if_drv_flags & IFF_DRV_RUNNING)){ 2032203134Sthompsa run_init_locked(sc); 2033203134Sthompsa } 2034208019Sthompsa#endif 2035203134Sthompsa 2036203134Sthompsa RUN_UNLOCK(sc); 2037203134Sthompsa 2038209917Sthompsa return (0); 2039203134Sthompsa} 2040203134Sthompsa 2041203134Sthompsastatic int 2042203134Sthompsarun_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 2043203134Sthompsa{ 2044203134Sthompsa const struct ieee80211_txparam *tp; 2045203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2046203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2047203134Sthompsa struct run_vap *rvp = RUN_VAP(vap); 2048203134Sthompsa enum ieee80211_state ostate; 2049208019Sthompsa uint32_t sta[3]; 2050203134Sthompsa uint32_t tmp; 2051208019Sthompsa uint8_t ratectl; 2052208019Sthompsa uint8_t restart_ratectl = 0; 2053208019Sthompsa uint8_t bid = 1 << rvp->rvp_id; 2054203134Sthompsa 2055203134Sthompsa ostate = vap->iv_state; 2056203134Sthompsa DPRINTF("%s -> %s\n", 2057203134Sthompsa ieee80211_state_name[ostate], 2058203134Sthompsa ieee80211_state_name[nstate]); 2059203134Sthompsa 2060203134Sthompsa IEEE80211_UNLOCK(ic); 2061203134Sthompsa RUN_LOCK(sc); 2062203134Sthompsa 2063208019Sthompsa ratectl = sc->ratectl_run; /* remember current state */ 2064208019Sthompsa sc->ratectl_run = RUN_RATECTL_OFF; 2065208019Sthompsa usb_callout_stop(&sc->ratectl_ch); 2066203134Sthompsa 2067203134Sthompsa if (ostate == IEEE80211_S_RUN) { 2068203134Sthompsa /* turn link LED off */ 2069203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO); 2070203134Sthompsa } 2071203134Sthompsa 2072203134Sthompsa switch (nstate) { 2073203134Sthompsa case IEEE80211_S_INIT: 2074208019Sthompsa restart_ratectl = 1; 2075208019Sthompsa 2076208019Sthompsa if (ostate != IEEE80211_S_RUN) 2077208019Sthompsa break; 2078208019Sthompsa 2079208019Sthompsa ratectl &= ~bid; 2080208019Sthompsa sc->runbmap &= ~bid; 2081208019Sthompsa 2082208019Sthompsa /* abort TSF synchronization if there is no vap running */ 2083209917Sthompsa if (--sc->running == 0) { 2084203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 2085203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, 2086203134Sthompsa tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 2087203134Sthompsa RT2860_TBTT_TIMER_EN)); 2088203134Sthompsa } 2089203134Sthompsa break; 2090203134Sthompsa 2091203134Sthompsa case IEEE80211_S_RUN: 2092209917Sthompsa if (!(sc->runbmap & bid)) { 2093208019Sthompsa if(sc->running++) 2094208019Sthompsa restart_ratectl = 1; 2095208019Sthompsa sc->runbmap |= bid; 2096208019Sthompsa } 2097203134Sthompsa 2098218492Sbschmidt m_freem(rvp->beacon_mbuf); 2099218492Sbschmidt rvp->beacon_mbuf = NULL; 2100218492Sbschmidt 2101209917Sthompsa switch (vap->iv_opmode) { 2102208019Sthompsa case IEEE80211_M_HOSTAP: 2103208019Sthompsa case IEEE80211_M_MBSS: 2104208019Sthompsa sc->ap_running |= bid; 2105208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2106208019Sthompsa run_update_beacon_cb(vap); 2107208019Sthompsa break; 2108208019Sthompsa case IEEE80211_M_IBSS: 2109208019Sthompsa sc->adhoc_running |= bid; 2110209917Sthompsa if (!sc->ap_running) 2111208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2112208019Sthompsa run_update_beacon_cb(vap); 2113208019Sthompsa break; 2114208019Sthompsa case IEEE80211_M_STA: 2115208019Sthompsa sc->sta_running |= bid; 2116209917Sthompsa if (!sc->ap_running && !sc->adhoc_running) 2117208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2118208019Sthompsa 2119208019Sthompsa /* read statistic counters (clear on read) */ 2120208019Sthompsa run_read_region_1(sc, RT2860_TX_STA_CNT0, 2121208019Sthompsa (uint8_t *)sta, sizeof sta); 2122208019Sthompsa 2123208019Sthompsa break; 2124208019Sthompsa default: 2125208019Sthompsa ic->ic_opmode = vap->iv_opmode; 2126208019Sthompsa break; 2127208019Sthompsa } 2128208019Sthompsa 2129203134Sthompsa if (vap->iv_opmode != IEEE80211_M_MONITOR) { 2130212127Sthompsa struct ieee80211_node *ni; 2131212127Sthompsa 2132236439Shselasky if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) { 2133236439Shselasky RUN_UNLOCK(sc); 2134236439Shselasky IEEE80211_LOCK(ic); 2135236439Shselasky return (-1); 2136236439Shselasky } 2137203134Sthompsa run_updateslot(ic->ic_ifp); 2138203134Sthompsa run_enable_mrr(sc); 2139203134Sthompsa run_set_txpreamble(sc); 2140203134Sthompsa run_set_basicrates(sc); 2141212127Sthompsa ni = ieee80211_ref_node(vap->iv_bss); 2142203134Sthompsa IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); 2143203134Sthompsa run_set_bssid(sc, ni->ni_bssid); 2144212127Sthompsa ieee80211_free_node(ni); 2145208019Sthompsa run_enable_tsf_sync(sc); 2146203134Sthompsa 2147208019Sthompsa /* enable automatic rate adaptation */ 2148208019Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 2149208019Sthompsa if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) 2150208019Sthompsa ratectl |= bid; 2151203134Sthompsa } 2152203134Sthompsa 2153203134Sthompsa /* turn link LED on */ 2154203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO | 2155208019Sthompsa (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 2156203134Sthompsa RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ)); 2157203134Sthompsa 2158203134Sthompsa break; 2159203134Sthompsa default: 2160203134Sthompsa DPRINTFN(6, "undefined case\n"); 2161203134Sthompsa break; 2162203134Sthompsa } 2163203134Sthompsa 2164208019Sthompsa /* restart amrr for running VAPs */ 2165209917Sthompsa if ((sc->ratectl_run = ratectl) && restart_ratectl) 2166208019Sthompsa usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2167208019Sthompsa 2168203134Sthompsa RUN_UNLOCK(sc); 2169203134Sthompsa IEEE80211_LOCK(ic); 2170203134Sthompsa 2171203134Sthompsa return(rvp->newstate(vap, nstate, arg)); 2172203134Sthompsa} 2173203134Sthompsa 2174203134Sthompsa/* ARGSUSED */ 2175203134Sthompsastatic void 2176208019Sthompsarun_wme_update_cb(void *arg) 2177203134Sthompsa{ 2178203134Sthompsa struct ieee80211com *ic = arg; 2179203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2180203134Sthompsa struct ieee80211_wme_state *wmesp = &ic->ic_wme; 2181203134Sthompsa int aci, error = 0; 2182203134Sthompsa 2183208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2184203134Sthompsa 2185203134Sthompsa /* update MAC TX configuration registers */ 2186203134Sthompsa for (aci = 0; aci < WME_NUM_AC; aci++) { 2187203134Sthompsa error = run_write(sc, RT2860_EDCA_AC_CFG(aci), 2188203134Sthompsa wmesp->wme_params[aci].wmep_logcwmax << 16 | 2189203134Sthompsa wmesp->wme_params[aci].wmep_logcwmin << 12 | 2190203134Sthompsa wmesp->wme_params[aci].wmep_aifsn << 8 | 2191203134Sthompsa wmesp->wme_params[aci].wmep_txopLimit); 2192209917Sthompsa if (error) goto err; 2193203134Sthompsa } 2194203134Sthompsa 2195203134Sthompsa /* update SCH/DMA registers too */ 2196203134Sthompsa error = run_write(sc, RT2860_WMM_AIFSN_CFG, 2197203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_aifsn << 12 | 2198203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_aifsn << 8 | 2199203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_aifsn << 4 | 2200203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_aifsn); 2201209917Sthompsa if (error) goto err; 2202203134Sthompsa error = run_write(sc, RT2860_WMM_CWMIN_CFG, 2203203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_logcwmin << 12 | 2204203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_logcwmin << 8 | 2205203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_logcwmin << 4 | 2206203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_logcwmin); 2207209917Sthompsa if (error) goto err; 2208203134Sthompsa error = run_write(sc, RT2860_WMM_CWMAX_CFG, 2209203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_logcwmax << 12 | 2210203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_logcwmax << 8 | 2211203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_logcwmax << 4 | 2212203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_logcwmax); 2213209917Sthompsa if (error) goto err; 2214203134Sthompsa error = run_write(sc, RT2860_WMM_TXOP0_CFG, 2215203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_txopLimit << 16 | 2216203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_txopLimit); 2217209917Sthompsa if (error) goto err; 2218203134Sthompsa error = run_write(sc, RT2860_WMM_TXOP1_CFG, 2219203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_txopLimit << 16 | 2220203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_txopLimit); 2221203134Sthompsa 2222203134Sthompsaerr: 2223209917Sthompsa if (error) 2224203134Sthompsa DPRINTF("WME update failed\n"); 2225203134Sthompsa 2226203134Sthompsa return; 2227203134Sthompsa} 2228203134Sthompsa 2229208019Sthompsastatic int 2230208019Sthompsarun_wme_update(struct ieee80211com *ic) 2231208019Sthompsa{ 2232208019Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2233208019Sthompsa 2234208019Sthompsa /* sometime called wothout lock */ 2235209917Sthompsa if (mtx_owned(&ic->ic_comlock.mtx)) { 2236208019Sthompsa uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 2237208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 2238208019Sthompsa sc->cmdq[i].func = run_wme_update_cb; 2239208019Sthompsa sc->cmdq[i].arg0 = ic; 2240208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2241209918Sthompsa return (0); 2242208019Sthompsa } 2243208019Sthompsa 2244208019Sthompsa RUN_LOCK(sc); 2245208019Sthompsa run_wme_update_cb(ic); 2246208019Sthompsa RUN_UNLOCK(sc); 2247208019Sthompsa 2248208019Sthompsa /* return whatever, upper layer desn't care anyway */ 2249208019Sthompsa return (0); 2250208019Sthompsa} 2251208019Sthompsa 2252203134Sthompsastatic void 2253203134Sthompsarun_key_update_begin(struct ieee80211vap *vap) 2254203134Sthompsa{ 2255203134Sthompsa /* 2256208019Sthompsa * To avoid out-of-order events, both run_key_set() and 2257208019Sthompsa * _delete() are deferred and handled by run_cmdq_cb(). 2258208019Sthompsa * So, there is nothing we need to do here. 2259203134Sthompsa */ 2260203134Sthompsa} 2261203134Sthompsa 2262203134Sthompsastatic void 2263203134Sthompsarun_key_update_end(struct ieee80211vap *vap) 2264203134Sthompsa{ 2265203134Sthompsa /* null */ 2266203134Sthompsa} 2267203134Sthompsa 2268208019Sthompsastatic void 2269208019Sthompsarun_key_set_cb(void *arg) 2270203134Sthompsa{ 2271208019Sthompsa struct run_cmdq *cmdq = arg; 2272208019Sthompsa struct ieee80211vap *vap = cmdq->arg1; 2273208019Sthompsa struct ieee80211_key *k = cmdq->k; 2274203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2275208019Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2276203134Sthompsa struct ieee80211_node *ni; 2277203134Sthompsa uint32_t attr; 2278203134Sthompsa uint16_t base, associd; 2279209144Sthompsa uint8_t mode, wcid, iv[8]; 2280203134Sthompsa 2281208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2282203134Sthompsa 2283209917Sthompsa if (vap->iv_opmode == IEEE80211_M_HOSTAP) 2284208019Sthompsa ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac); 2285209144Sthompsa else 2286203134Sthompsa ni = vap->iv_bss; 2287208019Sthompsa associd = (ni != NULL) ? ni->ni_associd : 0; 2288203134Sthompsa 2289203134Sthompsa /* map net80211 cipher to RT2860 security mode */ 2290203134Sthompsa switch (k->wk_cipher->ic_cipher) { 2291203134Sthompsa case IEEE80211_CIPHER_WEP: 2292203134Sthompsa if(k->wk_keylen < 8) 2293203134Sthompsa mode = RT2860_MODE_WEP40; 2294203134Sthompsa else 2295203134Sthompsa mode = RT2860_MODE_WEP104; 2296203134Sthompsa break; 2297203134Sthompsa case IEEE80211_CIPHER_TKIP: 2298203134Sthompsa mode = RT2860_MODE_TKIP; 2299203134Sthompsa break; 2300203134Sthompsa case IEEE80211_CIPHER_AES_CCM: 2301203134Sthompsa mode = RT2860_MODE_AES_CCMP; 2302203134Sthompsa break; 2303203134Sthompsa default: 2304203134Sthompsa DPRINTF("undefined case\n"); 2305208019Sthompsa return; 2306203134Sthompsa } 2307203134Sthompsa 2308208019Sthompsa DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n", 2309203134Sthompsa associd, k->wk_keyix, mode, 2310208019Sthompsa (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise", 2311208019Sthompsa (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off", 2312208019Sthompsa (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off"); 2313203134Sthompsa 2314203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 2315203134Sthompsa wcid = 0; /* NB: update WCID0 for group keys */ 2316208019Sthompsa base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix); 2317203134Sthompsa } else { 2318245047Shselasky wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 2319245047Shselasky 1 : RUN_AID2WCID(associd); 2320203134Sthompsa base = RT2860_PKEY(wcid); 2321203134Sthompsa } 2322203134Sthompsa 2323203134Sthompsa if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) { 2324203134Sthompsa if(run_write_region_1(sc, base, k->wk_key, 16)) 2325208019Sthompsa return; 2326209144Sthompsa if(run_write_region_1(sc, base + 16, &k->wk_key[16], 8)) /* wk_txmic */ 2327208019Sthompsa return; 2328209144Sthompsa if(run_write_region_1(sc, base + 24, &k->wk_key[24], 8)) /* wk_rxmic */ 2329208019Sthompsa return; 2330203134Sthompsa } else { 2331203134Sthompsa /* roundup len to 16-bit: XXX fix write_region_1() instead */ 2332203134Sthompsa if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1)) 2333208019Sthompsa return; 2334203134Sthompsa } 2335203134Sthompsa 2336203134Sthompsa if (!(k->wk_flags & IEEE80211_KEY_GROUP) || 2337203134Sthompsa (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) { 2338203134Sthompsa /* set initial packet number in IV+EIV */ 2339209917Sthompsa if (k->wk_cipher == IEEE80211_CIPHER_WEP) { 2340203134Sthompsa memset(iv, 0, sizeof iv); 2341208019Sthompsa iv[3] = vap->iv_def_txkey << 6; 2342203134Sthompsa } else { 2343203134Sthompsa if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) { 2344203134Sthompsa iv[0] = k->wk_keytsc >> 8; 2345203134Sthompsa iv[1] = (iv[0] | 0x20) & 0x7f; 2346203134Sthompsa iv[2] = k->wk_keytsc; 2347203134Sthompsa } else /* CCMP */ { 2348203134Sthompsa iv[0] = k->wk_keytsc; 2349203134Sthompsa iv[1] = k->wk_keytsc >> 8; 2350203134Sthompsa iv[2] = 0; 2351203134Sthompsa } 2352203134Sthompsa iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV; 2353203134Sthompsa iv[4] = k->wk_keytsc >> 16; 2354203134Sthompsa iv[5] = k->wk_keytsc >> 24; 2355203134Sthompsa iv[6] = k->wk_keytsc >> 32; 2356203134Sthompsa iv[7] = k->wk_keytsc >> 40; 2357203134Sthompsa } 2358209917Sthompsa if (run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8)) 2359208019Sthompsa return; 2360203134Sthompsa } 2361203134Sthompsa 2362203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 2363203134Sthompsa /* install group key */ 2364209917Sthompsa if (run_read(sc, RT2860_SKEY_MODE_0_7, &attr)) 2365208019Sthompsa return; 2366203134Sthompsa attr &= ~(0xf << (k->wk_keyix * 4)); 2367203134Sthompsa attr |= mode << (k->wk_keyix * 4); 2368209917Sthompsa if (run_write(sc, RT2860_SKEY_MODE_0_7, attr)) 2369208019Sthompsa return; 2370203134Sthompsa } else { 2371203134Sthompsa /* install pairwise key */ 2372209917Sthompsa if (run_read(sc, RT2860_WCID_ATTR(wcid), &attr)) 2373208019Sthompsa return; 2374203134Sthompsa attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN; 2375209917Sthompsa if (run_write(sc, RT2860_WCID_ATTR(wcid), attr)) 2376208019Sthompsa return; 2377203134Sthompsa } 2378203134Sthompsa 2379203134Sthompsa /* TODO create a pass-thru key entry? */ 2380203134Sthompsa 2381208019Sthompsa /* need wcid to delete the right key later */ 2382208019Sthompsa k->wk_pad = wcid; 2383203134Sthompsa} 2384203134Sthompsa 2385203134Sthompsa/* 2386208019Sthompsa * Don't have to be deferred, but in order to keep order of 2387208019Sthompsa * execution, i.e. with run_key_delete(), defer this and let 2388208019Sthompsa * run_cmdq_cb() maintain the order. 2389208019Sthompsa * 2390203134Sthompsa * return 0 on error 2391203134Sthompsa */ 2392203134Sthompsastatic int 2393208019Sthompsarun_key_set(struct ieee80211vap *vap, struct ieee80211_key *k, 2394208019Sthompsa const uint8_t mac[IEEE80211_ADDR_LEN]) 2395203134Sthompsa{ 2396203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2397203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2398208019Sthompsa uint32_t i; 2399208019Sthompsa 2400208019Sthompsa i = RUN_CMDQ_GET(&sc->cmdq_store); 2401208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 2402208019Sthompsa sc->cmdq[i].func = run_key_set_cb; 2403208019Sthompsa sc->cmdq[i].arg0 = NULL; 2404208019Sthompsa sc->cmdq[i].arg1 = vap; 2405208019Sthompsa sc->cmdq[i].k = k; 2406208019Sthompsa IEEE80211_ADDR_COPY(sc->cmdq[i].mac, mac); 2407208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2408208019Sthompsa 2409209144Sthompsa /* 2410209144Sthompsa * To make sure key will be set when hostapd 2411209144Sthompsa * calls iv_key_set() before if_init(). 2412209144Sthompsa */ 2413209917Sthompsa if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 2414209144Sthompsa RUN_LOCK(sc); 2415209144Sthompsa sc->cmdq_key_set = RUN_CMDQ_GO; 2416209144Sthompsa RUN_UNLOCK(sc); 2417209144Sthompsa } 2418209144Sthompsa 2419209917Sthompsa return (1); 2420208019Sthompsa} 2421208019Sthompsa 2422208019Sthompsa/* 2423208019Sthompsa * If wlan is destroyed without being brought down i.e. without 2424208019Sthompsa * wlan down or wpa_cli terminate, this function is called after 2425208019Sthompsa * vap is gone. Don't refer it. 2426208019Sthompsa */ 2427208019Sthompsastatic void 2428208019Sthompsarun_key_delete_cb(void *arg) 2429208019Sthompsa{ 2430208019Sthompsa struct run_cmdq *cmdq = arg; 2431208019Sthompsa struct run_softc *sc = cmdq->arg1; 2432208019Sthompsa struct ieee80211_key *k = &cmdq->key; 2433203134Sthompsa uint32_t attr; 2434203134Sthompsa uint8_t wcid; 2435203134Sthompsa 2436208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2437203134Sthompsa 2438203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 2439203134Sthompsa /* remove group key */ 2440208019Sthompsa DPRINTF("removing group key\n"); 2441208019Sthompsa run_read(sc, RT2860_SKEY_MODE_0_7, &attr); 2442203134Sthompsa attr &= ~(0xf << (k->wk_keyix * 4)); 2443208019Sthompsa run_write(sc, RT2860_SKEY_MODE_0_7, attr); 2444203134Sthompsa } else { 2445203134Sthompsa /* remove pairwise key */ 2446208019Sthompsa DPRINTF("removing key for wcid %x\n", k->wk_pad); 2447208019Sthompsa /* matching wcid was written to wk_pad in run_key_set() */ 2448208019Sthompsa wcid = k->wk_pad; 2449208019Sthompsa run_read(sc, RT2860_WCID_ATTR(wcid), &attr); 2450203134Sthompsa attr &= ~0xf; 2451208019Sthompsa run_write(sc, RT2860_WCID_ATTR(wcid), attr); 2452208019Sthompsa run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8); 2453203134Sthompsa } 2454203134Sthompsa 2455208019Sthompsa k->wk_pad = 0; 2456203134Sthompsa} 2457203134Sthompsa 2458208019Sthompsa/* 2459208019Sthompsa * return 0 on error 2460208019Sthompsa */ 2461208019Sthompsastatic int 2462208019Sthompsarun_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k) 2463203134Sthompsa{ 2464208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 2465208019Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2466208019Sthompsa struct ieee80211_key *k0; 2467208019Sthompsa uint32_t i; 2468203134Sthompsa 2469208019Sthompsa /* 2470208019Sthompsa * When called back, key might be gone. So, make a copy 2471208019Sthompsa * of some values need to delete keys before deferring. 2472208019Sthompsa * But, because of LOR with node lock, cannot use lock here. 2473208019Sthompsa * So, use atomic instead. 2474208019Sthompsa */ 2475208019Sthompsa i = RUN_CMDQ_GET(&sc->cmdq_store); 2476208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 2477208019Sthompsa sc->cmdq[i].func = run_key_delete_cb; 2478208019Sthompsa sc->cmdq[i].arg0 = NULL; 2479208019Sthompsa sc->cmdq[i].arg1 = sc; 2480208019Sthompsa k0 = &sc->cmdq[i].key; 2481208019Sthompsa k0->wk_flags = k->wk_flags; 2482208019Sthompsa k0->wk_keyix = k->wk_keyix; 2483208019Sthompsa /* matching wcid was written to wk_pad in run_key_set() */ 2484208019Sthompsa k0->wk_pad = k->wk_pad; 2485208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2486208019Sthompsa return (1); /* return fake success */ 2487203134Sthompsa 2488203134Sthompsa} 2489203134Sthompsa 2490203134Sthompsastatic void 2491206358Srpaulorun_ratectl_to(void *arg) 2492203134Sthompsa{ 2493208019Sthompsa struct run_softc *sc = arg; 2494203134Sthompsa 2495203134Sthompsa /* do it in a process context, so it can go sleep */ 2496208019Sthompsa ieee80211_runtask(sc->sc_ifp->if_l2com, &sc->ratectl_task); 2497203134Sthompsa /* next timeout will be rescheduled in the callback task */ 2498203134Sthompsa} 2499203134Sthompsa 2500203134Sthompsa/* ARGSUSED */ 2501203134Sthompsastatic void 2502206358Srpaulorun_ratectl_cb(void *arg, int pending) 2503203134Sthompsa{ 2504208019Sthompsa struct run_softc *sc = arg; 2505208019Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 2506208019Sthompsa struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2507203134Sthompsa 2508209917Sthompsa if (vap == NULL) 2509208019Sthompsa return; 2510208019Sthompsa 2511263073Shselasky if (sc->rvp_cnt > 1 || vap->iv_opmode != IEEE80211_M_STA) { 2512203134Sthompsa /* 2513203134Sthompsa * run_reset_livelock() doesn't do anything with AMRR, 2514203134Sthompsa * but Ralink wants us to call it every 1 sec. So, we 2515203134Sthompsa * piggyback here rather than creating another callout. 2516203134Sthompsa * Livelock may occur only in HOSTAP or IBSS mode 2517203134Sthompsa * (when h/w is sending beacons). 2518203134Sthompsa */ 2519203134Sthompsa RUN_LOCK(sc); 2520203134Sthompsa run_reset_livelock(sc); 2521208019Sthompsa /* just in case, there are some stats to drain */ 2522208019Sthompsa run_drain_fifo(sc); 2523203134Sthompsa RUN_UNLOCK(sc); 2524203134Sthompsa } 2525203134Sthompsa 2526263073Shselasky ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc); 2527263073Shselasky 2528259453Shselasky RUN_LOCK(sc); 2529208019Sthompsa if(sc->ratectl_run != RUN_RATECTL_OFF) 2530208019Sthompsa usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2531259453Shselasky RUN_UNLOCK(sc); 2532203134Sthompsa} 2533203134Sthompsa 2534203134Sthompsastatic void 2535208019Sthompsarun_drain_fifo(void *arg) 2536203134Sthompsa{ 2537208019Sthompsa struct run_softc *sc = arg; 2538208019Sthompsa struct ifnet *ifp = sc->sc_ifp; 2539208019Sthompsa uint32_t stat; 2540218676Shselasky uint16_t (*wstat)[3]; 2541203134Sthompsa uint8_t wcid, mcs, pid; 2542218676Shselasky int8_t retry; 2543203134Sthompsa 2544208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2545203134Sthompsa 2546208019Sthompsa for (;;) { 2547203134Sthompsa /* drain Tx status FIFO (maxsize = 16) */ 2548203134Sthompsa run_read(sc, RT2860_TX_STAT_FIFO, &stat); 2549208019Sthompsa DPRINTFN(4, "tx stat 0x%08x\n", stat); 2550209917Sthompsa if (!(stat & RT2860_TXQ_VLD)) 2551208019Sthompsa break; 2552203134Sthompsa 2553208019Sthompsa wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff; 2554203134Sthompsa 2555208019Sthompsa /* if no ACK was requested, no feedback is available */ 2556208019Sthompsa if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX || 2557208019Sthompsa wcid == 0) 2558208019Sthompsa continue; 2559203134Sthompsa 2560218676Shselasky /* 2561218676Shselasky * Even though each stat is Tx-complete-status like format, 2562218676Shselasky * the device can poll stats. Because there is no guarantee 2563218676Shselasky * that the referring node is still around when read the stats. 2564218676Shselasky * So that, if we use ieee80211_ratectl_tx_update(), we will 2565218676Shselasky * have hard time not to refer already freed node. 2566218676Shselasky * 2567218676Shselasky * To eliminate such page faults, we poll stats in softc. 2568218676Shselasky * Then, update the rates later with ieee80211_ratectl_tx_update(). 2569218676Shselasky */ 2570218676Shselasky wstat = &(sc->wcid_stats[wcid]); 2571218676Shselasky (*wstat)[RUN_TXCNT]++; 2572218676Shselasky if (stat & RT2860_TXQ_OK) 2573218676Shselasky (*wstat)[RUN_SUCCESS]++; 2574218676Shselasky else 2575208019Sthompsa ifp->if_oerrors++; 2576218676Shselasky /* 2577218676Shselasky * Check if there were retries, ie if the Tx success rate is 2578218676Shselasky * different from the requested rate. Note that it works only 2579218676Shselasky * because we do not allow rate fallback from OFDM to CCK. 2580218676Shselasky */ 2581218676Shselasky mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f; 2582218676Shselasky pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf; 2583218676Shselasky if ((retry = pid -1 - mcs) > 0) { 2584218676Shselasky (*wstat)[RUN_TXCNT] += retry; 2585218676Shselasky (*wstat)[RUN_RETRY] += retry; 2586203134Sthompsa } 2587208019Sthompsa } 2588208019Sthompsa DPRINTFN(3, "count=%d\n", sc->fifo_cnt); 2589208019Sthompsa 2590208019Sthompsa sc->fifo_cnt = 0; 2591208019Sthompsa} 2592208019Sthompsa 2593208019Sthompsastatic void 2594208019Sthompsarun_iter_func(void *arg, struct ieee80211_node *ni) 2595208019Sthompsa{ 2596208019Sthompsa struct run_softc *sc = arg; 2597208019Sthompsa struct ieee80211vap *vap = ni->ni_vap; 2598208019Sthompsa struct ieee80211com *ic = ni->ni_ic; 2599208019Sthompsa struct ifnet *ifp = ic->ic_ifp; 2600208019Sthompsa struct run_node *rn = (void *)ni; 2601218676Shselasky union run_stats sta[2]; 2602218676Shselasky uint16_t (*wstat)[3]; 2603218676Shselasky int txcnt, success, retrycnt, error; 2604208019Sthompsa 2605218676Shselasky RUN_LOCK(sc); 2606218676Shselasky 2607263073Shselasky /* Check for special case */ 2608263073Shselasky if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA && 2609263073Shselasky ni != vap->iv_bss) 2610263073Shselasky goto fail; 2611263073Shselasky 2612209917Sthompsa if (sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS || 2613209917Sthompsa vap->iv_opmode == IEEE80211_M_STA)) { 2614203134Sthompsa /* read statistic counters (clear on read) and update AMRR state */ 2615203134Sthompsa error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta, 2616203134Sthompsa sizeof sta); 2617203134Sthompsa if (error != 0) 2618218676Shselasky goto fail; 2619203134Sthompsa 2620203134Sthompsa /* count failed TX as errors */ 2621218676Shselasky ifp->if_oerrors += le16toh(sta[0].error.fail); 2622203134Sthompsa 2623218676Shselasky retrycnt = le16toh(sta[1].tx.retry); 2624218676Shselasky success = le16toh(sta[1].tx.success); 2625218676Shselasky txcnt = retrycnt + success + le16toh(sta[0].error.fail); 2626203134Sthompsa 2627218676Shselasky DPRINTFN(3, "retrycnt=%d success=%d failcnt=%d\n", 2628218676Shselasky retrycnt, success, le16toh(sta[0].error.fail)); 2629218676Shselasky } else { 2630218676Shselasky wstat = &(sc->wcid_stats[RUN_AID2WCID(ni->ni_associd)]); 2631203134Sthompsa 2632218676Shselasky if (wstat == &(sc->wcid_stats[0]) || 2633218676Shselasky wstat > &(sc->wcid_stats[RT2870_WCID_MAX])) 2634218676Shselasky goto fail; 2635208019Sthompsa 2636218676Shselasky txcnt = (*wstat)[RUN_TXCNT]; 2637218676Shselasky success = (*wstat)[RUN_SUCCESS]; 2638218676Shselasky retrycnt = (*wstat)[RUN_RETRY]; 2639218676Shselasky DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n", 2640218676Shselasky retrycnt, txcnt, success); 2641208019Sthompsa 2642218676Shselasky memset(wstat, 0, sizeof(*wstat)); 2643203134Sthompsa } 2644203134Sthompsa 2645218676Shselasky ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt); 2646208019Sthompsa rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0); 2647218676Shselasky 2648218676Shselaskyfail: 2649218676Shselasky RUN_UNLOCK(sc); 2650218676Shselasky 2651208019Sthompsa DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx); 2652208019Sthompsa} 2653203134Sthompsa 2654208019Sthompsastatic void 2655208019Sthompsarun_newassoc_cb(void *arg) 2656208019Sthompsa{ 2657208019Sthompsa struct run_cmdq *cmdq = arg; 2658208019Sthompsa struct ieee80211_node *ni = cmdq->arg1; 2659208019Sthompsa struct run_softc *sc = ni->ni_vap->iv_ic->ic_ifp->if_softc; 2660208019Sthompsa uint8_t wcid = cmdq->wcid; 2661203134Sthompsa 2662208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2663208019Sthompsa 2664208019Sthompsa run_write_region_1(sc, RT2860_WCID_ENTRY(wcid), 2665208019Sthompsa ni->ni_macaddr, IEEE80211_ADDR_LEN); 2666218676Shselasky 2667218676Shselasky memset(&(sc->wcid_stats[wcid]), 0, sizeof(sc->wcid_stats[wcid])); 2668203134Sthompsa} 2669203134Sthompsa 2670203134Sthompsastatic void 2671203134Sthompsarun_newassoc(struct ieee80211_node *ni, int isnew) 2672203134Sthompsa{ 2673203134Sthompsa struct run_node *rn = (void *)ni; 2674203134Sthompsa struct ieee80211_rateset *rs = &ni->ni_rates; 2675208019Sthompsa struct ieee80211vap *vap = ni->ni_vap; 2676208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 2677208019Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2678203134Sthompsa uint8_t rate; 2679208019Sthompsa uint8_t ridx; 2680245047Shselasky uint8_t wcid; 2681208019Sthompsa int i, j; 2682203134Sthompsa 2683245047Shselasky wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 2684245047Shselasky 1 : RUN_AID2WCID(ni->ni_associd); 2685245047Shselasky 2686209917Sthompsa if (wcid > RT2870_WCID_MAX) { 2687208019Sthompsa device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid); 2688208019Sthompsa return; 2689208019Sthompsa } 2690203134Sthompsa 2691208019Sthompsa /* only interested in true associations */ 2692209917Sthompsa if (isnew && ni->ni_associd != 0) { 2693208019Sthompsa 2694208019Sthompsa /* 2695208019Sthompsa * This function could is called though timeout function. 2696208019Sthompsa * Need to defer. 2697208019Sthompsa */ 2698208019Sthompsa uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store); 2699208019Sthompsa DPRINTF("cmdq_store=%d\n", cnt); 2700208019Sthompsa sc->cmdq[cnt].func = run_newassoc_cb; 2701208019Sthompsa sc->cmdq[cnt].arg0 = NULL; 2702208019Sthompsa sc->cmdq[cnt].arg1 = ni; 2703208019Sthompsa sc->cmdq[cnt].wcid = wcid; 2704208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 2705208019Sthompsa } 2706208019Sthompsa 2707208019Sthompsa DPRINTF("new assoc isnew=%d associd=%x addr=%s\n", 2708208019Sthompsa isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr)); 2709208019Sthompsa 2710203134Sthompsa for (i = 0; i < rs->rs_nrates; i++) { 2711203134Sthompsa rate = rs->rs_rates[i] & IEEE80211_RATE_VAL; 2712203134Sthompsa /* convert 802.11 rate to hardware rate index */ 2713203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2714203134Sthompsa if (rt2860_rates[ridx].rate == rate) 2715203134Sthompsa break; 2716203134Sthompsa rn->ridx[i] = ridx; 2717203134Sthompsa /* determine rate of control response frames */ 2718203134Sthompsa for (j = i; j >= 0; j--) { 2719203134Sthompsa if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) && 2720203134Sthompsa rt2860_rates[rn->ridx[i]].phy == 2721203134Sthompsa rt2860_rates[rn->ridx[j]].phy) 2722203134Sthompsa break; 2723203134Sthompsa } 2724203134Sthompsa if (j >= 0) { 2725203134Sthompsa rn->ctl_ridx[i] = rn->ridx[j]; 2726203134Sthompsa } else { 2727203134Sthompsa /* no basic rate found, use mandatory one */ 2728203134Sthompsa rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx; 2729203134Sthompsa } 2730203134Sthompsa DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n", 2731203134Sthompsa rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]); 2732203134Sthompsa } 2733208019Sthompsa rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate; 2734208019Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2735208019Sthompsa if (rt2860_rates[ridx].rate == rate) 2736208019Sthompsa break; 2737208019Sthompsa rn->mgt_ridx = ridx; 2738208019Sthompsa DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx); 2739208019Sthompsa 2740263073Shselasky RUN_LOCK(sc); 2741263073Shselasky if(sc->ratectl_run != RUN_RATECTL_OFF) 2742263073Shselasky usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2743263073Shselasky RUN_UNLOCK(sc); 2744203134Sthompsa} 2745203134Sthompsa 2746203134Sthompsa/* 2747203134Sthompsa * Return the Rx chain with the highest RSSI for a given frame. 2748203134Sthompsa */ 2749203134Sthompsastatic __inline uint8_t 2750203134Sthompsarun_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi) 2751203134Sthompsa{ 2752203134Sthompsa uint8_t rxchain = 0; 2753203134Sthompsa 2754203134Sthompsa if (sc->nrxchains > 1) { 2755203134Sthompsa if (rxwi->rssi[1] > rxwi->rssi[rxchain]) 2756203134Sthompsa rxchain = 1; 2757203134Sthompsa if (sc->nrxchains > 2) 2758203134Sthompsa if (rxwi->rssi[2] > rxwi->rssi[rxchain]) 2759203134Sthompsa rxchain = 2; 2760203134Sthompsa } 2761209917Sthompsa return (rxchain); 2762203134Sthompsa} 2763203134Sthompsa 2764203134Sthompsastatic void 2765203134Sthompsarun_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) 2766203134Sthompsa{ 2767203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 2768203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 2769203134Sthompsa struct ieee80211_frame *wh; 2770203134Sthompsa struct ieee80211_node *ni; 2771203134Sthompsa struct rt2870_rxd *rxd; 2772203134Sthompsa struct rt2860_rxwi *rxwi; 2773203134Sthompsa uint32_t flags; 2774259453Shselasky uint16_t len, rxwisize; 2775203134Sthompsa uint8_t ant, rssi; 2776203134Sthompsa int8_t nf; 2777203134Sthompsa 2778203134Sthompsa rxwi = mtod(m, struct rt2860_rxwi *); 2779203134Sthompsa len = le16toh(rxwi->len) & 0xfff; 2780261868Skevlo rxwisize = sizeof(struct rt2860_rxwi); 2781261868Skevlo if (sc->mac_ver == 0x5592) 2782261868Skevlo rxwisize += sizeof(uint64_t); 2783261868Skevlo else if (sc->mac_ver == 0x3593) 2784261868Skevlo rxwisize += sizeof(uint32_t); 2785203134Sthompsa if (__predict_false(len > dmalen)) { 2786203134Sthompsa m_freem(m); 2787203134Sthompsa ifp->if_ierrors++; 2788203134Sthompsa DPRINTF("bad RXWI length %u > %u\n", len, dmalen); 2789203134Sthompsa return; 2790203134Sthompsa } 2791203134Sthompsa /* Rx descriptor is located at the end */ 2792203134Sthompsa rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen); 2793203134Sthompsa flags = le32toh(rxd->flags); 2794203134Sthompsa 2795203134Sthompsa if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) { 2796203134Sthompsa m_freem(m); 2797203134Sthompsa ifp->if_ierrors++; 2798203134Sthompsa DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV"); 2799203134Sthompsa return; 2800203134Sthompsa } 2801203134Sthompsa 2802259453Shselasky m->m_data += rxwisize; 2803259453Shselasky m->m_pkthdr.len = m->m_len -= rxwisize; 2804203134Sthompsa 2805203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 2806203134Sthompsa 2807262007Skevlo if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 2808262007Skevlo wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; 2809203134Sthompsa m->m_flags |= M_WEP; 2810203134Sthompsa } 2811203134Sthompsa 2812209917Sthompsa if (flags & RT2860_RX_L2PAD) { 2813203134Sthompsa DPRINTFN(8, "received RT2860_RX_L2PAD frame\n"); 2814203134Sthompsa len += 2; 2815203134Sthompsa } 2816203134Sthompsa 2817208019Sthompsa ni = ieee80211_find_rxnode(ic, 2818208019Sthompsa mtod(m, struct ieee80211_frame_min *)); 2819208019Sthompsa 2820203134Sthompsa if (__predict_false(flags & RT2860_RX_MICERR)) { 2821203134Sthompsa /* report MIC failures to net80211 for TKIP */ 2822209917Sthompsa if (ni != NULL) 2823259453Shselasky ieee80211_notify_michael_failure(ni->ni_vap, wh, 2824259453Shselasky rxwi->keyidx); 2825203134Sthompsa m_freem(m); 2826203134Sthompsa ifp->if_ierrors++; 2827203134Sthompsa DPRINTF("MIC error. Someone is lying.\n"); 2828203134Sthompsa return; 2829203134Sthompsa } 2830203134Sthompsa 2831203134Sthompsa ant = run_maxrssi_chain(sc, rxwi); 2832203134Sthompsa rssi = rxwi->rssi[ant]; 2833203134Sthompsa nf = run_rssi2dbm(sc, rssi, ant); 2834203134Sthompsa 2835203134Sthompsa m->m_pkthdr.rcvif = ifp; 2836203134Sthompsa m->m_pkthdr.len = m->m_len = len; 2837203134Sthompsa 2838203134Sthompsa if (ni != NULL) { 2839203134Sthompsa (void)ieee80211_input(ni, m, rssi, nf); 2840203134Sthompsa ieee80211_free_node(ni); 2841203134Sthompsa } else { 2842203134Sthompsa (void)ieee80211_input_all(ic, m, rssi, nf); 2843203134Sthompsa } 2844203134Sthompsa 2845209917Sthompsa if (__predict_false(ieee80211_radiotap_active(ic))) { 2846203134Sthompsa struct run_rx_radiotap_header *tap = &sc->sc_rxtap; 2847259453Shselasky uint16_t phy; 2848203134Sthompsa 2849203134Sthompsa tap->wr_flags = 0; 2850236439Shselasky tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); 2851236439Shselasky tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); 2852203134Sthompsa tap->wr_antsignal = rssi; 2853203134Sthompsa tap->wr_antenna = ant; 2854203134Sthompsa tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant); 2855203134Sthompsa tap->wr_rate = 2; /* in case it can't be found below */ 2856203134Sthompsa phy = le16toh(rxwi->phy); 2857203134Sthompsa switch (phy & RT2860_PHY_MODE) { 2858203134Sthompsa case RT2860_PHY_CCK: 2859203134Sthompsa switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) { 2860203134Sthompsa case 0: tap->wr_rate = 2; break; 2861203134Sthompsa case 1: tap->wr_rate = 4; break; 2862203134Sthompsa case 2: tap->wr_rate = 11; break; 2863203134Sthompsa case 3: tap->wr_rate = 22; break; 2864203134Sthompsa } 2865203134Sthompsa if (phy & RT2860_PHY_SHPRE) 2866203134Sthompsa tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 2867203134Sthompsa break; 2868203134Sthompsa case RT2860_PHY_OFDM: 2869203134Sthompsa switch (phy & RT2860_PHY_MCS) { 2870203134Sthompsa case 0: tap->wr_rate = 12; break; 2871203134Sthompsa case 1: tap->wr_rate = 18; break; 2872203134Sthompsa case 2: tap->wr_rate = 24; break; 2873203134Sthompsa case 3: tap->wr_rate = 36; break; 2874203134Sthompsa case 4: tap->wr_rate = 48; break; 2875203134Sthompsa case 5: tap->wr_rate = 72; break; 2876203134Sthompsa case 6: tap->wr_rate = 96; break; 2877203134Sthompsa case 7: tap->wr_rate = 108; break; 2878203134Sthompsa } 2879203134Sthompsa break; 2880203134Sthompsa } 2881203134Sthompsa } 2882203134Sthompsa} 2883203134Sthompsa 2884203134Sthompsastatic void 2885203134Sthompsarun_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) 2886203134Sthompsa{ 2887203134Sthompsa struct run_softc *sc = usbd_xfer_softc(xfer); 2888203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 2889203134Sthompsa struct mbuf *m = NULL; 2890203134Sthompsa struct mbuf *m0; 2891203134Sthompsa uint32_t dmalen; 2892259453Shselasky uint16_t rxwisize; 2893203134Sthompsa int xferlen; 2894203134Sthompsa 2895261868Skevlo rxwisize = sizeof(struct rt2860_rxwi); 2896261868Skevlo if (sc->mac_ver == 0x5592) 2897261868Skevlo rxwisize += sizeof(uint64_t); 2898261868Skevlo else if (sc->mac_ver == 0x3593) 2899261868Skevlo rxwisize += sizeof(uint32_t); 2900259453Shselasky 2901203134Sthompsa usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL); 2902203134Sthompsa 2903203134Sthompsa switch (USB_GET_STATE(xfer)) { 2904203134Sthompsa case USB_ST_TRANSFERRED: 2905203134Sthompsa 2906203134Sthompsa DPRINTFN(15, "rx done, actlen=%d\n", xferlen); 2907203134Sthompsa 2908259453Shselasky if (xferlen < (int)(sizeof(uint32_t) + rxwisize + 2909259453Shselasky sizeof(struct rt2870_rxd))) { 2910203134Sthompsa DPRINTF("xfer too short %d\n", xferlen); 2911203134Sthompsa goto tr_setup; 2912203134Sthompsa } 2913203134Sthompsa 2914203134Sthompsa m = sc->rx_m; 2915203134Sthompsa sc->rx_m = NULL; 2916203134Sthompsa 2917203134Sthompsa /* FALLTHROUGH */ 2918203134Sthompsa case USB_ST_SETUP: 2919203134Sthompsatr_setup: 2920203134Sthompsa if (sc->rx_m == NULL) { 2921243857Sglebius sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, 2922203134Sthompsa MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */); 2923203134Sthompsa } 2924203134Sthompsa if (sc->rx_m == NULL) { 2925203134Sthompsa DPRINTF("could not allocate mbuf - idle with stall\n"); 2926203134Sthompsa ifp->if_ierrors++; 2927203134Sthompsa usbd_xfer_set_stall(xfer); 2928203134Sthompsa usbd_xfer_set_frames(xfer, 0); 2929203134Sthompsa } else { 2930203134Sthompsa /* 2931203134Sthompsa * Directly loading a mbuf cluster into DMA to 2932203134Sthompsa * save some data copying. This works because 2933203134Sthompsa * there is only one cluster. 2934203134Sthompsa */ 2935203134Sthompsa usbd_xfer_set_frame_data(xfer, 0, 2936203134Sthompsa mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ); 2937203134Sthompsa usbd_xfer_set_frames(xfer, 1); 2938203134Sthompsa } 2939203134Sthompsa usbd_transfer_submit(xfer); 2940203134Sthompsa break; 2941203134Sthompsa 2942203134Sthompsa default: /* Error */ 2943203134Sthompsa if (error != USB_ERR_CANCELLED) { 2944203134Sthompsa /* try to clear stall first */ 2945203134Sthompsa usbd_xfer_set_stall(xfer); 2946203134Sthompsa 2947203134Sthompsa if (error == USB_ERR_TIMEOUT) 2948203134Sthompsa device_printf(sc->sc_dev, "device timeout\n"); 2949203134Sthompsa 2950203134Sthompsa ifp->if_ierrors++; 2951203134Sthompsa 2952203134Sthompsa goto tr_setup; 2953203134Sthompsa } 2954209917Sthompsa if (sc->rx_m != NULL) { 2955203134Sthompsa m_freem(sc->rx_m); 2956203134Sthompsa sc->rx_m = NULL; 2957203134Sthompsa } 2958203134Sthompsa break; 2959203134Sthompsa } 2960203134Sthompsa 2961203134Sthompsa if (m == NULL) 2962203134Sthompsa return; 2963203134Sthompsa 2964203134Sthompsa /* inputting all the frames must be last */ 2965203134Sthompsa 2966203134Sthompsa RUN_UNLOCK(sc); 2967203134Sthompsa 2968203134Sthompsa m->m_pkthdr.len = m->m_len = xferlen; 2969203134Sthompsa 2970203134Sthompsa /* HW can aggregate multiple 802.11 frames in a single USB xfer */ 2971203134Sthompsa for(;;) { 2972203134Sthompsa dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff; 2973203134Sthompsa 2974233774Shselasky if ((dmalen >= (uint32_t)-8) || (dmalen == 0) || 2975233774Shselasky ((dmalen & 3) != 0)) { 2976203134Sthompsa DPRINTF("bad DMA length %u\n", dmalen); 2977203134Sthompsa break; 2978203134Sthompsa } 2979233774Shselasky if ((dmalen + 8) > (uint32_t)xferlen) { 2980203134Sthompsa DPRINTF("bad DMA length %u > %d\n", 2981203134Sthompsa dmalen + 8, xferlen); 2982203134Sthompsa break; 2983203134Sthompsa } 2984203134Sthompsa 2985203134Sthompsa /* If it is the last one or a single frame, we won't copy. */ 2986209917Sthompsa if ((xferlen -= dmalen + 8) <= 8) { 2987203134Sthompsa /* trim 32-bit DMA-len header */ 2988203134Sthompsa m->m_data += 4; 2989203134Sthompsa m->m_pkthdr.len = m->m_len -= 4; 2990203134Sthompsa run_rx_frame(sc, m, dmalen); 2991259453Shselasky m = NULL; /* don't free source buffer */ 2992203134Sthompsa break; 2993203134Sthompsa } 2994203134Sthompsa 2995203134Sthompsa /* copy aggregated frames to another mbuf */ 2996243857Sglebius m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 2997203134Sthompsa if (__predict_false(m0 == NULL)) { 2998203134Sthompsa DPRINTF("could not allocate mbuf\n"); 2999203134Sthompsa ifp->if_ierrors++; 3000203134Sthompsa break; 3001203134Sthompsa } 3002203134Sthompsa m_copydata(m, 4 /* skip 32-bit DMA-len header */, 3003203134Sthompsa dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t)); 3004203134Sthompsa m0->m_pkthdr.len = m0->m_len = 3005203134Sthompsa dmalen + sizeof(struct rt2870_rxd); 3006203134Sthompsa run_rx_frame(sc, m0, dmalen); 3007203134Sthompsa 3008203134Sthompsa /* update data ptr */ 3009203134Sthompsa m->m_data += dmalen + 8; 3010203134Sthompsa m->m_pkthdr.len = m->m_len -= dmalen + 8; 3011203134Sthompsa } 3012203134Sthompsa 3013259453Shselasky /* make sure we free the source buffer, if any */ 3014259453Shselasky m_freem(m); 3015259453Shselasky 3016203134Sthompsa RUN_LOCK(sc); 3017203134Sthompsa} 3018203134Sthompsa 3019203134Sthompsastatic void 3020203134Sthompsarun_tx_free(struct run_endpoint_queue *pq, 3021203134Sthompsa struct run_tx_data *data, int txerr) 3022203134Sthompsa{ 3023203134Sthompsa if (data->m != NULL) { 3024203134Sthompsa if (data->m->m_flags & M_TXCB) 3025203134Sthompsa ieee80211_process_callback(data->ni, data->m, 3026203134Sthompsa txerr ? ETIMEDOUT : 0); 3027203134Sthompsa m_freem(data->m); 3028203134Sthompsa data->m = NULL; 3029203134Sthompsa 3030209917Sthompsa if (data->ni == NULL) { 3031203134Sthompsa DPRINTF("no node\n"); 3032203134Sthompsa } else { 3033203134Sthompsa ieee80211_free_node(data->ni); 3034203134Sthompsa data->ni = NULL; 3035203134Sthompsa } 3036203134Sthompsa } 3037203134Sthompsa 3038203134Sthompsa STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); 3039203134Sthompsa pq->tx_nfree++; 3040203134Sthompsa} 3041203134Sthompsa 3042203134Sthompsastatic void 3043259453Shselaskyrun_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index) 3044203134Sthompsa{ 3045203134Sthompsa struct run_softc *sc = usbd_xfer_softc(xfer); 3046203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 3047208019Sthompsa struct ieee80211com *ic = ifp->if_l2com; 3048203134Sthompsa struct run_tx_data *data; 3049203134Sthompsa struct ieee80211vap *vap = NULL; 3050203134Sthompsa struct usb_page_cache *pc; 3051203134Sthompsa struct run_endpoint_queue *pq = &sc->sc_epq[index]; 3052203134Sthompsa struct mbuf *m; 3053203134Sthompsa usb_frlength_t size; 3054203134Sthompsa int actlen; 3055203134Sthompsa int sumlen; 3056203134Sthompsa 3057203134Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 3058203134Sthompsa 3059209917Sthompsa switch (USB_GET_STATE(xfer)) { 3060203134Sthompsa case USB_ST_TRANSFERRED: 3061203134Sthompsa DPRINTFN(11, "transfer complete: %d " 3062203134Sthompsa "bytes @ index %d\n", actlen, index); 3063203134Sthompsa 3064203134Sthompsa data = usbd_xfer_get_priv(xfer); 3065203134Sthompsa 3066203134Sthompsa run_tx_free(pq, data, 0); 3067203134Sthompsa ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 3068203134Sthompsa 3069203134Sthompsa usbd_xfer_set_priv(xfer, NULL); 3070203134Sthompsa 3071203134Sthompsa ifp->if_opackets++; 3072203134Sthompsa 3073203134Sthompsa /* FALLTHROUGH */ 3074203134Sthompsa case USB_ST_SETUP: 3075203134Sthompsatr_setup: 3076203134Sthompsa data = STAILQ_FIRST(&pq->tx_qh); 3077209917Sthompsa if (data == NULL) 3078203134Sthompsa break; 3079203134Sthompsa 3080203134Sthompsa STAILQ_REMOVE_HEAD(&pq->tx_qh, next); 3081203134Sthompsa 3082203134Sthompsa m = data->m; 3083261868Skevlo size = (sc->mac_ver == 0x5592) ? 3084261868Skevlo sizeof(data->desc) + sizeof(uint32_t) : sizeof(data->desc); 3085228508Shselasky if ((m->m_pkthdr.len + 3086261868Skevlo size + 3 + 8) > RUN_MAX_TXSZ) { 3087203134Sthompsa DPRINTF("data overflow, %u bytes\n", 3088203134Sthompsa m->m_pkthdr.len); 3089203134Sthompsa 3090203134Sthompsa ifp->if_oerrors++; 3091203134Sthompsa 3092203134Sthompsa run_tx_free(pq, data, 1); 3093203134Sthompsa 3094203134Sthompsa goto tr_setup; 3095203134Sthompsa } 3096203134Sthompsa 3097203134Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 3098203134Sthompsa usbd_copy_in(pc, 0, &data->desc, size); 3099203134Sthompsa usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len); 3100228508Shselasky size += m->m_pkthdr.len; 3101228508Shselasky /* 3102228508Shselasky * Align end on a 4-byte boundary, pad 8 bytes (CRC + 3103228508Shselasky * 4-byte padding), and be sure to zero those trailing 3104228508Shselasky * bytes: 3105228508Shselasky */ 3106228508Shselasky usbd_frame_zero(pc, size, ((-size) & 3) + 8); 3107228508Shselasky size += ((-size) & 3) + 8; 3108203134Sthompsa 3109203134Sthompsa vap = data->ni->ni_vap; 3110203134Sthompsa if (ieee80211_radiotap_active_vap(vap)) { 3111203134Sthompsa struct run_tx_radiotap_header *tap = &sc->sc_txtap; 3112259453Shselasky struct rt2860_txwi *txwi = 3113208019Sthompsa (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd)); 3114203134Sthompsa tap->wt_flags = 0; 3115203134Sthompsa tap->wt_rate = rt2860_rates[data->ridx].rate; 3116236439Shselasky tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 3117236439Shselasky tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 3118203134Sthompsa tap->wt_hwqueue = index; 3119208019Sthompsa if (le16toh(txwi->phy) & RT2860_PHY_SHPRE) 3120203134Sthompsa tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 3121203134Sthompsa 3122203134Sthompsa ieee80211_radiotap_tx(vap, m); 3123203134Sthompsa } 3124203134Sthompsa 3125228508Shselasky DPRINTFN(11, "sending frame len=%u/%u @ index %d\n", 3126228508Shselasky m->m_pkthdr.len, size, index); 3127203134Sthompsa 3128228508Shselasky usbd_xfer_set_frame_len(xfer, 0, size); 3129203134Sthompsa usbd_xfer_set_priv(xfer, data); 3130203134Sthompsa 3131203134Sthompsa usbd_transfer_submit(xfer); 3132203134Sthompsa 3133203134Sthompsa RUN_UNLOCK(sc); 3134203134Sthompsa run_start(ifp); 3135203134Sthompsa RUN_LOCK(sc); 3136203134Sthompsa 3137203134Sthompsa break; 3138203134Sthompsa 3139203134Sthompsa default: 3140203134Sthompsa DPRINTF("USB transfer error, %s\n", 3141203134Sthompsa usbd_errstr(error)); 3142203134Sthompsa 3143203134Sthompsa data = usbd_xfer_get_priv(xfer); 3144203134Sthompsa 3145203134Sthompsa ifp->if_oerrors++; 3146203134Sthompsa 3147203134Sthompsa if (data != NULL) { 3148208019Sthompsa if(data->ni != NULL) 3149208019Sthompsa vap = data->ni->ni_vap; 3150203134Sthompsa run_tx_free(pq, data, error); 3151203134Sthompsa usbd_xfer_set_priv(xfer, NULL); 3152203134Sthompsa } 3153209917Sthompsa if (vap == NULL) 3154208019Sthompsa vap = TAILQ_FIRST(&ic->ic_vaps); 3155203134Sthompsa 3156203134Sthompsa if (error != USB_ERR_CANCELLED) { 3157203134Sthompsa if (error == USB_ERR_TIMEOUT) { 3158203134Sthompsa device_printf(sc->sc_dev, "device timeout\n"); 3159208019Sthompsa uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 3160208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 3161208019Sthompsa sc->cmdq[i].func = run_usb_timeout_cb; 3162208019Sthompsa sc->cmdq[i].arg0 = vap; 3163208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 3164203134Sthompsa } 3165203134Sthompsa 3166203134Sthompsa /* 3167203134Sthompsa * Try to clear stall first, also if other 3168203134Sthompsa * errors occur, hence clearing stall 3169203134Sthompsa * introduces a 50 ms delay: 3170203134Sthompsa */ 3171203134Sthompsa usbd_xfer_set_stall(xfer); 3172203134Sthompsa goto tr_setup; 3173203134Sthompsa } 3174203134Sthompsa break; 3175203134Sthompsa } 3176203134Sthompsa} 3177203134Sthompsa 3178203134Sthompsastatic void 3179203134Sthompsarun_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error) 3180203134Sthompsa{ 3181203134Sthompsa run_bulk_tx_callbackN(xfer, error, 0); 3182203134Sthompsa} 3183203134Sthompsa 3184203134Sthompsastatic void 3185203134Sthompsarun_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error) 3186203134Sthompsa{ 3187203134Sthompsa run_bulk_tx_callbackN(xfer, error, 1); 3188203134Sthompsa} 3189203134Sthompsa 3190203134Sthompsastatic void 3191203134Sthompsarun_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error) 3192203134Sthompsa{ 3193203134Sthompsa run_bulk_tx_callbackN(xfer, error, 2); 3194203134Sthompsa} 3195203134Sthompsa 3196203134Sthompsastatic void 3197203134Sthompsarun_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error) 3198203134Sthompsa{ 3199203134Sthompsa run_bulk_tx_callbackN(xfer, error, 3); 3200203134Sthompsa} 3201203134Sthompsa 3202203134Sthompsastatic void 3203203134Sthompsarun_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error) 3204203134Sthompsa{ 3205203134Sthompsa run_bulk_tx_callbackN(xfer, error, 4); 3206203134Sthompsa} 3207203134Sthompsa 3208203134Sthompsastatic void 3209203134Sthompsarun_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error) 3210203134Sthompsa{ 3211203134Sthompsa run_bulk_tx_callbackN(xfer, error, 5); 3212203134Sthompsa} 3213203134Sthompsa 3214203134Sthompsastatic void 3215208019Sthompsarun_set_tx_desc(struct run_softc *sc, struct run_tx_data *data) 3216203134Sthompsa{ 3217203134Sthompsa struct mbuf *m = data->m; 3218203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 3219208019Sthompsa struct ieee80211vap *vap = data->ni->ni_vap; 3220203134Sthompsa struct ieee80211_frame *wh; 3221203134Sthompsa struct rt2870_txd *txd; 3222203134Sthompsa struct rt2860_txwi *txwi; 3223259453Shselasky uint16_t xferlen, txwisize; 3224208019Sthompsa uint16_t mcs; 3225203134Sthompsa uint8_t ridx = data->ridx; 3226208019Sthompsa uint8_t pad; 3227203134Sthompsa 3228203134Sthompsa /* get MCS code from rate index */ 3229208019Sthompsa mcs = rt2860_rates[ridx].mcs; 3230203134Sthompsa 3231259453Shselasky txwisize = (sc->mac_ver == 0x5592) ? 3232259453Shselasky sizeof(*txwi) + sizeof(uint32_t) : sizeof(*txwi); 3233259453Shselasky xferlen = txwisize + m->m_pkthdr.len; 3234203134Sthompsa 3235203134Sthompsa /* roundup to 32-bit alignment */ 3236203134Sthompsa xferlen = (xferlen + 3) & ~3; 3237203134Sthompsa 3238203134Sthompsa txd = (struct rt2870_txd *)&data->desc; 3239203134Sthompsa txd->len = htole16(xferlen); 3240203134Sthompsa 3241208019Sthompsa wh = mtod(m, struct ieee80211_frame *); 3242208019Sthompsa 3243208019Sthompsa /* 3244208019Sthompsa * Ether both are true or both are false, the header 3245208019Sthompsa * are nicely aligned to 32-bit. So, no L2 padding. 3246208019Sthompsa */ 3247208019Sthompsa if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh)) 3248208019Sthompsa pad = 0; 3249208019Sthompsa else 3250208019Sthompsa pad = 2; 3251208019Sthompsa 3252203134Sthompsa /* setup TX Wireless Information */ 3253203134Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3254203134Sthompsa txwi->len = htole16(m->m_pkthdr.len - pad); 3255203134Sthompsa if (rt2860_rates[ridx].phy == IEEE80211_T_DS) { 3256270515Skevlo mcs |= RT2860_PHY_CCK; 3257203134Sthompsa if (ridx != RT2860_RIDX_CCK1 && 3258203134Sthompsa (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 3259203134Sthompsa mcs |= RT2860_PHY_SHPRE; 3260203134Sthompsa } else 3261270515Skevlo mcs |= RT2860_PHY_OFDM; 3262270515Skevlo txwi->phy = htole16(mcs); 3263203134Sthompsa 3264203134Sthompsa /* check if RTS/CTS or CTS-to-self protection is required */ 3265203134Sthompsa if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 3266203134Sthompsa (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold || 3267203134Sthompsa ((ic->ic_flags & IEEE80211_F_USEPROT) && 3268203134Sthompsa rt2860_rates[ridx].phy == IEEE80211_T_OFDM))) 3269208019Sthompsa txwi->txop |= RT2860_TX_TXOP_HT; 3270203134Sthompsa else 3271208019Sthompsa txwi->txop |= RT2860_TX_TXOP_BACKOFF; 3272209144Sthompsa 3273209917Sthompsa if (vap->iv_opmode != IEEE80211_M_STA && !IEEE80211_QOS_HAS_SEQ(wh)) 3274209144Sthompsa txwi->xflags |= RT2860_TX_NSEQ; 3275203134Sthompsa} 3276203134Sthompsa 3277203134Sthompsa/* This function must be called locked */ 3278203134Sthompsastatic int 3279203134Sthompsarun_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) 3280203134Sthompsa{ 3281203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 3282208019Sthompsa struct ieee80211vap *vap = ni->ni_vap; 3283203134Sthompsa struct ieee80211_frame *wh; 3284208019Sthompsa struct ieee80211_channel *chan; 3285203134Sthompsa const struct ieee80211_txparam *tp; 3286208019Sthompsa struct run_node *rn = (void *)ni; 3287203134Sthompsa struct run_tx_data *data; 3288208019Sthompsa struct rt2870_txd *txd; 3289208019Sthompsa struct rt2860_txwi *txwi; 3290203134Sthompsa uint16_t qos; 3291203134Sthompsa uint16_t dur; 3292208019Sthompsa uint16_t qid; 3293203134Sthompsa uint8_t type; 3294203134Sthompsa uint8_t tid; 3295208019Sthompsa uint8_t ridx; 3296208019Sthompsa uint8_t ctl_ridx; 3297203134Sthompsa uint8_t qflags; 3298203134Sthompsa uint8_t xflags = 0; 3299203134Sthompsa int hasqos; 3300203134Sthompsa 3301203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3302203134Sthompsa 3303203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3304203134Sthompsa 3305203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3306203134Sthompsa 3307203134Sthompsa /* 3308203134Sthompsa * There are 7 bulk endpoints: 1 for RX 3309203134Sthompsa * and 6 for TX (4 EDCAs + HCCA + Prio). 3310203134Sthompsa * Update 03-14-2009: some devices like the Planex GW-US300MiniS 3311203134Sthompsa * seem to have only 4 TX bulk endpoints (Fukaumi Naoki). 3312203134Sthompsa */ 3313203134Sthompsa if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) { 3314203134Sthompsa uint8_t *frm; 3315203134Sthompsa 3316203134Sthompsa if(IEEE80211_HAS_ADDR4(wh)) 3317203134Sthompsa frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos; 3318203134Sthompsa else 3319203134Sthompsa frm =((struct ieee80211_qosframe *)wh)->i_qos; 3320203134Sthompsa 3321203134Sthompsa qos = le16toh(*(const uint16_t *)frm); 3322203134Sthompsa tid = qos & IEEE80211_QOS_TID; 3323203134Sthompsa qid = TID_TO_WME_AC(tid); 3324203134Sthompsa } else { 3325203134Sthompsa qos = 0; 3326203134Sthompsa tid = 0; 3327203134Sthompsa qid = WME_AC_BE; 3328203134Sthompsa } 3329203134Sthompsa qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA; 3330203134Sthompsa 3331203134Sthompsa DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n", 3332203134Sthompsa qos, qid, tid, qflags); 3333203134Sthompsa 3334208019Sthompsa chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan; 3335208019Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(chan)]; 3336203134Sthompsa 3337203134Sthompsa /* pickup a rate index */ 3338203134Sthompsa if (IEEE80211_IS_MULTICAST(wh->i_addr1) || 3339270515Skevlo type != IEEE80211_FC0_TYPE_DATA || m->m_flags & M_EAPOL) { 3340203134Sthompsa ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? 3341203134Sthompsa RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; 3342203134Sthompsa ctl_ridx = rt2860_rates[ridx].ctl_ridx; 3343203134Sthompsa } else { 3344208019Sthompsa if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) 3345208019Sthompsa ridx = rn->fix_ridx; 3346208019Sthompsa else 3347208019Sthompsa ridx = rn->amrr_ridx; 3348203134Sthompsa ctl_ridx = rt2860_rates[ridx].ctl_ridx; 3349203134Sthompsa } 3350203134Sthompsa 3351203134Sthompsa if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 3352203134Sthompsa (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) != 3353203134Sthompsa IEEE80211_QOS_ACKPOLICY_NOACK)) { 3354209144Sthompsa xflags |= RT2860_TX_ACK; 3355203134Sthompsa if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 3356208019Sthompsa dur = rt2860_rates[ctl_ridx].sp_ack_dur; 3357203134Sthompsa else 3358208019Sthompsa dur = rt2860_rates[ctl_ridx].lp_ack_dur; 3359259453Shselasky USETW(wh->i_dur, dur); 3360203134Sthompsa } 3361203134Sthompsa 3362203134Sthompsa /* reserve slots for mgmt packets, just in case */ 3363203134Sthompsa if (sc->sc_epq[qid].tx_nfree < 3) { 3364203134Sthompsa DPRINTFN(10, "tx ring %d is full\n", qid); 3365203134Sthompsa return (-1); 3366203134Sthompsa } 3367203134Sthompsa 3368203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh); 3369203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next); 3370203134Sthompsa sc->sc_epq[qid].tx_nfree--; 3371203134Sthompsa 3372208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3373208019Sthompsa txd->flags = qflags; 3374208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3375208019Sthompsa txwi->xflags = xflags; 3376259453Shselasky if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 3377245047Shselasky txwi->wcid = 0; 3378259453Shselasky else 3379245047Shselasky txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 3380245047Shselasky 1 : RUN_AID2WCID(ni->ni_associd); 3381259453Shselasky 3382208019Sthompsa /* clear leftover garbage bits */ 3383208019Sthompsa txwi->flags = 0; 3384208019Sthompsa txwi->txop = 0; 3385208019Sthompsa 3386203134Sthompsa data->m = m; 3387203134Sthompsa data->ni = ni; 3388203134Sthompsa data->ridx = ridx; 3389203134Sthompsa 3390208019Sthompsa run_set_tx_desc(sc, data); 3391203134Sthompsa 3392208019Sthompsa /* 3393208019Sthompsa * The chip keeps track of 2 kind of Tx stats, 3394208019Sthompsa * * TX_STAT_FIFO, for per WCID stats, and 3395208019Sthompsa * * TX_STA_CNT0 for all-TX-in-one stats. 3396208019Sthompsa * 3397208019Sthompsa * To use FIFO stats, we need to store MCS into the driver-private 3398208019Sthompsa * PacketID field. So that, we can tell whose stats when we read them. 3399208019Sthompsa * We add 1 to the MCS because setting the PacketID field to 0 means 3400208019Sthompsa * that we don't want feedback in TX_STAT_FIFO. 3401208019Sthompsa * And, that's what we want for STA mode, since TX_STA_CNT0 does the job. 3402208019Sthompsa * 3403208019Sthompsa * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx(). 3404208019Sthompsa */ 3405209917Sthompsa if (sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP || 3406209917Sthompsa vap->iv_opmode == IEEE80211_M_MBSS) { 3407208019Sthompsa uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf; 3408208019Sthompsa txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT); 3409208019Sthompsa 3410208019Sthompsa /* 3411208019Sthompsa * Unlike PCI based devices, we don't get any interrupt from 3412208019Sthompsa * USB devices, so we simulate FIFO-is-full interrupt here. 3413208019Sthompsa * Ralink recomends to drain FIFO stats every 100 ms, but 16 slots 3414208019Sthompsa * quickly get fulled. To prevent overflow, increment a counter on 3415208019Sthompsa * every FIFO stat request, so we know how many slots are left. 3416208019Sthompsa * We do this only in HOSTAP or multiple vap mode since FIFO stats 3417208019Sthompsa * are used only in those modes. 3418208019Sthompsa * We just drain stats. AMRR gets updated every 1 sec by 3419208019Sthompsa * run_ratectl_cb() via callout. 3420208019Sthompsa * Call it early. Otherwise overflow. 3421208019Sthompsa */ 3422209917Sthompsa if (sc->fifo_cnt++ == 10) { 3423208019Sthompsa /* 3424208019Sthompsa * With multiple vaps or if_bridge, if_start() is called 3425208019Sthompsa * with a non-sleepable lock, tcpinp. So, need to defer. 3426208019Sthompsa */ 3427208019Sthompsa uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 3428208019Sthompsa DPRINTFN(6, "cmdq_store=%d\n", i); 3429208019Sthompsa sc->cmdq[i].func = run_drain_fifo; 3430208019Sthompsa sc->cmdq[i].arg0 = sc; 3431208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 3432208019Sthompsa } 3433208019Sthompsa } 3434208019Sthompsa 3435203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next); 3436203134Sthompsa 3437203134Sthompsa usbd_transfer_start(sc->sc_xfer[qid]); 3438203134Sthompsa 3439259453Shselasky DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n", 3440259453Shselasky m->m_pkthdr.len + (int)(sizeof(struct rt2870_txd) + 3441259453Shselasky sizeof(struct rt2860_txwi)), rt2860_rates[ridx].rate, qid); 3442203134Sthompsa 3443203134Sthompsa return (0); 3444203134Sthompsa} 3445203134Sthompsa 3446203134Sthompsastatic int 3447203134Sthompsarun_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) 3448203134Sthompsa{ 3449203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 3450203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 3451208019Sthompsa struct run_node *rn = (void *)ni; 3452203134Sthompsa struct run_tx_data *data; 3453203134Sthompsa struct ieee80211_frame *wh; 3454208019Sthompsa struct rt2870_txd *txd; 3455208019Sthompsa struct rt2860_txwi *txwi; 3456203134Sthompsa uint16_t dur; 3457208019Sthompsa uint8_t ridx = rn->mgt_ridx; 3458203134Sthompsa uint8_t type; 3459203134Sthompsa uint8_t xflags = 0; 3460208019Sthompsa uint8_t wflags = 0; 3461203134Sthompsa 3462203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3463203134Sthompsa 3464203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3465203134Sthompsa 3466203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3467203134Sthompsa 3468208019Sthompsa /* tell hardware to add timestamp for probe responses */ 3469208019Sthompsa if ((wh->i_fc[0] & 3470208019Sthompsa (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == 3471208019Sthompsa (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) 3472208019Sthompsa wflags |= RT2860_TX_TS; 3473208019Sthompsa else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 3474203134Sthompsa xflags |= RT2860_TX_ACK; 3475203134Sthompsa 3476208019Sthompsa dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate, 3477203134Sthompsa ic->ic_flags & IEEE80211_F_SHPREAMBLE); 3478259453Shselasky USETW(wh->i_dur, dur); 3479203134Sthompsa } 3480203134Sthompsa 3481203134Sthompsa if (sc->sc_epq[0].tx_nfree == 0) { 3482203134Sthompsa /* let caller free mbuf */ 3483203134Sthompsa ifp->if_drv_flags |= IFF_DRV_OACTIVE; 3484203134Sthompsa return (EIO); 3485203134Sthompsa } 3486203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3487203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3488203134Sthompsa sc->sc_epq[0].tx_nfree--; 3489203134Sthompsa 3490208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3491208019Sthompsa txd->flags = RT2860_TX_QSEL_EDCA; 3492208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3493208019Sthompsa txwi->wcid = 0xff; 3494208019Sthompsa txwi->flags = wflags; 3495208019Sthompsa txwi->xflags = xflags; 3496208019Sthompsa txwi->txop = 0; /* clear leftover garbage bits */ 3497208019Sthompsa 3498203134Sthompsa data->m = m; 3499203134Sthompsa data->ni = ni; 3500203134Sthompsa data->ridx = ridx; 3501203134Sthompsa 3502208019Sthompsa run_set_tx_desc(sc, data); 3503203134Sthompsa 3504203134Sthompsa DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len + 3505259453Shselasky (int)(sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi)), 3506208019Sthompsa rt2860_rates[ridx].rate); 3507203134Sthompsa 3508203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3509203134Sthompsa 3510203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 3511203134Sthompsa 3512203134Sthompsa return (0); 3513203134Sthompsa} 3514203134Sthompsa 3515203134Sthompsastatic int 3516203134Sthompsarun_sendprot(struct run_softc *sc, 3517203134Sthompsa const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) 3518203134Sthompsa{ 3519203134Sthompsa struct ieee80211com *ic = ni->ni_ic; 3520203134Sthompsa struct ieee80211_frame *wh; 3521203134Sthompsa struct run_tx_data *data; 3522208019Sthompsa struct rt2870_txd *txd; 3523208019Sthompsa struct rt2860_txwi *txwi; 3524203134Sthompsa struct mbuf *mprot; 3525203134Sthompsa int ridx; 3526203134Sthompsa int protrate; 3527203134Sthompsa int ackrate; 3528203134Sthompsa int pktlen; 3529203134Sthompsa int isshort; 3530203134Sthompsa uint16_t dur; 3531203134Sthompsa uint8_t type; 3532208019Sthompsa uint8_t wflags = 0; 3533208019Sthompsa uint8_t xflags = 0; 3534203134Sthompsa 3535203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3536203134Sthompsa 3537203134Sthompsa KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, 3538203134Sthompsa ("protection %d", prot)); 3539203134Sthompsa 3540203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3541203134Sthompsa pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; 3542203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3543203134Sthompsa 3544203134Sthompsa protrate = ieee80211_ctl_rate(ic->ic_rt, rate); 3545203134Sthompsa ackrate = ieee80211_ack_rate(ic->ic_rt, rate); 3546203134Sthompsa 3547203134Sthompsa isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; 3548209189Sjkim dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort) 3549203134Sthompsa + ieee80211_ack_duration(ic->ic_rt, rate, isshort); 3550203134Sthompsa wflags = RT2860_TX_FRAG; 3551203134Sthompsa 3552203134Sthompsa /* check that there are free slots before allocating the mbuf */ 3553203134Sthompsa if (sc->sc_epq[0].tx_nfree == 0) { 3554203134Sthompsa /* let caller free mbuf */ 3555203134Sthompsa sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 3556203134Sthompsa return (ENOBUFS); 3557203134Sthompsa } 3558203134Sthompsa 3559203134Sthompsa if (prot == IEEE80211_PROT_RTSCTS) { 3560203134Sthompsa /* NB: CTS is the same size as an ACK */ 3561203134Sthompsa dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); 3562208019Sthompsa xflags |= RT2860_TX_ACK; 3563203134Sthompsa mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); 3564203134Sthompsa } else { 3565203134Sthompsa mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); 3566203134Sthompsa } 3567203134Sthompsa if (mprot == NULL) { 3568203134Sthompsa sc->sc_ifp->if_oerrors++; 3569203134Sthompsa DPRINTF("could not allocate mbuf\n"); 3570203134Sthompsa return (ENOBUFS); 3571203134Sthompsa } 3572203134Sthompsa 3573203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3574203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3575203134Sthompsa sc->sc_epq[0].tx_nfree--; 3576203134Sthompsa 3577208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3578208019Sthompsa txd->flags = RT2860_TX_QSEL_EDCA; 3579208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3580208019Sthompsa txwi->wcid = 0xff; 3581208019Sthompsa txwi->flags = wflags; 3582208019Sthompsa txwi->xflags = xflags; 3583208019Sthompsa txwi->txop = 0; /* clear leftover garbage bits */ 3584208019Sthompsa 3585203134Sthompsa data->m = mprot; 3586203134Sthompsa data->ni = ieee80211_ref_node(ni); 3587203134Sthompsa 3588203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 3589203134Sthompsa if (rt2860_rates[ridx].rate == protrate) 3590203134Sthompsa break; 3591203134Sthompsa data->ridx = ridx; 3592203134Sthompsa 3593208019Sthompsa run_set_tx_desc(sc, data); 3594203134Sthompsa 3595203134Sthompsa DPRINTFN(1, "sending prot len=%u rate=%u\n", 3596203134Sthompsa m->m_pkthdr.len, rate); 3597203134Sthompsa 3598203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3599203134Sthompsa 3600203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 3601203134Sthompsa 3602203134Sthompsa return (0); 3603203134Sthompsa} 3604203134Sthompsa 3605203134Sthompsastatic int 3606203134Sthompsarun_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, 3607203134Sthompsa const struct ieee80211_bpf_params *params) 3608203134Sthompsa{ 3609203134Sthompsa struct ieee80211com *ic = ni->ni_ic; 3610203134Sthompsa struct ieee80211_frame *wh; 3611203134Sthompsa struct run_tx_data *data; 3612208019Sthompsa struct rt2870_txd *txd; 3613208019Sthompsa struct rt2860_txwi *txwi; 3614203134Sthompsa uint8_t type; 3615208019Sthompsa uint8_t ridx; 3616208019Sthompsa uint8_t rate; 3617208019Sthompsa uint8_t opflags = 0; 3618208019Sthompsa uint8_t xflags = 0; 3619203134Sthompsa int error; 3620203134Sthompsa 3621203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 3622203134Sthompsa 3623203134Sthompsa KASSERT(params != NULL, ("no raw xmit params")); 3624203134Sthompsa 3625203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 3626203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3627203134Sthompsa 3628203134Sthompsa rate = params->ibp_rate0; 3629203134Sthompsa if (!ieee80211_isratevalid(ic->ic_rt, rate)) { 3630203134Sthompsa /* let caller free mbuf */ 3631203134Sthompsa return (EINVAL); 3632203134Sthompsa } 3633203134Sthompsa 3634203134Sthompsa if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) 3635208019Sthompsa xflags |= RT2860_TX_ACK; 3636203134Sthompsa if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { 3637203134Sthompsa error = run_sendprot(sc, m, ni, 3638203134Sthompsa params->ibp_flags & IEEE80211_BPF_RTS ? 3639203134Sthompsa IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, 3640203134Sthompsa rate); 3641203134Sthompsa if (error) { 3642203134Sthompsa /* let caller free mbuf */ 3643209917Sthompsa return error; 3644203134Sthompsa } 3645203134Sthompsa opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS; 3646203134Sthompsa } 3647203134Sthompsa 3648203134Sthompsa if (sc->sc_epq[0].tx_nfree == 0) { 3649203134Sthompsa /* let caller free mbuf */ 3650203134Sthompsa sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 3651203134Sthompsa DPRINTF("sending raw frame, but tx ring is full\n"); 3652203134Sthompsa return (EIO); 3653203134Sthompsa } 3654203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3655203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3656203134Sthompsa sc->sc_epq[0].tx_nfree--; 3657203134Sthompsa 3658208019Sthompsa txd = (struct rt2870_txd *)&data->desc; 3659208019Sthompsa txd->flags = RT2860_TX_QSEL_EDCA; 3660208019Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3661208019Sthompsa txwi->wcid = 0xff; 3662208019Sthompsa txwi->xflags = xflags; 3663208019Sthompsa txwi->txop = opflags; 3664208019Sthompsa txwi->flags = 0; /* clear leftover garbage bits */ 3665208019Sthompsa 3666203134Sthompsa data->m = m; 3667203134Sthompsa data->ni = ni; 3668203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 3669203134Sthompsa if (rt2860_rates[ridx].rate == rate) 3670203134Sthompsa break; 3671203134Sthompsa data->ridx = ridx; 3672203134Sthompsa 3673208019Sthompsa run_set_tx_desc(sc, data); 3674203134Sthompsa 3675203134Sthompsa DPRINTFN(10, "sending raw frame len=%u rate=%u\n", 3676203134Sthompsa m->m_pkthdr.len, rate); 3677203134Sthompsa 3678203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3679203134Sthompsa 3680203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 3681203134Sthompsa 3682209917Sthompsa return (0); 3683203134Sthompsa} 3684203134Sthompsa 3685203134Sthompsastatic int 3686203134Sthompsarun_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 3687203134Sthompsa const struct ieee80211_bpf_params *params) 3688203134Sthompsa{ 3689203134Sthompsa struct ifnet *ifp = ni->ni_ic->ic_ifp; 3690203134Sthompsa struct run_softc *sc = ifp->if_softc; 3691208019Sthompsa int error = 0; 3692208019Sthompsa 3693203134Sthompsa RUN_LOCK(sc); 3694203134Sthompsa 3695203134Sthompsa /* prevent management frames from being sent if we're not ready */ 3696203134Sthompsa if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 3697203134Sthompsa error = ENETDOWN; 3698208019Sthompsa goto done; 3699203134Sthompsa } 3700203134Sthompsa 3701203134Sthompsa if (params == NULL) { 3702203134Sthompsa /* tx mgt packet */ 3703209917Sthompsa if ((error = run_tx_mgt(sc, m, ni)) != 0) { 3704203134Sthompsa ifp->if_oerrors++; 3705203134Sthompsa DPRINTF("mgt tx failed\n"); 3706208019Sthompsa goto done; 3707203134Sthompsa } 3708203134Sthompsa } else { 3709203134Sthompsa /* tx raw packet with param */ 3710209917Sthompsa if ((error = run_tx_param(sc, m, ni, params)) != 0) { 3711203134Sthompsa ifp->if_oerrors++; 3712203134Sthompsa DPRINTF("tx with param failed\n"); 3713208019Sthompsa goto done; 3714203134Sthompsa } 3715203134Sthompsa } 3716203134Sthompsa 3717203134Sthompsa ifp->if_opackets++; 3718203134Sthompsa 3719208019Sthompsadone: 3720203134Sthompsa RUN_UNLOCK(sc); 3721203134Sthompsa 3722209917Sthompsa if (error != 0) { 3723208019Sthompsa if(m != NULL) 3724208019Sthompsa m_freem(m); 3725208019Sthompsa ieee80211_free_node(ni); 3726208019Sthompsa } 3727203134Sthompsa 3728203134Sthompsa return (error); 3729203134Sthompsa} 3730203134Sthompsa 3731203134Sthompsastatic void 3732203134Sthompsarun_start(struct ifnet *ifp) 3733203134Sthompsa{ 3734203134Sthompsa struct run_softc *sc = ifp->if_softc; 3735203134Sthompsa struct ieee80211_node *ni; 3736203134Sthompsa struct mbuf *m; 3737203134Sthompsa 3738203134Sthompsa RUN_LOCK(sc); 3739203134Sthompsa 3740203134Sthompsa if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 3741203134Sthompsa RUN_UNLOCK(sc); 3742203134Sthompsa return; 3743203134Sthompsa } 3744203134Sthompsa 3745203134Sthompsa for (;;) { 3746203134Sthompsa /* send data frames */ 3747203134Sthompsa IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 3748203134Sthompsa if (m == NULL) 3749203134Sthompsa break; 3750203134Sthompsa 3751203134Sthompsa ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 3752203134Sthompsa if (run_tx(sc, m, ni) != 0) { 3753203134Sthompsa IFQ_DRV_PREPEND(&ifp->if_snd, m); 3754203134Sthompsa ifp->if_drv_flags |= IFF_DRV_OACTIVE; 3755203134Sthompsa break; 3756203134Sthompsa } 3757203134Sthompsa } 3758203134Sthompsa 3759203134Sthompsa RUN_UNLOCK(sc); 3760203134Sthompsa} 3761203134Sthompsa 3762203134Sthompsastatic int 3763203134Sthompsarun_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 3764203134Sthompsa{ 3765203134Sthompsa struct run_softc *sc = ifp->if_softc; 3766203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 3767203134Sthompsa struct ifreq *ifr = (struct ifreq *) data; 3768208019Sthompsa int startall = 0; 3769246614Shselasky int error; 3770203134Sthompsa 3771246614Shselasky RUN_LOCK(sc); 3772246614Shselasky error = sc->sc_detached ? ENXIO : 0; 3773246614Shselasky RUN_UNLOCK(sc); 3774246614Shselasky if (error) 3775246614Shselasky return (error); 3776246614Shselasky 3777203134Sthompsa switch (cmd) { 3778203134Sthompsa case SIOCSIFFLAGS: 3779203134Sthompsa RUN_LOCK(sc); 3780203134Sthompsa if (ifp->if_flags & IFF_UP) { 3781203134Sthompsa if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)){ 3782208019Sthompsa startall = 1; 3783203134Sthompsa run_init_locked(sc); 3784203134Sthompsa } else 3785203134Sthompsa run_update_promisc_locked(ifp); 3786203134Sthompsa } else { 3787209917Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING && 3788209917Sthompsa (ic->ic_nrunning == 0 || sc->rvp_cnt <= 1)) { 3789208019Sthompsa run_stop(sc); 3790208019Sthompsa } 3791203134Sthompsa } 3792203134Sthompsa RUN_UNLOCK(sc); 3793209917Sthompsa if (startall) 3794208019Sthompsa ieee80211_start_all(ic); 3795203134Sthompsa break; 3796203134Sthompsa case SIOCGIFMEDIA: 3797203134Sthompsa error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); 3798203134Sthompsa break; 3799203134Sthompsa case SIOCGIFADDR: 3800203134Sthompsa error = ether_ioctl(ifp, cmd, data); 3801203134Sthompsa break; 3802203134Sthompsa default: 3803203134Sthompsa error = EINVAL; 3804203134Sthompsa break; 3805203134Sthompsa } 3806203134Sthompsa 3807203134Sthompsa return (error); 3808203134Sthompsa} 3809203134Sthompsa 3810203134Sthompsastatic void 3811261868Skevlorun_iq_calib(struct run_softc *sc, u_int chan) 3812261868Skevlo{ 3813261868Skevlo uint16_t val; 3814261868Skevlo 3815261868Skevlo /* Tx0 IQ gain. */ 3816261868Skevlo run_bbp_write(sc, 158, 0x2c); 3817261868Skevlo if (chan <= 14) 3818261868Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX0_2GHZ, &val, 1); 3819261868Skevlo else if (chan <= 64) { 3820261868Skevlo run_efuse_read(sc, 3821261868Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5GHZ, 3822261868Skevlo &val, 1); 3823261868Skevlo } else if (chan <= 138) { 3824261868Skevlo run_efuse_read(sc, 3825261868Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5GHZ, 3826261868Skevlo &val, 1); 3827261868Skevlo } else if (chan <= 165) { 3828261868Skevlo run_efuse_read(sc, 3829261868Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5GHZ, 3830261868Skevlo &val, 1); 3831261868Skevlo } else 3832261868Skevlo val = 0; 3833261868Skevlo run_bbp_write(sc, 159, val); 3834261868Skevlo 3835261868Skevlo /* Tx0 IQ phase. */ 3836261868Skevlo run_bbp_write(sc, 158, 0x2d); 3837261868Skevlo if (chan <= 14) { 3838261868Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX0_2GHZ, 3839261868Skevlo &val, 1); 3840261868Skevlo } else if (chan <= 64) { 3841261868Skevlo run_efuse_read(sc, 3842261868Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5GHZ, 3843261868Skevlo &val, 1); 3844261868Skevlo } else if (chan <= 138) { 3845261868Skevlo run_efuse_read(sc, 3846261868Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5GHZ, 3847261868Skevlo &val, 1); 3848261868Skevlo } else if (chan <= 165) { 3849261868Skevlo run_efuse_read(sc, 3850261868Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5GHZ, 3851261868Skevlo &val, 1); 3852261868Skevlo } else 3853261868Skevlo val = 0; 3854261868Skevlo run_bbp_write(sc, 159, val); 3855261868Skevlo 3856261868Skevlo /* Tx1 IQ gain. */ 3857261868Skevlo run_bbp_write(sc, 158, 0x4a); 3858261868Skevlo if (chan <= 14) { 3859261868Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX1_2GHZ, 3860261868Skevlo &val, 1); 3861261868Skevlo } else if (chan <= 64) { 3862261868Skevlo run_efuse_read(sc, 3863261868Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5GHZ, 3864261868Skevlo &val, 1); 3865261868Skevlo } else if (chan <= 138) { 3866261868Skevlo run_efuse_read(sc, 3867261868Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5GHZ, 3868261868Skevlo &val, 1); 3869261868Skevlo } else if (chan <= 165) { 3870261868Skevlo run_efuse_read(sc, 3871261868Skevlo RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5GHZ, 3872261868Skevlo &val, 1); 3873261868Skevlo } else 3874261868Skevlo val = 0; 3875261868Skevlo run_bbp_write(sc, 159, val); 3876261868Skevlo 3877261868Skevlo /* Tx1 IQ phase. */ 3878261868Skevlo run_bbp_write(sc, 158, 0x4b); 3879261868Skevlo if (chan <= 14) { 3880261868Skevlo run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX1_2GHZ, 3881261868Skevlo &val, 1); 3882261868Skevlo } else if (chan <= 64) { 3883261868Skevlo run_efuse_read(sc, 3884261868Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5GHZ, 3885261868Skevlo &val, 1); 3886261868Skevlo } else if (chan <= 138) { 3887261868Skevlo run_efuse_read(sc, 3888261868Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5GHZ, 3889261868Skevlo &val, 1); 3890261868Skevlo } else if (chan <= 165) { 3891261868Skevlo run_efuse_read(sc, 3892261868Skevlo RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5GHZ, 3893261868Skevlo &val, 1); 3894261868Skevlo } else 3895261868Skevlo val = 0; 3896261868Skevlo run_bbp_write(sc, 159, val); 3897261868Skevlo 3898261868Skevlo /* RF IQ compensation control. */ 3899261868Skevlo run_bbp_write(sc, 158, 0x04); 3900261868Skevlo run_efuse_read(sc, RT5390_EEPROM_RF_IQ_COMPENSATION_CTL, 3901261868Skevlo &val, 1); 3902261868Skevlo run_bbp_write(sc, 159, val); 3903261868Skevlo 3904261868Skevlo /* RF IQ imbalance compensation control. */ 3905261868Skevlo run_bbp_write(sc, 158, 0x03); 3906261868Skevlo run_efuse_read(sc, 3907261868Skevlo RT5390_EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CTL, &val, 1); 3908261868Skevlo run_bbp_write(sc, 159, val); 3909261868Skevlo} 3910261868Skevlo 3911261868Skevlostatic void 3912205042Sthompsarun_set_agc(struct run_softc *sc, uint8_t agc) 3913205042Sthompsa{ 3914205042Sthompsa uint8_t bbp; 3915205042Sthompsa 3916205042Sthompsa if (sc->mac_ver == 0x3572) { 3917205042Sthompsa run_bbp_read(sc, 27, &bbp); 3918205042Sthompsa bbp &= ~(0x3 << 5); 3919205042Sthompsa run_bbp_write(sc, 27, bbp | 0 << 5); /* select Rx0 */ 3920205042Sthompsa run_bbp_write(sc, 66, agc); 3921205042Sthompsa run_bbp_write(sc, 27, bbp | 1 << 5); /* select Rx1 */ 3922205042Sthompsa run_bbp_write(sc, 66, agc); 3923205042Sthompsa } else 3924205042Sthompsa run_bbp_write(sc, 66, agc); 3925205042Sthompsa} 3926205042Sthompsa 3927205042Sthompsastatic void 3928203134Sthompsarun_select_chan_group(struct run_softc *sc, int group) 3929203134Sthompsa{ 3930203134Sthompsa uint32_t tmp; 3931205042Sthompsa uint8_t agc; 3932203134Sthompsa 3933203134Sthompsa run_bbp_write(sc, 62, 0x37 - sc->lna[group]); 3934203134Sthompsa run_bbp_write(sc, 63, 0x37 - sc->lna[group]); 3935203134Sthompsa run_bbp_write(sc, 64, 0x37 - sc->lna[group]); 3936259453Shselasky if (sc->mac_ver < 0x3572) 3937259453Shselasky run_bbp_write(sc, 86, 0x00); 3938203134Sthompsa 3939261868Skevlo if (sc->mac_ver == 0x3593) { 3940261868Skevlo run_bbp_write(sc, 77, 0x98); 3941261868Skevlo run_bbp_write(sc, 83, (group == 0) ? 0x8a : 0x9a); 3942261868Skevlo } 3943261868Skevlo 3944203134Sthompsa if (group == 0) { 3945203134Sthompsa if (sc->ext_2ghz_lna) { 3946259453Shselasky if (sc->mac_ver >= 0x5390) 3947259453Shselasky run_bbp_write(sc, 75, 0x52); 3948259453Shselasky else { 3949259453Shselasky run_bbp_write(sc, 82, 0x62); 3950259453Shselasky run_bbp_write(sc, 75, 0x46); 3951259453Shselasky } 3952203134Sthompsa } else { 3953259453Shselasky if (sc->mac_ver == 0x5592) { 3954259453Shselasky run_bbp_write(sc, 79, 0x1c); 3955259453Shselasky run_bbp_write(sc, 80, 0x0e); 3956259453Shselasky run_bbp_write(sc, 81, 0x3a); 3957259453Shselasky run_bbp_write(sc, 82, 0x62); 3958259453Shselasky 3959259453Shselasky run_bbp_write(sc, 195, 0x80); 3960259453Shselasky run_bbp_write(sc, 196, 0xe0); 3961259453Shselasky run_bbp_write(sc, 195, 0x81); 3962259453Shselasky run_bbp_write(sc, 196, 0x1f); 3963259453Shselasky run_bbp_write(sc, 195, 0x82); 3964259453Shselasky run_bbp_write(sc, 196, 0x38); 3965259453Shselasky run_bbp_write(sc, 195, 0x83); 3966259453Shselasky run_bbp_write(sc, 196, 0x32); 3967259453Shselasky run_bbp_write(sc, 195, 0x85); 3968259453Shselasky run_bbp_write(sc, 196, 0x28); 3969259453Shselasky run_bbp_write(sc, 195, 0x86); 3970259453Shselasky run_bbp_write(sc, 196, 0x19); 3971259453Shselasky } else if (sc->mac_ver >= 0x5390) 3972259453Shselasky run_bbp_write(sc, 75, 0x50); 3973259453Shselasky else { 3974261868Skevlo run_bbp_write(sc, 82, 3975261868Skevlo (sc->mac_ver == 0x3593) ? 0x62 : 0x84); 3976259453Shselasky run_bbp_write(sc, 75, 0x50); 3977259453Shselasky } 3978203134Sthompsa } 3979203134Sthompsa } else { 3980259453Shselasky if (sc->mac_ver == 0x5592) { 3981259453Shselasky run_bbp_write(sc, 79, 0x18); 3982259453Shselasky run_bbp_write(sc, 80, 0x08); 3983259453Shselasky run_bbp_write(sc, 81, 0x38); 3984259453Shselasky run_bbp_write(sc, 82, 0x92); 3985259453Shselasky 3986259453Shselasky run_bbp_write(sc, 195, 0x80); 3987259453Shselasky run_bbp_write(sc, 196, 0xf0); 3988259453Shselasky run_bbp_write(sc, 195, 0x81); 3989259453Shselasky run_bbp_write(sc, 196, 0x1e); 3990259453Shselasky run_bbp_write(sc, 195, 0x82); 3991259453Shselasky run_bbp_write(sc, 196, 0x28); 3992259453Shselasky run_bbp_write(sc, 195, 0x83); 3993259453Shselasky run_bbp_write(sc, 196, 0x20); 3994259453Shselasky run_bbp_write(sc, 195, 0x85); 3995259453Shselasky run_bbp_write(sc, 196, 0x7f); 3996259453Shselasky run_bbp_write(sc, 195, 0x86); 3997259453Shselasky run_bbp_write(sc, 196, 0x7f); 3998259453Shselasky } else if (sc->mac_ver == 0x3572) 3999205042Sthompsa run_bbp_write(sc, 82, 0x94); 4000205042Sthompsa else 4001261868Skevlo run_bbp_write(sc, 82, 4002261868Skevlo (sc->mac_ver == 0x3593) ? 0x82 : 0xf2); 4003205042Sthompsa if (sc->ext_5ghz_lna) 4004203134Sthompsa run_bbp_write(sc, 75, 0x46); 4005205042Sthompsa else 4006203134Sthompsa run_bbp_write(sc, 75, 0x50); 4007203134Sthompsa } 4008203134Sthompsa 4009203134Sthompsa run_read(sc, RT2860_TX_BAND_CFG, &tmp); 4010203134Sthompsa tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P); 4011203134Sthompsa tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P; 4012203134Sthompsa run_write(sc, RT2860_TX_BAND_CFG, tmp); 4013203134Sthompsa 4014203134Sthompsa /* enable appropriate Power Amplifiers and Low Noise Amplifiers */ 4015208019Sthompsa tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN; 4016261868Skevlo if (sc->mac_ver == 0x3593) 4017261868Skevlo tmp |= 1 << 29 | 1 << 28; 4018208019Sthompsa if (sc->nrxchains > 1) 4019208019Sthompsa tmp |= RT2860_LNA_PE1_EN; 4020203134Sthompsa if (group == 0) { /* 2GHz */ 4021208019Sthompsa tmp |= RT2860_PA_PE_G0_EN; 4022203134Sthompsa if (sc->ntxchains > 1) 4023203134Sthompsa tmp |= RT2860_PA_PE_G1_EN; 4024261868Skevlo if (sc->mac_ver == 0x3593) { 4025261868Skevlo if (sc->ntxchains > 2) 4026261868Skevlo tmp |= 1 << 25; 4027261868Skevlo } 4028203134Sthompsa } else { /* 5GHz */ 4029208019Sthompsa tmp |= RT2860_PA_PE_A0_EN; 4030203134Sthompsa if (sc->ntxchains > 1) 4031203134Sthompsa tmp |= RT2860_PA_PE_A1_EN; 4032203134Sthompsa } 4033205042Sthompsa if (sc->mac_ver == 0x3572) { 4034205042Sthompsa run_rt3070_rf_write(sc, 8, 0x00); 4035205042Sthompsa run_write(sc, RT2860_TX_PIN_CFG, tmp); 4036205042Sthompsa run_rt3070_rf_write(sc, 8, 0x80); 4037205042Sthompsa } else 4038205042Sthompsa run_write(sc, RT2860_TX_PIN_CFG, tmp); 4039203134Sthompsa 4040259453Shselasky if (sc->mac_ver == 0x5592) { 4041259453Shselasky run_bbp_write(sc, 195, 0x8d); 4042259453Shselasky run_bbp_write(sc, 196, 0x1a); 4043259453Shselasky } 4044259453Shselasky 4045261868Skevlo if (sc->mac_ver == 0x3593) { 4046261868Skevlo run_read(sc, RT2860_GPIO_CTRL, &tmp); 4047261868Skevlo tmp &= ~0x01010000; 4048261868Skevlo if (group == 0) 4049261868Skevlo tmp |= 0x00010000; 4050261868Skevlo tmp = (tmp & ~0x00009090) | 0x00000090; 4051261868Skevlo run_write(sc, RT2860_GPIO_CTRL, tmp); 4052261868Skevlo } 4053261868Skevlo 4054203134Sthompsa /* set initial AGC value */ 4055205042Sthompsa if (group == 0) { /* 2GHz band */ 4056205042Sthompsa if (sc->mac_ver >= 0x3070) 4057205042Sthompsa agc = 0x1c + sc->lna[0] * 2; 4058205042Sthompsa else 4059205042Sthompsa agc = 0x2e + sc->lna[0]; 4060205042Sthompsa } else { /* 5GHz band */ 4061259453Shselasky if (sc->mac_ver == 0x5592) 4062259453Shselasky agc = 0x24 + sc->lna[group] * 2; 4063261868Skevlo else if (sc->mac_ver == 0x3572 || sc->mac_ver == 0x3593) 4064205042Sthompsa agc = 0x22 + (sc->lna[group] * 5) / 3; 4065205042Sthompsa else 4066205042Sthompsa agc = 0x32 + (sc->lna[group] * 5) / 3; 4067205042Sthompsa } 4068205042Sthompsa run_set_agc(sc, agc); 4069203134Sthompsa} 4070203134Sthompsa 4071203134Sthompsastatic void 4072259453Shselaskyrun_rt2870_set_chan(struct run_softc *sc, u_int chan) 4073203134Sthompsa{ 4074203134Sthompsa const struct rfprog *rfprog = rt2860_rf2850; 4075203134Sthompsa uint32_t r2, r3, r4; 4076203134Sthompsa int8_t txpow1, txpow2; 4077203134Sthompsa int i; 4078203134Sthompsa 4079203134Sthompsa /* find the settings for this channel (we know it exists) */ 4080203134Sthompsa for (i = 0; rfprog[i].chan != chan; i++); 4081203134Sthompsa 4082203134Sthompsa r2 = rfprog[i].r2; 4083203134Sthompsa if (sc->ntxchains == 1) 4084259453Shselasky r2 |= 1 << 14; /* 1T: disable Tx chain 2 */ 4085203134Sthompsa if (sc->nrxchains == 1) 4086259453Shselasky r2 |= 1 << 17 | 1 << 6; /* 1R: disable Rx chains 2 & 3 */ 4087203134Sthompsa else if (sc->nrxchains == 2) 4088259453Shselasky r2 |= 1 << 6; /* 2R: disable Rx chain 3 */ 4089203134Sthompsa 4090203134Sthompsa /* use Tx power values from EEPROM */ 4091203134Sthompsa txpow1 = sc->txpow1[i]; 4092203134Sthompsa txpow2 = sc->txpow2[i]; 4093259453Shselasky 4094259453Shselasky /* Initialize RF R3 and R4. */ 4095259453Shselasky r3 = rfprog[i].r3 & 0xffffc1ff; 4096259453Shselasky r4 = (rfprog[i].r4 & ~(0x001f87c0)) | (sc->freq << 15); 4097203134Sthompsa if (chan > 14) { 4098259453Shselasky if (txpow1 >= 0) { 4099259453Shselasky txpow1 = (txpow1 > 0xf) ? (0xf) : (txpow1); 4100259453Shselasky r3 |= (txpow1 << 10) | (1 << 9); 4101259453Shselasky } else { 4102259453Shselasky txpow1 += 7; 4103259453Shselasky 4104259453Shselasky /* txpow1 is not possible larger than 15. */ 4105259453Shselasky r3 |= (txpow1 << 10); 4106259453Shselasky } 4107259453Shselasky if (txpow2 >= 0) { 4108259453Shselasky txpow2 = (txpow2 > 0xf) ? (0xf) : (txpow2); 4109259453Shselasky r4 |= (txpow2 << 7) | (1 << 6); 4110259453Shselasky } else { 4111259453Shselasky txpow2 += 7; 4112259453Shselasky r4 |= (txpow2 << 7); 4113259453Shselasky } 4114259453Shselasky } else { 4115259453Shselasky /* Set Tx0 power. */ 4116259453Shselasky r3 |= (txpow1 << 9); 4117259453Shselasky 4118259453Shselasky /* Set frequency offset and Tx1 power. */ 4119259453Shselasky r4 |= (txpow2 << 6); 4120203134Sthompsa } 4121203134Sthompsa 4122259453Shselasky run_rt2870_rf_write(sc, rfprog[i].r1); 4123259453Shselasky run_rt2870_rf_write(sc, r2); 4124259453Shselasky run_rt2870_rf_write(sc, r3 & ~(1 << 2)); 4125259453Shselasky run_rt2870_rf_write(sc, r4); 4126203134Sthompsa 4127203134Sthompsa run_delay(sc, 10); 4128203134Sthompsa 4129259453Shselasky run_rt2870_rf_write(sc, rfprog[i].r1); 4130259453Shselasky run_rt2870_rf_write(sc, r2); 4131259453Shselasky run_rt2870_rf_write(sc, r3 | (1 << 2)); 4132259453Shselasky run_rt2870_rf_write(sc, r4); 4133203134Sthompsa 4134203134Sthompsa run_delay(sc, 10); 4135203134Sthompsa 4136259453Shselasky run_rt2870_rf_write(sc, rfprog[i].r1); 4137259453Shselasky run_rt2870_rf_write(sc, r2); 4138259453Shselasky run_rt2870_rf_write(sc, r3 & ~(1 << 2)); 4139259453Shselasky run_rt2870_rf_write(sc, r4); 4140203134Sthompsa} 4141203134Sthompsa 4142203134Sthompsastatic void 4143259453Shselaskyrun_rt3070_set_chan(struct run_softc *sc, u_int chan) 4144203134Sthompsa{ 4145203134Sthompsa int8_t txpow1, txpow2; 4146203134Sthompsa uint8_t rf; 4147205042Sthompsa int i; 4148203134Sthompsa 4149205042Sthompsa /* find the settings for this channel (we know it exists) */ 4150205042Sthompsa for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4151205042Sthompsa 4152203134Sthompsa /* use Tx power values from EEPROM */ 4153205042Sthompsa txpow1 = sc->txpow1[i]; 4154205042Sthompsa txpow2 = sc->txpow2[i]; 4155203134Sthompsa 4156205042Sthompsa run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n); 4157259453Shselasky 4158259453Shselasky /* RT3370/RT3390: RF R3 [7:4] is not reserved bits. */ 4159259453Shselasky run_rt3070_rf_read(sc, 3, &rf); 4160259453Shselasky rf = (rf & ~0x0f) | rt3070_freqs[i].k; 4161259453Shselasky run_rt3070_rf_write(sc, 3, rf); 4162259453Shselasky 4163203134Sthompsa run_rt3070_rf_read(sc, 6, &rf); 4164205042Sthompsa rf = (rf & ~0x03) | rt3070_freqs[i].r; 4165203134Sthompsa run_rt3070_rf_write(sc, 6, rf); 4166203134Sthompsa 4167203134Sthompsa /* set Tx0 power */ 4168203134Sthompsa run_rt3070_rf_read(sc, 12, &rf); 4169203134Sthompsa rf = (rf & ~0x1f) | txpow1; 4170203134Sthompsa run_rt3070_rf_write(sc, 12, rf); 4171203134Sthompsa 4172203134Sthompsa /* set Tx1 power */ 4173203134Sthompsa run_rt3070_rf_read(sc, 13, &rf); 4174203134Sthompsa rf = (rf & ~0x1f) | txpow2; 4175203134Sthompsa run_rt3070_rf_write(sc, 13, rf); 4176203134Sthompsa 4177203134Sthompsa run_rt3070_rf_read(sc, 1, &rf); 4178203134Sthompsa rf &= ~0xfc; 4179203134Sthompsa if (sc->ntxchains == 1) 4180203134Sthompsa rf |= 1 << 7 | 1 << 5; /* 1T: disable Tx chains 2 & 3 */ 4181203134Sthompsa else if (sc->ntxchains == 2) 4182203134Sthompsa rf |= 1 << 7; /* 2T: disable Tx chain 3 */ 4183203134Sthompsa if (sc->nrxchains == 1) 4184203134Sthompsa rf |= 1 << 6 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 4185203134Sthompsa else if (sc->nrxchains == 2) 4186203134Sthompsa rf |= 1 << 6; /* 2R: disable Rx chain 3 */ 4187203134Sthompsa run_rt3070_rf_write(sc, 1, rf); 4188203134Sthompsa 4189203134Sthompsa /* set RF offset */ 4190203134Sthompsa run_rt3070_rf_read(sc, 23, &rf); 4191203134Sthompsa rf = (rf & ~0x7f) | sc->freq; 4192203134Sthompsa run_rt3070_rf_write(sc, 23, rf); 4193203134Sthompsa 4194203134Sthompsa /* program RF filter */ 4195205042Sthompsa run_rt3070_rf_read(sc, 24, &rf); /* Tx */ 4196205042Sthompsa rf = (rf & ~0x3f) | sc->rf24_20mhz; 4197205042Sthompsa run_rt3070_rf_write(sc, 24, rf); 4198205042Sthompsa run_rt3070_rf_read(sc, 31, &rf); /* Rx */ 4199205042Sthompsa rf = (rf & ~0x3f) | sc->rf24_20mhz; 4200205042Sthompsa run_rt3070_rf_write(sc, 31, rf); 4201203134Sthompsa 4202203134Sthompsa /* enable RF tuning */ 4203203134Sthompsa run_rt3070_rf_read(sc, 7, &rf); 4204203134Sthompsa run_rt3070_rf_write(sc, 7, rf | 0x01); 4205203134Sthompsa} 4206203134Sthompsa 4207203134Sthompsastatic void 4208205042Sthompsarun_rt3572_set_chan(struct run_softc *sc, u_int chan) 4209205042Sthompsa{ 4210205042Sthompsa int8_t txpow1, txpow2; 4211205042Sthompsa uint32_t tmp; 4212205042Sthompsa uint8_t rf; 4213205042Sthompsa int i; 4214205042Sthompsa 4215205042Sthompsa /* find the settings for this channel (we know it exists) */ 4216205042Sthompsa for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4217205042Sthompsa 4218205042Sthompsa /* use Tx power values from EEPROM */ 4219205042Sthompsa txpow1 = sc->txpow1[i]; 4220205042Sthompsa txpow2 = sc->txpow2[i]; 4221205042Sthompsa 4222205042Sthompsa if (chan <= 14) { 4223205042Sthompsa run_bbp_write(sc, 25, sc->bbp25); 4224205042Sthompsa run_bbp_write(sc, 26, sc->bbp26); 4225205042Sthompsa } else { 4226205042Sthompsa /* enable IQ phase correction */ 4227205042Sthompsa run_bbp_write(sc, 25, 0x09); 4228205042Sthompsa run_bbp_write(sc, 26, 0xff); 4229205042Sthompsa } 4230205042Sthompsa 4231205042Sthompsa run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n); 4232205042Sthompsa run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k); 4233205042Sthompsa run_rt3070_rf_read(sc, 6, &rf); 4234205042Sthompsa rf = (rf & ~0x0f) | rt3070_freqs[i].r; 4235205042Sthompsa rf |= (chan <= 14) ? 0x08 : 0x04; 4236205042Sthompsa run_rt3070_rf_write(sc, 6, rf); 4237205042Sthompsa 4238205042Sthompsa /* set PLL mode */ 4239205042Sthompsa run_rt3070_rf_read(sc, 5, &rf); 4240205042Sthompsa rf &= ~(0x08 | 0x04); 4241205042Sthompsa rf |= (chan <= 14) ? 0x04 : 0x08; 4242205042Sthompsa run_rt3070_rf_write(sc, 5, rf); 4243205042Sthompsa 4244205042Sthompsa /* set Tx power for chain 0 */ 4245205042Sthompsa if (chan <= 14) 4246205042Sthompsa rf = 0x60 | txpow1; 4247205042Sthompsa else 4248205042Sthompsa rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3); 4249205042Sthompsa run_rt3070_rf_write(sc, 12, rf); 4250205042Sthompsa 4251205042Sthompsa /* set Tx power for chain 1 */ 4252205042Sthompsa if (chan <= 14) 4253205042Sthompsa rf = 0x60 | txpow2; 4254205042Sthompsa else 4255205042Sthompsa rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3); 4256205042Sthompsa run_rt3070_rf_write(sc, 13, rf); 4257205042Sthompsa 4258205042Sthompsa /* set Tx/Rx streams */ 4259205042Sthompsa run_rt3070_rf_read(sc, 1, &rf); 4260205042Sthompsa rf &= ~0xfc; 4261205042Sthompsa if (sc->ntxchains == 1) 4262205042Sthompsa rf |= 1 << 7 | 1 << 5; /* 1T: disable Tx chains 2 & 3 */ 4263205042Sthompsa else if (sc->ntxchains == 2) 4264205042Sthompsa rf |= 1 << 7; /* 2T: disable Tx chain 3 */ 4265205042Sthompsa if (sc->nrxchains == 1) 4266205042Sthompsa rf |= 1 << 6 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 4267205042Sthompsa else if (sc->nrxchains == 2) 4268205042Sthompsa rf |= 1 << 6; /* 2R: disable Rx chain 3 */ 4269205042Sthompsa run_rt3070_rf_write(sc, 1, rf); 4270205042Sthompsa 4271205042Sthompsa /* set RF offset */ 4272205042Sthompsa run_rt3070_rf_read(sc, 23, &rf); 4273205042Sthompsa rf = (rf & ~0x7f) | sc->freq; 4274205042Sthompsa run_rt3070_rf_write(sc, 23, rf); 4275205042Sthompsa 4276205042Sthompsa /* program RF filter */ 4277205042Sthompsa rf = sc->rf24_20mhz; 4278205042Sthompsa run_rt3070_rf_write(sc, 24, rf); /* Tx */ 4279205042Sthompsa run_rt3070_rf_write(sc, 31, rf); /* Rx */ 4280205042Sthompsa 4281205042Sthompsa /* enable RF tuning */ 4282205042Sthompsa run_rt3070_rf_read(sc, 7, &rf); 4283205042Sthompsa rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14); 4284205042Sthompsa run_rt3070_rf_write(sc, 7, rf); 4285205042Sthompsa 4286205042Sthompsa /* TSSI */ 4287205042Sthompsa rf = (chan <= 14) ? 0xc3 : 0xc0; 4288205042Sthompsa run_rt3070_rf_write(sc, 9, rf); 4289205042Sthompsa 4290205042Sthompsa /* set loop filter 1 */ 4291205042Sthompsa run_rt3070_rf_write(sc, 10, 0xf1); 4292205042Sthompsa /* set loop filter 2 */ 4293205042Sthompsa run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00); 4294205042Sthompsa 4295205042Sthompsa /* set tx_mx2_ic */ 4296205042Sthompsa run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43); 4297205042Sthompsa /* set tx_mx1_ic */ 4298205042Sthompsa if (chan <= 14) 4299205042Sthompsa rf = 0x48 | sc->txmixgain_2ghz; 4300205042Sthompsa else 4301205042Sthompsa rf = 0x78 | sc->txmixgain_5ghz; 4302205042Sthompsa run_rt3070_rf_write(sc, 16, rf); 4303205042Sthompsa 4304205042Sthompsa /* set tx_lo1 */ 4305205042Sthompsa run_rt3070_rf_write(sc, 17, 0x23); 4306205042Sthompsa /* set tx_lo2 */ 4307205042Sthompsa if (chan <= 14) 4308205042Sthompsa rf = 0x93; 4309205042Sthompsa else if (chan <= 64) 4310205042Sthompsa rf = 0xb7; 4311205042Sthompsa else if (chan <= 128) 4312205042Sthompsa rf = 0x74; 4313205042Sthompsa else 4314205042Sthompsa rf = 0x72; 4315205042Sthompsa run_rt3070_rf_write(sc, 19, rf); 4316205042Sthompsa 4317205042Sthompsa /* set rx_lo1 */ 4318205042Sthompsa if (chan <= 14) 4319205042Sthompsa rf = 0xb3; 4320205042Sthompsa else if (chan <= 64) 4321205042Sthompsa rf = 0xf6; 4322205042Sthompsa else if (chan <= 128) 4323205042Sthompsa rf = 0xf4; 4324205042Sthompsa else 4325205042Sthompsa rf = 0xf3; 4326205042Sthompsa run_rt3070_rf_write(sc, 20, rf); 4327205042Sthompsa 4328205042Sthompsa /* set pfd_delay */ 4329205042Sthompsa if (chan <= 14) 4330205042Sthompsa rf = 0x15; 4331205042Sthompsa else if (chan <= 64) 4332205042Sthompsa rf = 0x3d; 4333205042Sthompsa else 4334205042Sthompsa rf = 0x01; 4335205042Sthompsa run_rt3070_rf_write(sc, 25, rf); 4336205042Sthompsa 4337205042Sthompsa /* set rx_lo2 */ 4338205042Sthompsa run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87); 4339205042Sthompsa /* set ldo_rf_vc */ 4340205042Sthompsa run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01); 4341205042Sthompsa /* set drv_cc */ 4342205042Sthompsa run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f); 4343205042Sthompsa 4344205042Sthompsa run_read(sc, RT2860_GPIO_CTRL, &tmp); 4345205042Sthompsa tmp &= ~0x8080; 4346205042Sthompsa if (chan <= 14) 4347205042Sthompsa tmp |= 0x80; 4348205042Sthompsa run_write(sc, RT2860_GPIO_CTRL, tmp); 4349205042Sthompsa 4350205042Sthompsa /* enable RF tuning */ 4351205042Sthompsa run_rt3070_rf_read(sc, 7, &rf); 4352205042Sthompsa run_rt3070_rf_write(sc, 7, rf | 0x01); 4353205042Sthompsa 4354205042Sthompsa run_delay(sc, 2); 4355205042Sthompsa} 4356205042Sthompsa 4357205042Sthompsastatic void 4358261868Skevlorun_rt3593_set_chan(struct run_softc *sc, u_int chan) 4359261868Skevlo{ 4360261868Skevlo int8_t txpow1, txpow2, txpow3; 4361261868Skevlo uint8_t h20mhz, rf; 4362261868Skevlo int i; 4363261868Skevlo 4364261868Skevlo /* find the settings for this channel (we know it exists) */ 4365261868Skevlo for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4366261868Skevlo 4367261868Skevlo /* use Tx power values from EEPROM */ 4368261868Skevlo txpow1 = sc->txpow1[i]; 4369261868Skevlo txpow2 = sc->txpow2[i]; 4370261868Skevlo txpow3 = (sc->ntxchains == 3) ? sc->txpow3[i] : 0; 4371261868Skevlo 4372261868Skevlo if (chan <= 14) { 4373261868Skevlo run_bbp_write(sc, 25, sc->bbp25); 4374261868Skevlo run_bbp_write(sc, 26, sc->bbp26); 4375261868Skevlo } else { 4376261868Skevlo /* Enable IQ phase correction. */ 4377261868Skevlo run_bbp_write(sc, 25, 0x09); 4378261868Skevlo run_bbp_write(sc, 26, 0xff); 4379261868Skevlo } 4380261868Skevlo 4381261868Skevlo run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n); 4382261868Skevlo run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f); 4383261868Skevlo run_rt3070_rf_read(sc, 11, &rf); 4384261868Skevlo rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03); 4385261868Skevlo run_rt3070_rf_write(sc, 11, rf); 4386261868Skevlo 4387261868Skevlo /* Set pll_idoh. */ 4388261868Skevlo run_rt3070_rf_read(sc, 11, &rf); 4389261868Skevlo rf &= ~0x4c; 4390261868Skevlo rf |= (chan <= 14) ? 0x44 : 0x48; 4391261868Skevlo run_rt3070_rf_write(sc, 11, rf); 4392261868Skevlo 4393261868Skevlo if (chan <= 14) 4394261868Skevlo rf = txpow1 & 0x1f; 4395261868Skevlo else 4396261868Skevlo rf = 0x40 | ((txpow1 & 0x18) << 1) | (txpow1 & 0x07); 4397261868Skevlo run_rt3070_rf_write(sc, 53, rf); 4398261868Skevlo 4399261868Skevlo if (chan <= 14) 4400261868Skevlo rf = txpow2 & 0x1f; 4401261868Skevlo else 4402261868Skevlo rf = 0x40 | ((txpow2 & 0x18) << 1) | (txpow2 & 0x07); 4403261868Skevlo run_rt3070_rf_write(sc, 55, rf); 4404261868Skevlo 4405261868Skevlo if (chan <= 14) 4406261868Skevlo rf = txpow3 & 0x1f; 4407261868Skevlo else 4408261868Skevlo rf = 0x40 | ((txpow3 & 0x18) << 1) | (txpow3 & 0x07); 4409261868Skevlo run_rt3070_rf_write(sc, 54, rf); 4410261868Skevlo 4411261868Skevlo rf = RT3070_RF_BLOCK | RT3070_PLL_PD; 4412261868Skevlo if (sc->ntxchains == 3) 4413261868Skevlo rf |= RT3070_TX0_PD | RT3070_TX1_PD | RT3070_TX2_PD; 4414261868Skevlo else 4415261868Skevlo rf |= RT3070_TX0_PD | RT3070_TX1_PD; 4416261868Skevlo rf |= RT3070_RX0_PD | RT3070_RX1_PD | RT3070_RX2_PD; 4417261868Skevlo run_rt3070_rf_write(sc, 1, rf); 4418261868Skevlo 4419261868Skevlo run_adjust_freq_offset(sc); 4420261868Skevlo 4421261868Skevlo run_rt3070_rf_write(sc, 31, (chan <= 14) ? 0xa0 : 0x80); 4422261868Skevlo 4423261868Skevlo h20mhz = (sc->rf24_20mhz & 0x20) >> 5; 4424261868Skevlo run_rt3070_rf_read(sc, 30, &rf); 4425261868Skevlo rf = (rf & ~0x06) | (h20mhz << 1) | (h20mhz << 2); 4426261868Skevlo run_rt3070_rf_write(sc, 30, rf); 4427261868Skevlo 4428261868Skevlo run_rt3070_rf_read(sc, 36, &rf); 4429261868Skevlo if (chan <= 14) 4430261868Skevlo rf |= 0x80; 4431261868Skevlo else 4432261868Skevlo rf &= ~0x80; 4433261868Skevlo run_rt3070_rf_write(sc, 36, rf); 4434261868Skevlo 4435261868Skevlo /* Set vcolo_bs. */ 4436261868Skevlo run_rt3070_rf_write(sc, 34, (chan <= 14) ? 0x3c : 0x20); 4437261868Skevlo /* Set pfd_delay. */ 4438261868Skevlo run_rt3070_rf_write(sc, 12, (chan <= 14) ? 0x1a : 0x12); 4439261868Skevlo 4440261868Skevlo /* Set vco bias current control. */ 4441261868Skevlo run_rt3070_rf_read(sc, 6, &rf); 4442261868Skevlo rf &= ~0xc0; 4443261868Skevlo if (chan <= 14) 4444261868Skevlo rf |= 0x40; 4445261868Skevlo else if (chan <= 128) 4446261868Skevlo rf |= 0x80; 4447261868Skevlo else 4448261868Skevlo rf |= 0x40; 4449261868Skevlo run_rt3070_rf_write(sc, 6, rf); 4450261868Skevlo 4451261868Skevlo run_rt3070_rf_read(sc, 30, &rf); 4452261868Skevlo rf = (rf & ~0x18) | 0x10; 4453261868Skevlo run_rt3070_rf_write(sc, 30, rf); 4454261868Skevlo 4455261868Skevlo run_rt3070_rf_write(sc, 10, (chan <= 14) ? 0xd3 : 0xd8); 4456261868Skevlo run_rt3070_rf_write(sc, 13, (chan <= 14) ? 0x12 : 0x23); 4457261868Skevlo 4458261868Skevlo run_rt3070_rf_read(sc, 51, &rf); 4459261868Skevlo rf = (rf & ~0x03) | 0x01; 4460261868Skevlo run_rt3070_rf_write(sc, 51, rf); 4461261868Skevlo /* Set tx_mx1_cc. */ 4462261868Skevlo run_rt3070_rf_read(sc, 51, &rf); 4463261868Skevlo rf &= ~0x1c; 4464261868Skevlo rf |= (chan <= 14) ? 0x14 : 0x10; 4465261868Skevlo run_rt3070_rf_write(sc, 51, rf); 4466261868Skevlo /* Set tx_mx1_ic. */ 4467261868Skevlo run_rt3070_rf_read(sc, 51, &rf); 4468261868Skevlo rf &= ~0xe0; 4469261868Skevlo rf |= (chan <= 14) ? 0x60 : 0x40; 4470261868Skevlo run_rt3070_rf_write(sc, 51, rf); 4471261868Skevlo /* Set tx_lo1_ic. */ 4472261868Skevlo run_rt3070_rf_read(sc, 49, &rf); 4473261868Skevlo rf &= ~0x1c; 4474261868Skevlo rf |= (chan <= 14) ? 0x0c : 0x08; 4475261868Skevlo run_rt3070_rf_write(sc, 49, rf); 4476261868Skevlo /* Set tx_lo1_en. */ 4477261868Skevlo run_rt3070_rf_read(sc, 50, &rf); 4478261868Skevlo run_rt3070_rf_write(sc, 50, rf & ~0x20); 4479261868Skevlo /* Set drv_cc. */ 4480261868Skevlo run_rt3070_rf_read(sc, 57, &rf); 4481261868Skevlo rf &= ~0xfc; 4482261868Skevlo rf |= (chan <= 14) ? 0x6c : 0x3c; 4483261868Skevlo run_rt3070_rf_write(sc, 57, rf); 4484261868Skevlo /* Set rx_mix1_ic, rxa_lnactr, lna_vc, lna_inbias_en and lna_en. */ 4485261868Skevlo run_rt3070_rf_write(sc, 44, (chan <= 14) ? 0x93 : 0x9b); 4486261868Skevlo /* Set drv_gnd_a, tx_vga_cc_a and tx_mx2_gain. */ 4487261868Skevlo run_rt3070_rf_write(sc, 52, (chan <= 14) ? 0x45 : 0x05); 4488261868Skevlo /* Enable VCO calibration. */ 4489261868Skevlo run_rt3070_rf_read(sc, 3, &rf); 4490261868Skevlo rf &= ~RT5390_VCOCAL; 4491261868Skevlo rf |= (chan <= 14) ? RT5390_VCOCAL : 0xbe; 4492261868Skevlo run_rt3070_rf_write(sc, 3, rf); 4493261868Skevlo 4494261868Skevlo if (chan <= 14) 4495261868Skevlo rf = 0x23; 4496261868Skevlo else if (chan <= 64) 4497261868Skevlo rf = 0x36; 4498261868Skevlo else if (chan <= 128) 4499261868Skevlo rf = 0x32; 4500261868Skevlo else 4501261868Skevlo rf = 0x30; 4502261868Skevlo run_rt3070_rf_write(sc, 39, rf); 4503261868Skevlo if (chan <= 14) 4504261868Skevlo rf = 0xbb; 4505261868Skevlo else if (chan <= 64) 4506261868Skevlo rf = 0xeb; 4507261868Skevlo else if (chan <= 128) 4508261868Skevlo rf = 0xb3; 4509261868Skevlo else 4510261868Skevlo rf = 0x9b; 4511261868Skevlo run_rt3070_rf_write(sc, 45, rf); 4512261868Skevlo 4513261868Skevlo /* Set FEQ/AEQ control. */ 4514261868Skevlo run_bbp_write(sc, 105, 0x34); 4515261868Skevlo} 4516261868Skevlo 4517261868Skevlostatic void 4518259453Shselaskyrun_rt5390_set_chan(struct run_softc *sc, u_int chan) 4519259453Shselasky{ 4520259453Shselasky int8_t txpow1, txpow2; 4521259453Shselasky uint8_t rf; 4522259453Shselasky int i; 4523259453Shselasky 4524259453Shselasky /* find the settings for this channel (we know it exists) */ 4525259453Shselasky for (i = 0; rt2860_rf2850[i].chan != chan; i++); 4526259453Shselasky 4527259453Shselasky /* use Tx power values from EEPROM */ 4528259453Shselasky txpow1 = sc->txpow1[i]; 4529259453Shselasky txpow2 = sc->txpow2[i]; 4530259453Shselasky 4531259453Shselasky run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n); 4532259453Shselasky run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f); 4533259453Shselasky run_rt3070_rf_read(sc, 11, &rf); 4534259453Shselasky rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03); 4535259453Shselasky run_rt3070_rf_write(sc, 11, rf); 4536259453Shselasky 4537259453Shselasky run_rt3070_rf_read(sc, 49, &rf); 4538259453Shselasky rf = (rf & ~0x3f) | (txpow1 & 0x3f); 4539259453Shselasky /* The valid range of the RF R49 is 0x00 to 0x27. */ 4540259453Shselasky if ((rf & 0x3f) > 0x27) 4541259453Shselasky rf = (rf & ~0x3f) | 0x27; 4542259453Shselasky run_rt3070_rf_write(sc, 49, rf); 4543259453Shselasky 4544259453Shselasky if (sc->mac_ver == 0x5392) { 4545259453Shselasky run_rt3070_rf_read(sc, 50, &rf); 4546259453Shselasky rf = (rf & ~0x3f) | (txpow2 & 0x3f); 4547259453Shselasky /* The valid range of the RF R50 is 0x00 to 0x27. */ 4548259453Shselasky if ((rf & 0x3f) > 0x27) 4549259453Shselasky rf = (rf & ~0x3f) | 0x27; 4550259453Shselasky run_rt3070_rf_write(sc, 50, rf); 4551259453Shselasky } 4552259453Shselasky 4553259453Shselasky run_rt3070_rf_read(sc, 1, &rf); 4554259453Shselasky rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD; 4555259453Shselasky if (sc->mac_ver == 0x5392) 4556259453Shselasky rf |= RT3070_RX1_PD | RT3070_TX1_PD; 4557259453Shselasky run_rt3070_rf_write(sc, 1, rf); 4558259453Shselasky 4559259453Shselasky if (sc->mac_ver != 0x5392) { 4560259453Shselasky run_rt3070_rf_read(sc, 2, &rf); 4561259453Shselasky rf |= 0x80; 4562259453Shselasky run_rt3070_rf_write(sc, 2, rf); 4563259453Shselasky run_delay(sc, 10); 4564259453Shselasky rf &= 0x7f; 4565259453Shselasky run_rt3070_rf_write(sc, 2, rf); 4566259453Shselasky } 4567259453Shselasky 4568259453Shselasky run_adjust_freq_offset(sc); 4569259453Shselasky 4570259453Shselasky if (sc->mac_ver == 0x5392) { 4571259453Shselasky /* Fix for RT5392C. */ 4572259453Shselasky if (sc->mac_rev >= 0x0223) { 4573259453Shselasky if (chan <= 4) 4574259453Shselasky rf = 0x0f; 4575259453Shselasky else if (chan >= 5 && chan <= 7) 4576259453Shselasky rf = 0x0e; 4577259453Shselasky else 4578259453Shselasky rf = 0x0d; 4579259453Shselasky run_rt3070_rf_write(sc, 23, rf); 4580259453Shselasky 4581259453Shselasky if (chan <= 4) 4582259453Shselasky rf = 0x0c; 4583259453Shselasky else if (chan == 5) 4584259453Shselasky rf = 0x0b; 4585259453Shselasky else if (chan >= 6 && chan <= 7) 4586259453Shselasky rf = 0x0a; 4587259453Shselasky else if (chan >= 8 && chan <= 10) 4588259453Shselasky rf = 0x09; 4589259453Shselasky else 4590259453Shselasky rf = 0x08; 4591259453Shselasky run_rt3070_rf_write(sc, 59, rf); 4592259453Shselasky } else { 4593259453Shselasky if (chan <= 11) 4594259453Shselasky rf = 0x0f; 4595259453Shselasky else 4596259453Shselasky rf = 0x0b; 4597259453Shselasky run_rt3070_rf_write(sc, 59, rf); 4598259453Shselasky } 4599259453Shselasky } else { 4600259453Shselasky /* Fix for RT5390F. */ 4601259453Shselasky if (sc->mac_rev >= 0x0502) { 4602259453Shselasky if (chan <= 11) 4603259453Shselasky rf = 0x43; 4604259453Shselasky else 4605259453Shselasky rf = 0x23; 4606259453Shselasky run_rt3070_rf_write(sc, 55, rf); 4607259453Shselasky 4608259453Shselasky if (chan <= 11) 4609259453Shselasky rf = 0x0f; 4610259453Shselasky else if (chan == 12) 4611259453Shselasky rf = 0x0d; 4612259453Shselasky else 4613259453Shselasky rf = 0x0b; 4614259453Shselasky run_rt3070_rf_write(sc, 59, rf); 4615259453Shselasky } else { 4616259453Shselasky run_rt3070_rf_write(sc, 55, 0x44); 4617259453Shselasky run_rt3070_rf_write(sc, 59, 0x8f); 4618259453Shselasky } 4619259453Shselasky } 4620259453Shselasky 4621259453Shselasky /* Enable VCO calibration. */ 4622259453Shselasky run_rt3070_rf_read(sc, 3, &rf); 4623259453Shselasky rf |= RT5390_VCOCAL; 4624259453Shselasky run_rt3070_rf_write(sc, 3, rf); 4625259453Shselasky} 4626259453Shselasky 4627259453Shselaskystatic void 4628259453Shselaskyrun_rt5592_set_chan(struct run_softc *sc, u_int chan) 4629259453Shselasky{ 4630259453Shselasky const struct rt5592_freqs *freqs; 4631259453Shselasky uint32_t tmp; 4632259453Shselasky uint8_t reg, rf, txpow_bound; 4633259453Shselasky int8_t txpow1, txpow2; 4634259453Shselasky int i; 4635259453Shselasky 4636259453Shselasky run_read(sc, RT5592_DEBUG_INDEX, &tmp); 4637259453Shselasky freqs = (tmp & RT5592_SEL_XTAL) ? 4638259453Shselasky rt5592_freqs_40mhz : rt5592_freqs_20mhz; 4639259453Shselasky 4640259453Shselasky /* find the settings for this channel (we know it exists) */ 4641259453Shselasky for (i = 0; rt2860_rf2850[i].chan != chan; i++, freqs++); 4642259453Shselasky 4643259453Shselasky /* use Tx power values from EEPROM */ 4644259453Shselasky txpow1 = sc->txpow1[i]; 4645259453Shselasky txpow2 = sc->txpow2[i]; 4646259453Shselasky 4647259453Shselasky run_read(sc, RT3070_LDO_CFG0, &tmp); 4648259453Shselasky tmp &= ~0x1c000000; 4649259453Shselasky if (chan > 14) 4650259453Shselasky tmp |= 0x14000000; 4651259453Shselasky run_write(sc, RT3070_LDO_CFG0, tmp); 4652259453Shselasky 4653259453Shselasky /* N setting. */ 4654259453Shselasky run_rt3070_rf_write(sc, 8, freqs->n & 0xff); 4655259453Shselasky run_rt3070_rf_read(sc, 9, &rf); 4656259453Shselasky rf &= ~(1 << 4); 4657259453Shselasky rf |= ((freqs->n & 0x0100) >> 8) << 4; 4658259453Shselasky run_rt3070_rf_write(sc, 9, rf); 4659259453Shselasky 4660259453Shselasky /* K setting. */ 4661259453Shselasky run_rt3070_rf_read(sc, 9, &rf); 4662259453Shselasky rf &= ~0x0f; 4663259453Shselasky rf |= (freqs->k & 0x0f); 4664259453Shselasky run_rt3070_rf_write(sc, 9, rf); 4665259453Shselasky 4666259453Shselasky /* Mode setting. */ 4667259453Shselasky run_rt3070_rf_read(sc, 11, &rf); 4668259453Shselasky rf &= ~0x0c; 4669259453Shselasky rf |= ((freqs->m - 0x8) & 0x3) << 2; 4670259453Shselasky run_rt3070_rf_write(sc, 11, rf); 4671259453Shselasky run_rt3070_rf_read(sc, 9, &rf); 4672259453Shselasky rf &= ~(1 << 7); 4673259453Shselasky rf |= (((freqs->m - 0x8) & 0x4) >> 2) << 7; 4674259453Shselasky run_rt3070_rf_write(sc, 9, rf); 4675259453Shselasky 4676259453Shselasky /* R setting. */ 4677259453Shselasky run_rt3070_rf_read(sc, 11, &rf); 4678259453Shselasky rf &= ~0x03; 4679259453Shselasky rf |= (freqs->r - 0x1); 4680259453Shselasky run_rt3070_rf_write(sc, 11, rf); 4681259453Shselasky 4682259453Shselasky if (chan <= 14) { 4683259453Shselasky /* Initialize RF registers for 2GHZ. */ 4684259453Shselasky for (i = 0; i < nitems(rt5592_2ghz_def_rf); i++) { 4685259453Shselasky run_rt3070_rf_write(sc, rt5592_2ghz_def_rf[i].reg, 4686259453Shselasky rt5592_2ghz_def_rf[i].val); 4687259453Shselasky } 4688259453Shselasky 4689259453Shselasky rf = (chan <= 10) ? 0x07 : 0x06; 4690259453Shselasky run_rt3070_rf_write(sc, 23, rf); 4691259453Shselasky run_rt3070_rf_write(sc, 59, rf); 4692259453Shselasky 4693259453Shselasky run_rt3070_rf_write(sc, 55, 0x43); 4694259453Shselasky 4695259453Shselasky /* 4696259453Shselasky * RF R49/R50 Tx power ALC code. 4697259453Shselasky * G-band bit<7:6>=1:0, bit<5:0> range from 0x0 ~ 0x27. 4698259453Shselasky */ 4699259453Shselasky reg = 2; 4700259453Shselasky txpow_bound = 0x27; 4701259453Shselasky } else { 4702259453Shselasky /* Initialize RF registers for 5GHZ. */ 4703259453Shselasky for (i = 0; i < nitems(rt5592_5ghz_def_rf); i++) { 4704259453Shselasky run_rt3070_rf_write(sc, rt5592_5ghz_def_rf[i].reg, 4705259453Shselasky rt5592_5ghz_def_rf[i].val); 4706259453Shselasky } 4707259453Shselasky for (i = 0; i < nitems(rt5592_chan_5ghz); i++) { 4708259453Shselasky if (chan >= rt5592_chan_5ghz[i].firstchan && 4709259453Shselasky chan <= rt5592_chan_5ghz[i].lastchan) { 4710259453Shselasky run_rt3070_rf_write(sc, rt5592_chan_5ghz[i].reg, 4711259453Shselasky rt5592_chan_5ghz[i].val); 4712259453Shselasky } 4713259453Shselasky } 4714259453Shselasky 4715259453Shselasky /* 4716259453Shselasky * RF R49/R50 Tx power ALC code. 4717259453Shselasky * A-band bit<7:6>=1:1, bit<5:0> range from 0x0 ~ 0x2b. 4718259453Shselasky */ 4719259453Shselasky reg = 3; 4720259453Shselasky txpow_bound = 0x2b; 4721259453Shselasky } 4722259453Shselasky 4723259453Shselasky /* RF R49 ch0 Tx power ALC code. */ 4724259453Shselasky run_rt3070_rf_read(sc, 49, &rf); 4725259453Shselasky rf &= ~0xc0; 4726259453Shselasky rf |= (reg << 6); 4727259453Shselasky rf = (rf & ~0x3f) | (txpow1 & 0x3f); 4728259453Shselasky if ((rf & 0x3f) > txpow_bound) 4729259453Shselasky rf = (rf & ~0x3f) | txpow_bound; 4730259453Shselasky run_rt3070_rf_write(sc, 49, rf); 4731259453Shselasky 4732259453Shselasky /* RF R50 ch1 Tx power ALC code. */ 4733259453Shselasky run_rt3070_rf_read(sc, 50, &rf); 4734259453Shselasky rf &= ~(1 << 7 | 1 << 6); 4735259453Shselasky rf |= (reg << 6); 4736259453Shselasky rf = (rf & ~0x3f) | (txpow2 & 0x3f); 4737259453Shselasky if ((rf & 0x3f) > txpow_bound) 4738259453Shselasky rf = (rf & ~0x3f) | txpow_bound; 4739259453Shselasky run_rt3070_rf_write(sc, 50, rf); 4740259453Shselasky 4741259453Shselasky /* Enable RF_BLOCK, PLL_PD, RX0_PD, and TX0_PD. */ 4742259453Shselasky run_rt3070_rf_read(sc, 1, &rf); 4743259453Shselasky rf |= (RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD); 4744259453Shselasky if (sc->ntxchains > 1) 4745259453Shselasky rf |= RT3070_TX1_PD; 4746259453Shselasky if (sc->nrxchains > 1) 4747259453Shselasky rf |= RT3070_RX1_PD; 4748259453Shselasky run_rt3070_rf_write(sc, 1, rf); 4749259453Shselasky 4750259453Shselasky run_rt3070_rf_write(sc, 6, 0xe4); 4751259453Shselasky 4752259453Shselasky run_rt3070_rf_write(sc, 30, 0x10); 4753259453Shselasky run_rt3070_rf_write(sc, 31, 0x80); 4754259453Shselasky run_rt3070_rf_write(sc, 32, 0x80); 4755259453Shselasky 4756259453Shselasky run_adjust_freq_offset(sc); 4757259453Shselasky 4758259453Shselasky /* Enable VCO calibration. */ 4759259453Shselasky run_rt3070_rf_read(sc, 3, &rf); 4760259453Shselasky rf |= RT5390_VCOCAL; 4761259453Shselasky run_rt3070_rf_write(sc, 3, rf); 4762259453Shselasky} 4763259453Shselasky 4764259453Shselaskystatic void 4765203134Sthompsarun_set_rx_antenna(struct run_softc *sc, int aux) 4766203134Sthompsa{ 4767203134Sthompsa uint32_t tmp; 4768259453Shselasky uint8_t bbp152; 4769203134Sthompsa 4770203134Sthompsa if (aux) { 4771259453Shselasky if (sc->rf_rev == RT5390_RF_5370) { 4772259453Shselasky run_bbp_read(sc, 152, &bbp152); 4773259453Shselasky run_bbp_write(sc, 152, bbp152 & ~0x80); 4774259453Shselasky } else { 4775259453Shselasky run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0); 4776259453Shselasky run_read(sc, RT2860_GPIO_CTRL, &tmp); 4777259453Shselasky run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08); 4778259453Shselasky } 4779203134Sthompsa } else { 4780259453Shselasky if (sc->rf_rev == RT5390_RF_5370) { 4781259453Shselasky run_bbp_read(sc, 152, &bbp152); 4782259453Shselasky run_bbp_write(sc, 152, bbp152 | 0x80); 4783259453Shselasky } else { 4784259453Shselasky run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1); 4785259453Shselasky run_read(sc, RT2860_GPIO_CTRL, &tmp); 4786259453Shselasky run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808); 4787259453Shselasky } 4788203134Sthompsa } 4789203134Sthompsa} 4790203134Sthompsa 4791203134Sthompsastatic int 4792203134Sthompsarun_set_chan(struct run_softc *sc, struct ieee80211_channel *c) 4793203134Sthompsa{ 4794203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 4795259453Shselasky u_int chan, group; 4796203134Sthompsa 4797203134Sthompsa chan = ieee80211_chan2ieee(ic, c); 4798203134Sthompsa if (chan == 0 || chan == IEEE80211_CHAN_ANY) 4799209917Sthompsa return (EINVAL); 4800203134Sthompsa 4801259453Shselasky if (sc->mac_ver == 0x5592) 4802259453Shselasky run_rt5592_set_chan(sc, chan); 4803259453Shselasky else if (sc->mac_ver >= 0x5390) 4804259453Shselasky run_rt5390_set_chan(sc, chan); 4805261868Skevlo else if (sc->mac_ver == 0x3593) 4806261868Skevlo run_rt3593_set_chan(sc, chan); 4807259453Shselasky else if (sc->mac_ver == 0x3572) 4808205042Sthompsa run_rt3572_set_chan(sc, chan); 4809205042Sthompsa else if (sc->mac_ver >= 0x3070) 4810203134Sthompsa run_rt3070_set_chan(sc, chan); 4811203134Sthompsa else 4812203134Sthompsa run_rt2870_set_chan(sc, chan); 4813203134Sthompsa 4814203134Sthompsa /* determine channel group */ 4815203134Sthompsa if (chan <= 14) 4816203134Sthompsa group = 0; 4817203134Sthompsa else if (chan <= 64) 4818203134Sthompsa group = 1; 4819203134Sthompsa else if (chan <= 128) 4820203134Sthompsa group = 2; 4821203134Sthompsa else 4822203134Sthompsa group = 3; 4823203134Sthompsa 4824203134Sthompsa /* XXX necessary only when group has changed! */ 4825203134Sthompsa run_select_chan_group(sc, group); 4826203134Sthompsa 4827203134Sthompsa run_delay(sc, 10); 4828203134Sthompsa 4829261868Skevlo /* Perform IQ calibration. */ 4830261868Skevlo if (sc->mac_ver >= 0x5392) 4831261868Skevlo run_iq_calib(sc, chan); 4832261868Skevlo 4833209917Sthompsa return (0); 4834203134Sthompsa} 4835203134Sthompsa 4836203134Sthompsastatic void 4837203134Sthompsarun_set_channel(struct ieee80211com *ic) 4838203134Sthompsa{ 4839203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 4840203134Sthompsa 4841203134Sthompsa RUN_LOCK(sc); 4842203134Sthompsa run_set_chan(sc, ic->ic_curchan); 4843203134Sthompsa RUN_UNLOCK(sc); 4844203134Sthompsa 4845203134Sthompsa return; 4846203134Sthompsa} 4847203134Sthompsa 4848203134Sthompsastatic void 4849203134Sthompsarun_scan_start(struct ieee80211com *ic) 4850203134Sthompsa{ 4851203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 4852203134Sthompsa uint32_t tmp; 4853203134Sthompsa 4854203134Sthompsa RUN_LOCK(sc); 4855203134Sthompsa 4856203134Sthompsa /* abort TSF synchronization */ 4857203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 4858203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, 4859203134Sthompsa tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 4860203134Sthompsa RT2860_TBTT_TIMER_EN)); 4861203134Sthompsa run_set_bssid(sc, sc->sc_ifp->if_broadcastaddr); 4862203134Sthompsa 4863203134Sthompsa RUN_UNLOCK(sc); 4864203134Sthompsa 4865203134Sthompsa return; 4866203134Sthompsa} 4867203134Sthompsa 4868203134Sthompsastatic void 4869203134Sthompsarun_scan_end(struct ieee80211com *ic) 4870203134Sthompsa{ 4871203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 4872203134Sthompsa 4873203134Sthompsa RUN_LOCK(sc); 4874203134Sthompsa 4875203134Sthompsa run_enable_tsf_sync(sc); 4876203134Sthompsa /* XXX keep local copy */ 4877203134Sthompsa run_set_bssid(sc, sc->sc_bssid); 4878203134Sthompsa 4879203134Sthompsa RUN_UNLOCK(sc); 4880203134Sthompsa 4881203134Sthompsa return; 4882203134Sthompsa} 4883203134Sthompsa 4884208019Sthompsa/* 4885208019Sthompsa * Could be called from ieee80211_node_timeout() 4886208019Sthompsa * (non-sleepable thread) 4887208019Sthompsa */ 4888208019Sthompsastatic void 4889208019Sthompsarun_update_beacon(struct ieee80211vap *vap, int item) 4890203134Sthompsa{ 4891208019Sthompsa struct ieee80211com *ic = vap->iv_ic; 4892208019Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 4893218492Sbschmidt struct run_vap *rvp = RUN_VAP(vap); 4894218492Sbschmidt int mcast = 0; 4895208019Sthompsa uint32_t i; 4896208019Sthompsa 4897218492Sbschmidt KASSERT(vap != NULL, ("no beacon")); 4898218492Sbschmidt 4899218492Sbschmidt switch (item) { 4900218492Sbschmidt case IEEE80211_BEACON_ERP: 4901218492Sbschmidt run_updateslot(ic->ic_ifp); 4902218492Sbschmidt break; 4903218492Sbschmidt case IEEE80211_BEACON_HTINFO: 4904218492Sbschmidt run_updateprot(ic); 4905218492Sbschmidt break; 4906218492Sbschmidt case IEEE80211_BEACON_TIM: 4907218492Sbschmidt mcast = 1; /*TODO*/ 4908218492Sbschmidt break; 4909218492Sbschmidt default: 4910218492Sbschmidt break; 4911218492Sbschmidt } 4912218492Sbschmidt 4913218492Sbschmidt setbit(rvp->bo.bo_flags, item); 4914273636Skevlo if (rvp->beacon_mbuf == NULL) { 4915273636Skevlo rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss, 4916273636Skevlo &rvp->bo); 4917273636Skevlo if (rvp->beacon_mbuf == NULL) 4918273636Skevlo return; 4919273636Skevlo } 4920218492Sbschmidt ieee80211_beacon_update(vap->iv_bss, &rvp->bo, rvp->beacon_mbuf, mcast); 4921218492Sbschmidt 4922208019Sthompsa i = RUN_CMDQ_GET(&sc->cmdq_store); 4923208019Sthompsa DPRINTF("cmdq_store=%d\n", i); 4924208019Sthompsa sc->cmdq[i].func = run_update_beacon_cb; 4925208019Sthompsa sc->cmdq[i].arg0 = vap; 4926208019Sthompsa ieee80211_runtask(ic, &sc->cmdq_task); 4927208019Sthompsa 4928208019Sthompsa return; 4929203134Sthompsa} 4930203134Sthompsa 4931203134Sthompsastatic void 4932208019Sthompsarun_update_beacon_cb(void *arg) 4933203134Sthompsa{ 4934208019Sthompsa struct ieee80211vap *vap = arg; 4935218492Sbschmidt struct run_vap *rvp = RUN_VAP(vap); 4936203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 4937203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 4938203134Sthompsa struct rt2860_txwi txwi; 4939203134Sthompsa struct mbuf *m; 4940259453Shselasky uint16_t txwisize; 4941208019Sthompsa uint8_t ridx; 4942203134Sthompsa 4943209917Sthompsa if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC) 4944208019Sthompsa return; 4945236439Shselasky if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) 4946236439Shselasky return; 4947208019Sthompsa 4948218492Sbschmidt /* 4949218492Sbschmidt * No need to call ieee80211_beacon_update(), run_update_beacon() 4950218492Sbschmidt * is taking care of apropriate calls. 4951218492Sbschmidt */ 4952218492Sbschmidt if (rvp->beacon_mbuf == NULL) { 4953218492Sbschmidt rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss, 4954218492Sbschmidt &rvp->bo); 4955218492Sbschmidt if (rvp->beacon_mbuf == NULL) 4956218492Sbschmidt return; 4957218492Sbschmidt } 4958218492Sbschmidt m = rvp->beacon_mbuf; 4959203134Sthompsa 4960259453Shselasky memset(&txwi, 0, sizeof(txwi)); 4961203134Sthompsa txwi.wcid = 0xff; 4962203134Sthompsa txwi.len = htole16(m->m_pkthdr.len); 4963259453Shselasky 4964203134Sthompsa /* send beacons at the lowest available rate */ 4965208019Sthompsa ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? 4966208019Sthompsa RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; 4967208019Sthompsa txwi.phy = htole16(rt2860_rates[ridx].mcs); 4968208019Sthompsa if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM) 4969259453Shselasky txwi.phy |= htole16(RT2860_PHY_OFDM); 4970203134Sthompsa txwi.txop = RT2860_TX_TXOP_HT; 4971203134Sthompsa txwi.flags = RT2860_TX_TS; 4972209144Sthompsa txwi.xflags = RT2860_TX_NSEQ; 4973203134Sthompsa 4974259453Shselasky txwisize = (sc->mac_ver == 0x5592) ? 4975259453Shselasky sizeof(txwi) + sizeof(uint32_t) : sizeof(txwi); 4976259453Shselasky run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id), (uint8_t *)&txwi, 4977259453Shselasky txwisize); 4978259453Shselasky run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id) + txwisize, 4979259453Shselasky mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1); 4980203134Sthompsa} 4981203134Sthompsa 4982203134Sthompsastatic void 4983203134Sthompsarun_updateprot(struct ieee80211com *ic) 4984203134Sthompsa{ 4985203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 4986218492Sbschmidt uint32_t i; 4987218492Sbschmidt 4988218492Sbschmidt i = RUN_CMDQ_GET(&sc->cmdq_store); 4989218492Sbschmidt DPRINTF("cmdq_store=%d\n", i); 4990218492Sbschmidt sc->cmdq[i].func = run_updateprot_cb; 4991218492Sbschmidt sc->cmdq[i].arg0 = ic; 4992218492Sbschmidt ieee80211_runtask(ic, &sc->cmdq_task); 4993218492Sbschmidt} 4994218492Sbschmidt 4995218492Sbschmidtstatic void 4996218492Sbschmidtrun_updateprot_cb(void *arg) 4997218492Sbschmidt{ 4998218492Sbschmidt struct ieee80211com *ic = arg; 4999218492Sbschmidt struct run_softc *sc = ic->ic_ifp->if_softc; 5000203134Sthompsa uint32_t tmp; 5001203134Sthompsa 5002203134Sthompsa tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL; 5003203134Sthompsa /* setup protection frame rate (MCS code) */ 5004203134Sthompsa tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ? 5005270515Skevlo rt2860_rates[RT2860_RIDX_OFDM6].mcs | RT2860_PHY_OFDM : 5006203134Sthompsa rt2860_rates[RT2860_RIDX_CCK11].mcs; 5007203134Sthompsa 5008203134Sthompsa /* CCK frames don't require protection */ 5009203134Sthompsa run_write(sc, RT2860_CCK_PROT_CFG, tmp); 5010203134Sthompsa if (ic->ic_flags & IEEE80211_F_USEPROT) { 5011203134Sthompsa if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) 5012203134Sthompsa tmp |= RT2860_PROT_CTRL_RTS_CTS; 5013203134Sthompsa else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) 5014203134Sthompsa tmp |= RT2860_PROT_CTRL_CTS; 5015203134Sthompsa } 5016203134Sthompsa run_write(sc, RT2860_OFDM_PROT_CFG, tmp); 5017203134Sthompsa} 5018203134Sthompsa 5019203134Sthompsastatic void 5020208019Sthompsarun_usb_timeout_cb(void *arg) 5021203134Sthompsa{ 5022208019Sthompsa struct ieee80211vap *vap = arg; 5023208019Sthompsa struct run_softc *sc = vap->iv_ic->ic_ifp->if_softc; 5024203134Sthompsa 5025208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 5026203134Sthompsa 5027203134Sthompsa if(vap->iv_state == IEEE80211_S_RUN && 5028203134Sthompsa vap->iv_opmode != IEEE80211_M_STA) 5029203134Sthompsa run_reset_livelock(sc); 5030209917Sthompsa else if (vap->iv_state == IEEE80211_S_SCAN) { 5031203134Sthompsa DPRINTF("timeout caused by scan\n"); 5032203134Sthompsa /* cancel bgscan */ 5033203134Sthompsa ieee80211_cancel_scan(vap); 5034203134Sthompsa } else 5035203134Sthompsa DPRINTF("timeout by unknown cause\n"); 5036203134Sthompsa} 5037203134Sthompsa 5038203134Sthompsastatic void 5039203134Sthompsarun_reset_livelock(struct run_softc *sc) 5040203134Sthompsa{ 5041203134Sthompsa uint32_t tmp; 5042203134Sthompsa 5043208019Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 5044208019Sthompsa 5045203134Sthompsa /* 5046203134Sthompsa * In IBSS or HostAP modes (when the hardware sends beacons), the MAC 5047203134Sthompsa * can run into a livelock and start sending CTS-to-self frames like 5048203134Sthompsa * crazy if protection is enabled. Reset MAC/BBP for a while 5049203134Sthompsa */ 5050203134Sthompsa run_read(sc, RT2860_DEBUG, &tmp); 5051208019Sthompsa DPRINTFN(3, "debug reg %08x\n", tmp); 5052209917Sthompsa if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) { 5053203134Sthompsa DPRINTF("CTS-to-self livelock detected\n"); 5054203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST); 5055203134Sthompsa run_delay(sc, 1); 5056203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 5057203134Sthompsa RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 5058203134Sthompsa } 5059203134Sthompsa} 5060203134Sthompsa 5061203134Sthompsastatic void 5062203134Sthompsarun_update_promisc_locked(struct ifnet *ifp) 5063203134Sthompsa{ 5064203134Sthompsa struct run_softc *sc = ifp->if_softc; 5065203134Sthompsa uint32_t tmp; 5066203134Sthompsa 5067203134Sthompsa run_read(sc, RT2860_RX_FILTR_CFG, &tmp); 5068203134Sthompsa 5069203134Sthompsa tmp |= RT2860_DROP_UC_NOME; 5070203134Sthompsa if (ifp->if_flags & IFF_PROMISC) 5071203134Sthompsa tmp &= ~RT2860_DROP_UC_NOME; 5072203134Sthompsa 5073203134Sthompsa run_write(sc, RT2860_RX_FILTR_CFG, tmp); 5074203134Sthompsa 5075203134Sthompsa DPRINTF("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ? 5076203134Sthompsa "entering" : "leaving"); 5077203134Sthompsa} 5078203134Sthompsa 5079203134Sthompsastatic void 5080203134Sthompsarun_update_promisc(struct ifnet *ifp) 5081203134Sthompsa{ 5082203134Sthompsa struct run_softc *sc = ifp->if_softc; 5083203134Sthompsa 5084203134Sthompsa if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 5085203134Sthompsa return; 5086203134Sthompsa 5087203134Sthompsa RUN_LOCK(sc); 5088203134Sthompsa run_update_promisc_locked(ifp); 5089203134Sthompsa RUN_UNLOCK(sc); 5090203134Sthompsa} 5091203134Sthompsa 5092203134Sthompsastatic void 5093203134Sthompsarun_enable_tsf_sync(struct run_softc *sc) 5094203134Sthompsa{ 5095208019Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 5096203134Sthompsa struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 5097203134Sthompsa uint32_t tmp; 5098203134Sthompsa 5099259453Shselasky DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id, 5100259453Shselasky ic->ic_opmode); 5101208019Sthompsa 5102203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 5103203134Sthompsa tmp &= ~0x1fffff; 5104203134Sthompsa tmp |= vap->iv_bss->ni_intval * 16; 5105203134Sthompsa tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN; 5106203134Sthompsa 5107208019Sthompsa if (ic->ic_opmode == IEEE80211_M_STA) { 5108203134Sthompsa /* 5109203134Sthompsa * Local TSF is always updated with remote TSF on beacon 5110203134Sthompsa * reception. 5111203134Sthompsa */ 5112203134Sthompsa tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT; 5113208019Sthompsa } else if (ic->ic_opmode == IEEE80211_M_IBSS) { 5114203134Sthompsa tmp |= RT2860_BCN_TX_EN; 5115203134Sthompsa /* 5116203134Sthompsa * Local TSF is updated with remote TSF on beacon reception 5117203134Sthompsa * only if the remote TSF is greater than local TSF. 5118203134Sthompsa */ 5119203134Sthompsa tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT; 5120208019Sthompsa } else if (ic->ic_opmode == IEEE80211_M_HOSTAP || 5121208019Sthompsa ic->ic_opmode == IEEE80211_M_MBSS) { 5122203134Sthompsa tmp |= RT2860_BCN_TX_EN; 5123203134Sthompsa /* SYNC with nobody */ 5124203134Sthompsa tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT; 5125208019Sthompsa } else { 5126203134Sthompsa DPRINTF("Enabling TSF failed. undefined opmode\n"); 5127208019Sthompsa return; 5128208019Sthompsa } 5129203134Sthompsa 5130203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, tmp); 5131203134Sthompsa} 5132203134Sthompsa 5133203134Sthompsastatic void 5134203134Sthompsarun_enable_mrr(struct run_softc *sc) 5135203134Sthompsa{ 5136261868Skevlo#define CCK(mcs) (mcs) 5137261868Skevlo#define OFDM(mcs) (1 << 3 | (mcs)) 5138203134Sthompsa run_write(sc, RT2860_LG_FBK_CFG0, 5139203134Sthompsa OFDM(6) << 28 | /* 54->48 */ 5140203134Sthompsa OFDM(5) << 24 | /* 48->36 */ 5141203134Sthompsa OFDM(4) << 20 | /* 36->24 */ 5142203134Sthompsa OFDM(3) << 16 | /* 24->18 */ 5143203134Sthompsa OFDM(2) << 12 | /* 18->12 */ 5144203134Sthompsa OFDM(1) << 8 | /* 12-> 9 */ 5145203134Sthompsa OFDM(0) << 4 | /* 9-> 6 */ 5146203134Sthompsa OFDM(0)); /* 6-> 6 */ 5147203134Sthompsa 5148203134Sthompsa run_write(sc, RT2860_LG_FBK_CFG1, 5149203134Sthompsa CCK(2) << 12 | /* 11->5.5 */ 5150203134Sthompsa CCK(1) << 8 | /* 5.5-> 2 */ 5151203134Sthompsa CCK(0) << 4 | /* 2-> 1 */ 5152203134Sthompsa CCK(0)); /* 1-> 1 */ 5153203134Sthompsa#undef OFDM 5154203134Sthompsa#undef CCK 5155203134Sthompsa} 5156203134Sthompsa 5157203134Sthompsastatic void 5158203134Sthompsarun_set_txpreamble(struct run_softc *sc) 5159203134Sthompsa{ 5160203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 5161203134Sthompsa uint32_t tmp; 5162203134Sthompsa 5163203134Sthompsa run_read(sc, RT2860_AUTO_RSP_CFG, &tmp); 5164203134Sthompsa if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 5165203134Sthompsa tmp |= RT2860_CCK_SHORT_EN; 5166203134Sthompsa else 5167203134Sthompsa tmp &= ~RT2860_CCK_SHORT_EN; 5168203134Sthompsa run_write(sc, RT2860_AUTO_RSP_CFG, tmp); 5169203134Sthompsa} 5170203134Sthompsa 5171203134Sthompsastatic void 5172203134Sthompsarun_set_basicrates(struct run_softc *sc) 5173203134Sthompsa{ 5174203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 5175203134Sthompsa 5176203134Sthompsa /* set basic rates mask */ 5177203134Sthompsa if (ic->ic_curmode == IEEE80211_MODE_11B) 5178203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003); 5179203134Sthompsa else if (ic->ic_curmode == IEEE80211_MODE_11A) 5180203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150); 5181203134Sthompsa else /* 11g */ 5182203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f); 5183203134Sthompsa} 5184203134Sthompsa 5185203134Sthompsastatic void 5186203134Sthompsarun_set_leds(struct run_softc *sc, uint16_t which) 5187203134Sthompsa{ 5188203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS, 5189203134Sthompsa which | (sc->leds & 0x7f)); 5190203134Sthompsa} 5191203134Sthompsa 5192203134Sthompsastatic void 5193203134Sthompsarun_set_bssid(struct run_softc *sc, const uint8_t *bssid) 5194203134Sthompsa{ 5195203134Sthompsa run_write(sc, RT2860_MAC_BSSID_DW0, 5196203134Sthompsa bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24); 5197203134Sthompsa run_write(sc, RT2860_MAC_BSSID_DW1, 5198203134Sthompsa bssid[4] | bssid[5] << 8); 5199203134Sthompsa} 5200203134Sthompsa 5201203134Sthompsastatic void 5202203134Sthompsarun_set_macaddr(struct run_softc *sc, const uint8_t *addr) 5203203134Sthompsa{ 5204203134Sthompsa run_write(sc, RT2860_MAC_ADDR_DW0, 5205203134Sthompsa addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24); 5206203134Sthompsa run_write(sc, RT2860_MAC_ADDR_DW1, 5207203134Sthompsa addr[4] | addr[5] << 8 | 0xff << 16); 5208203134Sthompsa} 5209203134Sthompsa 5210203134Sthompsastatic void 5211203134Sthompsarun_updateslot(struct ifnet *ifp) 5212203134Sthompsa{ 5213203134Sthompsa struct run_softc *sc = ifp->if_softc; 5214203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 5215218492Sbschmidt uint32_t i; 5216218492Sbschmidt 5217218492Sbschmidt i = RUN_CMDQ_GET(&sc->cmdq_store); 5218218492Sbschmidt DPRINTF("cmdq_store=%d\n", i); 5219218492Sbschmidt sc->cmdq[i].func = run_updateslot_cb; 5220218492Sbschmidt sc->cmdq[i].arg0 = ifp; 5221218492Sbschmidt ieee80211_runtask(ic, &sc->cmdq_task); 5222218492Sbschmidt 5223218492Sbschmidt return; 5224218492Sbschmidt} 5225218492Sbschmidt 5226218492Sbschmidt/* ARGSUSED */ 5227218492Sbschmidtstatic void 5228218492Sbschmidtrun_updateslot_cb(void *arg) 5229218492Sbschmidt{ 5230218492Sbschmidt struct ifnet *ifp = arg; 5231218492Sbschmidt struct run_softc *sc = ifp->if_softc; 5232218492Sbschmidt struct ieee80211com *ic = ifp->if_l2com; 5233203134Sthompsa uint32_t tmp; 5234203134Sthompsa 5235203134Sthompsa run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp); 5236203134Sthompsa tmp &= ~0xff; 5237203134Sthompsa tmp |= (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; 5238203134Sthompsa run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp); 5239203134Sthompsa} 5240203134Sthompsa 5241208019Sthompsastatic void 5242208019Sthompsarun_update_mcast(struct ifnet *ifp) 5243208019Sthompsa{ 5244208019Sthompsa /* h/w filter supports getting everything or nothing */ 5245208019Sthompsa ifp->if_flags |= IFF_ALLMULTI; 5246208019Sthompsa} 5247208019Sthompsa 5248203134Sthompsastatic int8_t 5249203134Sthompsarun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain) 5250203134Sthompsa{ 5251203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 5252203134Sthompsa struct ieee80211_channel *c = ic->ic_curchan; 5253203134Sthompsa int delta; 5254203134Sthompsa 5255203134Sthompsa if (IEEE80211_IS_CHAN_5GHZ(c)) { 5256259453Shselasky u_int chan = ieee80211_chan2ieee(ic, c); 5257203134Sthompsa delta = sc->rssi_5ghz[rxchain]; 5258203134Sthompsa 5259203134Sthompsa /* determine channel group */ 5260203134Sthompsa if (chan <= 64) 5261203134Sthompsa delta -= sc->lna[1]; 5262203134Sthompsa else if (chan <= 128) 5263203134Sthompsa delta -= sc->lna[2]; 5264203134Sthompsa else 5265203134Sthompsa delta -= sc->lna[3]; 5266203134Sthompsa } else 5267203134Sthompsa delta = sc->rssi_2ghz[rxchain] - sc->lna[0]; 5268203134Sthompsa 5269209917Sthompsa return (-12 - delta - rssi); 5270203134Sthompsa} 5271203134Sthompsa 5272259453Shselaskystatic void 5273259453Shselaskyrun_rt5390_bbp_init(struct run_softc *sc) 5274259453Shselasky{ 5275259453Shselasky int i; 5276259453Shselasky uint8_t bbp; 5277259453Shselasky 5278259453Shselasky /* Apply maximum likelihood detection for 2 stream case. */ 5279259453Shselasky run_bbp_read(sc, 105, &bbp); 5280259453Shselasky if (sc->nrxchains > 1) 5281259453Shselasky run_bbp_write(sc, 105, bbp | RT5390_MLD); 5282259453Shselasky 5283259453Shselasky /* Avoid data lost and CRC error. */ 5284259453Shselasky run_bbp_read(sc, 4, &bbp); 5285259453Shselasky run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 5286259453Shselasky 5287259453Shselasky if (sc->mac_ver == 0x5592) { 5288259453Shselasky for (i = 0; i < nitems(rt5592_def_bbp); i++) { 5289259453Shselasky run_bbp_write(sc, rt5592_def_bbp[i].reg, 5290259453Shselasky rt5592_def_bbp[i].val); 5291259453Shselasky } 5292259453Shselasky for (i = 0; i < nitems(rt5592_bbp_r196); i++) { 5293259453Shselasky run_bbp_write(sc, 195, i + 0x80); 5294259453Shselasky run_bbp_write(sc, 196, rt5592_bbp_r196[i]); 5295259453Shselasky } 5296259453Shselasky } else { 5297259453Shselasky for (i = 0; i < nitems(rt5390_def_bbp); i++) { 5298259453Shselasky run_bbp_write(sc, rt5390_def_bbp[i].reg, 5299259453Shselasky rt5390_def_bbp[i].val); 5300259453Shselasky } 5301259453Shselasky } 5302259453Shselasky if (sc->mac_ver == 0x5392) { 5303259453Shselasky run_bbp_write(sc, 88, 0x90); 5304259453Shselasky run_bbp_write(sc, 95, 0x9a); 5305259453Shselasky run_bbp_write(sc, 98, 0x12); 5306259453Shselasky run_bbp_write(sc, 106, 0x12); 5307259453Shselasky run_bbp_write(sc, 134, 0xd0); 5308259453Shselasky run_bbp_write(sc, 135, 0xf6); 5309259453Shselasky run_bbp_write(sc, 148, 0x84); 5310259453Shselasky } 5311259453Shselasky 5312259453Shselasky run_bbp_read(sc, 152, &bbp); 5313259453Shselasky run_bbp_write(sc, 152, bbp | 0x80); 5314259453Shselasky 5315259453Shselasky /* Fix BBP254 for RT5592C. */ 5316259453Shselasky if (sc->mac_ver == 0x5592 && sc->mac_rev >= 0x0221) { 5317259453Shselasky run_bbp_read(sc, 254, &bbp); 5318259453Shselasky run_bbp_write(sc, 254, bbp | 0x80); 5319259453Shselasky } 5320259453Shselasky 5321259453Shselasky /* Disable hardware antenna diversity. */ 5322259453Shselasky if (sc->mac_ver == 0x5390) 5323259453Shselasky run_bbp_write(sc, 154, 0); 5324259453Shselasky 5325259453Shselasky /* Initialize Rx CCK/OFDM frequency offset report. */ 5326259453Shselasky run_bbp_write(sc, 142, 1); 5327259453Shselasky run_bbp_write(sc, 143, 57); 5328259453Shselasky} 5329259453Shselasky 5330203134Sthompsastatic int 5331203134Sthompsarun_bbp_init(struct run_softc *sc) 5332203134Sthompsa{ 5333203134Sthompsa int i, error, ntries; 5334203134Sthompsa uint8_t bbp0; 5335203134Sthompsa 5336203134Sthompsa /* wait for BBP to wake up */ 5337203134Sthompsa for (ntries = 0; ntries < 20; ntries++) { 5338203134Sthompsa if ((error = run_bbp_read(sc, 0, &bbp0)) != 0) 5339203134Sthompsa return error; 5340203134Sthompsa if (bbp0 != 0 && bbp0 != 0xff) 5341203134Sthompsa break; 5342203134Sthompsa } 5343203134Sthompsa if (ntries == 20) 5344209917Sthompsa return (ETIMEDOUT); 5345203134Sthompsa 5346203134Sthompsa /* initialize BBP registers to default values */ 5347259453Shselasky if (sc->mac_ver >= 0x5390) 5348259453Shselasky run_rt5390_bbp_init(sc); 5349259453Shselasky else { 5350259453Shselasky for (i = 0; i < nitems(rt2860_def_bbp); i++) { 5351259453Shselasky run_bbp_write(sc, rt2860_def_bbp[i].reg, 5352259453Shselasky rt2860_def_bbp[i].val); 5353259453Shselasky } 5354203134Sthompsa } 5355203134Sthompsa 5356261868Skevlo if (sc->mac_ver == 0x3593) { 5357261868Skevlo run_bbp_write(sc, 79, 0x13); 5358261868Skevlo run_bbp_write(sc, 80, 0x05); 5359261868Skevlo run_bbp_write(sc, 81, 0x33); 5360261868Skevlo run_bbp_write(sc, 86, 0x46); 5361261868Skevlo run_bbp_write(sc, 137, 0x0f); 5362261868Skevlo } 5363261868Skevlo 5364203134Sthompsa /* fix BBP84 for RT2860E */ 5365205042Sthompsa if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101) 5366205042Sthompsa run_bbp_write(sc, 84, 0x19); 5367203134Sthompsa 5368261868Skevlo if (sc->mac_ver >= 0x3070 && (sc->mac_ver != 0x3593 && 5369261868Skevlo sc->mac_ver != 0x5592)) { 5370203134Sthompsa run_bbp_write(sc, 79, 0x13); 5371203134Sthompsa run_bbp_write(sc, 80, 0x05); 5372203134Sthompsa run_bbp_write(sc, 81, 0x33); 5373205042Sthompsa } else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) { 5374203134Sthompsa run_bbp_write(sc, 69, 0x16); 5375203134Sthompsa run_bbp_write(sc, 73, 0x12); 5376203134Sthompsa } 5377209917Sthompsa return (0); 5378203134Sthompsa} 5379203134Sthompsa 5380203134Sthompsastatic int 5381203134Sthompsarun_rt3070_rf_init(struct run_softc *sc) 5382203134Sthompsa{ 5383203134Sthompsa uint32_t tmp; 5384259453Shselasky uint8_t bbp4, mingain, rf, target; 5385203134Sthompsa int i; 5386203134Sthompsa 5387203134Sthompsa run_rt3070_rf_read(sc, 30, &rf); 5388203134Sthompsa /* toggle RF R30 bit 7 */ 5389203134Sthompsa run_rt3070_rf_write(sc, 30, rf | 0x80); 5390203134Sthompsa run_delay(sc, 10); 5391203134Sthompsa run_rt3070_rf_write(sc, 30, rf & ~0x80); 5392203134Sthompsa 5393203134Sthompsa /* initialize RF registers to default value */ 5394205042Sthompsa if (sc->mac_ver == 0x3572) { 5395259453Shselasky for (i = 0; i < nitems(rt3572_def_rf); i++) { 5396205042Sthompsa run_rt3070_rf_write(sc, rt3572_def_rf[i].reg, 5397205042Sthompsa rt3572_def_rf[i].val); 5398205042Sthompsa } 5399205042Sthompsa } else { 5400259453Shselasky for (i = 0; i < nitems(rt3070_def_rf); i++) { 5401205042Sthompsa run_rt3070_rf_write(sc, rt3070_def_rf[i].reg, 5402205042Sthompsa rt3070_def_rf[i].val); 5403205042Sthompsa } 5404203134Sthompsa } 5405205042Sthompsa 5406259453Shselasky if (sc->mac_ver == 0x3070 && sc->mac_rev < 0x0201) { 5407259453Shselasky /* 5408259453Shselasky * Change voltage from 1.2V to 1.35V for RT3070. 5409259453Shselasky * The DAC issue (RT3070_LDO_CFG0) has been fixed 5410259453Shselasky * in RT3070(F). 5411259453Shselasky */ 5412203134Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 5413203134Sthompsa tmp = (tmp & ~0x0f000000) | 0x0d000000; 5414203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5415203134Sthompsa 5416205042Sthompsa } else if (sc->mac_ver == 0x3071) { 5417203134Sthompsa run_rt3070_rf_read(sc, 6, &rf); 5418203134Sthompsa run_rt3070_rf_write(sc, 6, rf | 0x40); 5419203134Sthompsa run_rt3070_rf_write(sc, 31, 0x14); 5420203134Sthompsa 5421203134Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 5422203134Sthompsa tmp &= ~0x1f000000; 5423205042Sthompsa if (sc->mac_rev < 0x0211) 5424205042Sthompsa tmp |= 0x0d000000; /* 1.3V */ 5425203134Sthompsa else 5426205042Sthompsa tmp |= 0x01000000; /* 1.2V */ 5427203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5428203134Sthompsa 5429203134Sthompsa /* patch LNA_PE_G1 */ 5430203134Sthompsa run_read(sc, RT3070_GPIO_SWITCH, &tmp); 5431203134Sthompsa run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20); 5432208019Sthompsa 5433209917Sthompsa } else if (sc->mac_ver == 0x3572) { 5434205042Sthompsa run_rt3070_rf_read(sc, 6, &rf); 5435205042Sthompsa run_rt3070_rf_write(sc, 6, rf | 0x40); 5436205042Sthompsa 5437208019Sthompsa /* increase voltage from 1.2V to 1.35V */ 5438208019Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 5439208019Sthompsa tmp = (tmp & ~0x1f000000) | 0x0d000000; 5440208019Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5441203134Sthompsa 5442209917Sthompsa if (sc->mac_rev < 0x0211 || !sc->patch_dac) { 5443203134Sthompsa run_delay(sc, 1); /* wait for 1msec */ 5444205042Sthompsa /* decrease voltage back to 1.2V */ 5445203134Sthompsa tmp = (tmp & ~0x1f000000) | 0x01000000; 5446203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 5447203134Sthompsa } 5448203134Sthompsa } 5449203134Sthompsa 5450203134Sthompsa /* select 20MHz bandwidth */ 5451203134Sthompsa run_rt3070_rf_read(sc, 31, &rf); 5452203134Sthompsa run_rt3070_rf_write(sc, 31, rf & ~0x20); 5453203134Sthompsa 5454203134Sthompsa /* calibrate filter for 20MHz bandwidth */ 5455203134Sthompsa sc->rf24_20mhz = 0x1f; /* default value */ 5456205042Sthompsa target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13; 5457205042Sthompsa run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz); 5458203134Sthompsa 5459203134Sthompsa /* select 40MHz bandwidth */ 5460203134Sthompsa run_bbp_read(sc, 4, &bbp4); 5461259453Shselasky run_bbp_write(sc, 4, (bbp4 & ~0x18) | 0x10); 5462205042Sthompsa run_rt3070_rf_read(sc, 31, &rf); 5463205042Sthompsa run_rt3070_rf_write(sc, 31, rf | 0x20); 5464203134Sthompsa 5465203134Sthompsa /* calibrate filter for 40MHz bandwidth */ 5466203134Sthompsa sc->rf24_40mhz = 0x2f; /* default value */ 5467205042Sthompsa target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15; 5468205042Sthompsa run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz); 5469203134Sthompsa 5470203134Sthompsa /* go back to 20MHz bandwidth */ 5471203134Sthompsa run_bbp_read(sc, 4, &bbp4); 5472203134Sthompsa run_bbp_write(sc, 4, bbp4 & ~0x18); 5473203134Sthompsa 5474205042Sthompsa if (sc->mac_ver == 0x3572) { 5475205042Sthompsa /* save default BBP registers 25 and 26 values */ 5476205042Sthompsa run_bbp_read(sc, 25, &sc->bbp25); 5477205042Sthompsa run_bbp_read(sc, 26, &sc->bbp26); 5478259453Shselasky } else if (sc->mac_rev < 0x0201 || sc->mac_rev < 0x0211) 5479203134Sthompsa run_rt3070_rf_write(sc, 27, 0x03); 5480203134Sthompsa 5481203134Sthompsa run_read(sc, RT3070_OPT_14, &tmp); 5482203134Sthompsa run_write(sc, RT3070_OPT_14, tmp | 1); 5483203134Sthompsa 5484205042Sthompsa if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) { 5485205042Sthompsa run_rt3070_rf_read(sc, 17, &rf); 5486205042Sthompsa rf &= ~RT3070_TX_LO1; 5487205042Sthompsa if ((sc->mac_ver == 0x3070 || 5488205042Sthompsa (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) && 5489205042Sthompsa !sc->ext_2ghz_lna) 5490205042Sthompsa rf |= 0x20; /* fix for long range Rx issue */ 5491259453Shselasky mingain = (sc->mac_ver == 0x3070) ? 1 : 2; 5492259453Shselasky if (sc->txmixgain_2ghz >= mingain) 5493205042Sthompsa rf = (rf & ~0x7) | sc->txmixgain_2ghz; 5494205042Sthompsa run_rt3070_rf_write(sc, 17, rf); 5495205042Sthompsa } 5496205042Sthompsa 5497270843Skevlo if (sc->mac_ver == 0x3071) { 5498203134Sthompsa run_rt3070_rf_read(sc, 1, &rf); 5499203134Sthompsa rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD); 5500203134Sthompsa rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD; 5501203134Sthompsa run_rt3070_rf_write(sc, 1, rf); 5502203134Sthompsa 5503203134Sthompsa run_rt3070_rf_read(sc, 15, &rf); 5504203134Sthompsa run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2); 5505203134Sthompsa 5506203134Sthompsa run_rt3070_rf_read(sc, 20, &rf); 5507203134Sthompsa run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1); 5508203134Sthompsa 5509203134Sthompsa run_rt3070_rf_read(sc, 21, &rf); 5510203134Sthompsa run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2); 5511205042Sthompsa } 5512203134Sthompsa 5513205042Sthompsa if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) { 5514205042Sthompsa /* fix Tx to Rx IQ glitch by raising RF voltage */ 5515203134Sthompsa run_rt3070_rf_read(sc, 27, &rf); 5516203134Sthompsa rf &= ~0x77; 5517205042Sthompsa if (sc->mac_rev < 0x0211) 5518203134Sthompsa rf |= 0x03; 5519203134Sthompsa run_rt3070_rf_write(sc, 27, rf); 5520203134Sthompsa } 5521209917Sthompsa return (0); 5522203134Sthompsa} 5523203134Sthompsa 5524259453Shselaskystatic void 5525261868Skevlorun_rt3593_rf_init(struct run_softc *sc) 5526261868Skevlo{ 5527261868Skevlo uint32_t tmp; 5528261868Skevlo uint8_t rf; 5529261868Skevlo int i; 5530261868Skevlo 5531261868Skevlo /* Disable the GPIO bits 4 and 7 for LNA PE control. */ 5532261868Skevlo run_read(sc, RT3070_GPIO_SWITCH, &tmp); 5533261868Skevlo tmp &= ~(1 << 4 | 1 << 7); 5534261868Skevlo run_write(sc, RT3070_GPIO_SWITCH, tmp); 5535261868Skevlo 5536261868Skevlo /* Initialize RF registers to default value. */ 5537261868Skevlo for (i = 0; i < nitems(rt3593_def_rf); i++) { 5538261868Skevlo run_rt3070_rf_write(sc, rt3593_def_rf[i].reg, 5539261868Skevlo rt3593_def_rf[i].val); 5540261868Skevlo } 5541261868Skevlo 5542261868Skevlo /* Toggle RF R2 to initiate calibration. */ 5543261868Skevlo run_rt3070_rf_write(sc, 2, RT5390_RESCAL); 5544261868Skevlo 5545261868Skevlo /* Initialize RF frequency offset. */ 5546261868Skevlo run_adjust_freq_offset(sc); 5547261868Skevlo 5548261868Skevlo run_rt3070_rf_read(sc, 18, &rf); 5549261868Skevlo run_rt3070_rf_write(sc, 18, rf | RT3593_AUTOTUNE_BYPASS); 5550261868Skevlo 5551261868Skevlo /* 5552261868Skevlo * Increase voltage from 1.2V to 1.35V, wait for 1 msec to 5553261868Skevlo * decrease voltage back to 1.2V. 5554261868Skevlo */ 5555261868Skevlo run_read(sc, RT3070_LDO_CFG0, &tmp); 5556261868Skevlo tmp = (tmp & ~0x1f000000) | 0x0d000000; 5557261868Skevlo run_write(sc, RT3070_LDO_CFG0, tmp); 5558261868Skevlo run_delay(sc, 1); 5559261868Skevlo tmp = (tmp & ~0x1f000000) | 0x01000000; 5560261868Skevlo run_write(sc, RT3070_LDO_CFG0, tmp); 5561261868Skevlo 5562261868Skevlo sc->rf24_20mhz = 0x1f; 5563261868Skevlo sc->rf24_40mhz = 0x2f; 5564261868Skevlo 5565261868Skevlo /* Save default BBP registers 25 and 26 values. */ 5566261868Skevlo run_bbp_read(sc, 25, &sc->bbp25); 5567261868Skevlo run_bbp_read(sc, 26, &sc->bbp26); 5568261868Skevlo 5569261868Skevlo run_read(sc, RT3070_OPT_14, &tmp); 5570261868Skevlo run_write(sc, RT3070_OPT_14, tmp | 1); 5571261868Skevlo} 5572261868Skevlo 5573261868Skevlostatic void 5574259453Shselaskyrun_rt5390_rf_init(struct run_softc *sc) 5575259453Shselasky{ 5576259453Shselasky uint32_t tmp; 5577259453Shselasky uint8_t rf; 5578259453Shselasky int i; 5579259453Shselasky 5580259453Shselasky /* Toggle RF R2 to initiate calibration. */ 5581259453Shselasky if (sc->mac_ver == 0x5390) { 5582259453Shselasky run_rt3070_rf_read(sc, 2, &rf); 5583259453Shselasky run_rt3070_rf_write(sc, 2, rf | RT5390_RESCAL); 5584259453Shselasky run_delay(sc, 10); 5585259453Shselasky run_rt3070_rf_write(sc, 2, rf & ~RT5390_RESCAL); 5586259453Shselasky } else { 5587259453Shselasky run_rt3070_rf_write(sc, 2, RT5390_RESCAL); 5588259453Shselasky run_delay(sc, 10); 5589259453Shselasky } 5590259453Shselasky 5591259453Shselasky /* Initialize RF registers to default value. */ 5592259453Shselasky if (sc->mac_ver == 0x5592) { 5593259453Shselasky for (i = 0; i < nitems(rt5592_def_rf); i++) { 5594259453Shselasky run_rt3070_rf_write(sc, rt5592_def_rf[i].reg, 5595259453Shselasky rt5592_def_rf[i].val); 5596259453Shselasky } 5597259453Shselasky /* Initialize RF frequency offset. */ 5598259453Shselasky run_adjust_freq_offset(sc); 5599259453Shselasky } else if (sc->mac_ver == 0x5392) { 5600259453Shselasky for (i = 0; i < nitems(rt5392_def_rf); i++) { 5601259453Shselasky run_rt3070_rf_write(sc, rt5392_def_rf[i].reg, 5602259453Shselasky rt5392_def_rf[i].val); 5603259453Shselasky } 5604259453Shselasky if (sc->mac_rev >= 0x0223) { 5605259453Shselasky run_rt3070_rf_write(sc, 23, 0x0f); 5606259453Shselasky run_rt3070_rf_write(sc, 24, 0x3e); 5607259453Shselasky run_rt3070_rf_write(sc, 51, 0x32); 5608259453Shselasky run_rt3070_rf_write(sc, 53, 0x22); 5609259453Shselasky run_rt3070_rf_write(sc, 56, 0xc1); 5610259453Shselasky run_rt3070_rf_write(sc, 59, 0x0f); 5611259453Shselasky } 5612259453Shselasky } else { 5613259453Shselasky for (i = 0; i < nitems(rt5390_def_rf); i++) { 5614259453Shselasky run_rt3070_rf_write(sc, rt5390_def_rf[i].reg, 5615259453Shselasky rt5390_def_rf[i].val); 5616259453Shselasky } 5617259453Shselasky if (sc->mac_rev >= 0x0502) { 5618259453Shselasky run_rt3070_rf_write(sc, 6, 0xe0); 5619259453Shselasky run_rt3070_rf_write(sc, 25, 0x80); 5620259453Shselasky run_rt3070_rf_write(sc, 46, 0x73); 5621259453Shselasky run_rt3070_rf_write(sc, 53, 0x00); 5622259453Shselasky run_rt3070_rf_write(sc, 56, 0x42); 5623259453Shselasky run_rt3070_rf_write(sc, 61, 0xd1); 5624259453Shselasky } 5625259453Shselasky } 5626259453Shselasky 5627259453Shselasky sc->rf24_20mhz = 0x1f; /* default value */ 5628259453Shselasky sc->rf24_40mhz = (sc->mac_ver == 0x5592) ? 0 : 0x2f; 5629259453Shselasky 5630259453Shselasky if (sc->mac_rev < 0x0211) 5631259453Shselasky run_rt3070_rf_write(sc, 27, 0x3); 5632259453Shselasky 5633259453Shselasky run_read(sc, RT3070_OPT_14, &tmp); 5634259453Shselasky run_write(sc, RT3070_OPT_14, tmp | 1); 5635259453Shselasky} 5636259453Shselasky 5637203134Sthompsastatic int 5638203134Sthompsarun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target, 5639203134Sthompsa uint8_t *val) 5640203134Sthompsa{ 5641203134Sthompsa uint8_t rf22, rf24; 5642203134Sthompsa uint8_t bbp55_pb, bbp55_sb, delta; 5643203134Sthompsa int ntries; 5644203134Sthompsa 5645203134Sthompsa /* program filter */ 5646205042Sthompsa run_rt3070_rf_read(sc, 24, &rf24); 5647205042Sthompsa rf24 = (rf24 & 0xc0) | init; /* initial filter value */ 5648203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 5649203134Sthompsa 5650203134Sthompsa /* enable baseband loopback mode */ 5651203134Sthompsa run_rt3070_rf_read(sc, 22, &rf22); 5652203134Sthompsa run_rt3070_rf_write(sc, 22, rf22 | 0x01); 5653203134Sthompsa 5654203134Sthompsa /* set power and frequency of passband test tone */ 5655203134Sthompsa run_bbp_write(sc, 24, 0x00); 5656203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5657203134Sthompsa /* transmit test tone */ 5658203134Sthompsa run_bbp_write(sc, 25, 0x90); 5659203134Sthompsa run_delay(sc, 10); 5660203134Sthompsa /* read received power */ 5661203134Sthompsa run_bbp_read(sc, 55, &bbp55_pb); 5662203134Sthompsa if (bbp55_pb != 0) 5663203134Sthompsa break; 5664203134Sthompsa } 5665203134Sthompsa if (ntries == 100) 5666259453Shselasky return (ETIMEDOUT); 5667203134Sthompsa 5668203134Sthompsa /* set power and frequency of stopband test tone */ 5669203134Sthompsa run_bbp_write(sc, 24, 0x06); 5670203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5671203134Sthompsa /* transmit test tone */ 5672203134Sthompsa run_bbp_write(sc, 25, 0x90); 5673203134Sthompsa run_delay(sc, 10); 5674203134Sthompsa /* read received power */ 5675203134Sthompsa run_bbp_read(sc, 55, &bbp55_sb); 5676203134Sthompsa 5677203134Sthompsa delta = bbp55_pb - bbp55_sb; 5678203134Sthompsa if (delta > target) 5679203134Sthompsa break; 5680203134Sthompsa 5681203134Sthompsa /* reprogram filter */ 5682203134Sthompsa rf24++; 5683203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 5684203134Sthompsa } 5685203134Sthompsa if (ntries < 100) { 5686203134Sthompsa if (rf24 != init) 5687203134Sthompsa rf24--; /* backtrack */ 5688203134Sthompsa *val = rf24; 5689203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 5690203134Sthompsa } 5691203134Sthompsa 5692203134Sthompsa /* restore initial state */ 5693203134Sthompsa run_bbp_write(sc, 24, 0x00); 5694203134Sthompsa 5695203134Sthompsa /* disable baseband loopback mode */ 5696203134Sthompsa run_rt3070_rf_read(sc, 22, &rf22); 5697203134Sthompsa run_rt3070_rf_write(sc, 22, rf22 & ~0x01); 5698203134Sthompsa 5699209917Sthompsa return (0); 5700203134Sthompsa} 5701203134Sthompsa 5702205042Sthompsastatic void 5703205042Sthompsarun_rt3070_rf_setup(struct run_softc *sc) 5704205042Sthompsa{ 5705205042Sthompsa uint8_t bbp, rf; 5706205042Sthompsa int i; 5707205042Sthompsa 5708261868Skevlo if (sc->mac_ver == 0x3572) { 5709205042Sthompsa /* enable DC filter */ 5710205042Sthompsa if (sc->mac_rev >= 0x0201) 5711205042Sthompsa run_bbp_write(sc, 103, 0xc0); 5712205042Sthompsa 5713205042Sthompsa run_bbp_read(sc, 138, &bbp); 5714205042Sthompsa if (sc->ntxchains == 1) 5715205042Sthompsa bbp |= 0x20; /* turn off DAC1 */ 5716205042Sthompsa if (sc->nrxchains == 1) 5717205042Sthompsa bbp &= ~0x02; /* turn off ADC1 */ 5718205042Sthompsa run_bbp_write(sc, 138, bbp); 5719205042Sthompsa 5720205042Sthompsa if (sc->mac_rev >= 0x0211) { 5721205042Sthompsa /* improve power consumption */ 5722205042Sthompsa run_bbp_read(sc, 31, &bbp); 5723205042Sthompsa run_bbp_write(sc, 31, bbp & ~0x03); 5724205042Sthompsa } 5725205042Sthompsa 5726205042Sthompsa run_rt3070_rf_read(sc, 16, &rf); 5727205042Sthompsa rf = (rf & ~0x07) | sc->txmixgain_2ghz; 5728205042Sthompsa run_rt3070_rf_write(sc, 16, rf); 5729205042Sthompsa 5730205042Sthompsa } else if (sc->mac_ver == 0x3071) { 5731259453Shselasky if (sc->mac_rev >= 0x0211) { 5732259453Shselasky /* enable DC filter */ 5733205042Sthompsa run_bbp_write(sc, 103, 0xc0); 5734205042Sthompsa 5735259453Shselasky /* improve power consumption */ 5736259453Shselasky run_bbp_read(sc, 31, &bbp); 5737259453Shselasky run_bbp_write(sc, 31, bbp & ~0x03); 5738259453Shselasky } 5739259453Shselasky 5740205042Sthompsa run_bbp_read(sc, 138, &bbp); 5741205042Sthompsa if (sc->ntxchains == 1) 5742205042Sthompsa bbp |= 0x20; /* turn off DAC1 */ 5743205042Sthompsa if (sc->nrxchains == 1) 5744205042Sthompsa bbp &= ~0x02; /* turn off ADC1 */ 5745205042Sthompsa run_bbp_write(sc, 138, bbp); 5746205042Sthompsa 5747205042Sthompsa run_write(sc, RT2860_TX_SW_CFG1, 0); 5748205042Sthompsa if (sc->mac_rev < 0x0211) { 5749205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 5750205042Sthompsa sc->patch_dac ? 0x2c : 0x0f); 5751205042Sthompsa } else 5752205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0); 5753205042Sthompsa 5754205042Sthompsa } else if (sc->mac_ver == 0x3070) { 5755205042Sthompsa if (sc->mac_rev >= 0x0201) { 5756205042Sthompsa /* enable DC filter */ 5757205042Sthompsa run_bbp_write(sc, 103, 0xc0); 5758205042Sthompsa 5759205042Sthompsa /* improve power consumption */ 5760205042Sthompsa run_bbp_read(sc, 31, &bbp); 5761205042Sthompsa run_bbp_write(sc, 31, bbp & ~0x03); 5762205042Sthompsa } 5763205042Sthompsa 5764259453Shselasky if (sc->mac_rev < 0x0201) { 5765205042Sthompsa run_write(sc, RT2860_TX_SW_CFG1, 0); 5766205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0x2c); 5767205042Sthompsa } else 5768205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0); 5769205042Sthompsa } 5770205042Sthompsa 5771205042Sthompsa /* initialize RF registers from ROM for >=RT3071*/ 5772261868Skevlo if (sc->mac_ver >= 0x3071) { 5773205042Sthompsa for (i = 0; i < 10; i++) { 5774205042Sthompsa if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff) 5775205042Sthompsa continue; 5776205042Sthompsa run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val); 5777205042Sthompsa } 5778205042Sthompsa } 5779205042Sthompsa} 5780205042Sthompsa 5781261868Skevlostatic void 5782261868Skevlorun_rt3593_rf_setup(struct run_softc *sc) 5783261868Skevlo{ 5784261868Skevlo uint8_t bbp, rf; 5785261868Skevlo 5786261868Skevlo if (sc->mac_rev >= 0x0211) { 5787261868Skevlo /* Enable DC filter. */ 5788261868Skevlo run_bbp_write(sc, 103, 0xc0); 5789261868Skevlo } 5790261868Skevlo run_write(sc, RT2860_TX_SW_CFG1, 0); 5791261868Skevlo if (sc->mac_rev < 0x0211) { 5792261868Skevlo run_write(sc, RT2860_TX_SW_CFG2, 5793261868Skevlo sc->patch_dac ? 0x2c : 0x0f); 5794261868Skevlo } else 5795261868Skevlo run_write(sc, RT2860_TX_SW_CFG2, 0); 5796261868Skevlo 5797261868Skevlo run_rt3070_rf_read(sc, 50, &rf); 5798261868Skevlo run_rt3070_rf_write(sc, 50, rf & ~RT3593_TX_LO2); 5799261868Skevlo 5800261868Skevlo run_rt3070_rf_read(sc, 51, &rf); 5801261868Skevlo rf = (rf & ~(RT3593_TX_LO1 | 0x0c)) | 5802261868Skevlo ((sc->txmixgain_2ghz & 0x07) << 2); 5803261868Skevlo run_rt3070_rf_write(sc, 51, rf); 5804261868Skevlo 5805261868Skevlo run_rt3070_rf_read(sc, 38, &rf); 5806261868Skevlo run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1); 5807261868Skevlo 5808261868Skevlo run_rt3070_rf_read(sc, 39, &rf); 5809261868Skevlo run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2); 5810261868Skevlo 5811261868Skevlo run_rt3070_rf_read(sc, 1, &rf); 5812261868Skevlo run_rt3070_rf_write(sc, 1, rf & ~(RT3070_RF_BLOCK | RT3070_PLL_PD)); 5813261868Skevlo 5814261868Skevlo run_rt3070_rf_read(sc, 30, &rf); 5815261868Skevlo rf = (rf & ~0x18) | 0x10; 5816261868Skevlo run_rt3070_rf_write(sc, 30, rf); 5817261868Skevlo 5818261868Skevlo /* Apply maximum likelihood detection for 2 stream case. */ 5819261868Skevlo run_bbp_read(sc, 105, &bbp); 5820261868Skevlo if (sc->nrxchains > 1) 5821261868Skevlo run_bbp_write(sc, 105, bbp | RT5390_MLD); 5822261868Skevlo 5823261868Skevlo /* Avoid data lost and CRC error. */ 5824261868Skevlo run_bbp_read(sc, 4, &bbp); 5825261868Skevlo run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 5826261868Skevlo 5827261868Skevlo run_bbp_write(sc, 92, 0x02); 5828261868Skevlo run_bbp_write(sc, 82, 0x82); 5829261868Skevlo run_bbp_write(sc, 106, 0x05); 5830261868Skevlo run_bbp_write(sc, 104, 0x92); 5831261868Skevlo run_bbp_write(sc, 88, 0x90); 5832261868Skevlo run_bbp_write(sc, 148, 0xc8); 5833261868Skevlo run_bbp_write(sc, 47, 0x48); 5834261868Skevlo run_bbp_write(sc, 120, 0x50); 5835261868Skevlo 5836261868Skevlo run_bbp_write(sc, 163, 0x9d); 5837261868Skevlo 5838261868Skevlo /* SNR mapping. */ 5839261868Skevlo run_bbp_write(sc, 142, 0x06); 5840261868Skevlo run_bbp_write(sc, 143, 0xa0); 5841261868Skevlo run_bbp_write(sc, 142, 0x07); 5842261868Skevlo run_bbp_write(sc, 143, 0xa1); 5843261868Skevlo run_bbp_write(sc, 142, 0x08); 5844261868Skevlo run_bbp_write(sc, 143, 0xa2); 5845261868Skevlo 5846261868Skevlo run_bbp_write(sc, 31, 0x08); 5847261868Skevlo run_bbp_write(sc, 68, 0x0b); 5848261868Skevlo run_bbp_write(sc, 105, 0x04); 5849261868Skevlo} 5850261868Skevlo 5851261868Skevlostatic void 5852261868Skevlorun_rt5390_rf_setup(struct run_softc *sc) 5853261868Skevlo{ 5854261868Skevlo uint8_t bbp, rf; 5855261868Skevlo 5856261868Skevlo if (sc->mac_rev >= 0x0211) { 5857261868Skevlo /* Enable DC filter. */ 5858261868Skevlo run_bbp_write(sc, 103, 0xc0); 5859261868Skevlo 5860261868Skevlo if (sc->mac_ver != 0x5592) { 5861261868Skevlo /* Improve power consumption. */ 5862261868Skevlo run_bbp_read(sc, 31, &bbp); 5863261868Skevlo run_bbp_write(sc, 31, bbp & ~0x03); 5864261868Skevlo } 5865261868Skevlo } 5866261868Skevlo 5867261868Skevlo run_bbp_read(sc, 138, &bbp); 5868261868Skevlo if (sc->ntxchains == 1) 5869261868Skevlo bbp |= 0x20; /* turn off DAC1 */ 5870261868Skevlo if (sc->nrxchains == 1) 5871261868Skevlo bbp &= ~0x02; /* turn off ADC1 */ 5872261868Skevlo run_bbp_write(sc, 138, bbp); 5873261868Skevlo 5874261868Skevlo run_rt3070_rf_read(sc, 38, &rf); 5875261868Skevlo run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1); 5876261868Skevlo 5877261868Skevlo run_rt3070_rf_read(sc, 39, &rf); 5878261868Skevlo run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2); 5879261868Skevlo 5880261868Skevlo /* Avoid data lost and CRC error. */ 5881261868Skevlo run_bbp_read(sc, 4, &bbp); 5882261868Skevlo run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 5883261868Skevlo 5884261868Skevlo run_rt3070_rf_read(sc, 30, &rf); 5885261868Skevlo rf = (rf & ~0x18) | 0x10; 5886261868Skevlo run_rt3070_rf_write(sc, 30, rf); 5887261868Skevlo 5888261868Skevlo if (sc->mac_ver != 0x5592) { 5889261868Skevlo run_write(sc, RT2860_TX_SW_CFG1, 0); 5890261868Skevlo if (sc->mac_rev < 0x0211) { 5891261868Skevlo run_write(sc, RT2860_TX_SW_CFG2, 5892261868Skevlo sc->patch_dac ? 0x2c : 0x0f); 5893261868Skevlo } else 5894261868Skevlo run_write(sc, RT2860_TX_SW_CFG2, 0); 5895261868Skevlo } 5896261868Skevlo} 5897261868Skevlo 5898203134Sthompsastatic int 5899203134Sthompsarun_txrx_enable(struct run_softc *sc) 5900203134Sthompsa{ 5901203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 5902203134Sthompsa uint32_t tmp; 5903203134Sthompsa int error, ntries; 5904203134Sthompsa 5905203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN); 5906203134Sthompsa for (ntries = 0; ntries < 200; ntries++) { 5907203134Sthompsa if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0) 5908259453Shselasky return (error); 5909203134Sthompsa if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 5910203134Sthompsa break; 5911203134Sthompsa run_delay(sc, 50); 5912203134Sthompsa } 5913203134Sthompsa if (ntries == 200) 5914259453Shselasky return (ETIMEDOUT); 5915203134Sthompsa 5916203134Sthompsa run_delay(sc, 50); 5917203134Sthompsa 5918203134Sthompsa tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE; 5919203134Sthompsa run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 5920203134Sthompsa 5921203134Sthompsa /* enable Rx bulk aggregation (set timeout and limit) */ 5922203134Sthompsa tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN | 5923203134Sthompsa RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2); 5924203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, tmp); 5925203134Sthompsa 5926203134Sthompsa /* set Rx filter */ 5927203134Sthompsa tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR; 5928203134Sthompsa if (ic->ic_opmode != IEEE80211_M_MONITOR) { 5929203134Sthompsa tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL | 5930203134Sthompsa RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK | 5931203134Sthompsa RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV | 5932203134Sthompsa RT2860_DROP_CFACK | RT2860_DROP_CFEND; 5933203134Sthompsa if (ic->ic_opmode == IEEE80211_M_STA) 5934203134Sthompsa tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL; 5935203134Sthompsa } 5936203134Sthompsa run_write(sc, RT2860_RX_FILTR_CFG, tmp); 5937203134Sthompsa 5938203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 5939203134Sthompsa RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 5940203134Sthompsa 5941209917Sthompsa return (0); 5942203134Sthompsa} 5943203134Sthompsa 5944203134Sthompsastatic void 5945259453Shselaskyrun_adjust_freq_offset(struct run_softc *sc) 5946259453Shselasky{ 5947259453Shselasky uint8_t rf, tmp; 5948259453Shselasky 5949259453Shselasky run_rt3070_rf_read(sc, 17, &rf); 5950259453Shselasky tmp = rf; 5951259453Shselasky rf = (rf & ~0x7f) | (sc->freq & 0x7f); 5952259453Shselasky rf = MIN(rf, 0x5f); 5953259453Shselasky 5954259453Shselasky if (tmp != rf) 5955259453Shselasky run_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf); 5956259453Shselasky} 5957259453Shselasky 5958259453Shselaskystatic void 5959203134Sthompsarun_init_locked(struct run_softc *sc) 5960203134Sthompsa{ 5961203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 5962203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 5963203134Sthompsa uint32_t tmp; 5964203134Sthompsa uint8_t bbp1, bbp3; 5965203134Sthompsa int i; 5966203134Sthompsa int ridx; 5967203134Sthompsa int ntries; 5968203134Sthompsa 5969209917Sthompsa if (ic->ic_nrunning > 1) 5970208019Sthompsa return; 5971208019Sthompsa 5972203134Sthompsa run_stop(sc); 5973203134Sthompsa 5974233283Sbschmidt if (run_load_microcode(sc) != 0) { 5975233283Sbschmidt device_printf(sc->sc_dev, "could not load 8051 microcode\n"); 5976233283Sbschmidt goto fail; 5977233283Sbschmidt } 5978233283Sbschmidt 5979203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5980203134Sthompsa if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0) 5981203134Sthompsa goto fail; 5982203134Sthompsa if (tmp != 0 && tmp != 0xffffffff) 5983203134Sthompsa break; 5984203134Sthompsa run_delay(sc, 10); 5985203134Sthompsa } 5986203134Sthompsa if (ntries == 100) 5987203134Sthompsa goto fail; 5988203134Sthompsa 5989203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 5990203134Sthompsa run_setup_tx_list(sc, &sc->sc_epq[i]); 5991203134Sthompsa 5992203134Sthompsa run_set_macaddr(sc, IF_LLADDR(ifp)); 5993203134Sthompsa 5994203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 5995203134Sthompsa if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 5996203134Sthompsa goto fail; 5997203134Sthompsa if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 5998203134Sthompsa break; 5999203134Sthompsa run_delay(sc, 10); 6000203134Sthompsa } 6001203134Sthompsa if (ntries == 100) { 6002203138Sthompsa device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); 6003203134Sthompsa goto fail; 6004203134Sthompsa } 6005203134Sthompsa tmp &= 0xff0; 6006203134Sthompsa tmp |= RT2860_TX_WB_DDONE; 6007203134Sthompsa run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 6008203134Sthompsa 6009203134Sthompsa /* turn off PME_OEN to solve high-current issue */ 6010203134Sthompsa run_read(sc, RT2860_SYS_CTRL, &tmp); 6011203134Sthompsa run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN); 6012203134Sthompsa 6013203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 6014203134Sthompsa RT2860_BBP_HRST | RT2860_MAC_SRST); 6015203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, 0); 6016203134Sthompsa 6017203134Sthompsa if (run_reset(sc) != 0) { 6018203138Sthompsa device_printf(sc->sc_dev, "could not reset chipset\n"); 6019203134Sthompsa goto fail; 6020203134Sthompsa } 6021203134Sthompsa 6022203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 0); 6023203134Sthompsa 6024203134Sthompsa /* init Tx power for all Tx rates (from EEPROM) */ 6025203134Sthompsa for (ridx = 0; ridx < 5; ridx++) { 6026203134Sthompsa if (sc->txpow20mhz[ridx] == 0xffffffff) 6027203134Sthompsa continue; 6028203134Sthompsa run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]); 6029203134Sthompsa } 6030203134Sthompsa 6031259453Shselasky for (i = 0; i < nitems(rt2870_def_mac); i++) 6032203134Sthompsa run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val); 6033203134Sthompsa run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273); 6034203134Sthompsa run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344); 6035203134Sthompsa run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa); 6036203134Sthompsa 6037259453Shselasky if (sc->mac_ver >= 0x5390) { 6038259453Shselasky run_write(sc, RT2860_TX_SW_CFG0, 6039259453Shselasky 4 << RT2860_DLY_PAPE_EN_SHIFT | 4); 6040259453Shselasky if (sc->mac_ver >= 0x5392) { 6041259453Shselasky run_write(sc, RT2860_MAX_LEN_CFG, 0x00002fff); 6042259453Shselasky if (sc->mac_ver == 0x5592) { 6043259453Shselasky run_write(sc, RT2860_HT_FBK_CFG1, 0xedcba980); 6044259453Shselasky run_write(sc, RT2860_TXOP_HLDR_ET, 0x00000082); 6045259453Shselasky } else { 6046259453Shselasky run_write(sc, RT2860_HT_FBK_CFG1, 0xedcb4980); 6047259453Shselasky run_write(sc, RT2860_LG_FBK_CFG0, 0xedcba322); 6048259453Shselasky } 6049259453Shselasky } 6050261868Skevlo } else if (sc->mac_ver == 0x3593) { 6051261868Skevlo run_write(sc, RT2860_TX_SW_CFG0, 6052261868Skevlo 4 << RT2860_DLY_PAPE_EN_SHIFT | 2); 6053259453Shselasky } else if (sc->mac_ver >= 0x3070) { 6054203134Sthompsa /* set delay of PA_PE assertion to 1us (unit of 0.25us) */ 6055203134Sthompsa run_write(sc, RT2860_TX_SW_CFG0, 6056203134Sthompsa 4 << RT2860_DLY_PAPE_EN_SHIFT); 6057203134Sthompsa } 6058203134Sthompsa 6059203134Sthompsa /* wait while MAC is busy */ 6060203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 6061203134Sthompsa if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0) 6062203134Sthompsa goto fail; 6063203134Sthompsa if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY))) 6064203134Sthompsa break; 6065203134Sthompsa run_delay(sc, 10); 6066203134Sthompsa } 6067203134Sthompsa if (ntries == 100) 6068203134Sthompsa goto fail; 6069203134Sthompsa 6070203134Sthompsa /* clear Host to MCU mailbox */ 6071203134Sthompsa run_write(sc, RT2860_H2M_BBPAGENT, 0); 6072203134Sthompsa run_write(sc, RT2860_H2M_MAILBOX, 0); 6073203134Sthompsa run_delay(sc, 10); 6074203134Sthompsa 6075203134Sthompsa if (run_bbp_init(sc) != 0) { 6076203138Sthompsa device_printf(sc->sc_dev, "could not initialize BBP\n"); 6077203134Sthompsa goto fail; 6078203134Sthompsa } 6079203134Sthompsa 6080203134Sthompsa /* abort TSF synchronization */ 6081203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 6082203134Sthompsa tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 6083203134Sthompsa RT2860_TBTT_TIMER_EN); 6084203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, tmp); 6085203134Sthompsa 6086203134Sthompsa /* clear RX WCID search table */ 6087203134Sthompsa run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512); 6088203134Sthompsa /* clear WCID attribute table */ 6089203134Sthompsa run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32); 6090203134Sthompsa 6091209144Sthompsa /* hostapd sets a key before init. So, don't clear it. */ 6092209917Sthompsa if (sc->cmdq_key_set != RUN_CMDQ_GO) { 6093209144Sthompsa /* clear shared key table */ 6094209144Sthompsa run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32); 6095209144Sthompsa /* clear shared key mode */ 6096209144Sthompsa run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4); 6097209144Sthompsa } 6098209144Sthompsa 6099203134Sthompsa run_read(sc, RT2860_US_CYC_CNT, &tmp); 6100203134Sthompsa tmp = (tmp & ~0xff) | 0x1e; 6101203134Sthompsa run_write(sc, RT2860_US_CYC_CNT, tmp); 6102203134Sthompsa 6103205042Sthompsa if (sc->mac_rev != 0x0101) 6104203134Sthompsa run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f); 6105203134Sthompsa 6106203134Sthompsa run_write(sc, RT2860_WMM_TXOP0_CFG, 0); 6107203134Sthompsa run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96); 6108203134Sthompsa 6109203134Sthompsa /* write vendor-specific BBP values (from EEPROM) */ 6110261868Skevlo if (sc->mac_ver < 0x3593) { 6111259453Shselasky for (i = 0; i < 10; i++) { 6112259453Shselasky if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff) 6113259453Shselasky continue; 6114259453Shselasky run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val); 6115259453Shselasky } 6116203134Sthompsa } 6117203134Sthompsa 6118203134Sthompsa /* select Main antenna for 1T1R devices */ 6119259453Shselasky if (sc->rf_rev == RT3070_RF_3020 || sc->rf_rev == RT5390_RF_5370) 6120203134Sthompsa run_set_rx_antenna(sc, 0); 6121203134Sthompsa 6122203134Sthompsa /* send LEDs operating mode to microcontroller */ 6123203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]); 6124203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]); 6125203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]); 6126203134Sthompsa 6127259453Shselasky if (sc->mac_ver >= 0x5390) 6128259453Shselasky run_rt5390_rf_init(sc); 6129261868Skevlo else if (sc->mac_ver == 0x3593) 6130261868Skevlo run_rt3593_rf_init(sc); 6131259453Shselasky else if (sc->mac_ver >= 0x3070) 6132205042Sthompsa run_rt3070_rf_init(sc); 6133205042Sthompsa 6134203134Sthompsa /* disable non-existing Rx chains */ 6135203134Sthompsa run_bbp_read(sc, 3, &bbp3); 6136203134Sthompsa bbp3 &= ~(1 << 3 | 1 << 4); 6137203134Sthompsa if (sc->nrxchains == 2) 6138203134Sthompsa bbp3 |= 1 << 3; 6139203134Sthompsa else if (sc->nrxchains == 3) 6140203134Sthompsa bbp3 |= 1 << 4; 6141203134Sthompsa run_bbp_write(sc, 3, bbp3); 6142203134Sthompsa 6143203134Sthompsa /* disable non-existing Tx chains */ 6144203134Sthompsa run_bbp_read(sc, 1, &bbp1); 6145203134Sthompsa if (sc->ntxchains == 1) 6146203134Sthompsa bbp1 &= ~(1 << 3 | 1 << 4); 6147203134Sthompsa run_bbp_write(sc, 1, bbp1); 6148203134Sthompsa 6149261868Skevlo if (sc->mac_ver >= 0x5390) 6150261868Skevlo run_rt5390_rf_setup(sc); 6151261868Skevlo else if (sc->mac_ver == 0x3593) 6152261868Skevlo run_rt3593_rf_setup(sc); 6153261868Skevlo else if (sc->mac_ver >= 0x3070) 6154205042Sthompsa run_rt3070_rf_setup(sc); 6155203134Sthompsa 6156203134Sthompsa /* select default channel */ 6157203134Sthompsa run_set_chan(sc, ic->ic_curchan); 6158203134Sthompsa 6159203134Sthompsa /* setup initial protection mode */ 6160218492Sbschmidt run_updateprot_cb(ic); 6161203134Sthompsa 6162203134Sthompsa /* turn radio LED on */ 6163203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO); 6164203134Sthompsa 6165203134Sthompsa ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 6166203134Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 6167208019Sthompsa sc->cmdq_run = RUN_CMDQ_GO; 6168203134Sthompsa 6169209917Sthompsa for (i = 0; i != RUN_N_XFER; i++) 6170203134Sthompsa usbd_xfer_set_stall(sc->sc_xfer[i]); 6171203134Sthompsa 6172203134Sthompsa usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]); 6173203134Sthompsa 6174203134Sthompsa if (run_txrx_enable(sc) != 0) 6175203134Sthompsa goto fail; 6176203134Sthompsa 6177203134Sthompsa return; 6178203134Sthompsa 6179203134Sthompsafail: 6180203134Sthompsa run_stop(sc); 6181203134Sthompsa} 6182203134Sthompsa 6183203134Sthompsastatic void 6184203134Sthompsarun_init(void *arg) 6185203134Sthompsa{ 6186203134Sthompsa struct run_softc *sc = arg; 6187203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 6188203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 6189203134Sthompsa 6190203134Sthompsa RUN_LOCK(sc); 6191203134Sthompsa run_init_locked(sc); 6192203134Sthompsa RUN_UNLOCK(sc); 6193203134Sthompsa 6194203134Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING) 6195208019Sthompsa ieee80211_start_all(ic); 6196203134Sthompsa} 6197203134Sthompsa 6198203134Sthompsastatic void 6199203134Sthompsarun_stop(void *arg) 6200203134Sthompsa{ 6201203134Sthompsa struct run_softc *sc = (struct run_softc *)arg; 6202203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 6203203134Sthompsa uint32_t tmp; 6204203134Sthompsa int i; 6205203134Sthompsa int ntries; 6206203134Sthompsa 6207203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 6208203134Sthompsa 6209203134Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING) 6210203134Sthompsa run_set_leds(sc, 0); /* turn all LEDs off */ 6211203134Sthompsa 6212203134Sthompsa ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 6213203134Sthompsa 6214208019Sthompsa sc->ratectl_run = RUN_RATECTL_OFF; 6215209144Sthompsa sc->cmdq_run = sc->cmdq_key_set; 6216208019Sthompsa 6217203134Sthompsa RUN_UNLOCK(sc); 6218203134Sthompsa 6219203134Sthompsa for(i = 0; i < RUN_N_XFER; i++) 6220203134Sthompsa usbd_transfer_drain(sc->sc_xfer[i]); 6221203134Sthompsa 6222203134Sthompsa RUN_LOCK(sc); 6223203134Sthompsa 6224209917Sthompsa if (sc->rx_m != NULL) { 6225203134Sthompsa m_free(sc->rx_m); 6226203134Sthompsa sc->rx_m = NULL; 6227203134Sthompsa } 6228203134Sthompsa 6229259453Shselasky /* Disable Tx/Rx DMA. */ 6230259453Shselasky if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 6231259453Shselasky return; 6232259453Shselasky tmp &= ~(RT2860_RX_DMA_EN | RT2860_TX_DMA_EN); 6233259453Shselasky run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 6234259453Shselasky 6235259453Shselasky for (ntries = 0; ntries < 100; ntries++) { 6236259453Shselasky if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 6237259453Shselasky return; 6238259453Shselasky if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 6239259453Shselasky break; 6240259453Shselasky run_delay(sc, 10); 6241259453Shselasky } 6242259453Shselasky if (ntries == 100) { 6243259453Shselasky device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); 6244259453Shselasky return; 6245259453Shselasky } 6246259453Shselasky 6247203134Sthompsa /* disable Tx/Rx */ 6248203134Sthompsa run_read(sc, RT2860_MAC_SYS_CTRL, &tmp); 6249203134Sthompsa tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 6250203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, tmp); 6251203134Sthompsa 6252203134Sthompsa /* wait for pending Tx to complete */ 6253203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 6254209917Sthompsa if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0) { 6255203134Sthompsa DPRINTF("Cannot read Tx queue count\n"); 6256203134Sthompsa break; 6257203134Sthompsa } 6258209917Sthompsa if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0) { 6259203134Sthompsa DPRINTF("All Tx cleared\n"); 6260203134Sthompsa break; 6261203134Sthompsa } 6262203134Sthompsa run_delay(sc, 10); 6263203134Sthompsa } 6264209917Sthompsa if (ntries >= 100) 6265203134Sthompsa DPRINTF("There are still pending Tx\n"); 6266203134Sthompsa run_delay(sc, 10); 6267203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, 0); 6268203134Sthompsa 6269203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST); 6270203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 0); 6271203134Sthompsa 6272203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 6273203134Sthompsa run_unsetup_tx_list(sc, &sc->sc_epq[i]); 6274203134Sthompsa} 6275203134Sthompsa 6276203134Sthompsastatic void 6277259453Shselaskyrun_delay(struct run_softc *sc, u_int ms) 6278203134Sthompsa{ 6279203134Sthompsa usb_pause_mtx(mtx_owned(&sc->sc_mtx) ? 6280203134Sthompsa &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms)); 6281203134Sthompsa} 6282203134Sthompsa 6283203134Sthompsastatic device_method_t run_methods[] = { 6284203134Sthompsa /* Device interface */ 6285203134Sthompsa DEVMETHOD(device_probe, run_match), 6286203134Sthompsa DEVMETHOD(device_attach, run_attach), 6287203134Sthompsa DEVMETHOD(device_detach, run_detach), 6288246614Shselasky DEVMETHOD_END 6289203134Sthompsa}; 6290203134Sthompsa 6291203134Sthompsastatic driver_t run_driver = { 6292233774Shselasky .name = "run", 6293233774Shselasky .methods = run_methods, 6294233774Shselasky .size = sizeof(struct run_softc) 6295203134Sthompsa}; 6296203134Sthompsa 6297203134Sthompsastatic devclass_t run_devclass; 6298203134Sthompsa 6299261868SkevloDRIVER_MODULE(run, uhub, run_driver, run_devclass, run_driver_loaded, NULL); 6300212122SthompsaMODULE_DEPEND(run, wlan, 1, 1, 1); 6301212122SthompsaMODULE_DEPEND(run, usb, 1, 1, 1); 6302212122SthompsaMODULE_DEPEND(run, firmware, 1, 1, 1); 6303212122SthompsaMODULE_VERSION(run, 1); 6304