if_run.c revision 245047
1178676Ssam/*- 2198429Srpaulo * Copyright (c) 2008,2010 Damien Bergamini <damien.bergamini@free.fr> 3178676Ssam * ported to FreeBSD by Akinori Furukoshi <moonlightakkiy@yahoo.ca> 4178676Ssam * USB Consulting, Hans Petter Selasky <hselasky@freebsd.org> 5178676Ssam * 6178676Ssam * Permission to use, copy, modify, and distribute this software for any 7178676Ssam * purpose with or without fee is hereby granted, provided that the above 8178676Ssam * copyright notice and this permission notice appear in all copies. 9178676Ssam * 10178676Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11178676Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12178676Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13178676Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14178676Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15178676Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16178676Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17178676Ssam */ 18178676Ssam 19178676Ssam#include <sys/cdefs.h> 20178676Ssam__FBSDID("$FreeBSD: head/sys/dev/usb/wlan/if_run.c 245047 2013-01-04 20:44:17Z hselasky $"); 21178676Ssam 22201209Srpaulo/*- 23201209Srpaulo * Ralink Technology RT2700U/RT2800U/RT3000U chipset driver. 24178676Ssam * http://www.ralinktech.com/ 25178676Ssam */ 26178676Ssam 27178676Ssam#include <sys/param.h> 28178676Ssam#include <sys/sockio.h> 29178676Ssam#include <sys/sysctl.h> 30178676Ssam#include <sys/lock.h> 31178676Ssam#include <sys/mutex.h> 32178676Ssam#include <sys/mbuf.h> 33178676Ssam#include <sys/kernel.h> 34178676Ssam#include <sys/socket.h> 35178676Ssam#include <sys/systm.h> 36178676Ssam#include <sys/malloc.h> 37178676Ssam#include <sys/module.h> 38178676Ssam#include <sys/bus.h> 39178676Ssam#include <sys/endian.h> 40178676Ssam#include <sys/linker.h> 41178676Ssam#include <sys/firmware.h> 42178676Ssam#include <sys/kdb.h> 43178676Ssam 44178676Ssam#include <machine/bus.h> 45178676Ssam#include <machine/resource.h> 46178676Ssam#include <sys/rman.h> 47178676Ssam 48178676Ssam#include <net/bpf.h> 49178676Ssam#include <net/if.h> 50178676Ssam#include <net/if_arp.h> 51178676Ssam#include <net/ethernet.h> 52178676Ssam#include <net/if_dl.h> 53178676Ssam#include <net/if_media.h> 54178676Ssam#include <net/if_types.h> 55178676Ssam 56178676Ssam#include <netinet/in.h> 57178676Ssam#include <netinet/in_systm.h> 58178676Ssam#include <netinet/in_var.h> 59178676Ssam#include <netinet/if_ether.h> 60178676Ssam#include <netinet/ip.h> 61178676Ssam 62178676Ssam#include <net80211/ieee80211_var.h> 63178676Ssam#include <net80211/ieee80211_regdomain.h> 64178676Ssam#include <net80211/ieee80211_radiotap.h> 65178676Ssam#include <net80211/ieee80211_ratectl.h> 66178676Ssam 67178676Ssam#include <dev/usb/usb.h> 68178676Ssam#include <dev/usb/usbdi.h> 69178676Ssam#include "usbdevs.h" 70206358Srpaulo 71178676Ssam#define USB_DEBUG_VAR run_debug 72178676Ssam#include <dev/usb/usb_debug.h> 73178676Ssam 74178676Ssam#include <dev/usb/wlan/if_runreg.h> 75220723Sbschmidt#include <dev/usb/wlan/if_runvar.h> 76220723Sbschmidt 77220723Sbschmidt#define N(_a) ((int)(sizeof((_a)) / sizeof((_a)[0]))) 78220723Sbschmidt 79220723Sbschmidt#ifdef USB_DEBUG 80220723Sbschmidt#define RUN_DEBUG 81220895Sbschmidt#endif 82220895Sbschmidt 83220895Sbschmidt#ifdef RUN_DEBUG 84220895Sbschmidtint run_debug = 0; 85220895Sbschmidtstatic SYSCTL_NODE(_hw_usb, OID_AUTO, run, CTLFLAG_RW, 0, "USB run"); 86220895SbschmidtSYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RW, &run_debug, 0, 87220895Sbschmidt "run debug level"); 88220895Sbschmidt#endif 89220895Sbschmidt 90220895Sbschmidt#define IEEE80211_HAS_ADDR4(wh) \ 91220895Sbschmidt (((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) 92220895Sbschmidt 93220895Sbschmidt/* 94220895Sbschmidt * Because of LOR in run_key_delete(), use atomic instead. 95221634Sbschmidt * '& RUN_CMDQ_MASQ' is to loop cmdq[]. 96220895Sbschmidt */ 97220895Sbschmidt#define RUN_CMDQ_GET(c) (atomic_fetchadd_32((c), 1) & RUN_CMDQ_MASQ) 98221634Sbschmidt 99220895Sbschmidtstatic const STRUCT_USB_HOST_ID run_devs[] = { 100220895Sbschmidt#define RUN_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } 101220895Sbschmidt RUN_DEV(ABOCOM, RT2770), 102220895Sbschmidt RUN_DEV(ABOCOM, RT2870), 103220895Sbschmidt RUN_DEV(ABOCOM, RT3070), 104220895Sbschmidt RUN_DEV(ABOCOM, RT3071), 105220895Sbschmidt RUN_DEV(ABOCOM, RT3072), 106220895Sbschmidt RUN_DEV(ABOCOM2, RT2870_1), 107220895Sbschmidt RUN_DEV(ACCTON, RT2770), 108220723Sbschmidt RUN_DEV(ACCTON, RT2870_1), 109220723Sbschmidt RUN_DEV(ACCTON, RT2870_2), 110220723Sbschmidt RUN_DEV(ACCTON, RT2870_3), 111178676Ssam RUN_DEV(ACCTON, RT2870_4), 112178676Ssam RUN_DEV(ACCTON, RT2870_5), 113220728Sbschmidt RUN_DEV(ACCTON, RT3070), 114220728Sbschmidt RUN_DEV(ACCTON, RT3070_1), 115206477Sbschmidt RUN_DEV(ACCTON, RT3070_2), 116220723Sbschmidt RUN_DEV(ACCTON, RT3070_3), 117178676Ssam RUN_DEV(ACCTON, RT3070_4), 118178676Ssam RUN_DEV(ACCTON, RT3070_5), 119178676Ssam RUN_DEV(AIRTIES, RT3070), 120178676Ssam RUN_DEV(ALLWIN, RT2070), 121178676Ssam RUN_DEV(ALLWIN, RT2770), 122206474Sbschmidt RUN_DEV(ALLWIN, RT2870), 123220723Sbschmidt RUN_DEV(ALLWIN, RT3070), 124220723Sbschmidt RUN_DEV(ALLWIN, RT3071), 125220723Sbschmidt RUN_DEV(ALLWIN, RT3072), 126206477Sbschmidt RUN_DEV(ALLWIN, RT3572), 127206477Sbschmidt RUN_DEV(AMIGO, RT2870_1), 128206477Sbschmidt RUN_DEV(AMIGO, RT2870_2), 129206477Sbschmidt RUN_DEV(AMIT, CGWLUSB2GNR), 130206474Sbschmidt RUN_DEV(AMIT, RT2870_1), 131178676Ssam RUN_DEV(AMIT2, RT2870), 132220691Sbschmidt RUN_DEV(ASUS, RT2870_1), 133178676Ssam RUN_DEV(ASUS, RT2870_2), 134206477Sbschmidt RUN_DEV(ASUS, RT2870_3), 135206477Sbschmidt RUN_DEV(ASUS, RT2870_4), 136206477Sbschmidt RUN_DEV(ASUS, RT2870_5), 137206477Sbschmidt RUN_DEV(ASUS, USBN13), 138206477Sbschmidt RUN_DEV(ASUS, RT3070_1), 139206477Sbschmidt RUN_DEV(ASUS, USB_N53), 140206477Sbschmidt RUN_DEV(ASUS2, USBN11), 141206477Sbschmidt RUN_DEV(AZUREWAVE, RT2870_1), 142206477Sbschmidt RUN_DEV(AZUREWAVE, RT2870_2), 143206477Sbschmidt RUN_DEV(AZUREWAVE, RT3070_1), 144206477Sbschmidt RUN_DEV(AZUREWAVE, RT3070_2), 145206477Sbschmidt RUN_DEV(AZUREWAVE, RT3070_3), 146178676Ssam RUN_DEV(BELKIN, F5D8053V3), 147206477Sbschmidt RUN_DEV(BELKIN, F5D8055), 148206477Sbschmidt RUN_DEV(BELKIN, F5D8055V2), 149206477Sbschmidt RUN_DEV(BELKIN, F6D4050V1), 150206477Sbschmidt RUN_DEV(BELKIN, RT2870_1), 151198429Srpaulo RUN_DEV(BELKIN, RT2870_2), 152206477Sbschmidt RUN_DEV(CISCOLINKSYS, AE1000), 153206477Sbschmidt RUN_DEV(CISCOLINKSYS2, RT3070), 154206477Sbschmidt RUN_DEV(CISCOLINKSYS3, RT3070), 155206474Sbschmidt RUN_DEV(CONCEPTRONIC2, RT2870_1), 156206474Sbschmidt RUN_DEV(CONCEPTRONIC2, RT2870_2), 157206474Sbschmidt RUN_DEV(CONCEPTRONIC2, RT2870_3), 158220726Sbschmidt RUN_DEV(CONCEPTRONIC2, RT2870_4), 159220723Sbschmidt RUN_DEV(CONCEPTRONIC2, RT2870_5), 160220723Sbschmidt RUN_DEV(CONCEPTRONIC2, RT2870_6), 161220723Sbschmidt RUN_DEV(CONCEPTRONIC2, RT2870_7), 162220723Sbschmidt RUN_DEV(CONCEPTRONIC2, RT2870_8), 163220726Sbschmidt RUN_DEV(CONCEPTRONIC2, RT3070_1), 164206477Sbschmidt RUN_DEV(CONCEPTRONIC2, RT3070_2), 165206477Sbschmidt RUN_DEV(CONCEPTRONIC2, VIGORN61), 166198429Srpaulo RUN_DEV(COREGA, CGWLUSB300GNM), 167220715Sbschmidt RUN_DEV(COREGA, RT2870_1), 168206477Sbschmidt RUN_DEV(COREGA, RT2870_2), 169206477Sbschmidt RUN_DEV(COREGA, RT2870_3), 170220667Sbschmidt RUN_DEV(COREGA, RT3070), 171206477Sbschmidt RUN_DEV(CYBERTAN, RT2870), 172198429Srpaulo RUN_DEV(DLINK, RT2870), 173206477Sbschmidt RUN_DEV(DLINK, RT3072), 174178676Ssam RUN_DEV(DLINK2, DWA130), 175206477Sbschmidt RUN_DEV(DLINK2, RT2870_1), 176201209Srpaulo RUN_DEV(DLINK2, RT2870_2), 177220674Sbschmidt RUN_DEV(DLINK2, RT3070_1), 178220674Sbschmidt RUN_DEV(DLINK2, RT3070_2), 179206477Sbschmidt RUN_DEV(DLINK2, RT3070_3), 180198429Srpaulo RUN_DEV(DLINK2, RT3070_4), 181206477Sbschmidt RUN_DEV(DLINK2, RT3070_5), 182198429Srpaulo RUN_DEV(DLINK2, RT3072), 183206477Sbschmidt RUN_DEV(DLINK2, RT3072_1), 184198429Srpaulo RUN_DEV(EDIMAX, EW7717), 185206477Sbschmidt RUN_DEV(EDIMAX, EW7718), 186198429Srpaulo RUN_DEV(EDIMAX, RT2870_1), 187221651Sbschmidt RUN_DEV(ENCORE, RT3070_1), 188206477Sbschmidt RUN_DEV(ENCORE, RT3070_2), 189206477Sbschmidt RUN_DEV(ENCORE, RT3070_3), 190206477Sbschmidt RUN_DEV(GIGABYTE, GNWB31N), 191206477Sbschmidt RUN_DEV(GIGABYTE, GNWB32L), 192206477Sbschmidt RUN_DEV(GIGABYTE, RT2870_1), 193206477Sbschmidt RUN_DEV(GIGASET, RT3070_1), 194206477Sbschmidt RUN_DEV(GIGASET, RT3070_2), 195198429Srpaulo RUN_DEV(GUILLEMOT, HWNU300), 196206477Sbschmidt RUN_DEV(HAWKING, HWUN2), 197198429Srpaulo RUN_DEV(HAWKING, RT2870_1), 198206475Sbschmidt RUN_DEV(HAWKING, RT2870_2), 199206477Sbschmidt RUN_DEV(HAWKING, RT3070), 200206475Sbschmidt RUN_DEV(IODATA, RT3072_1), 201206477Sbschmidt RUN_DEV(IODATA, RT3072_2), 202220720Sbschmidt RUN_DEV(IODATA, RT3072_3), 203220720Sbschmidt RUN_DEV(IODATA, RT3072_4), 204220720Sbschmidt RUN_DEV(LINKSYS4, RT3070), 205220720Sbschmidt RUN_DEV(LINKSYS4, WUSB100), 206198429Srpaulo RUN_DEV(LINKSYS4, WUSB54GCV3), 207198429Srpaulo RUN_DEV(LINKSYS4, WUSB600N), 208206477Sbschmidt RUN_DEV(LINKSYS4, WUSB600NV2), 209206477Sbschmidt RUN_DEV(LOGITEC, RT2870_1), 210220667Sbschmidt RUN_DEV(LOGITEC, RT2870_2), 211206477Sbschmidt RUN_DEV(LOGITEC, RT2870_3), 212206477Sbschmidt RUN_DEV(LOGITEC, LANW300NU2), 213206477Sbschmidt RUN_DEV(LOGITEC, LANW150NU2), 214198429Srpaulo RUN_DEV(MELCO, RT2870_1), 215206477Sbschmidt RUN_DEV(MELCO, RT2870_2), 216198429Srpaulo RUN_DEV(MELCO, WLIUCAG300N), 217220715Sbschmidt RUN_DEV(MELCO, WLIUCG300N), 218220715Sbschmidt RUN_DEV(MELCO, WLIUCG301N), 219206477Sbschmidt RUN_DEV(MELCO, WLIUCGN), 220220721Sbschmidt RUN_DEV(MELCO, WLIUCGNM), 221201209Srpaulo RUN_DEV(MELCO, WLIUCGNM2), 222206477Sbschmidt RUN_DEV(MOTOROLA4, RT2770), 223206477Sbschmidt RUN_DEV(MOTOROLA4, RT3070), 224206477Sbschmidt RUN_DEV(MSI, RT3070_1), 225206477Sbschmidt RUN_DEV(MSI, RT3070_2), 226206477Sbschmidt RUN_DEV(MSI, RT3070_3), 227201882Skeramida RUN_DEV(MSI, RT3070_4), 228206477Sbschmidt RUN_DEV(MSI, RT3070_5), 229201882Skeramida RUN_DEV(MSI, RT3070_6), 230206477Sbschmidt RUN_DEV(MSI, RT3070_7), 231206477Sbschmidt RUN_DEV(MSI, RT3070_8), 232206477Sbschmidt RUN_DEV(MSI, RT3070_9), 233206477Sbschmidt RUN_DEV(MSI, RT3070_10), 234206477Sbschmidt RUN_DEV(MSI, RT3070_11), 235206477Sbschmidt RUN_DEV(OVISLINK, RT3072), 236206477Sbschmidt RUN_DEV(PARA, RT3070), 237178676Ssam RUN_DEV(PEGATRON, RT2870), 238206477Sbschmidt RUN_DEV(PEGATRON, RT3070), 239206477Sbschmidt RUN_DEV(PEGATRON, RT3070_2), 240206477Sbschmidt RUN_DEV(PEGATRON, RT3070_3), 241206477Sbschmidt RUN_DEV(PHILIPS, RT2870), 242206477Sbschmidt RUN_DEV(PLANEX2, GWUS300MINIS), 243178676Ssam RUN_DEV(PLANEX2, GWUSMICRON), 244206477Sbschmidt RUN_DEV(PLANEX2, RT2870), 245206477Sbschmidt RUN_DEV(PLANEX2, RT3070), 246220662Sbschmidt RUN_DEV(QCOM, RT2870), 247220891Sbschmidt RUN_DEV(QUANTA, RT3070), 248206477Sbschmidt RUN_DEV(RALINK, RT2070), 249220634Sbschmidt RUN_DEV(RALINK, RT2770), 250206477Sbschmidt RUN_DEV(RALINK, RT2870), 251206477Sbschmidt RUN_DEV(RALINK, RT3070), 252206477Sbschmidt RUN_DEV(RALINK, RT3071), 253221650Sbschmidt RUN_DEV(RALINK, RT3072), 254221650Sbschmidt RUN_DEV(RALINK, RT3370), 255221650Sbschmidt RUN_DEV(RALINK, RT3572), 256221650Sbschmidt RUN_DEV(RALINK, RT8070), 257221651Sbschmidt RUN_DEV(SAMSUNG, WIS09ABGN), 258221651Sbschmidt RUN_DEV(SAMSUNG2, RT2870_1), 259221651Sbschmidt RUN_DEV(SENAO, RT2870_1), 260221651Sbschmidt RUN_DEV(SENAO, RT2870_2), 261206474Sbschmidt RUN_DEV(SENAO, RT2870_3), 262206474Sbschmidt RUN_DEV(SENAO, RT2870_4), 263221651Sbschmidt RUN_DEV(SENAO, RT3070), 264221651Sbschmidt RUN_DEV(SENAO, RT3071), 265206474Sbschmidt RUN_DEV(SENAO, RT3072_1), 266221651Sbschmidt RUN_DEV(SENAO, RT3072_2), 267221651Sbschmidt RUN_DEV(SENAO, RT3072_3), 268220726Sbschmidt RUN_DEV(SENAO, RT3072_4), 269206474Sbschmidt RUN_DEV(SENAO, RT3072_5), 270221651Sbschmidt RUN_DEV(SITECOMEU, RT2770), 271221651Sbschmidt RUN_DEV(SITECOMEU, RT2870_1), 272220726Sbschmidt RUN_DEV(SITECOMEU, RT2870_2), 273220674Sbschmidt RUN_DEV(SITECOMEU, RT2870_3), 274220674Sbschmidt RUN_DEV(SITECOMEU, RT2870_4), 275206477Sbschmidt RUN_DEV(SITECOMEU, RT3070), 276220677Sbschmidt RUN_DEV(SITECOMEU, RT3070_2), 277220676Sbschmidt RUN_DEV(SITECOMEU, RT3070_3), 278206477Sbschmidt RUN_DEV(SITECOMEU, RT3070_4), 279206477Sbschmidt RUN_DEV(SITECOMEU, RT3071), 280206477Sbschmidt RUN_DEV(SITECOMEU, RT3072_1), 281198429Srpaulo RUN_DEV(SITECOMEU, RT3072_2), 282206477Sbschmidt RUN_DEV(SITECOMEU, RT3072_3), 283206477Sbschmidt RUN_DEV(SITECOMEU, RT3072_4), 284198429Srpaulo RUN_DEV(SITECOMEU, RT3072_5), 285206477Sbschmidt RUN_DEV(SITECOMEU, RT3072_6), 286210111Sbschmidt RUN_DEV(SITECOMEU, WL608), 287210111Sbschmidt RUN_DEV(SPARKLAN, RT2870_1), 288210111Sbschmidt RUN_DEV(SPARKLAN, RT3070), 289210111Sbschmidt RUN_DEV(SWEEX2, LW153), 290206477Sbschmidt RUN_DEV(SWEEX2, LW303), 291206477Sbschmidt RUN_DEV(SWEEX2, LW313), 292206477Sbschmidt RUN_DEV(TOSHIBA, RT3070), 293206477Sbschmidt RUN_DEV(UMEDIA, RT2870_1), 294206477Sbschmidt RUN_DEV(ZCOM, RT2870_1), 295206477Sbschmidt RUN_DEV(ZCOM, RT2870_2), 296206477Sbschmidt RUN_DEV(ZINWELL, RT2870_1), 297206477Sbschmidt RUN_DEV(ZINWELL, RT2870_2), 298206477Sbschmidt RUN_DEV(ZINWELL, RT3070), 299206477Sbschmidt RUN_DEV(ZINWELL, RT3072_1), 300220723Sbschmidt RUN_DEV(ZINWELL, RT3072_2), 301220723Sbschmidt RUN_DEV(ZYXEL, RT2870_1), 302206477Sbschmidt RUN_DEV(ZYXEL, RT2870_2), 303206477Sbschmidt#undef RUN_DEV 304206477Sbschmidt}; 305206477Sbschmidt 306220726Sbschmidtstatic device_probe_t run_match; 307220726Sbschmidtstatic device_attach_t run_attach; 308220726Sbschmidtstatic device_detach_t run_detach; 309220726Sbschmidt 310220726Sbschmidtstatic usb_callback_t run_bulk_rx_callback; 311198429Srpaulostatic usb_callback_t run_bulk_tx_callback0; 312178676Ssamstatic usb_callback_t run_bulk_tx_callback1; 313178676Ssamstatic usb_callback_t run_bulk_tx_callback2; 314178676Ssamstatic usb_callback_t run_bulk_tx_callback3; 315178676Ssamstatic usb_callback_t run_bulk_tx_callback4; 316178676Ssamstatic usb_callback_t run_bulk_tx_callback5; 317178676Ssam 318178676Ssamstatic void run_bulk_tx_callbackN(struct usb_xfer *xfer, 319178676Ssam usb_error_t error, unsigned int index); 320178676Ssamstatic struct ieee80211vap *run_vap_create(struct ieee80211com *, 321178676Ssam const char [IFNAMSIZ], int, enum ieee80211_opmode, int, 322178676Ssam const uint8_t [IEEE80211_ADDR_LEN], 323178676Ssam const uint8_t [IEEE80211_ADDR_LEN]); 324178676Ssamstatic void run_vap_delete(struct ieee80211vap *); 325178676Ssamstatic void run_cmdq_cb(void *, int); 326178676Ssamstatic void run_setup_tx_list(struct run_softc *, 327178676Ssam struct run_endpoint_queue *); 328178676Ssamstatic void run_unsetup_tx_list(struct run_softc *, 329178676Ssam struct run_endpoint_queue *); 330178676Ssamstatic int run_load_microcode(struct run_softc *); 331178676Ssamstatic int run_reset(struct run_softc *); 332178676Ssamstatic usb_error_t run_do_request(struct run_softc *, 333178676Ssam struct usb_device_request *, void *); 334178676Ssamstatic int run_read(struct run_softc *, uint16_t, uint32_t *); 335178676Ssamstatic int run_read_region_1(struct run_softc *, uint16_t, uint8_t *, int); 336178676Ssamstatic int run_write_2(struct run_softc *, uint16_t, uint16_t); 337178676Ssamstatic int run_write(struct run_softc *, uint16_t, uint32_t); 338220723Sbschmidtstatic int run_write_region_1(struct run_softc *, uint16_t, 339220723Sbschmidt const uint8_t *, int); 340220723Sbschmidtstatic int run_set_region_4(struct run_softc *, uint16_t, uint32_t, int); 341220723Sbschmidtstatic int run_efuse_read_2(struct run_softc *, uint16_t, uint16_t *); 342220723Sbschmidtstatic int run_eeprom_read_2(struct run_softc *, uint16_t, uint16_t *); 343220723Sbschmidtstatic int run_rt2870_rf_write(struct run_softc *, uint8_t, uint32_t); 344220723Sbschmidtstatic int run_rt3070_rf_read(struct run_softc *, uint8_t, uint8_t *); 345220723Sbschmidtstatic int run_rt3070_rf_write(struct run_softc *, uint8_t, uint8_t); 346220723Sbschmidtstatic int run_bbp_read(struct run_softc *, uint8_t, uint8_t *); 347220723Sbschmidtstatic int run_bbp_write(struct run_softc *, uint8_t, uint8_t); 348220723Sbschmidtstatic int run_mcu_cmd(struct run_softc *, uint8_t, uint16_t); 349220723Sbschmidtstatic const char *run_get_rf(int); 350220723Sbschmidtstatic int run_read_eeprom(struct run_softc *); 351220723Sbschmidtstatic struct ieee80211_node *run_node_alloc(struct ieee80211vap *, 352220723Sbschmidt const uint8_t mac[IEEE80211_ADDR_LEN]); 353220723Sbschmidtstatic int run_media_change(struct ifnet *); 354220723Sbschmidtstatic int run_newstate(struct ieee80211vap *, enum ieee80211_state, int); 355220723Sbschmidtstatic int run_wme_update(struct ieee80211com *); 356220723Sbschmidtstatic void run_wme_update_cb(void *); 357220723Sbschmidtstatic void run_key_update_begin(struct ieee80211vap *); 358220723Sbschmidtstatic void run_key_update_end(struct ieee80211vap *); 359220723Sbschmidtstatic void run_key_set_cb(void *); 360220723Sbschmidtstatic int run_key_set(struct ieee80211vap *, struct ieee80211_key *, 361220723Sbschmidt const uint8_t mac[IEEE80211_ADDR_LEN]); 362220723Sbschmidtstatic void run_key_delete_cb(void *); 363220723Sbschmidtstatic int run_key_delete(struct ieee80211vap *, struct ieee80211_key *); 364220723Sbschmidtstatic void run_ratectl_to(void *); 365220723Sbschmidtstatic void run_ratectl_cb(void *, int); 366220723Sbschmidtstatic void run_drain_fifo(void *); 367220723Sbschmidtstatic void run_iter_func(void *, struct ieee80211_node *); 368220723Sbschmidtstatic void run_newassoc_cb(void *); 369220723Sbschmidtstatic void run_newassoc(struct ieee80211_node *, int); 370220723Sbschmidtstatic void run_rx_frame(struct run_softc *, struct mbuf *, uint32_t); 371220723Sbschmidtstatic void run_tx_free(struct run_endpoint_queue *pq, 372220723Sbschmidt struct run_tx_data *, int); 373220723Sbschmidtstatic void run_set_tx_desc(struct run_softc *, struct run_tx_data *); 374220723Sbschmidtstatic int run_tx(struct run_softc *, struct mbuf *, 375220723Sbschmidt struct ieee80211_node *); 376220723Sbschmidtstatic int run_tx_mgt(struct run_softc *, struct mbuf *, 377220723Sbschmidt struct ieee80211_node *); 378220723Sbschmidtstatic int run_sendprot(struct run_softc *, const struct mbuf *, 379220723Sbschmidt struct ieee80211_node *, int, int); 380178676Ssamstatic int run_tx_param(struct run_softc *, struct mbuf *, 381178676Ssam struct ieee80211_node *, 382178676Ssam const struct ieee80211_bpf_params *); 383178676Ssamstatic int run_raw_xmit(struct ieee80211_node *, struct mbuf *, 384220723Sbschmidt const struct ieee80211_bpf_params *); 385220723Sbschmidtstatic void run_start(struct ifnet *); 386220723Sbschmidtstatic int run_ioctl(struct ifnet *, u_long, caddr_t); 387220723Sbschmidtstatic void run_set_agc(struct run_softc *, uint8_t); 388220723Sbschmidtstatic void run_select_chan_group(struct run_softc *, int); 389220723Sbschmidtstatic void run_set_rx_antenna(struct run_softc *, int); 390220723Sbschmidtstatic void run_rt2870_set_chan(struct run_softc *, u_int); 391220723Sbschmidtstatic void run_rt3070_set_chan(struct run_softc *, u_int); 392220723Sbschmidtstatic void run_rt3572_set_chan(struct run_softc *, u_int); 393178676Ssamstatic int run_set_chan(struct run_softc *, struct ieee80211_channel *); 394178676Ssamstatic void run_set_channel(struct ieee80211com *); 395220723Sbschmidtstatic void run_scan_start(struct ieee80211com *); 396220723Sbschmidtstatic void run_scan_end(struct ieee80211com *); 397220723Sbschmidtstatic void run_update_beacon(struct ieee80211vap *, int); 398220726Sbschmidtstatic void run_update_beacon_cb(void *); 399178676Ssamstatic void run_updateprot(struct ieee80211com *); 400220723Sbschmidtstatic void run_updateprot_cb(void *); 401178676Ssamstatic void run_usb_timeout_cb(void *); 402220723Sbschmidtstatic void run_reset_livelock(struct run_softc *); 403220726Sbschmidtstatic void run_enable_tsf_sync(struct run_softc *); 404220723Sbschmidtstatic void run_enable_mrr(struct run_softc *); 405220723Sbschmidtstatic void run_set_txpreamble(struct run_softc *); 406220723Sbschmidtstatic void run_set_basicrates(struct run_softc *); 407220723Sbschmidtstatic void run_set_leds(struct run_softc *, uint16_t); 408178676Ssamstatic void run_set_bssid(struct run_softc *, const uint8_t *); 409178676Ssamstatic void run_set_macaddr(struct run_softc *, const uint8_t *); 410178676Ssamstatic void run_updateslot(struct ifnet *); 411198429Srpaulostatic void run_updateslot_cb(void *); 412178676Ssamstatic void run_update_mcast(struct ifnet *); 413198429Srpaulostatic int8_t run_rssi2dbm(struct run_softc *, uint8_t, uint8_t); 414198429Srpaulostatic void run_update_promisc_locked(struct ifnet *); 415198429Srpaulostatic void run_update_promisc(struct ifnet *); 416198429Srpaulostatic int run_bbp_init(struct run_softc *); 417198429Srpaulostatic int run_rt3070_rf_init(struct run_softc *); 418198429Srpaulostatic int run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t, 419198429Srpaulo uint8_t *); 420198429Srpaulostatic void run_rt3070_rf_setup(struct run_softc *); 421178676Ssamstatic int run_txrx_enable(struct run_softc *); 422178676Ssamstatic void run_init(void *); 423178676Ssamstatic void run_init_locked(struct run_softc *); 424178676Ssamstatic void run_stop(void *); 425178676Ssamstatic void run_delay(struct run_softc *, unsigned int); 426178676Ssam 427178676Ssamstatic const struct { 428178676Ssam uint16_t reg; 429220721Sbschmidt uint32_t val; 430184233Smav} rt2870_def_mac[] = { 431190526Ssam RT2870_DEF_MAC 432178676Ssam}; 433178676Ssam 434178676Ssamstatic const struct { 435198429Srpaulo uint8_t reg; 436198429Srpaulo uint8_t val; 437198429Srpaulo} rt2860_def_bbp[] = { 438198429Srpaulo RT2860_DEF_BBP 439219902Sjhb}; 440198429Srpaulo 441198429Srpaulostatic const struct rfprog { 442198429Srpaulo uint8_t chan; 443178676Ssam uint32_t r1, r2, r3, r4; 444178676Ssam} rt2860_rf2850[] = { 445198429Srpaulo RT2860_RF2850 446178676Ssam}; 447178676Ssam 448198429Srpaulostruct { 449220721Sbschmidt uint8_t n, r, k; 450220721Sbschmidt} rt3070_freqs[] = { 451198429Srpaulo RT3070_RF3052 452198429Srpaulo}; 453220721Sbschmidt 454220721Sbschmidtstatic const struct { 455198429Srpaulo uint8_t reg; 456198429Srpaulo uint8_t val; 457198429Srpaulo} rt3070_def_rf[] = { 458178676Ssam RT3070_DEF_RF 459178676Ssam},rt3572_def_rf[] = { 460198429Srpaulo RT3572_DEF_RF 461178676Ssam}; 462198429Srpaulo 463220726Sbschmidtstatic const struct usb_config run_config[RUN_N_XFER] = { 464220724Sbschmidt [RUN_BULK_TX_BE] = { 465198429Srpaulo .type = UE_BULK, 466178676Ssam .endpoint = UE_ADDR_ANY, 467178676Ssam .ep_index = 0, 468178676Ssam .direction = UE_DIR_OUT, 469178676Ssam .bufsize = RUN_MAX_TXSZ, 470220726Sbschmidt .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 471178676Ssam .callback = run_bulk_tx_callback0, 472184233Smav .timeout = 5000, /* ms */ 473184233Smav }, 474184233Smav [RUN_BULK_TX_BK] = { 475220725Sbschmidt .type = UE_BULK, 476178676Ssam .endpoint = UE_ADDR_ANY, 477198429Srpaulo .direction = UE_DIR_OUT, 478178676Ssam .ep_index = 1, 479220724Sbschmidt .bufsize = RUN_MAX_TXSZ, 480178676Ssam .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 481198429Srpaulo .callback = run_bulk_tx_callback1, 482178676Ssam .timeout = 5000, /* ms */ 483178676Ssam }, 484178676Ssam [RUN_BULK_TX_VI] = { 485178676Ssam .type = UE_BULK, 486220728Sbschmidt .endpoint = UE_ADDR_ANY, 487220728Sbschmidt .direction = UE_DIR_OUT, 488220728Sbschmidt .ep_index = 2, 489220728Sbschmidt .bufsize = RUN_MAX_TXSZ, 490220728Sbschmidt .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 491220728Sbschmidt .callback = run_bulk_tx_callback2, 492220728Sbschmidt .timeout = 5000, /* ms */ 493220728Sbschmidt }, 494220728Sbschmidt [RUN_BULK_TX_VO] = { 495198429Srpaulo .type = UE_BULK, 496198429Srpaulo .endpoint = UE_ADDR_ANY, 497198429Srpaulo .direction = UE_DIR_OUT, 498220726Sbschmidt .ep_index = 3, 499198429Srpaulo .bufsize = RUN_MAX_TXSZ, 500178676Ssam .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 501178676Ssam .callback = run_bulk_tx_callback3, 502178676Ssam .timeout = 5000, /* ms */ 503198429Srpaulo }, 504220726Sbschmidt [RUN_BULK_TX_HCCA] = { 505178676Ssam .type = UE_BULK, 506198429Srpaulo .endpoint = UE_ADDR_ANY, 507198429Srpaulo .direction = UE_DIR_OUT, 508178676Ssam .ep_index = 4, 509178676Ssam .bufsize = RUN_MAX_TXSZ, 510178676Ssam .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 511198429Srpaulo .callback = run_bulk_tx_callback4, 512220726Sbschmidt .timeout = 5000, /* ms */ 513178676Ssam }, 514220724Sbschmidt [RUN_BULK_TX_PRIO] = { 515178676Ssam .type = UE_BULK, 516178676Ssam .endpoint = UE_ADDR_ANY, 517178676Ssam .direction = UE_DIR_OUT, 518201209Srpaulo .ep_index = 5, 519201209Srpaulo .bufsize = RUN_MAX_TXSZ, 520201209Srpaulo .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 521220724Sbschmidt .callback = run_bulk_tx_callback5, 522220724Sbschmidt .timeout = 5000, /* ms */ 523201209Srpaulo }, 524201209Srpaulo [RUN_BULK_RX] = { 525201209Srpaulo .type = UE_BULK, 526198429Srpaulo .endpoint = UE_ADDR_ANY, 527220726Sbschmidt .direction = UE_DIR_IN, 528178676Ssam .bufsize = RUN_MAX_RXSZ, 529220726Sbschmidt .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 530178676Ssam .callback = run_bulk_rx_callback, 531178676Ssam } 532178676Ssam}; 533220725Sbschmidt 534220728Sbschmidtstatic int 535220726Sbschmidtrun_match(device_t self) 536178676Ssam{ 537220724Sbschmidt struct usb_attach_arg *uaa = device_get_ivars(self); 538220724Sbschmidt 539178676Ssam if (uaa->usb_mode != USB_MODE_HOST) 540178676Ssam return (ENXIO); 541178676Ssam if (uaa->info.bConfigIndex != 0) 542178676Ssam return (ENXIO); 543198429Srpaulo if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX) 544220726Sbschmidt return (ENXIO); 545220724Sbschmidt 546220724Sbschmidt return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa)); 547178676Ssam} 548178676Ssam 549178676Ssamstatic int 550198429Srpaulorun_attach(device_t self) 551198429Srpaulo{ 552198429Srpaulo struct run_softc *sc = device_get_softc(self); 553178676Ssam struct usb_attach_arg *uaa = device_get_ivars(self); 554178676Ssam struct ieee80211com *ic; 555178676Ssam struct ifnet *ifp; 556178676Ssam uint32_t ver; 557178676Ssam int i, ntries, error; 558220726Sbschmidt uint8_t iface_index, bands; 559178676Ssam 560198429Srpaulo device_set_usb_desc(self); 561178676Ssam sc->sc_udev = uaa->device; 562178676Ssam sc->sc_dev = self; 563178676Ssam 564198429Srpaulo mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), 565178676Ssam MTX_NETWORK_LOCK, MTX_DEF); 566178957Ssam 567178957Ssam iface_index = RT2860_IFACE_INDEX; 568178676Ssam 569178676Ssam error = usbd_transfer_setup(uaa->device, &iface_index, 570178676Ssam sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx); 571178676Ssam if (error) { 572178676Ssam device_printf(self, "could not allocate USB transfers, " 573178676Ssam "err=%s\n", usbd_errstr(error)); 574178676Ssam goto detach; 575178676Ssam } 576178676Ssam 577221640Sbschmidt RUN_LOCK(sc); 578221640Sbschmidt 579221640Sbschmidt /* wait for the chip to settle */ 580221642Sbschmidt for (ntries = 0; ntries < 100; ntries++) { 581221642Sbschmidt if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0) { 582221642Sbschmidt RUN_UNLOCK(sc); 583221642Sbschmidt goto detach; 584221642Sbschmidt } 585221642Sbschmidt if (ver != 0 && ver != 0xffffffff) 586221642Sbschmidt break; 587221642Sbschmidt run_delay(sc, 10); 588221642Sbschmidt } 589221642Sbschmidt if (ntries == 100) { 590221642Sbschmidt device_printf(sc->sc_dev, 591221642Sbschmidt "timeout waiting for NIC to initialize\n"); 592221642Sbschmidt RUN_UNLOCK(sc); 593221642Sbschmidt goto detach; 594221642Sbschmidt } 595221642Sbschmidt sc->mac_ver = ver >> 16; 596221642Sbschmidt sc->mac_rev = ver & 0xffff; 597221642Sbschmidt 598221642Sbschmidt /* retrieve RF rev. no and various other things from EEPROM */ 599221642Sbschmidt run_read_eeprom(sc); 600221642Sbschmidt 601221642Sbschmidt device_printf(sc->sc_dev, 602221657Sbschmidt "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n", 603221657Sbschmidt sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev), 604221657Sbschmidt sc->ntxchains, sc->nrxchains, ether_sprintf(sc->sc_bssid)); 605221657Sbschmidt 606221657Sbschmidt RUN_UNLOCK(sc); 607221657Sbschmidt 608221657Sbschmidt ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); 609221657Sbschmidt if (ifp == NULL) { 610221657Sbschmidt device_printf(sc->sc_dev, "can not if_alloc()\n"); 611221657Sbschmidt goto detach; 612201209Srpaulo } 613221657Sbschmidt ic = ifp->if_l2com; 614221657Sbschmidt 615221657Sbschmidt ifp->if_softc = sc; 616178678Ssam if_initname(ifp, "run", device_get_unit(sc->sc_dev)); 617201209Srpaulo ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 618221657Sbschmidt ifp->if_init = run_init; 619221657Sbschmidt ifp->if_ioctl = run_ioctl; 620221657Sbschmidt ifp->if_start = run_start; 621221657Sbschmidt IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 622221657Sbschmidt ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 623201209Srpaulo IFQ_SET_READY(&ifp->if_snd); 624221657Sbschmidt 625221657Sbschmidt ic->ic_ifp = ifp; 626201209Srpaulo ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 627178676Ssam ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 628178676Ssam 629178676Ssam /* set device capabilities */ 630178676Ssam ic->ic_caps = 631178676Ssam IEEE80211_C_STA | /* station mode supported */ 632178676Ssam IEEE80211_C_MONITOR | /* monitor mode supported */ 633207554Ssobomax IEEE80211_C_IBSS | 634207554Ssobomax IEEE80211_C_HOSTAP | 635178676Ssam IEEE80211_C_WDS | /* 4-address traffic works */ 636178676Ssam IEEE80211_C_MBSS | 637190526Ssam IEEE80211_C_SHPREAMBLE | /* short preamble supported */ 638178676Ssam IEEE80211_C_SHSLOT | /* short slot time supported */ 639178676Ssam IEEE80211_C_WME | /* WME */ 640178676Ssam IEEE80211_C_WPA; /* WPA1|WPA2(RSN) */ 641178676Ssam 642221650Sbschmidt ic->ic_cryptocaps = 643220723Sbschmidt IEEE80211_CRYPTO_WEP | 644221650Sbschmidt IEEE80211_CRYPTO_AES_CCM | 645220723Sbschmidt IEEE80211_CRYPTO_TKIPMIC | 646221651Sbschmidt IEEE80211_CRYPTO_TKIP; 647221651Sbschmidt 648221651Sbschmidt ic->ic_flags |= IEEE80211_F_DATAPAD; 649221651Sbschmidt ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; 650221651Sbschmidt 651221651Sbschmidt bands = 0; 652220715Sbschmidt setbit(&bands, IEEE80211_MODE_11B); 653220721Sbschmidt setbit(&bands, IEEE80211_MODE_11G); 654201209Srpaulo ieee80211_init_channels(ic, NULL, &bands); 655198429Srpaulo 656198429Srpaulo /* 657198429Srpaulo * Do this by own because h/w supports 658198429Srpaulo * more channels than ieee80211_init_channels() 659198429Srpaulo */ 660201209Srpaulo if (sc->rf_rev == RT2860_RF_2750 || 661178676Ssam sc->rf_rev == RT2860_RF_2850 || 662198429Srpaulo sc->rf_rev == RT3070_RF_3052) { 663220667Sbschmidt /* set supported .11a rates */ 664220667Sbschmidt for (i = 14; i < N(rt2860_rf2850); i++) { 665220667Sbschmidt uint8_t chan = rt2860_rf2850[i].chan; 666220726Sbschmidt ic->ic_channels[ic->ic_nchans].ic_freq = 667220726Sbschmidt ieee80211_ieee2mhz(chan, IEEE80211_CHAN_A); 668220726Sbschmidt ic->ic_channels[ic->ic_nchans].ic_ieee = chan; 669220667Sbschmidt ic->ic_channels[ic->ic_nchans].ic_flags = IEEE80211_CHAN_A; 670178676Ssam ic->ic_channels[ic->ic_nchans].ic_extieee = 0; 671178676Ssam ic->ic_nchans++; 672198429Srpaulo } 673198429Srpaulo } 674198429Srpaulo 675198429Srpaulo ieee80211_ifattach(ic, sc->sc_bssid); 676178676Ssam 677198429Srpaulo ic->ic_scan_start = run_scan_start; 678220724Sbschmidt ic->ic_scan_end = run_scan_end; 679198429Srpaulo ic->ic_set_channel = run_set_channel; 680198429Srpaulo ic->ic_node_alloc = run_node_alloc; 681198429Srpaulo ic->ic_newassoc = run_newassoc; 682178676Ssam ic->ic_updateslot = run_updateslot; 683220724Sbschmidt ic->ic_update_mcast = run_update_mcast; 684220724Sbschmidt ic->ic_wme.wme_update = run_wme_update; 685178676Ssam ic->ic_raw_xmit = run_raw_xmit; 686178676Ssam ic->ic_update_promisc = run_update_promisc; 687220635Sbschmidt 688178676Ssam ic->ic_vap_create = run_vap_create; 689178676Ssam ic->ic_vap_delete = run_vap_delete; 690178676Ssam 691220728Sbschmidt ieee80211_radiotap_attach(ic, 692220728Sbschmidt &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), 693178676Ssam RUN_TX_RADIOTAP_PRESENT, 694220728Sbschmidt &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 695198429Srpaulo RUN_RX_RADIOTAP_PRESENT); 696220728Sbschmidt 697220728Sbschmidt TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc); 698220728Sbschmidt TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc); 699220728Sbschmidt callout_init((struct callout *)&sc->ratectl_ch, 1); 700220728Sbschmidt 701220728Sbschmidt if (bootverbose) 702220728Sbschmidt ieee80211_announce(ic); 703220728Sbschmidt 704220728Sbschmidt return (0); 705220728Sbschmidt 706220728Sbschmidtdetach: 707220728Sbschmidt run_detach(self); 708220728Sbschmidt return (ENXIO); 709220728Sbschmidt} 710220728Sbschmidt 711221651Sbschmidtstatic int 712220728Sbschmidtrun_detach(device_t self) 713220728Sbschmidt{ 714220728Sbschmidt struct run_softc *sc = device_get_softc(self); 715220728Sbschmidt struct ifnet *ifp = sc->sc_ifp; 716220728Sbschmidt struct ieee80211com *ic; 717220728Sbschmidt int i; 718220728Sbschmidt 719220728Sbschmidt /* stop all USB transfers */ 720220728Sbschmidt usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER); 721220728Sbschmidt 722220728Sbschmidt RUN_LOCK(sc); 723220728Sbschmidt 724220728Sbschmidt sc->ratectl_run = RUN_RATECTL_OFF; 725220728Sbschmidt sc->cmdq_run = sc->cmdq_key_set = RUN_CMDQ_ABORT; 726220728Sbschmidt 727220728Sbschmidt /* free TX list, if any */ 728220728Sbschmidt for (i = 0; i != RUN_EP_QUEUES; i++) 729220728Sbschmidt run_unsetup_tx_list(sc, &sc->sc_epq[i]); 730220728Sbschmidt RUN_UNLOCK(sc); 731220728Sbschmidt 732220728Sbschmidt if (ifp) { 733220728Sbschmidt ic = ifp->if_l2com; 734220728Sbschmidt /* drain tasks */ 735220728Sbschmidt usb_callout_drain(&sc->ratectl_ch); 736220728Sbschmidt ieee80211_draintask(ic, &sc->cmdq_task); 737220728Sbschmidt ieee80211_draintask(ic, &sc->ratectl_task); 738220728Sbschmidt ieee80211_ifdetach(ic); 739220728Sbschmidt if_free(ifp); 740220728Sbschmidt } 741220728Sbschmidt 742220728Sbschmidt mtx_destroy(&sc->sc_mtx); 743220728Sbschmidt 744220728Sbschmidt return (0); 745220728Sbschmidt} 746220728Sbschmidt 747220728Sbschmidtstatic struct ieee80211vap * 748220728Sbschmidtrun_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, 749221651Sbschmidt enum ieee80211_opmode opmode, int flags, 750220728Sbschmidt const uint8_t bssid[IEEE80211_ADDR_LEN], 751220728Sbschmidt const uint8_t mac[IEEE80211_ADDR_LEN]) 752220728Sbschmidt{ 753220728Sbschmidt struct ifnet *ifp = ic->ic_ifp; 754220728Sbschmidt struct run_softc *sc = ifp->if_softc; 755220728Sbschmidt struct run_vap *rvp; 756220728Sbschmidt struct ieee80211vap *vap; 757220728Sbschmidt int i; 758220866Sbschmidt 759220866Sbschmidt if (sc->rvp_cnt >= RUN_VAP_MAX) { 760220728Sbschmidt if_printf(ifp, "number of VAPs maxed out\n"); 761198429Srpaulo return (NULL); 762198429Srpaulo } 763201209Srpaulo 764198439Srpaulo switch (opmode) { 765220727Sbschmidt case IEEE80211_M_STA: 766201209Srpaulo /* enable s/w bmiss handling for sta mode */ 767201209Srpaulo flags |= IEEE80211_CLONE_NOBEACONS; 768198429Srpaulo /* fall though */ 769198429Srpaulo case IEEE80211_M_IBSS: 770201209Srpaulo case IEEE80211_M_MONITOR: 771198439Srpaulo case IEEE80211_M_HOSTAP: 772198429Srpaulo case IEEE80211_M_MBSS: 773198429Srpaulo /* other than WDS vaps, only one at a time */ 774198429Srpaulo if (!TAILQ_EMPTY(&ic->ic_vaps)) 775201209Srpaulo return (NULL); 776198439Srpaulo break; 777198429Srpaulo case IEEE80211_M_WDS: 778198429Srpaulo TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next){ 779206444Sbschmidt if(vap->iv_opmode != IEEE80211_M_HOSTAP) 780198439Srpaulo continue; 781198429Srpaulo /* WDS vap's always share the local mac address. */ 782198429Srpaulo flags &= ~IEEE80211_CLONE_BSSID; 783201209Srpaulo break; 784198439Srpaulo } 785220728Sbschmidt if (vap == NULL) { 786201209Srpaulo if_printf(ifp, "wds only supported in ap mode\n"); 787220727Sbschmidt return (NULL); 788201209Srpaulo } 789201209Srpaulo break; 790201209Srpaulo default: 791198429Srpaulo if_printf(ifp, "unknown opmode %d\n", opmode); 792198429Srpaulo return (NULL); 793201209Srpaulo } 794210109Sbschmidt 795220867Sbschmidt rvp = (struct run_vap *) malloc(sizeof(struct run_vap), 796220867Sbschmidt M_80211_VAP, M_NOWAIT | M_ZERO); 797220867Sbschmidt if (rvp == NULL) 798198429Srpaulo return (NULL); 799210109Sbschmidt vap = &rvp->vap; 800210109Sbschmidt ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); 801220894Sbschmidt 802220894Sbschmidt vap->iv_key_update_begin = run_key_update_begin; 803220891Sbschmidt vap->iv_key_update_end = run_key_update_end; 804220894Sbschmidt vap->iv_update_beacon = run_update_beacon; 805220894Sbschmidt vap->iv_max_aid = RT2870_WCID_MAX; 806210109Sbschmidt /* 807198429Srpaulo * To delete the right key from h/w, we need wcid. 808198429Srpaulo * Luckily, there is unused space in ieee80211_key{}, wk_pad, 809198429Srpaulo * and matching wcid will be written into there. So, cast 810220728Sbschmidt * some spells to remove 'const' from ieee80211_key{} 811198429Srpaulo */ 812220728Sbschmidt vap->iv_key_delete = (void *)run_key_delete; 813178676Ssam vap->iv_key_set = (void *)run_key_set; 814178676Ssam 815178676Ssam /* override state transition machine */ 816198429Srpaulo rvp->newstate = vap->iv_newstate; 817178676Ssam vap->iv_newstate = run_newstate; 818206477Sbschmidt 819198429Srpaulo ieee80211_ratectl_init(vap); 820178676Ssam ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */); 821178676Ssam 822178676Ssam /* complete setup */ 823178676Ssam ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status); 824198429Srpaulo 825198429Srpaulo /* make sure id is always unique */ 826198429Srpaulo for (i = 0; i < RUN_VAP_MAX; i++) { 827198429Srpaulo if((sc->rvp_bmap & 1 << i) == 0){ 828198429Srpaulo sc->rvp_bmap |= 1 << i; 829178676Ssam rvp->rvp_id = i; 830178676Ssam break; 831220723Sbschmidt } 832220723Sbschmidt } 833220723Sbschmidt if (sc->rvp_cnt++ == 0) 834220723Sbschmidt ic->ic_opmode = opmode; 835220723Sbschmidt 836220723Sbschmidt if (opmode == IEEE80211_M_HOSTAP) 837220723Sbschmidt sc->cmdq_run = RUN_CMDQ_GO; 838220723Sbschmidt 839220723Sbschmidt DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n", 840220723Sbschmidt rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt); 841220723Sbschmidt 842220723Sbschmidt return (vap); 843220723Sbschmidt} 844178676Ssam 845178676Ssamstatic void 846220726Sbschmidtrun_vap_delete(struct ieee80211vap *vap) 847220726Sbschmidt{ 848220726Sbschmidt struct run_vap *rvp = RUN_VAP(vap); 849178676Ssam struct ifnet *ifp; 850178676Ssam struct ieee80211com *ic; 851178676Ssam struct run_softc *sc; 852178676Ssam uint8_t rvp_id; 853178676Ssam 854178676Ssam if (vap == NULL) 855178676Ssam return; 856178676Ssam 857178676Ssam ic = vap->iv_ic; 858178676Ssam ifp = ic->ic_ifp; 859178676Ssam 860178676Ssam sc = ifp->if_softc; 861178676Ssam 862198429Srpaulo RUN_LOCK(sc); 863178676Ssam 864178676Ssam m_freem(rvp->beacon_mbuf); 865178676Ssam rvp->beacon_mbuf = NULL; 866206358Srpaulo 867198429Srpaulo rvp_id = rvp->rvp_id; 868206476Sbschmidt sc->ratectl_run &= ~(1 << rvp_id); 869178676Ssam sc->rvp_bmap &= ~(1 << rvp_id); 870178676Ssam run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128); 871178676Ssam run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512); 872178676Ssam --sc->rvp_cnt; 873178676Ssam 874178676Ssam DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n", 875178676Ssam vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt); 876178676Ssam 877178676Ssam RUN_UNLOCK(sc); 878206358Srpaulo 879178676Ssam ieee80211_ratectl_deinit(vap); 880178676Ssam ieee80211_vap_detach(vap); 881178676Ssam free(rvp, M_80211_VAP); 882178676Ssam} 883206477Sbschmidt 884220635Sbschmidt/* 885178676Ssam * There are numbers of functions need to be called in context thread. 886178676Ssam * Rather than creating taskqueue event for each of those functions, 887198429Srpaulo * here is all-for-one taskqueue callback function. This function 888198429Srpaulo * gurantees deferred functions are executed in the same order they 889220721Sbschmidt * were enqueued. 890178676Ssam * '& RUN_CMDQ_MASQ' is to loop cmdq[]. 891198429Srpaulo */ 892198429Srpaulostatic void 893198429Srpaulorun_cmdq_cb(void *arg, int pending) 894198429Srpaulo{ 895198429Srpaulo struct run_softc *sc = arg; 896198429Srpaulo uint8_t i; 897198429Srpaulo 898198429Srpaulo /* call cmdq[].func locked */ 899220667Sbschmidt RUN_LOCK(sc); 900220667Sbschmidt for (i = sc->cmdq_exec; sc->cmdq[i].func && pending; 901198429Srpaulo i = sc->cmdq_exec, pending--) { 902198429Srpaulo DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending); 903198429Srpaulo if (sc->cmdq_run == RUN_CMDQ_GO) { 904220725Sbschmidt /* 905220723Sbschmidt * If arg0 is NULL, callback func needs more 906220723Sbschmidt * than one arg. So, pass ptr to cmdq struct. 907220723Sbschmidt */ 908220723Sbschmidt if (sc->cmdq[i].arg0) 909220723Sbschmidt sc->cmdq[i].func(sc->cmdq[i].arg0); 910220723Sbschmidt else 911220723Sbschmidt sc->cmdq[i].func(&sc->cmdq[i]); 912201209Srpaulo } 913198429Srpaulo sc->cmdq[i].arg0 = NULL; 914220728Sbschmidt sc->cmdq[i].func = NULL; 915220728Sbschmidt sc->cmdq_exec++; 916198429Srpaulo sc->cmdq_exec &= RUN_CMDQ_MASQ; 917198429Srpaulo } 918201209Srpaulo RUN_UNLOCK(sc); 919201209Srpaulo} 920198429Srpaulo 921198429Srpaulostatic void 922198429Srpaulorun_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq) 923198429Srpaulo{ 924198429Srpaulo struct run_tx_data *data; 925198429Srpaulo 926198429Srpaulo memset(pq, 0, sizeof(*pq)); 927198429Srpaulo 928198429Srpaulo STAILQ_INIT(&pq->tx_qh); 929178676Ssam STAILQ_INIT(&pq->tx_fh); 930178676Ssam 931178676Ssam for (data = &pq->tx_data[0]; 932178676Ssam data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) { 933220723Sbschmidt data->sc = sc; 934220723Sbschmidt STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); 935220723Sbschmidt } 936220723Sbschmidt pq->tx_nfree = RUN_TX_RING_COUNT; 937220723Sbschmidt} 938220723Sbschmidt 939220723Sbschmidtstatic void 940220723Sbschmidtrun_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq) 941220723Sbschmidt{ 942220723Sbschmidt struct run_tx_data *data; 943220723Sbschmidt 944220723Sbschmidt /* make sure any subsequent use of the queues will fail */ 945220723Sbschmidt pq->tx_nfree = 0; 946220723Sbschmidt STAILQ_INIT(&pq->tx_fh); 947220723Sbschmidt STAILQ_INIT(&pq->tx_qh); 948220723Sbschmidt 949220723Sbschmidt /* free up all node references and mbufs */ 950220723Sbschmidt for (data = &pq->tx_data[0]; 951220723Sbschmidt data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) { 952220723Sbschmidt if (data->m != NULL) { 953220723Sbschmidt m_freem(data->m); 954220723Sbschmidt data->m = NULL; 955220723Sbschmidt } 956220723Sbschmidt if (data->ni != NULL) { 957220723Sbschmidt ieee80211_free_node(data->ni); 958220723Sbschmidt data->ni = NULL; 959220723Sbschmidt } 960220723Sbschmidt } 961220723Sbschmidt} 962220723Sbschmidt 963220723Sbschmidtstatic int 964220723Sbschmidtrun_load_microcode(struct run_softc *sc) 965220723Sbschmidt{ 966220723Sbschmidt usb_device_request_t req; 967220723Sbschmidt const struct firmware *fw; 968220723Sbschmidt const u_char *base; 969220723Sbschmidt uint32_t tmp; 970220723Sbschmidt int ntries, error; 971220723Sbschmidt const uint64_t *temp; 972220723Sbschmidt uint64_t bytes; 973220723Sbschmidt 974220723Sbschmidt RUN_UNLOCK(sc); 975220723Sbschmidt fw = firmware_get("runfw"); 976220723Sbschmidt RUN_LOCK(sc); 977198429Srpaulo if (fw == NULL) { 978178676Ssam device_printf(sc->sc_dev, 979198429Srpaulo "failed loadfirmware of file %s\n", "runfw"); 980178676Ssam return ENOENT; 981198429Srpaulo } 982198429Srpaulo 983178676Ssam if (fw->datasize != 8192) { 984198429Srpaulo device_printf(sc->sc_dev, 985198429Srpaulo "invalid firmware size (should be 8KB)\n"); 986198429Srpaulo error = EINVAL; 987220726Sbschmidt goto fail; 988198429Srpaulo } 989198429Srpaulo 990198429Srpaulo /* 991198429Srpaulo * RT3071/RT3072 use a different firmware 992198429Srpaulo * run-rt2870 (8KB) contains both, 993198429Srpaulo * first half (4KB) is for rt2870, 994198429Srpaulo * last half is for rt3071. 995198429Srpaulo */ 996198429Srpaulo base = fw->data; 997198429Srpaulo if ((sc->mac_ver) != 0x2860 && 998198429Srpaulo (sc->mac_ver) != 0x2872 && 999198429Srpaulo (sc->mac_ver) != 0x3070) { 1000198429Srpaulo base += 4096; 1001198429Srpaulo } 1002198429Srpaulo 1003198429Srpaulo /* cheap sanity check */ 1004198429Srpaulo temp = fw->data; 1005201209Srpaulo bytes = *temp; 1006198429Srpaulo if (bytes != be64toh(0xffffff0210280210)) { 1007198429Srpaulo device_printf(sc->sc_dev, "firmware checksum failed\n"); 1008198429Srpaulo error = EINVAL; 1009198429Srpaulo goto fail; 1010198429Srpaulo } 1011198429Srpaulo 1012198429Srpaulo run_read(sc, RT2860_ASIC_VER_ID, &tmp); 1013201209Srpaulo /* write microcode image */ 1014198429Srpaulo run_write_region_1(sc, RT2870_FW_BASE, base, 4096); 1015198429Srpaulo run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff); 1016198429Srpaulo run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff); 1017198429Srpaulo 1018198429Srpaulo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1019198429Srpaulo req.bRequest = RT2870_RESET; 1020198429Srpaulo USETW(req.wValue, 8); 1021198429Srpaulo USETW(req.wIndex, 0); 1022198429Srpaulo USETW(req.wLength, 0); 1023198429Srpaulo if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)) 1024198429Srpaulo != 0) { 1025198429Srpaulo device_printf(sc->sc_dev, "firmware reset failed\n"); 1026198429Srpaulo goto fail; 1027198429Srpaulo } 1028198429Srpaulo 1029198429Srpaulo run_delay(sc, 10); 1030198429Srpaulo 1031198429Srpaulo run_write(sc, RT2860_H2M_MAILBOX, 0); 1032198429Srpaulo if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0) 1033198429Srpaulo goto fail; 1034198429Srpaulo 1035198429Srpaulo /* wait until microcontroller is ready */ 1036198429Srpaulo for (ntries = 0; ntries < 1000; ntries++) { 1037198429Srpaulo if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0) { 1038198429Srpaulo goto fail; 1039198429Srpaulo } 1040198429Srpaulo if (tmp & RT2860_MCU_READY) 1041201209Srpaulo break; 1042198429Srpaulo run_delay(sc, 10); 1043198429Srpaulo } 1044198429Srpaulo if (ntries == 1000) { 1045198429Srpaulo device_printf(sc->sc_dev, 1046198429Srpaulo "timeout waiting for MCU to initialize\n"); 1047198429Srpaulo error = ETIMEDOUT; 1048198429Srpaulo goto fail; 1049201209Srpaulo } 1050198429Srpaulo device_printf(sc->sc_dev, "firmware %s ver. %u.%u loaded\n", 1051198429Srpaulo (base == fw->data) ? "RT2870" : "RT3071", 1052198429Srpaulo *(base + 4092), *(base + 4093)); 1053198429Srpaulo 1054198429Srpaulofail: 1055198429Srpaulo firmware_put(fw, FIRMWARE_UNLOAD); 1056198429Srpaulo return (error); 1057198429Srpaulo} 1058198429Srpaulo 1059198429Srpauloint 1060198429Srpaulorun_reset(struct run_softc *sc) 1061198429Srpaulo{ 1062198429Srpaulo usb_device_request_t req; 1063198429Srpaulo 1064198429Srpaulo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1065198429Srpaulo req.bRequest = RT2870_RESET; 1066198429Srpaulo USETW(req.wValue, 1); 1067198429Srpaulo USETW(req.wIndex, 0); 1068198429Srpaulo USETW(req.wLength, 0); 1069198429Srpaulo return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)); 1070198429Srpaulo} 1071198429Srpaulo 1072198429Srpaulostatic usb_error_t 1073198429Srpaulorun_do_request(struct run_softc *sc, 1074198429Srpaulo struct usb_device_request *req, void *data) 1075198429Srpaulo{ 1076198429Srpaulo usb_error_t err; 1077198429Srpaulo int ntries = 10; 1078198429Srpaulo 1079198429Srpaulo RUN_LOCK_ASSERT(sc, MA_OWNED); 1080198429Srpaulo 1081198429Srpaulo while (ntries--) { 1082206477Sbschmidt err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, 1083198429Srpaulo req, data, 0, NULL, 250 /* ms */); 1084198429Srpaulo if (err == 0) 1085198429Srpaulo break; 1086198429Srpaulo DPRINTFN(1, "Control request failed, %s (retrying)\n", 1087198429Srpaulo usbd_errstr(err)); 1088198429Srpaulo run_delay(sc, 10); 1089198429Srpaulo } 1090198429Srpaulo return (err); 1091198429Srpaulo} 1092198429Srpaulo 1093198429Srpaulostatic int 1094198429Srpaulorun_read(struct run_softc *sc, uint16_t reg, uint32_t *val) 1095198429Srpaulo{ 1096198429Srpaulo uint32_t tmp; 1097198429Srpaulo int error; 1098198429Srpaulo 1099198429Srpaulo error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp); 1100198429Srpaulo if (error == 0) 1101198429Srpaulo *val = le32toh(tmp); 1102198429Srpaulo else 1103198429Srpaulo *val = 0xffffffff; 1104198429Srpaulo return (error); 1105198429Srpaulo} 1106198429Srpaulo 1107198429Srpaulostatic int 1108198429Srpaulorun_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len) 1109198429Srpaulo{ 1110198429Srpaulo usb_device_request_t req; 1111198429Srpaulo 1112198429Srpaulo req.bmRequestType = UT_READ_VENDOR_DEVICE; 1113206477Sbschmidt req.bRequest = RT2870_READ_REGION_1; 1114198429Srpaulo USETW(req.wValue, 0); 1115198429Srpaulo USETW(req.wIndex, reg); 1116203934Sbschmidt USETW(req.wLength, len); 1117201209Srpaulo 1118198429Srpaulo return (run_do_request(sc, &req, buf)); 1119201209Srpaulo} 1120220726Sbschmidt 1121198429Srpaulostatic int 1122198429Srpaulorun_write_2(struct run_softc *sc, uint16_t reg, uint16_t val) 1123220726Sbschmidt{ 1124198429Srpaulo usb_device_request_t req; 1125198429Srpaulo 1126198429Srpaulo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1127198429Srpaulo req.bRequest = RT2870_WRITE_2; 1128198429Srpaulo USETW(req.wValue, val); 1129198429Srpaulo USETW(req.wIndex, reg); 1130201209Srpaulo USETW(req.wLength, 0); 1131201209Srpaulo 1132201209Srpaulo return (run_do_request(sc, &req, NULL)); 1133201209Srpaulo} 1134201209Srpaulo 1135198429Srpaulostatic int 1136198429Srpaulorun_write(struct run_softc *sc, uint16_t reg, uint32_t val) 1137198429Srpaulo{ 1138198429Srpaulo int error; 1139198429Srpaulo 1140201209Srpaulo if ((error = run_write_2(sc, reg, val & 0xffff)) == 0) 1141203934Sbschmidt error = run_write_2(sc, reg + 2, val >> 16); 1142203934Sbschmidt return (error); 1143201209Srpaulo} 1144201209Srpaulo 1145201209Srpaulostatic int 1146201209Srpaulorun_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf, 1147203934Sbschmidt int len) 1148201209Srpaulo{ 1149201209Srpaulo#if 1 1150201209Srpaulo int i, error = 0; 1151201209Srpaulo /* 1152201209Srpaulo * NB: the WRITE_REGION_1 command is not stable on RT2860. 1153201209Srpaulo * We thus issue multiple WRITE_2 commands instead. 1154203934Sbschmidt */ 1155201209Srpaulo KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n")); 1156201209Srpaulo for (i = 0; i < len && error == 0; i += 2) 1157203934Sbschmidt error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8); 1158201209Srpaulo return (error); 1159201209Srpaulo#else 1160203934Sbschmidt usb_device_request_t req; 1161201209Srpaulo 1162178676Ssam req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1163178676Ssam req.bRequest = RT2870_WRITE_REGION_1; 1164178676Ssam USETW(req.wValue, 0); 1165206477Sbschmidt USETW(req.wIndex, reg); 1166198429Srpaulo USETW(req.wLength, len); 1167198429Srpaulo return (run_do_request(sc, &req, buf)); 1168220723Sbschmidt#endif 1169198429Srpaulo} 1170198429Srpaulo 1171198429Srpaulostatic int 1172201209Srpaulorun_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len) 1173198429Srpaulo{ 1174198429Srpaulo int i, error = 0; 1175201209Srpaulo 1176198429Srpaulo KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n")); 1177198429Srpaulo for (i = 0; i < len && error == 0; i += 4) 1178198429Srpaulo error = run_write(sc, reg + i, val); 1179198429Srpaulo return (error); 1180198429Srpaulo} 1181201209Srpaulo 1182198429Srpaulo/* Read 16-bit from eFUSE ROM (RT3070 only.) */ 1183198429Srpaulostatic int 1184198429Srpaulorun_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val) 1185198429Srpaulo{ 1186198429Srpaulo uint32_t tmp; 1187198429Srpaulo uint16_t reg; 1188198429Srpaulo int error, ntries; 1189198429Srpaulo 1190198429Srpaulo if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0) 1191198429Srpaulo return (error); 1192198429Srpaulo 1193198429Srpaulo addr *= 2; 1194198429Srpaulo /*- 1195198429Srpaulo * Read one 16-byte block into registers EFUSE_DATA[0-3]: 1196198429Srpaulo * DATA0: F E D C 1197198429Srpaulo * DATA1: B A 9 8 1198198429Srpaulo * DATA2: 7 6 5 4 1199198429Srpaulo * DATA3: 3 2 1 0 1200198429Srpaulo */ 1201198429Srpaulo tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK); 1202198429Srpaulo tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK; 1203198429Srpaulo run_write(sc, RT3070_EFUSE_CTRL, tmp); 1204198429Srpaulo for (ntries = 0; ntries < 100; ntries++) { 1205198429Srpaulo if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0) 1206198429Srpaulo return (error); 1207178676Ssam if (!(tmp & RT3070_EFSROM_KICK)) 1208178676Ssam break; 1209178676Ssam run_delay(sc, 2); 1210198429Srpaulo } 1211198429Srpaulo if (ntries == 100) 1212198429Srpaulo return (ETIMEDOUT); 1213198429Srpaulo 1214178676Ssam if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) { 1215178676Ssam *val = 0xffff; /* address not found */ 1216198429Srpaulo return (0); 1217178676Ssam } 1218220691Sbschmidt /* determine to which 32-bit register our 16-bit word belongs */ 1219178676Ssam reg = RT3070_EFUSE_DATA3 - (addr & 0xc); 1220198429Srpaulo if ((error = run_read(sc, reg, &tmp)) != 0) 1221178676Ssam return (error); 1222220723Sbschmidt 1223178676Ssam *val = (addr & 2) ? tmp >> 16 : tmp & 0xffff; 1224178676Ssam return (0); 1225198429Srpaulo} 1226178676Ssam 1227220691Sbschmidtstatic int 1228220711Sbschmidtrun_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val) 1229178676Ssam{ 1230220711Sbschmidt usb_device_request_t req; 1231178676Ssam uint16_t tmp; 1232220691Sbschmidt int error; 1233220711Sbschmidt 1234178676Ssam addr *= 2; 1235220711Sbschmidt req.bmRequestType = UT_READ_VENDOR_DEVICE; 1236220691Sbschmidt req.bRequest = RT2870_EEPROM_READ; 1237220691Sbschmidt USETW(req.wValue, 0); 1238220711Sbschmidt USETW(req.wIndex, addr); 1239178676Ssam USETW(req.wLength, sizeof tmp); 1240178676Ssam 1241220704Sbschmidt error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp); 1242220704Sbschmidt if (error == 0) 1243178676Ssam *val = le16toh(tmp); 1244178676Ssam else 1245220726Sbschmidt *val = 0xffff; 1246178676Ssam return (error); 1247220726Sbschmidt} 1248220726Sbschmidt 1249178676Ssamstatic __inline int 1250178676Ssamrun_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val) 1251178676Ssam{ 1252206477Sbschmidt /* either eFUSE ROM or EEPROM */ 1253178676Ssam return sc->sc_srom_read(sc, addr, val); 1254178676Ssam} 1255220701Sbschmidt 1256220701Sbschmidtstatic int 1257220701Sbschmidtrun_rt2870_rf_write(struct run_softc *sc, uint8_t reg, uint32_t val) 1258220701Sbschmidt{ 1259220701Sbschmidt uint32_t tmp; 1260178676Ssam int error, ntries; 1261220701Sbschmidt 1262178676Ssam for (ntries = 0; ntries < 10; ntries++) { 1263220701Sbschmidt if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0) 1264220701Sbschmidt return (error); 1265220701Sbschmidt if (!(tmp & RT2860_RF_REG_CTRL)) 1266220701Sbschmidt break; 1267178676Ssam } 1268220701Sbschmidt if (ntries == 10) 1269178676Ssam return (ETIMEDOUT); 1270178676Ssam 1271178676Ssam /* RF registers are 24-bit on the RT2860 */ 1272206477Sbschmidt tmp = RT2860_RF_REG_CTRL | 24 << RT2860_RF_REG_WIDTH_SHIFT | 1273198429Srpaulo (val & 0x3fffff) << 2 | (reg & 3); 1274178676Ssam return (run_write(sc, RT2860_RF_CSR_CFG0, tmp)); 1275198429Srpaulo} 1276220691Sbschmidt 1277220728Sbschmidtstatic int 1278178676Ssamrun_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val) 1279178676Ssam{ 1280206477Sbschmidt uint32_t tmp; 1281198429Srpaulo int error, ntries; 1282178676Ssam 1283198429Srpaulo for (ntries = 0; ntries < 100; ntries++) { 1284178676Ssam if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1285178676Ssam return (error); 1286206477Sbschmidt if (!(tmp & RT3070_RF_KICK)) 1287178676Ssam break; 1288178676Ssam } 1289198429Srpaulo if (ntries == 100) 1290220691Sbschmidt return (ETIMEDOUT); 1291178676Ssam 1292178676Ssam tmp = RT3070_RF_KICK | reg << 8; 1293206477Sbschmidt if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0) 1294178676Ssam return (error); 1295178676Ssam 1296178676Ssam for (ntries = 0; ntries < 100; ntries++) { 1297178676Ssam if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1298178676Ssam return (error); 1299206477Sbschmidt if (!(tmp & RT3070_RF_KICK)) 1300201209Srpaulo break; 1301201209Srpaulo } 1302201209Srpaulo if (ntries == 100) 1303220691Sbschmidt return (ETIMEDOUT); 1304220691Sbschmidt 1305201209Srpaulo *val = tmp & 0xff; 1306201209Srpaulo return (0); 1307206477Sbschmidt} 1308201209Srpaulo 1309201209Srpaulostatic int 1310201209Srpaulorun_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val) 1311201209Srpaulo{ 1312201209Srpaulo uint32_t tmp; 1313206477Sbschmidt int error, ntries; 1314178676Ssam 1315178676Ssam for (ntries = 0; ntries < 10; ntries++) { 1316198429Srpaulo if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1317220728Sbschmidt return (error); 1318178676Ssam if (!(tmp & RT3070_RF_KICK)) 1319178676Ssam break; 1320206477Sbschmidt } 1321178676Ssam if (ntries == 10) 1322178676Ssam return (ETIMEDOUT); 1323178676Ssam 1324178676Ssam tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val; 1325178676Ssam return (run_write(sc, RT3070_RF_CSR_CFG, tmp)); 1326206477Sbschmidt} 1327178676Ssam 1328178676Ssamstatic int 1329198429Srpaulorun_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val) 1330178676Ssam{ 1331178676Ssam uint32_t tmp; 1332178676Ssam int ntries, error; 1333178676Ssam 1334198429Srpaulo for (ntries = 0; ntries < 10; ntries++) { 1335198429Srpaulo if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1336220691Sbschmidt return (error); 1337220691Sbschmidt if (!(tmp & RT2860_BBP_CSR_KICK)) 1338178676Ssam break; 1339178676Ssam } 1340220711Sbschmidt if (ntries == 10) 1341178676Ssam return (ETIMEDOUT); 1342178676Ssam 1343178676Ssam tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8; 1344178676Ssam if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0) 1345220702Sbschmidt return (error); 1346220702Sbschmidt 1347220702Sbschmidt for (ntries = 0; ntries < 10; ntries++) { 1348198429Srpaulo if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1349198429Srpaulo return (error); 1350220711Sbschmidt if (!(tmp & RT2860_BBP_CSR_KICK)) 1351178676Ssam break; 1352198429Srpaulo } 1353198429Srpaulo if (ntries == 10) 1354178676Ssam return (ETIMEDOUT); 1355220702Sbschmidt 1356220702Sbschmidt *val = tmp & 0xff; 1357220702Sbschmidt return (0); 1358220702Sbschmidt} 1359220702Sbschmidt 1360198429Srpaulostatic int 1361198429Srpaulorun_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val) 1362220711Sbschmidt{ 1363198429Srpaulo uint32_t tmp; 1364198429Srpaulo int ntries, error; 1365198429Srpaulo 1366198429Srpaulo for (ntries = 0; ntries < 10; ntries++) { 1367178676Ssam if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1368198429Srpaulo return (error); 1369178676Ssam if (!(tmp & RT2860_BBP_CSR_KICK)) 1370178676Ssam break; 1371178676Ssam } 1372178676Ssam if (ntries == 10) 1373178676Ssam return (ETIMEDOUT); 1374201209Srpaulo 1375178676Ssam tmp = RT2860_BBP_CSR_KICK | reg << 8 | val; 1376178676Ssam return (run_write(sc, RT2860_BBP_CSR_CFG, tmp)); 1377220711Sbschmidt} 1378178676Ssam 1379178676Ssam/* 1380178676Ssam * Send a command to the 8051 microcontroller unit. 1381198429Srpaulo */ 1382220692Sbschmidtstatic int 1383220692Sbschmidtrun_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg) 1384198439Srpaulo{ 1385178676Ssam uint32_t tmp; 1386220711Sbschmidt int error, ntries; 1387220710Sbschmidt 1388178676Ssam for (ntries = 0; ntries < 100; ntries++) { 1389178676Ssam if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0) 1390198429Srpaulo return error; 1391201209Srpaulo if (!(tmp & RT2860_H2M_BUSY)) 1392220692Sbschmidt break; 1393220692Sbschmidt } 1394178676Ssam if (ntries == 100) 1395178676Ssam return ETIMEDOUT; 1396220711Sbschmidt 1397220711Sbschmidt tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg; 1398178676Ssam if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0) 1399178676Ssam error = run_write(sc, RT2860_HOST_CMD, cmd); 1400178676Ssam return (error); 1401198429Srpaulo} 1402178676Ssam 1403178676Ssam/* 1404220726Sbschmidt * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word. 1405178676Ssam * Used to adjust per-rate Tx power registers. 1406178676Ssam */ 1407220726Sbschmidtstatic __inline uint32_t 1408178676Ssamb4inc(uint32_t b32, int8_t delta) 1409220726Sbschmidt{ 1410220726Sbschmidt int8_t i, b4; 1411178676Ssam 1412178676Ssam for (i = 0; i < 8; i++) { 1413178676Ssam b4 = b32 & 0xf; 1414206477Sbschmidt b4 += delta; 1415178676Ssam if (b4 < 0) 1416178676Ssam b4 = 0; 1417178676Ssam else if (b4 > 0xf) 1418178676Ssam b4 = 0xf; 1419198429Srpaulo b32 = b32 >> 4 | b4 << 28; 1420198429Srpaulo } 1421198429Srpaulo return (b32); 1422198429Srpaulo} 1423198429Srpaulo 1424198429Srpaulostatic const char * 1425198429Srpaulorun_get_rf(int rev) 1426198429Srpaulo{ 1427198429Srpaulo switch (rev) { 1428198429Srpaulo case RT2860_RF_2820: return "RT2820"; 1429178676Ssam case RT2860_RF_2850: return "RT2850"; 1430198429Srpaulo case RT2860_RF_2720: return "RT2720"; 1431178676Ssam case RT2860_RF_2750: return "RT2750"; 1432178676Ssam case RT3070_RF_3020: return "RT3020"; 1433206477Sbschmidt case RT3070_RF_2020: return "RT2020"; 1434178676Ssam case RT3070_RF_3021: return "RT3021"; 1435178676Ssam case RT3070_RF_3022: return "RT3022"; 1436178676Ssam case RT3070_RF_3052: return "RT3052"; 1437178676Ssam } 1438178676Ssam return ("unknown"); 1439198429Srpaulo} 1440178676Ssam 1441198429Srpauloint 1442198429Srpaulorun_read_eeprom(struct run_softc *sc) 1443198429Srpaulo{ 1444198429Srpaulo int8_t delta_2ghz, delta_5ghz; 1445201209Srpaulo uint32_t tmp; 1446198439Srpaulo uint16_t val; 1447201209Srpaulo int ridx, ant, i; 1448198429Srpaulo 1449220710Sbschmidt /* check whether the ROM is eFUSE ROM or EEPROM */ 1450198429Srpaulo sc->sc_srom_read = run_eeprom_read_2; 1451201209Srpaulo if (sc->mac_ver >= 0x3070) { 1452201209Srpaulo run_read(sc, RT3070_EFUSE_CTRL, &tmp); 1453198429Srpaulo DPRINTF("EFUSE_CTRL=0x%08x\n", tmp); 1454220701Sbschmidt if (tmp & RT3070_SEL_EFUSE) 1455220701Sbschmidt sc->sc_srom_read = run_efuse_read_2; 1456220701Sbschmidt } 1457220701Sbschmidt 1458178676Ssam /* read ROM version */ 1459178676Ssam run_srom_read(sc, RT2860_EEPROM_VERSION, &val); 1460206477Sbschmidt DPRINTF("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8); 1461178676Ssam 1462178676Ssam /* read MAC address */ 1463220723Sbschmidt run_srom_read(sc, RT2860_EEPROM_MAC01, &val); 1464178676Ssam sc->sc_bssid[0] = val & 0xff; 1465178676Ssam sc->sc_bssid[1] = val >> 8; 1466178676Ssam run_srom_read(sc, RT2860_EEPROM_MAC23, &val); 1467178676Ssam sc->sc_bssid[2] = val & 0xff; 1468178676Ssam sc->sc_bssid[3] = val >> 8; 1469178676Ssam run_srom_read(sc, RT2860_EEPROM_MAC45, &val); 1470178676Ssam sc->sc_bssid[4] = val & 0xff; 1471220725Sbschmidt sc->sc_bssid[5] = val >> 8; 1472220726Sbschmidt 1473220691Sbschmidt /* read vender BBP settings */ 1474220691Sbschmidt for (i = 0; i < 10; i++) { 1475178676Ssam run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val); 1476178676Ssam sc->bbp[i].val = val & 0xff; 1477198429Srpaulo sc->bbp[i].reg = val >> 8; 1478178676Ssam DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg, sc->bbp[i].val); 1479178676Ssam } 1480178676Ssam if (sc->mac_ver >= 0x3071) { 1481198429Srpaulo /* read vendor RF settings */ 1482220726Sbschmidt for (i = 0; i < 10; i++) { 1483220691Sbschmidt run_srom_read(sc, RT3071_EEPROM_RF_BASE + i, &val); 1484220691Sbschmidt sc->rf[i].val = val & 0xff; 1485178676Ssam sc->rf[i].reg = val >> 8; 1486178676Ssam DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg, 1487198429Srpaulo sc->rf[i].val); 1488178676Ssam } 1489178676Ssam } 1490178676Ssam 1491178676Ssam /* read RF frequency offset from EEPROM */ 1492198429Srpaulo run_srom_read(sc, RT2860_EEPROM_FREQ_LEDS, &val); 1493220726Sbschmidt sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0; 1494220726Sbschmidt DPRINTF("EEPROM freq offset %d\n", sc->freq & 0xff); 1495220726Sbschmidt 1496198429Srpaulo if (val >> 8 != 0xff) { 1497198429Srpaulo /* read LEDs operating mode */ 1498220711Sbschmidt sc->leds = val >> 8; 1499178676Ssam run_srom_read(sc, RT2860_EEPROM_LED1, &sc->led[0]); 1500198429Srpaulo run_srom_read(sc, RT2860_EEPROM_LED2, &sc->led[1]); 1501198429Srpaulo run_srom_read(sc, RT2860_EEPROM_LED3, &sc->led[2]); 1502178676Ssam } else { 1503198429Srpaulo /* broken EEPROM, use default settings */ 1504178676Ssam sc->leds = 0x01; 1505178676Ssam sc->led[0] = 0x5555; 1506178676Ssam sc->led[1] = 0x2221; 1507198429Srpaulo sc->led[2] = 0x5627; /* differs from RT2860 */ 1508198429Srpaulo } 1509198429Srpaulo DPRINTF("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n", 1510198429Srpaulo sc->leds, sc->led[0], sc->led[1], sc->led[2]); 1511201209Srpaulo 1512178676Ssam /* read RF information */ 1513178676Ssam run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val); 1514220711Sbschmidt if (val == 0xffff) { 1515178676Ssam DPRINTF("invalid EEPROM antenna info, using default\n"); 1516178676Ssam if (sc->mac_ver == 0x3572) { 1517178676Ssam /* default to RF3052 2T2R */ 1518178676Ssam sc->rf_rev = RT3070_RF_3052; 1519178676Ssam sc->ntxchains = 2; 1520220726Sbschmidt sc->nrxchains = 2; 1521220726Sbschmidt } else if (sc->mac_ver >= 0x3070) { 1522178676Ssam /* default to RF3020 1T1R */ 1523178676Ssam sc->rf_rev = RT3070_RF_3020; 1524178676Ssam sc->ntxchains = 1; 1525206477Sbschmidt sc->nrxchains = 1; 1526178676Ssam } else { 1527178676Ssam /* default to RF2820 1T2R */ 1528198429Srpaulo sc->rf_rev = RT2860_RF_2820; 1529178676Ssam sc->ntxchains = 1; 1530178676Ssam sc->nrxchains = 2; 1531178676Ssam } 1532178676Ssam } else { 1533178676Ssam sc->rf_rev = (val >> 8) & 0xf; 1534220704Sbschmidt sc->ntxchains = (val >> 4) & 0xf; 1535220704Sbschmidt sc->nrxchains = val & 0xf; 1536201209Srpaulo } 1537178676Ssam DPRINTF("EEPROM RF rev=0x%02x chains=%dT%dR\n", 1538178676Ssam sc->rf_rev, sc->ntxchains, sc->nrxchains); 1539178676Ssam 1540178676Ssam /* check if RF supports automatic Tx access gain control */ 1541198429Srpaulo run_srom_read(sc, RT2860_EEPROM_CONFIG, &val); 1542198429Srpaulo DPRINTF("EEPROM CFG 0x%04x\n", val); 1543198439Srpaulo /* check if driver should patch the DAC issue */ 1544198439Srpaulo if ((val >> 8) != 0xff) 1545198429Srpaulo sc->patch_dac = (val >> 15) & 1; 1546178676Ssam if ((val & 0xff) != 0xff) { 1547178676Ssam sc->ext_5ghz_lna = (val >> 3) & 1; 1548178676Ssam sc->ext_2ghz_lna = (val >> 2) & 1; 1549178676Ssam /* check if RF supports automatic Tx access gain control */ 1550206477Sbschmidt sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1; 1551178676Ssam /* check if we have a hardware radio switch */ 1552178676Ssam sc->rfswitch = val & 1; 1553178676Ssam } 1554178676Ssam 1555178676Ssam /* read power settings for 2GHz channels */ 1556178676Ssam for (i = 0; i < 14; i += 2) { 1557178676Ssam run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val); 1558201209Srpaulo sc->txpow1[i + 0] = (int8_t)(val & 0xff); 1559201209Srpaulo sc->txpow1[i + 1] = (int8_t)(val >> 8); 1560178676Ssam 1561201209Srpaulo run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val); 1562201209Srpaulo sc->txpow2[i + 0] = (int8_t)(val & 0xff); 1563201209Srpaulo sc->txpow2[i + 1] = (int8_t)(val >> 8); 1564201209Srpaulo } 1565201209Srpaulo /* fix broken Tx power entries */ 1566178676Ssam for (i = 0; i < 14; i++) { 1567201209Srpaulo if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31) 1568201209Srpaulo sc->txpow1[i] = 5; 1569178676Ssam if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31) 1570220701Sbschmidt sc->txpow2[i] = 5; 1571220701Sbschmidt DPRINTF("chan %d: power1=%d, power2=%d\n", 1572220701Sbschmidt rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]); 1573220701Sbschmidt } 1574178676Ssam /* read power settings for 5GHz channels */ 1575178676Ssam for (i = 0; i < 40; i += 2) { 1576206477Sbschmidt run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val); 1577201209Srpaulo sc->txpow1[i + 14] = (int8_t)(val & 0xff); 1578201209Srpaulo sc->txpow1[i + 15] = (int8_t)(val >> 8); 1579201209Srpaulo 1580201209Srpaulo run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val); 1581201209Srpaulo sc->txpow2[i + 14] = (int8_t)(val & 0xff); 1582201209Srpaulo sc->txpow2[i + 15] = (int8_t)(val >> 8); 1583201209Srpaulo } 1584201209Srpaulo /* fix broken Tx power entries */ 1585201209Srpaulo for (i = 0; i < 40; i++) { 1586220725Sbschmidt if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15) 1587201209Srpaulo sc->txpow1[14 + i] = 5; 1588201209Srpaulo if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15) 1589201209Srpaulo sc->txpow2[14 + i] = 5; 1590201209Srpaulo DPRINTF("chan %d: power1=%d, power2=%d\n", 1591201209Srpaulo rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i], 1592201209Srpaulo sc->txpow2[14 + i]); 1593201209Srpaulo } 1594201209Srpaulo 1595201209Srpaulo /* read Tx power compensation for each Tx rate */ 1596201209Srpaulo run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val); 1597201209Srpaulo delta_2ghz = delta_5ghz = 0; 1598201209Srpaulo if ((val & 0xff) != 0xff && (val & 0x80)) { 1599201209Srpaulo delta_2ghz = val & 0xf; 1600201209Srpaulo if (!(val & 0x40)) /* negative number */ 1601206477Sbschmidt delta_2ghz = -delta_2ghz; 1602198429Srpaulo } 1603178676Ssam val >>= 8; 1604220728Sbschmidt if ((val & 0xff) != 0xff && (val & 0x80)) { 1605220723Sbschmidt delta_5ghz = val & 0xf; 1606198429Srpaulo if (!(val & 0x40)) /* negative number */ 1607178676Ssam delta_5ghz = -delta_5ghz; 1608198429Srpaulo } 1609198429Srpaulo DPRINTF("power compensation=%d (2GHz), %d (5GHz)\n", 1610198429Srpaulo delta_2ghz, delta_5ghz); 1611198429Srpaulo 1612198429Srpaulo for (ridx = 0; ridx < 5; ridx++) { 1613198429Srpaulo uint32_t reg; 1614178676Ssam 1615201209Srpaulo run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val); 1616220726Sbschmidt reg = val; 1617201209Srpaulo run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val); 1618220726Sbschmidt reg |= (uint32_t)val << 16; 1619220726Sbschmidt 1620201209Srpaulo sc->txpow20mhz[ridx] = reg; 1621201209Srpaulo sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz); 1622201209Srpaulo sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz); 1623198429Srpaulo 1624198429Srpaulo DPRINTF("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, " 1625198429Srpaulo "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx], 1626198429Srpaulo sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]); 1627220726Sbschmidt } 1628220726Sbschmidt 1629198429Srpaulo /* read RSSI offsets and LNA gains from EEPROM */ 1630198429Srpaulo run_srom_read(sc, RT2860_EEPROM_RSSI1_2GHZ, &val); 1631198429Srpaulo sc->rssi_2ghz[0] = val & 0xff; /* Ant A */ 1632201209Srpaulo sc->rssi_2ghz[1] = val >> 8; /* Ant B */ 1633220726Sbschmidt run_srom_read(sc, RT2860_EEPROM_RSSI2_2GHZ, &val); 1634201209Srpaulo if (sc->mac_ver >= 0x3070) { 1635201209Srpaulo /* 1636201209Srpaulo * On RT3070 chips (limited to 2 Rx chains), this ROM 1637201209Srpaulo * field contains the Tx mixer gain for the 2GHz band. 1638201209Srpaulo */ 1639198429Srpaulo if ((val & 0xff) != 0xff) 1640178676Ssam sc->txmixgain_2ghz = val & 0x7; 1641220729Sbschmidt DPRINTF("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz); 1642220729Sbschmidt } else 1643220729Sbschmidt sc->rssi_2ghz[2] = val & 0xff; /* Ant C */ 1644220729Sbschmidt sc->lna[2] = val >> 8; /* channel group 2 */ 1645220729Sbschmidt 1646220729Sbschmidt run_srom_read(sc, RT2860_EEPROM_RSSI1_5GHZ, &val); 1647198429Srpaulo sc->rssi_5ghz[0] = val & 0xff; /* Ant A */ 1648198429Srpaulo sc->rssi_5ghz[1] = val >> 8; /* Ant B */ 1649198429Srpaulo run_srom_read(sc, RT2860_EEPROM_RSSI2_5GHZ, &val); 1650220727Sbschmidt if (sc->mac_ver == 0x3572) { 1651220727Sbschmidt /* 1652220727Sbschmidt * On RT3572 chips (limited to 2 Rx chains), this ROM 1653220727Sbschmidt * field contains the Tx mixer gain for the 5GHz band. 1654220727Sbschmidt */ 1655178676Ssam if ((val & 0xff) != 0xff) 1656198429Srpaulo sc->txmixgain_5ghz = val & 0x7; 1657198429Srpaulo DPRINTF("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz); 1658178676Ssam } else 1659198429Srpaulo sc->rssi_5ghz[2] = val & 0xff; /* Ant C */ 1660220728Sbschmidt sc->lna[3] = val >> 8; /* channel group 3 */ 1661178676Ssam 1662201209Srpaulo run_srom_read(sc, RT2860_EEPROM_LNA, &val); 1663201209Srpaulo sc->lna[0] = val & 0xff; /* channel group 0 */ 1664198429Srpaulo sc->lna[1] = val >> 8; /* channel group 1 */ 1665198429Srpaulo 1666178676Ssam /* fix broken 5GHz LNA entries */ 1667178676Ssam if (sc->lna[2] == 0 || sc->lna[2] == 0xff) { 1668206477Sbschmidt DPRINTF("invalid LNA for channel group %d\n", 2); 1669198429Srpaulo sc->lna[2] = sc->lna[1]; 1670178676Ssam } 1671201209Srpaulo if (sc->lna[3] == 0 || sc->lna[3] == 0xff) { 1672220723Sbschmidt DPRINTF("invalid LNA for channel group %d\n", 3); 1673198429Srpaulo sc->lna[3] = sc->lna[1]; 1674178676Ssam } 1675220725Sbschmidt 1676198429Srpaulo /* fix broken RSSI offset entries */ 1677178676Ssam for (ant = 0; ant < 3; ant++) { 1678220725Sbschmidt if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) { 1679221636Sbschmidt DPRINTF("invalid RSSI%d offset: %d (2GHz)\n", 1680201209Srpaulo ant + 1, sc->rssi_2ghz[ant]); 1681201209Srpaulo sc->rssi_2ghz[ant] = 0; 1682201209Srpaulo } 1683198429Srpaulo if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) { 1684198429Srpaulo DPRINTF("invalid RSSI%d offset: %d (5GHz)\n", 1685198429Srpaulo ant + 1, sc->rssi_5ghz[ant]); 1686198429Srpaulo sc->rssi_5ghz[ant] = 0; 1687198429Srpaulo } 1688198429Srpaulo } 1689198429Srpaulo return (0); 1690198429Srpaulo} 1691198429Srpaulo 1692198429Srpaulostatic struct ieee80211_node * 1693198429Srpaulorun_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) 1694198429Srpaulo{ 1695198429Srpaulo return malloc(sizeof (struct run_node), M_DEVBUF, M_NOWAIT | M_ZERO); 1696198429Srpaulo} 1697198429Srpaulo 1698198429Srpaulostatic int 1699198429Srpaulorun_media_change(struct ifnet *ifp) 1700198429Srpaulo{ 1701198429Srpaulo struct ieee80211vap *vap = ifp->if_softc; 1702198429Srpaulo struct ieee80211com *ic = vap->iv_ic; 1703198429Srpaulo const struct ieee80211_txparam *tp; 1704198429Srpaulo struct run_softc *sc = ic->ic_ifp->if_softc; 1705198429Srpaulo uint8_t rate, ridx; 1706198429Srpaulo int error; 1707198429Srpaulo 1708201209Srpaulo RUN_LOCK(sc); 1709198429Srpaulo 1710198429Srpaulo error = ieee80211_media_change(ifp); 1711178676Ssam if (error != ENETRESET) { 1712198429Srpaulo RUN_UNLOCK(sc); 1713178676Ssam return (error); 1714178676Ssam } 1715198429Srpaulo 1716206477Sbschmidt tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 1717198429Srpaulo if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 1718178676Ssam struct ieee80211_node *ni; 1719198429Srpaulo struct run_node *rn; 1720198429Srpaulo 1721198429Srpaulo rate = ic->ic_sup_rates[ic->ic_curmode]. 1722178676Ssam rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL; 1723198429Srpaulo for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 1724198429Srpaulo if (rt2860_rates[ridx].rate == rate) 1725198429Srpaulo break; 1726198429Srpaulo ni = ieee80211_ref_node(vap->iv_bss); 1727198429Srpaulo rn = (struct run_node *)ni; 1728198429Srpaulo rn->fix_ridx = ridx; 1729198429Srpaulo DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx); 1730198429Srpaulo ieee80211_free_node(ni); 1731198429Srpaulo } 1732198429Srpaulo 1733198429Srpaulo#if 0 1734198429Srpaulo if ((ifp->if_flags & IFF_UP) && 1735198429Srpaulo (ifp->if_drv_flags & IFF_DRV_RUNNING)){ 1736198429Srpaulo run_init_locked(sc); 1737198429Srpaulo } 1738198429Srpaulo#endif 1739198429Srpaulo 1740198429Srpaulo RUN_UNLOCK(sc); 1741198429Srpaulo 1742198429Srpaulo return (0); 1743198429Srpaulo} 1744198429Srpaulo 1745198429Srpaulostatic int 1746198429Srpaulorun_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 1747178676Ssam{ 1748198429Srpaulo const struct ieee80211_txparam *tp; 1749178676Ssam struct ieee80211com *ic = vap->iv_ic; 1750206477Sbschmidt struct run_softc *sc = ic->ic_ifp->if_softc; 1751198429Srpaulo struct run_vap *rvp = RUN_VAP(vap); 1752178676Ssam enum ieee80211_state ostate; 1753206444Sbschmidt uint32_t sta[3]; 1754220674Sbschmidt uint32_t tmp; 1755220723Sbschmidt uint8_t ratectl; 1756220723Sbschmidt uint8_t restart_ratectl = 0; 1757198429Srpaulo uint8_t bid = 1 << rvp->rvp_id; 1758178676Ssam 1759220725Sbschmidt ostate = vap->iv_state; 1760198429Srpaulo DPRINTF("%s -> %s\n", 1761198429Srpaulo ieee80211_state_name[ostate], 1762198429Srpaulo ieee80211_state_name[nstate]); 1763198429Srpaulo 1764178676Ssam IEEE80211_UNLOCK(ic); 1765220725Sbschmidt RUN_LOCK(sc); 1766221636Sbschmidt 1767221635Sbschmidt ratectl = sc->ratectl_run; /* remember current state */ 1768221635Sbschmidt sc->ratectl_run = RUN_RATECTL_OFF; 1769221635Sbschmidt usb_callout_stop(&sc->ratectl_ch); 1770221635Sbschmidt 1771201209Srpaulo if (ostate == IEEE80211_S_RUN) { 1772198429Srpaulo /* turn link LED off */ 1773178676Ssam run_set_leds(sc, RT2860_LED_RADIO); 1774201209Srpaulo } 1775201209Srpaulo 1776201209Srpaulo switch (nstate) { 1777201209Srpaulo case IEEE80211_S_INIT: 1778198429Srpaulo restart_ratectl = 1; 1779198429Srpaulo 1780206444Sbschmidt if (ostate != IEEE80211_S_RUN) 1781206444Sbschmidt break; 1782220726Sbschmidt 1783220726Sbschmidt ratectl &= ~bid; 1784210108Sbschmidt sc->runbmap &= ~bid; 1785206444Sbschmidt 1786198429Srpaulo /* abort TSF synchronization if there is no vap running */ 1787201209Srpaulo if (--sc->running == 0) { 1788198429Srpaulo run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 1789220674Sbschmidt run_write(sc, RT2860_BCN_TIME_CFG, 1790198429Srpaulo tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 1791198429Srpaulo RT2860_TBTT_TIMER_EN)); 1792220674Sbschmidt } 1793201209Srpaulo break; 1794220674Sbschmidt 1795220674Sbschmidt case IEEE80211_S_RUN: 1796220674Sbschmidt if (!(sc->runbmap & bid)) { 1797220674Sbschmidt if(sc->running++) 1798220674Sbschmidt restart_ratectl = 1; 1799220674Sbschmidt sc->runbmap |= bid; 1800220674Sbschmidt } 1801178676Ssam 1802178676Ssam m_freem(rvp->beacon_mbuf); 1803178676Ssam rvp->beacon_mbuf = NULL; 1804201209Srpaulo 1805201209Srpaulo switch (vap->iv_opmode) { 1806201209Srpaulo case IEEE80211_M_HOSTAP: 1807201209Srpaulo case IEEE80211_M_MBSS: 1808201209Srpaulo sc->ap_running |= bid; 1809201209Srpaulo ic->ic_opmode = vap->iv_opmode; 1810201209Srpaulo run_update_beacon_cb(vap); 1811201209Srpaulo break; 1812201209Srpaulo case IEEE80211_M_IBSS: 1813201209Srpaulo sc->adhoc_running |= bid; 1814201209Srpaulo if (!sc->ap_running) 1815201209Srpaulo ic->ic_opmode = vap->iv_opmode; 1816201209Srpaulo run_update_beacon_cb(vap); 1817201209Srpaulo break; 1818201209Srpaulo case IEEE80211_M_STA: 1819201209Srpaulo sc->sta_running |= bid; 1820201209Srpaulo if (!sc->ap_running && !sc->adhoc_running) 1821201209Srpaulo ic->ic_opmode = vap->iv_opmode; 1822201209Srpaulo 1823201209Srpaulo /* read statistic counters (clear on read) */ 1824201209Srpaulo run_read_region_1(sc, RT2860_TX_STA_CNT0, 1825201209Srpaulo (uint8_t *)sta, sizeof sta); 1826198429Srpaulo 1827201209Srpaulo break; 1828178676Ssam default: 1829198429Srpaulo ic->ic_opmode = vap->iv_opmode; 1830198429Srpaulo break; 1831201209Srpaulo } 1832201209Srpaulo 1833198429Srpaulo if (vap->iv_opmode != IEEE80211_M_MONITOR) { 1834220687Sbschmidt struct ieee80211_node *ni; 1835220687Sbschmidt 1836178676Ssam if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) { 1837198429Srpaulo RUN_UNLOCK(sc); 1838198429Srpaulo IEEE80211_LOCK(ic); 1839198429Srpaulo return (-1); 1840198429Srpaulo } 1841198429Srpaulo run_updateslot(ic->ic_ifp); 1842198429Srpaulo run_enable_mrr(sc); 1843198429Srpaulo run_set_txpreamble(sc); 1844198429Srpaulo run_set_basicrates(sc); 1845198429Srpaulo ni = ieee80211_ref_node(vap->iv_bss); 1846201209Srpaulo IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); 1847178676Ssam run_set_bssid(sc, ni->ni_bssid); 1848198429Srpaulo ieee80211_free_node(ni); 1849198429Srpaulo run_enable_tsf_sync(sc); 1850198429Srpaulo 1851198429Srpaulo /* enable automatic rate adaptation */ 1852206445Sbschmidt tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 1853201209Srpaulo if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) 1854220726Sbschmidt ratectl |= bid; 1855198429Srpaulo } 1856198429Srpaulo 1857198429Srpaulo /* turn link LED on */ 1858198429Srpaulo run_set_leds(sc, RT2860_LED_RADIO | 1859198429Srpaulo (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 1860198429Srpaulo RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ)); 1861220726Sbschmidt 1862198429Srpaulo break; 1863178676Ssam default: 1864220723Sbschmidt DPRINTFN(6, "undefined case\n"); 1865220723Sbschmidt break; 1866220723Sbschmidt } 1867220723Sbschmidt 1868220723Sbschmidt /* restart amrr for running VAPs */ 1869220726Sbschmidt if ((sc->ratectl_run = ratectl) && restart_ratectl) 1870220726Sbschmidt usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 1871220723Sbschmidt 1872221636Sbschmidt RUN_UNLOCK(sc); 1873221636Sbschmidt IEEE80211_LOCK(ic); 1874221636Sbschmidt 1875221636Sbschmidt return(rvp->newstate(vap, nstate, arg)); 1876221636Sbschmidt} 1877221636Sbschmidt 1878178676Ssam/* ARGSUSED */ 1879178676Ssamstatic void 1880178676Ssamrun_wme_update_cb(void *arg) 1881198429Srpaulo{ 1882201209Srpaulo struct ieee80211com *ic = arg; 1883178676Ssam struct run_softc *sc = ic->ic_ifp->if_softc; 1884198429Srpaulo struct ieee80211_wme_state *wmesp = &ic->ic_wme; 1885198429Srpaulo int aci, error = 0; 1886201209Srpaulo 1887201209Srpaulo RUN_LOCK_ASSERT(sc, MA_OWNED); 1888198429Srpaulo 1889221636Sbschmidt /* update MAC TX configuration registers */ 1890221636Sbschmidt for (aci = 0; aci < WME_NUM_AC; aci++) { 1891178676Ssam error = run_write(sc, RT2860_EDCA_AC_CFG(aci), 1892221636Sbschmidt wmesp->wme_params[aci].wmep_logcwmax << 16 | 1893221636Sbschmidt wmesp->wme_params[aci].wmep_logcwmin << 12 | 1894221636Sbschmidt wmesp->wme_params[aci].wmep_aifsn << 8 | 1895198429Srpaulo wmesp->wme_params[aci].wmep_txopLimit); 1896221636Sbschmidt if (error) goto err; 1897198429Srpaulo } 1898198429Srpaulo 1899198429Srpaulo /* update SCH/DMA registers too */ 1900198429Srpaulo error = run_write(sc, RT2860_WMM_AIFSN_CFG, 1901198429Srpaulo wmesp->wme_params[WME_AC_VO].wmep_aifsn << 12 | 1902198429Srpaulo wmesp->wme_params[WME_AC_VI].wmep_aifsn << 8 | 1903221636Sbschmidt wmesp->wme_params[WME_AC_BK].wmep_aifsn << 4 | 1904221636Sbschmidt wmesp->wme_params[WME_AC_BE].wmep_aifsn); 1905221636Sbschmidt if (error) goto err; 1906198429Srpaulo error = run_write(sc, RT2860_WMM_CWMIN_CFG, 1907198429Srpaulo wmesp->wme_params[WME_AC_VO].wmep_logcwmin << 12 | 1908198429Srpaulo wmesp->wme_params[WME_AC_VI].wmep_logcwmin << 8 | 1909198429Srpaulo wmesp->wme_params[WME_AC_BK].wmep_logcwmin << 4 | 1910221636Sbschmidt wmesp->wme_params[WME_AC_BE].wmep_logcwmin); 1911221636Sbschmidt if (error) goto err; 1912198429Srpaulo error = run_write(sc, RT2860_WMM_CWMAX_CFG, 1913198429Srpaulo wmesp->wme_params[WME_AC_VO].wmep_logcwmax << 12 | 1914221636Sbschmidt wmesp->wme_params[WME_AC_VI].wmep_logcwmax << 8 | 1915198429Srpaulo wmesp->wme_params[WME_AC_BK].wmep_logcwmax << 4 | 1916198429Srpaulo wmesp->wme_params[WME_AC_BE].wmep_logcwmax); 1917198429Srpaulo if (error) goto err; 1918221636Sbschmidt error = run_write(sc, RT2860_WMM_TXOP0_CFG, 1919198429Srpaulo wmesp->wme_params[WME_AC_BK].wmep_txopLimit << 16 | 1920198429Srpaulo wmesp->wme_params[WME_AC_BE].wmep_txopLimit); 1921221636Sbschmidt if (error) goto err; 1922221636Sbschmidt error = run_write(sc, RT2860_WMM_TXOP1_CFG, 1923198429Srpaulo wmesp->wme_params[WME_AC_VO].wmep_txopLimit << 16 | 1924198429Srpaulo wmesp->wme_params[WME_AC_VI].wmep_txopLimit); 1925178676Ssam 1926198429Srpauloerr: 1927198429Srpaulo if (error) 1928221636Sbschmidt DPRINTF("WME update failed\n"); 1929178676Ssam 1930198429Srpaulo return; 1931198429Srpaulo} 1932198429Srpaulo 1933198429Srpaulostatic int 1934221636Sbschmidtrun_wme_update(struct ieee80211com *ic) 1935198429Srpaulo{ 1936198429Srpaulo struct run_softc *sc = ic->ic_ifp->if_softc; 1937198429Srpaulo 1938198429Srpaulo /* sometime called wothout lock */ 1939221636Sbschmidt if (mtx_owned(&ic->ic_comlock.mtx)) { 1940178676Ssam uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 1941198429Srpaulo DPRINTF("cmdq_store=%d\n", i); 1942178676Ssam sc->cmdq[i].func = run_wme_update_cb; 1943198429Srpaulo sc->cmdq[i].arg0 = ic; 1944201209Srpaulo ieee80211_runtask(ic, &sc->cmdq_task); 1945198429Srpaulo return (0); 1946198429Srpaulo } 1947198429Srpaulo 1948178676Ssam RUN_LOCK(sc); 1949201209Srpaulo run_wme_update_cb(ic); 1950201209Srpaulo RUN_UNLOCK(sc); 1951201209Srpaulo 1952198429Srpaulo /* return whatever, upper layer desn't care anyway */ 1953201209Srpaulo return (0); 1954198429Srpaulo} 1955201209Srpaulo 1956198429Srpaulostatic void 1957178676Ssamrun_key_update_begin(struct ieee80211vap *vap) 1958178676Ssam{ 1959220723Sbschmidt /* 1960220723Sbschmidt * To avoid out-of-order events, both run_key_set() and 1961220723Sbschmidt * _delete() are deferred and handled by run_cmdq_cb(). 1962221636Sbschmidt * So, there is nothing we need to do here. 1963220723Sbschmidt */ 1964221636Sbschmidt} 1965221636Sbschmidt 1966221636Sbschmidtstatic void 1967221636Sbschmidtrun_key_update_end(struct ieee80211vap *vap) 1968221636Sbschmidt{ 1969221636Sbschmidt /* null */ 1970221636Sbschmidt} 1971221636Sbschmidt 1972221636Sbschmidtstatic void 1973220723Sbschmidtrun_key_set_cb(void *arg) 1974221636Sbschmidt{ 1975221636Sbschmidt struct run_cmdq *cmdq = arg; 1976221636Sbschmidt struct ieee80211vap *vap = cmdq->arg1; 1977221636Sbschmidt struct ieee80211_key *k = cmdq->k; 1978221636Sbschmidt struct ieee80211com *ic = vap->iv_ic; 1979221636Sbschmidt struct run_softc *sc = ic->ic_ifp->if_softc; 1980221636Sbschmidt struct ieee80211_node *ni; 1981220723Sbschmidt uint32_t attr; 1982220723Sbschmidt uint16_t base, associd; 1983220723Sbschmidt uint8_t mode, wcid, iv[8]; 1984220723Sbschmidt 1985220723Sbschmidt RUN_LOCK_ASSERT(sc, MA_OWNED); 1986220723Sbschmidt 1987220723Sbschmidt if (vap->iv_opmode == IEEE80211_M_HOSTAP) 1988220723Sbschmidt ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac); 1989220723Sbschmidt else 1990220723Sbschmidt ni = vap->iv_bss; 1991220723Sbschmidt associd = (ni != NULL) ? ni->ni_associd : 0; 1992220723Sbschmidt 1993220723Sbschmidt /* map net80211 cipher to RT2860 security mode */ 1994220723Sbschmidt switch (k->wk_cipher->ic_cipher) { 1995220723Sbschmidt case IEEE80211_CIPHER_WEP: 1996220723Sbschmidt if(k->wk_keylen < 8) 1997220723Sbschmidt mode = RT2860_MODE_WEP40; 1998220723Sbschmidt else 1999220723Sbschmidt mode = RT2860_MODE_WEP104; 2000220723Sbschmidt break; 2001220723Sbschmidt case IEEE80211_CIPHER_TKIP: 2002220723Sbschmidt mode = RT2860_MODE_TKIP; 2003220723Sbschmidt break; 2004220723Sbschmidt case IEEE80211_CIPHER_AES_CCM: 2005220723Sbschmidt mode = RT2860_MODE_AES_CCMP; 2006220723Sbschmidt break; 2007220723Sbschmidt default: 2008220723Sbschmidt DPRINTF("undefined case\n"); 2009220723Sbschmidt return; 2010220723Sbschmidt } 2011220723Sbschmidt 2012201209Srpaulo DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n", 2013201209Srpaulo associd, k->wk_keyix, mode, 2014206477Sbschmidt (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise", 2015201209Srpaulo (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off", 2016201209Srpaulo (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off"); 2017201209Srpaulo 2018221637Sbschmidt if (k->wk_flags & IEEE80211_KEY_GROUP) { 2019221637Sbschmidt wcid = 0; /* NB: update WCID0 for group keys */ 2020221637Sbschmidt base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix); 2021201209Srpaulo } else { 2022201209Srpaulo wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 2023221637Sbschmidt 1 : RUN_AID2WCID(associd); 2024221637Sbschmidt base = RT2860_PKEY(wcid); 2025201209Srpaulo } 2026201209Srpaulo 2027201209Srpaulo if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) { 2028201209Srpaulo if(run_write_region_1(sc, base, k->wk_key, 16)) 2029201209Srpaulo return; 2030201209Srpaulo if(run_write_region_1(sc, base + 16, &k->wk_key[16], 8)) /* wk_txmic */ 2031201209Srpaulo return; 2032221637Sbschmidt if(run_write_region_1(sc, base + 24, &k->wk_key[24], 8)) /* wk_rxmic */ 2033221637Sbschmidt return; 2034201209Srpaulo } else { 2035201209Srpaulo /* roundup len to 16-bit: XXX fix write_region_1() instead */ 2036201209Srpaulo if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1)) 2037201209Srpaulo return; 2038201209Srpaulo } 2039201209Srpaulo 2040201209Srpaulo if (!(k->wk_flags & IEEE80211_KEY_GROUP) || 2041201209Srpaulo (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) { 2042201209Srpaulo /* set initial packet number in IV+EIV */ 2043201209Srpaulo if (k->wk_cipher == IEEE80211_CIPHER_WEP) { 2044201209Srpaulo memset(iv, 0, sizeof iv); 2045201209Srpaulo iv[3] = vap->iv_def_txkey << 6; 2046201209Srpaulo } else { 2047201209Srpaulo if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) { 2048221637Sbschmidt iv[0] = k->wk_keytsc >> 8; 2049221637Sbschmidt iv[1] = (iv[0] | 0x20) & 0x7f; 2050221637Sbschmidt iv[2] = k->wk_keytsc; 2051221637Sbschmidt } else /* CCMP */ { 2052221637Sbschmidt iv[0] = k->wk_keytsc; 2053221637Sbschmidt iv[1] = k->wk_keytsc >> 8; 2054221637Sbschmidt iv[2] = 0; 2055221637Sbschmidt } 2056221637Sbschmidt iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV; 2057221637Sbschmidt iv[4] = k->wk_keytsc >> 16; 2058221637Sbschmidt iv[5] = k->wk_keytsc >> 24; 2059221637Sbschmidt iv[6] = k->wk_keytsc >> 32; 2060221637Sbschmidt iv[7] = k->wk_keytsc >> 40; 2061221637Sbschmidt } 2062221637Sbschmidt if (run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8)) 2063221637Sbschmidt return; 2064221637Sbschmidt } 2065221637Sbschmidt 2066221637Sbschmidt if (k->wk_flags & IEEE80211_KEY_GROUP) { 2067221637Sbschmidt /* install group key */ 2068221637Sbschmidt if (run_read(sc, RT2860_SKEY_MODE_0_7, &attr)) 2069221637Sbschmidt return; 2070221637Sbschmidt attr &= ~(0xf << (k->wk_keyix * 4)); 2071221637Sbschmidt attr |= mode << (k->wk_keyix * 4); 2072221637Sbschmidt if (run_write(sc, RT2860_SKEY_MODE_0_7, attr)) 2073221637Sbschmidt return; 2074221637Sbschmidt } else { 2075201209Srpaulo /* install pairwise key */ 2076201209Srpaulo if (run_read(sc, RT2860_WCID_ATTR(wcid), &attr)) 2077201209Srpaulo return; 2078206477Sbschmidt attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN; 2079198429Srpaulo if (run_write(sc, RT2860_WCID_ATTR(wcid), attr)) 2080178676Ssam return; 2081198429Srpaulo } 2082198429Srpaulo 2083178676Ssam /* TODO create a pass-thru key entry? */ 2084221648Sbschmidt 2085221648Sbschmidt /* need wcid to delete the right key later */ 2086221648Sbschmidt k->wk_pad = wcid; 2087221648Sbschmidt} 2088221648Sbschmidt 2089221648Sbschmidt/* 2090221648Sbschmidt * Don't have to be deferred, but in order to keep order of 2091221648Sbschmidt * execution, i.e. with run_key_delete(), defer this and let 2092221648Sbschmidt * run_cmdq_cb() maintain the order. 2093221648Sbschmidt * 2094221648Sbschmidt * return 0 on error 2095221648Sbschmidt */ 2096221648Sbschmidtstatic int 2097221648Sbschmidtrun_key_set(struct ieee80211vap *vap, struct ieee80211_key *k, 2098221648Sbschmidt const uint8_t mac[IEEE80211_ADDR_LEN]) 2099221648Sbschmidt{ 2100221648Sbschmidt struct ieee80211com *ic = vap->iv_ic; 2101221648Sbschmidt struct run_softc *sc = ic->ic_ifp->if_softc; 2102221648Sbschmidt uint32_t i; 2103221648Sbschmidt 2104220715Sbschmidt i = RUN_CMDQ_GET(&sc->cmdq_store); 2105220715Sbschmidt DPRINTF("cmdq_store=%d\n", i); 2106220715Sbschmidt sc->cmdq[i].func = run_key_set_cb; 2107221648Sbschmidt sc->cmdq[i].arg0 = NULL; 2108221648Sbschmidt sc->cmdq[i].arg1 = vap; 2109220715Sbschmidt sc->cmdq[i].k = k; 2110221649Sbschmidt IEEE80211_ADDR_COPY(sc->cmdq[i].mac, mac); 2111221648Sbschmidt ieee80211_runtask(ic, &sc->cmdq_task); 2112220715Sbschmidt 2113221648Sbschmidt /* 2114221649Sbschmidt * To make sure key will be set when hostapd 2115221649Sbschmidt * calls iv_key_set() before if_init(). 2116221648Sbschmidt */ 2117221649Sbschmidt if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 2118221649Sbschmidt RUN_LOCK(sc); 2119221649Sbschmidt sc->cmdq_key_set = RUN_CMDQ_GO; 2120221649Sbschmidt RUN_UNLOCK(sc); 2121221649Sbschmidt } 2122221649Sbschmidt 2123221649Sbschmidt return (1); 2124221649Sbschmidt} 2125221649Sbschmidt 2126221649Sbschmidt/* 2127221649Sbschmidt * If wlan is destroyed without being brought down i.e. without 2128221649Sbschmidt * wlan down or wpa_cli terminate, this function is called after 2129221649Sbschmidt * vap is gone. Don't refer it. 2130221649Sbschmidt */ 2131221649Sbschmidtstatic void 2132221649Sbschmidtrun_key_delete_cb(void *arg) 2133221649Sbschmidt{ 2134221649Sbschmidt struct run_cmdq *cmdq = arg; 2135221649Sbschmidt struct run_softc *sc = cmdq->arg1; 2136221649Sbschmidt struct ieee80211_key *k = &cmdq->key; 2137221649Sbschmidt uint32_t attr; 2138221649Sbschmidt uint8_t wcid; 2139221649Sbschmidt 2140221649Sbschmidt RUN_LOCK_ASSERT(sc, MA_OWNED); 2141221649Sbschmidt 2142221648Sbschmidt if (k->wk_flags & IEEE80211_KEY_GROUP) { 2143221649Sbschmidt /* remove group key */ 2144221649Sbschmidt DPRINTF("removing group key\n"); 2145221649Sbschmidt run_read(sc, RT2860_SKEY_MODE_0_7, &attr); 2146221649Sbschmidt attr &= ~(0xf << (k->wk_keyix * 4)); 2147221649Sbschmidt run_write(sc, RT2860_SKEY_MODE_0_7, attr); 2148221649Sbschmidt } else { 2149221649Sbschmidt /* remove pairwise key */ 2150221649Sbschmidt DPRINTF("removing key for wcid %x\n", k->wk_pad); 2151220715Sbschmidt /* matching wcid was written to wk_pad in run_key_set() */ 2152220715Sbschmidt wcid = k->wk_pad; 2153220715Sbschmidt run_read(sc, RT2860_WCID_ATTR(wcid), &attr); 2154206477Sbschmidt attr &= ~0xf; 2155198429Srpaulo run_write(sc, RT2860_WCID_ATTR(wcid), attr); 2156178676Ssam run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8); 2157220726Sbschmidt } 2158220726Sbschmidt 2159220726Sbschmidt k->wk_pad = 0; 2160198429Srpaulo} 2161198429Srpaulo 2162198429Srpaulo/* 2163178676Ssam * return 0 on error 2164206477Sbschmidt */ 2165198429Srpaulostatic int 2166198429Srpaulorun_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k) 2167198429Srpaulo{ 2168198429Srpaulo struct ieee80211com *ic = vap->iv_ic; 2169198429Srpaulo struct run_softc *sc = ic->ic_ifp->if_softc; 2170220688Sbschmidt struct ieee80211_key *k0; 2171178676Ssam uint32_t i; 2172198429Srpaulo 2173220726Sbschmidt /* 2174178676Ssam * When called back, key might be gone. So, make a copy 2175198429Srpaulo * of some values need to delete keys before deferring. 2176198429Srpaulo * But, because of LOR with node lock, cannot use lock here. 2177220667Sbschmidt * So, use atomic instead. 2178178676Ssam */ 2179210114Sbschmidt i = RUN_CMDQ_GET(&sc->cmdq_store); 2180210114Sbschmidt DPRINTF("cmdq_store=%d\n", i); 2181210114Sbschmidt sc->cmdq[i].func = run_key_delete_cb; 2182210114Sbschmidt sc->cmdq[i].arg0 = NULL; 2183210114Sbschmidt sc->cmdq[i].arg1 = sc; 2184210114Sbschmidt k0 = &sc->cmdq[i].key; 2185210114Sbschmidt k0->wk_flags = k->wk_flags; 2186210114Sbschmidt k0->wk_keyix = k->wk_keyix; 2187210114Sbschmidt /* matching wcid was written to wk_pad in run_key_set() */ 2188210114Sbschmidt k0->wk_pad = k->wk_pad; 2189210114Sbschmidt ieee80211_runtask(ic, &sc->cmdq_task); 2190210114Sbschmidt return (1); /* return fake success */ 2191210114Sbschmidt 2192198439Srpaulo} 2193198439Srpaulo 2194220667Sbschmidtstatic void 2195220667Sbschmidtrun_ratectl_to(void *arg) 2196220688Sbschmidt{ 2197220688Sbschmidt struct run_softc *sc = arg; 2198220688Sbschmidt 2199220688Sbschmidt /* do it in a process context, so it can go sleep */ 2200210114Sbschmidt ieee80211_runtask(sc->sc_ifp->if_l2com, &sc->ratectl_task); 2201210114Sbschmidt /* next timeout will be rescheduled in the callback task */ 2202210114Sbschmidt} 2203198429Srpaulo 2204210114Sbschmidt/* ARGSUSED */ 2205210114Sbschmidtstatic void 2206220667Sbschmidtrun_ratectl_cb(void *arg, int pending) 2207220667Sbschmidt{ 2208210114Sbschmidt struct run_softc *sc = arg; 2209210114Sbschmidt struct ieee80211com *ic = sc->sc_ifp->if_l2com; 2210210114Sbschmidt struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2211210114Sbschmidt 2212198429Srpaulo if (vap == NULL) 2213198429Srpaulo return; 2214198429Srpaulo 2215198429Srpaulo if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA) 2216220688Sbschmidt run_iter_func(sc, vap->iv_bss); 2217220688Sbschmidt else { 2218220688Sbschmidt /* 2219220688Sbschmidt * run_reset_livelock() doesn't do anything with AMRR, 2220210114Sbschmidt * but Ralink wants us to call it every 1 sec. So, we 2221210114Sbschmidt * piggyback here rather than creating another callout. 2222220667Sbschmidt * Livelock may occur only in HOSTAP or IBSS mode 2223220667Sbschmidt * (when h/w is sending beacons). 2224220667Sbschmidt */ 2225220667Sbschmidt RUN_LOCK(sc); 2226210114Sbschmidt run_reset_livelock(sc); 2227210114Sbschmidt /* just in case, there are some stats to drain */ 2228178676Ssam run_drain_fifo(sc); 2229198429Srpaulo RUN_UNLOCK(sc); 2230198429Srpaulo ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc); 2231220688Sbschmidt } 2232220688Sbschmidt 2233198429Srpaulo if(sc->ratectl_run != RUN_RATECTL_OFF) 2234178676Ssam usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2235178676Ssam} 2236220667Sbschmidt 2237220667Sbschmidtstatic void 2238220667Sbschmidtrun_drain_fifo(void *arg) 2239220667Sbschmidt{ 2240220667Sbschmidt struct run_softc *sc = arg; 2241220667Sbschmidt struct ifnet *ifp = sc->sc_ifp; 2242220667Sbschmidt uint32_t stat; 2243220667Sbschmidt uint16_t (*wstat)[3]; 2244220667Sbschmidt uint8_t wcid, mcs, pid; 2245220667Sbschmidt int8_t retry; 2246220667Sbschmidt 2247220667Sbschmidt RUN_LOCK_ASSERT(sc, MA_OWNED); 2248220667Sbschmidt 2249220667Sbschmidt for (;;) { 2250220667Sbschmidt /* drain Tx status FIFO (maxsize = 16) */ 2251220667Sbschmidt run_read(sc, RT2860_TX_STAT_FIFO, &stat); 2252220667Sbschmidt DPRINTFN(4, "tx stat 0x%08x\n", stat); 2253220667Sbschmidt if (!(stat & RT2860_TXQ_VLD)) 2254220667Sbschmidt break; 2255220667Sbschmidt 2256220667Sbschmidt wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff; 2257198429Srpaulo 2258198429Srpaulo /* if no ACK was requested, no feedback is available */ 2259198429Srpaulo if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX || 2260198429Srpaulo wcid == 0) 2261206477Sbschmidt continue; 2262198429Srpaulo 2263198429Srpaulo /* 2264178676Ssam * Even though each stat is Tx-complete-status like format, 2265198429Srpaulo * the device can poll stats. Because there is no guarantee 2266198429Srpaulo * that the referring node is still around when read the stats. 2267198429Srpaulo * So that, if we use ieee80211_ratectl_tx_update(), we will 2268202986Srpaulo * have hard time not to refer already freed node. 2269198429Srpaulo * 2270198429Srpaulo * To eliminate such page faults, we poll stats in softc. 2271198429Srpaulo * Then, update the rates later with ieee80211_ratectl_tx_update(). 2272198429Srpaulo */ 2273178676Ssam wstat = &(sc->wcid_stats[wcid]); 2274178676Ssam (*wstat)[RUN_TXCNT]++; 2275198429Srpaulo if (stat & RT2860_TXQ_OK) 2276198429Srpaulo (*wstat)[RUN_SUCCESS]++; 2277198429Srpaulo else 2278198429Srpaulo ifp->if_oerrors++; 2279206477Sbschmidt /* 2280198429Srpaulo * Check if there were retries, ie if the Tx success rate is 2281178676Ssam * different from the requested rate. Note that it works only 2282178676Ssam * because we do not allow rate fallback from OFDM to CCK. 2283220728Sbschmidt */ 2284178676Ssam mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f; 2285178676Ssam pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf; 2286178676Ssam if ((retry = pid -1 - mcs) > 0) { 2287178676Ssam (*wstat)[RUN_TXCNT] += retry; 2288178676Ssam (*wstat)[RUN_RETRY] += retry; 2289198429Srpaulo } 2290178676Ssam } 2291178676Ssam DPRINTFN(3, "count=%d\n", sc->fifo_cnt); 2292178676Ssam 2293198429Srpaulo sc->fifo_cnt = 0; 2294198429Srpaulo} 2295178676Ssam 2296198429Srpaulostatic void 2297198429Srpaulorun_iter_func(void *arg, struct ieee80211_node *ni) 2298178676Ssam{ 2299178676Ssam struct run_softc *sc = arg; 2300201209Srpaulo struct ieee80211vap *vap = ni->ni_vap; 2301178676Ssam struct ieee80211com *ic = ni->ni_ic; 2302178676Ssam struct ifnet *ifp = ic->ic_ifp; 2303178676Ssam struct run_node *rn = (void *)ni; 2304178676Ssam union run_stats sta[2]; 2305178676Ssam uint16_t (*wstat)[3]; 2306178676Ssam int txcnt, success, retrycnt, error; 2307201209Srpaulo 2308198439Srpaulo RUN_LOCK(sc); 2309178676Ssam 2310178676Ssam if (sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS || 2311220724Sbschmidt vap->iv_opmode == IEEE80211_M_STA)) { 2312220724Sbschmidt /* read statistic counters (clear on read) and update AMRR state */ 2313178676Ssam error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta, 2314178676Ssam sizeof sta); 2315198429Srpaulo if (error != 0) 2316198429Srpaulo goto fail; 2317198429Srpaulo 2318198429Srpaulo /* count failed TX as errors */ 2319178676Ssam ifp->if_oerrors += le16toh(sta[0].error.fail); 2320178676Ssam 2321178676Ssam retrycnt = le16toh(sta[1].tx.retry); 2322178676Ssam success = le16toh(sta[1].tx.success); 2323178676Ssam txcnt = retrycnt + success + le16toh(sta[0].error.fail); 2324198429Srpaulo 2325198429Srpaulo DPRINTFN(3, "retrycnt=%d success=%d failcnt=%d\n", 2326198429Srpaulo retrycnt, success, le16toh(sta[0].error.fail)); 2327198429Srpaulo } else { 2328220724Sbschmidt wstat = &(sc->wcid_stats[RUN_AID2WCID(ni->ni_associd)]); 2329198429Srpaulo 2330178676Ssam if (wstat == &(sc->wcid_stats[0]) || 2331178676Ssam wstat > &(sc->wcid_stats[RT2870_WCID_MAX])) 2332178676Ssam goto fail; 2333198429Srpaulo 2334198429Srpaulo txcnt = (*wstat)[RUN_TXCNT]; 2335178676Ssam success = (*wstat)[RUN_SUCCESS]; 2336178676Ssam retrycnt = (*wstat)[RUN_RETRY]; 2337178676Ssam DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n", 2338178676Ssam retrycnt, txcnt, success); 2339178676Ssam 2340178676Ssam memset(wstat, 0, sizeof(*wstat)); 2341220692Sbschmidt } 2342198429Srpaulo 2343178676Ssam ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt); 2344178676Ssam rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0); 2345178676Ssam 2346178676Ssamfail: 2347178676Ssam RUN_UNLOCK(sc); 2348201209Srpaulo 2349201209Srpaulo DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx); 2350220692Sbschmidt} 2351220692Sbschmidt 2352178676Ssamstatic void 2353178676Ssamrun_newassoc_cb(void *arg) 2354178676Ssam{ 2355198429Srpaulo struct run_cmdq *cmdq = arg; 2356220693Sbschmidt struct ieee80211_node *ni = cmdq->arg1; 2357220693Sbschmidt struct run_softc *sc = ni->ni_vap->iv_ic->ic_ifp->if_softc; 2358220693Sbschmidt uint8_t wcid = cmdq->wcid; 2359220693Sbschmidt 2360220693Sbschmidt RUN_LOCK_ASSERT(sc, MA_OWNED); 2361220693Sbschmidt 2362220693Sbschmidt run_write_region_1(sc, RT2860_WCID_ENTRY(wcid), 2363220693Sbschmidt ni->ni_macaddr, IEEE80211_ADDR_LEN); 2364220693Sbschmidt 2365220693Sbschmidt memset(&(sc->wcid_stats[wcid]), 0, sizeof(sc->wcid_stats[wcid])); 2366220693Sbschmidt} 2367220693Sbschmidt 2368178676Ssamstatic void 2369178676Ssamrun_newassoc(struct ieee80211_node *ni, int isnew) 2370178676Ssam{ 2371178676Ssam struct run_node *rn = (void *)ni; 2372178676Ssam struct ieee80211_rateset *rs = &ni->ni_rates; 2373198429Srpaulo struct ieee80211vap *vap = ni->ni_vap; 2374198429Srpaulo struct ieee80211com *ic = vap->iv_ic; 2375198429Srpaulo struct run_softc *sc = ic->ic_ifp->if_softc; 2376201209Srpaulo uint8_t rate; 2377201209Srpaulo uint8_t ridx; 2378198429Srpaulo uint8_t wcid; 2379198429Srpaulo int i, j; 2380178676Ssam 2381178676Ssam wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 2382178676Ssam 1 : RUN_AID2WCID(ni->ni_associd); 2383178676Ssam 2384198429Srpaulo if (wcid > RT2870_WCID_MAX) { 2385178676Ssam device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid); 2386178676Ssam return; 2387178676Ssam } 2388178676Ssam 2389178676Ssam /* only interested in true associations */ 2390220728Sbschmidt if (isnew && ni->ni_associd != 0) { 2391220689Sbschmidt 2392192468Ssam /* 2393178676Ssam * This function could is called though timeout function. 2394178676Ssam * Need to defer. 2395178676Ssam */ 2396201209Srpaulo uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store); 2397192468Ssam DPRINTF("cmdq_store=%d\n", cnt); 2398220723Sbschmidt sc->cmdq[cnt].func = run_newassoc_cb; 2399220723Sbschmidt sc->cmdq[cnt].arg0 = NULL; 2400220723Sbschmidt sc->cmdq[cnt].arg1 = ni; 2401201209Srpaulo sc->cmdq[cnt].wcid = wcid; 2402201209Srpaulo ieee80211_runtask(ic, &sc->cmdq_task); 2403201209Srpaulo } 2404201209Srpaulo 2405201209Srpaulo DPRINTF("new assoc isnew=%d associd=%x addr=%s\n", 2406201209Srpaulo isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr)); 2407201209Srpaulo 2408201209Srpaulo for (i = 0; i < rs->rs_nrates; i++) { 2409201209Srpaulo rate = rs->rs_rates[i] & IEEE80211_RATE_VAL; 2410201209Srpaulo /* convert 802.11 rate to hardware rate index */ 2411201209Srpaulo for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2412201209Srpaulo if (rt2860_rates[ridx].rate == rate) 2413201209Srpaulo break; 2414201209Srpaulo rn->ridx[i] = ridx; 2415201209Srpaulo /* determine rate of control response frames */ 2416201209Srpaulo for (j = i; j >= 0; j--) { 2417201209Srpaulo if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) && 2418201209Srpaulo rt2860_rates[rn->ridx[i]].phy == 2419178676Ssam rt2860_rates[rn->ridx[j]].phy) 2420178676Ssam break; 2421178676Ssam } 2422178676Ssam if (j >= 0) { 2423198429Srpaulo rn->ctl_ridx[i] = rn->ridx[j]; 2424178676Ssam } else { 2425221650Sbschmidt /* no basic rate found, use mandatory one */ 2426221650Sbschmidt rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx; 2427220726Sbschmidt } 2428198429Srpaulo DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n", 2429178676Ssam rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]); 2430178676Ssam } 2431220726Sbschmidt rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate; 2432178676Ssam for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2433178676Ssam if (rt2860_rates[ridx].rate == rate) 2434178676Ssam break; 2435178676Ssam rn->mgt_ridx = ridx; 2436201209Srpaulo DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx); 2437206477Sbschmidt 2438201209Srpaulo usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); 2439201209Srpaulo} 2440201209Srpaulo 2441221651Sbschmidt/* 2442221651Sbschmidt * Return the Rx chain with the highest RSSI for a given frame. 2443221651Sbschmidt */ 2444201209Srpaulostatic __inline uint8_t 2445201209Srpaulorun_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi) 2446221651Sbschmidt{ 2447221651Sbschmidt uint8_t rxchain = 0; 2448221651Sbschmidt 2449221651Sbschmidt if (sc->nrxchains > 1) { 2450201209Srpaulo if (rxwi->rssi[1] > rxwi->rssi[rxchain]) 2451220704Sbschmidt rxchain = 1; 2452220704Sbschmidt if (sc->nrxchains > 2) 2453221651Sbschmidt if (rxwi->rssi[2] > rxwi->rssi[rxchain]) 2454221651Sbschmidt rxchain = 2; 2455221651Sbschmidt } 2456221651Sbschmidt return (rxchain); 2457221651Sbschmidt} 2458221651Sbschmidt 2459221651Sbschmidtstatic void 2460221651Sbschmidtrun_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) 2461221651Sbschmidt{ 2462221651Sbschmidt struct ifnet *ifp = sc->sc_ifp; 2463221651Sbschmidt struct ieee80211com *ic = ifp->if_l2com; 2464221651Sbschmidt struct ieee80211_frame *wh; 2465221651Sbschmidt struct ieee80211_node *ni; 2466221651Sbschmidt struct rt2870_rxd *rxd; 2467221651Sbschmidt struct rt2860_rxwi *rxwi; 2468221651Sbschmidt uint32_t flags; 2469221651Sbschmidt uint16_t len, phy; 2470221651Sbschmidt uint8_t ant, rssi; 2471221651Sbschmidt int8_t nf; 2472221651Sbschmidt 2473221651Sbschmidt rxwi = mtod(m, struct rt2860_rxwi *); 2474221651Sbschmidt len = le16toh(rxwi->len) & 0xfff; 2475221651Sbschmidt if (__predict_false(len > dmalen)) { 2476221651Sbschmidt m_freem(m); 2477221651Sbschmidt ifp->if_ierrors++; 2478221651Sbschmidt DPRINTF("bad RXWI length %u > %u\n", len, dmalen); 2479221651Sbschmidt return; 2480221651Sbschmidt } 2481221651Sbschmidt /* Rx descriptor is located at the end */ 2482201209Srpaulo rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen); 2483201209Srpaulo flags = le32toh(rxd->flags); 2484198429Srpaulo 2485220674Sbschmidt if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) { 2486220674Sbschmidt m_freem(m); 2487220674Sbschmidt ifp->if_ierrors++; 2488220674Sbschmidt DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV"); 2489220674Sbschmidt return; 2490220674Sbschmidt } 2491220674Sbschmidt 2492220674Sbschmidt m->m_data += sizeof(struct rt2860_rxwi); 2493220674Sbschmidt m->m_pkthdr.len = m->m_len -= sizeof(struct rt2860_rxwi); 2494220674Sbschmidt 2495220674Sbschmidt wh = mtod(m, struct ieee80211_frame *); 2496220674Sbschmidt 2497220674Sbschmidt if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 2498220674Sbschmidt wh->i_fc[1] &= ~IEEE80211_FC1_WEP; 2499220674Sbschmidt m->m_flags |= M_WEP; 2500220674Sbschmidt } 2501220674Sbschmidt 2502220674Sbschmidt if (flags & RT2860_RX_L2PAD) { 2503220674Sbschmidt DPRINTFN(8, "received RT2860_RX_L2PAD frame\n"); 2504220867Sbschmidt len += 2; 2505220867Sbschmidt } 2506220867Sbschmidt 2507220674Sbschmidt ni = ieee80211_find_rxnode(ic, 2508220674Sbschmidt mtod(m, struct ieee80211_frame_min *)); 2509220674Sbschmidt 2510220674Sbschmidt if (__predict_false(flags & RT2860_RX_MICERR)) { 2511220674Sbschmidt /* report MIC failures to net80211 for TKIP */ 2512220674Sbschmidt if (ni != NULL) 2513220674Sbschmidt ieee80211_notify_michael_failure(ni->ni_vap, wh, rxwi->keyidx); 2514220674Sbschmidt m_freem(m); 2515220674Sbschmidt ifp->if_ierrors++; 2516220674Sbschmidt DPRINTF("MIC error. Someone is lying.\n"); 2517220674Sbschmidt return; 2518220674Sbschmidt } 2519220674Sbschmidt 2520220674Sbschmidt ant = run_maxrssi_chain(sc, rxwi); 2521220674Sbschmidt rssi = rxwi->rssi[ant]; 2522220674Sbschmidt nf = run_rssi2dbm(sc, rssi, ant); 2523220674Sbschmidt 2524220674Sbschmidt m->m_pkthdr.rcvif = ifp; 2525220674Sbschmidt m->m_pkthdr.len = m->m_len = len; 2526220674Sbschmidt 2527220674Sbschmidt if (ni != NULL) { 2528220674Sbschmidt (void)ieee80211_input(ni, m, rssi, nf); 2529220674Sbschmidt ieee80211_free_node(ni); 2530220674Sbschmidt } else { 2531220674Sbschmidt (void)ieee80211_input_all(ic, m, rssi, nf); 2532220674Sbschmidt } 2533220674Sbschmidt 2534220674Sbschmidt if (__predict_false(ieee80211_radiotap_active(ic))) { 2535220674Sbschmidt struct run_rx_radiotap_header *tap = &sc->sc_rxtap; 2536220674Sbschmidt 2537220674Sbschmidt tap->wr_flags = 0; 2538220674Sbschmidt tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); 2539220674Sbschmidt tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); 2540220674Sbschmidt tap->wr_antsignal = rssi; 2541220674Sbschmidt tap->wr_antenna = ant; 2542220674Sbschmidt tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant); 2543220674Sbschmidt tap->wr_rate = 2; /* in case it can't be found below */ 2544198429Srpaulo phy = le16toh(rxwi->phy); 2545198429Srpaulo switch (phy & RT2860_PHY_MODE) { 2546198429Srpaulo case RT2860_PHY_CCK: 2547206477Sbschmidt switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) { 2548198429Srpaulo case 0: tap->wr_rate = 2; break; 2549198429Srpaulo case 1: tap->wr_rate = 4; break; 2550198429Srpaulo case 2: tap->wr_rate = 11; break; 2551220728Sbschmidt case 3: tap->wr_rate = 22; break; 2552178676Ssam } 2553178676Ssam if (phy & RT2860_PHY_SHPRE) 2554178676Ssam tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 2555178676Ssam break; 2556178676Ssam case RT2860_PHY_OFDM: 2557198429Srpaulo switch (phy & RT2860_PHY_MCS) { 2558178676Ssam case 0: tap->wr_rate = 12; break; 2559220725Sbschmidt case 1: tap->wr_rate = 18; break; 2560178676Ssam case 2: tap->wr_rate = 24; break; 2561178676Ssam case 3: tap->wr_rate = 36; break; 2562178676Ssam case 4: tap->wr_rate = 48; break; 2563178676Ssam case 5: tap->wr_rate = 72; break; 2564202986Srpaulo case 6: tap->wr_rate = 96; break; 2565220724Sbschmidt case 7: tap->wr_rate = 108; break; 2566220724Sbschmidt } 2567220724Sbschmidt break; 2568220667Sbschmidt } 2569178676Ssam } 2570198429Srpaulo} 2571178676Ssam 2572198429Srpaulostatic void 2573178676Ssamrun_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) 2574220728Sbschmidt{ 2575178676Ssam struct run_softc *sc = usbd_xfer_softc(xfer); 2576178676Ssam struct ifnet *ifp = sc->sc_ifp; 2577178676Ssam struct mbuf *m = NULL; 2578220725Sbschmidt struct mbuf *m0; 2579198429Srpaulo uint32_t dmalen; 2580198429Srpaulo int xferlen; 2581178676Ssam 2582178676Ssam usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL); 2583178676Ssam 2584198429Srpaulo switch (USB_GET_STATE(xfer)) { 2585178676Ssam case USB_ST_TRANSFERRED: 2586178676Ssam 2587178676Ssam DPRINTFN(15, "rx done, actlen=%d\n", xferlen); 2588178676Ssam 2589198429Srpaulo if (xferlen < (int)(sizeof(uint32_t) + 2590198429Srpaulo sizeof(struct rt2860_rxwi) + sizeof(struct rt2870_rxd))) { 2591178676Ssam DPRINTF("xfer too short %d\n", xferlen); 2592178676Ssam goto tr_setup; 2593178676Ssam } 2594178676Ssam 2595178676Ssam m = sc->rx_m; 2596178676Ssam sc->rx_m = NULL; 2597198429Srpaulo 2598178676Ssam /* FALLTHROUGH */ 2599178676Ssam case USB_ST_SETUP: 2600178676Ssamtr_setup: 2601178676Ssam if (sc->rx_m == NULL) { 2602198429Srpaulo sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, 2603198429Srpaulo MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */); 2604198429Srpaulo } 2605198429Srpaulo if (sc->rx_m == NULL) { 2606206477Sbschmidt DPRINTF("could not allocate mbuf - idle with stall\n"); 2607198429Srpaulo ifp->if_ierrors++; 2608198429Srpaulo usbd_xfer_set_stall(xfer); 2609178676Ssam usbd_xfer_set_frames(xfer, 0); 2610198429Srpaulo } else { 2611221651Sbschmidt /* 2612221651Sbschmidt * Directly loading a mbuf cluster into DMA to 2613198429Srpaulo * save some data copying. This works because 2614221651Sbschmidt * there is only one cluster. 2615221651Sbschmidt */ 2616221651Sbschmidt usbd_xfer_set_frame_data(xfer, 0, 2617198429Srpaulo mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ); 2618198429Srpaulo usbd_xfer_set_frames(xfer, 1); 2619201209Srpaulo } 2620201209Srpaulo usbd_transfer_submit(xfer); 2621198429Srpaulo break; 2622201209Srpaulo 2623207001Sbschmidt default: /* Error */ 2624221651Sbschmidt if (error != USB_ERR_CANCELLED) { 2625221651Sbschmidt /* try to clear stall first */ 2626221651Sbschmidt usbd_xfer_set_stall(xfer); 2627221651Sbschmidt 2628221651Sbschmidt if (error == USB_ERR_TIMEOUT) 2629221651Sbschmidt device_printf(sc->sc_dev, "device timeout\n"); 2630221651Sbschmidt 2631198429Srpaulo ifp->if_ierrors++; 2632198429Srpaulo 2633206477Sbschmidt goto tr_setup; 2634198429Srpaulo } 2635198429Srpaulo if (sc->rx_m != NULL) { 2636198429Srpaulo m_freem(sc->rx_m); 2637198429Srpaulo sc->rx_m = NULL; 2638221651Sbschmidt } 2639221651Sbschmidt break; 2640198429Srpaulo } 2641221651Sbschmidt 2642221651Sbschmidt if (m == NULL) 2643221651Sbschmidt return; 2644198429Srpaulo 2645198429Srpaulo /* inputting all the frames must be last */ 2646201209Srpaulo 2647201209Srpaulo RUN_UNLOCK(sc); 2648198429Srpaulo 2649198429Srpaulo m->m_pkthdr.len = m->m_len = xferlen; 2650201209Srpaulo 2651198429Srpaulo /* HW can aggregate multiple 802.11 frames in a single USB xfer */ 2652198429Srpaulo for(;;) { 2653201209Srpaulo dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff; 2654202986Srpaulo 2655207001Sbschmidt if ((dmalen >= (uint32_t)-8) || (dmalen == 0) || 2656221651Sbschmidt ((dmalen & 3) != 0)) { 2657221651Sbschmidt DPRINTF("bad DMA length %u\n", dmalen); 2658221651Sbschmidt break; 2659221651Sbschmidt } 2660221651Sbschmidt if ((dmalen + 8) > (uint32_t)xferlen) { 2661221651Sbschmidt DPRINTF("bad DMA length %u > %d\n", 2662221651Sbschmidt dmalen + 8, xferlen); 2663198429Srpaulo break; 2664198429Srpaulo } 2665198429Srpaulo 2666198429Srpaulo /* If it is the last one or a single frame, we won't copy. */ 2667198429Srpaulo if ((xferlen -= dmalen + 8) <= 8) { 2668206477Sbschmidt /* trim 32-bit DMA-len header */ 2669201209Srpaulo m->m_data += 4; 2670198429Srpaulo m->m_pkthdr.len = m->m_len -= 4; 2671198429Srpaulo run_rx_frame(sc, m, dmalen); 2672178676Ssam break; 2673178676Ssam } 2674178676Ssam 2675178676Ssam /* copy aggregated frames to another mbuf */ 2676178676Ssam m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 2677206358Srpaulo if (__predict_false(m0 == NULL)) { 2678178676Ssam DPRINTF("could not allocate mbuf\n"); 2679178676Ssam ifp->if_ierrors++; 2680178676Ssam break; 2681198429Srpaulo } 2682201209Srpaulo m_copydata(m, 4 /* skip 32-bit DMA-len header */, 2683201209Srpaulo dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t)); 2684178676Ssam m0->m_pkthdr.len = m0->m_len = 2685178676Ssam dmalen + sizeof(struct rt2870_rxd); 2686206358Srpaulo run_rx_frame(sc, m0, dmalen); 2687178676Ssam 2688178676Ssam /* update data ptr */ 2689178676Ssam m->m_data += dmalen + 8; 2690178676Ssam m->m_pkthdr.len = m->m_len -= dmalen + 8; 2691178676Ssam } 2692178676Ssam 2693178676Ssam RUN_LOCK(sc); 2694178676Ssam} 2695178676Ssam 2696178676Ssamstatic void 2697178676Ssamrun_tx_free(struct run_endpoint_queue *pq, 2698178676Ssam struct run_tx_data *data, int txerr) 2699178676Ssam{ 2700178676Ssam if (data->m != NULL) { 2701178676Ssam if (data->m->m_flags & M_TXCB) 2702178676Ssam ieee80211_process_callback(data->ni, data->m, 2703178676Ssam txerr ? ETIMEDOUT : 0); 2704178676Ssam m_freem(data->m); 2705178676Ssam data->m = NULL; 2706178676Ssam 2707178676Ssam if (data->ni == NULL) { 2708178676Ssam DPRINTF("no node\n"); 2709178676Ssam } else { 2710201209Srpaulo ieee80211_free_node(data->ni); 2711201209Srpaulo data->ni = NULL; 2712201209Srpaulo } 2713201209Srpaulo } 2714220719Sbschmidt 2715201209Srpaulo STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); 2716206358Srpaulo pq->tx_nfree++; 2717206358Srpaulo} 2718201209Srpaulo 2719220719Sbschmidtstatic void 2720206358Srpaulorun_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, unsigned int index) 2721206358Srpaulo{ 2722201209Srpaulo struct run_softc *sc = usbd_xfer_softc(xfer); 2723178676Ssam struct ifnet *ifp = sc->sc_ifp; 2724178676Ssam struct ieee80211com *ic = ifp->if_l2com; 2725178676Ssam struct run_tx_data *data; 2726178676Ssam struct ieee80211vap *vap = NULL; 2727198429Srpaulo struct usb_page_cache *pc; 2728198429Srpaulo struct run_endpoint_queue *pq = &sc->sc_epq[index]; 2729198429Srpaulo struct mbuf *m; 2730198429Srpaulo usb_frlength_t size; 2731198429Srpaulo int actlen; 2732198429Srpaulo int sumlen; 2733198429Srpaulo 2734198429Srpaulo usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 2735178676Ssam 2736178676Ssam switch (USB_GET_STATE(xfer)) { 2737198429Srpaulo case USB_ST_TRANSFERRED: 2738198429Srpaulo DPRINTFN(11, "transfer complete: %d " 2739198429Srpaulo "bytes @ index %d\n", actlen, index); 2740198429Srpaulo 2741206477Sbschmidt data = usbd_xfer_get_priv(xfer); 2742198429Srpaulo 2743178676Ssam run_tx_free(pq, data, 0); 2744178676Ssam ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2745178676Ssam 2746178676Ssam usbd_xfer_set_priv(xfer, NULL); 2747178676Ssam 2748198429Srpaulo ifp->if_opackets++; 2749178676Ssam 2750178676Ssam /* FALLTHROUGH */ 2751178676Ssam case USB_ST_SETUP: 2752198429Srpaulotr_setup: 2753178676Ssam data = STAILQ_FIRST(&pq->tx_qh); 2754220704Sbschmidt if (data == NULL) 2755220704Sbschmidt break; 2756201209Srpaulo 2757178676Ssam STAILQ_REMOVE_HEAD(&pq->tx_qh, next); 2758178676Ssam 2759178676Ssam m = data->m; 2760198439Srpaulo if ((m->m_pkthdr.len + 2761178676Ssam sizeof(data->desc) + 3 + 8) > RUN_MAX_TXSZ) { 2762178676Ssam DPRINTF("data overflow, %u bytes\n", 2763221651Sbschmidt m->m_pkthdr.len); 2764221651Sbschmidt 2765221651Sbschmidt ifp->if_oerrors++; 2766221651Sbschmidt 2767221651Sbschmidt run_tx_free(pq, data, 1); 2768221651Sbschmidt 2769221651Sbschmidt goto tr_setup; 2770221651Sbschmidt } 2771221651Sbschmidt 2772221651Sbschmidt pc = usbd_xfer_get_frame(xfer, 0); 2773221651Sbschmidt size = sizeof(data->desc); 2774221651Sbschmidt usbd_copy_in(pc, 0, &data->desc, size); 2775221651Sbschmidt usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len); 2776221651Sbschmidt size += m->m_pkthdr.len; 2777221651Sbschmidt /* 2778221651Sbschmidt * Align end on a 4-byte boundary, pad 8 bytes (CRC + 2779221651Sbschmidt * 4-byte padding), and be sure to zero those trailing 2780221651Sbschmidt * bytes: 2781221651Sbschmidt */ 2782221651Sbschmidt usbd_frame_zero(pc, size, ((-size) & 3) + 8); 2783221651Sbschmidt size += ((-size) & 3) + 8; 2784221651Sbschmidt 2785221651Sbschmidt vap = data->ni->ni_vap; 2786221651Sbschmidt if (ieee80211_radiotap_active_vap(vap)) { 2787221651Sbschmidt struct run_tx_radiotap_header *tap = &sc->sc_txtap; 2788221651Sbschmidt struct rt2860_txwi *txwi = 2789221651Sbschmidt (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd)); 2790221651Sbschmidt 2791221651Sbschmidt tap->wt_flags = 0; 2792221651Sbschmidt tap->wt_rate = rt2860_rates[data->ridx].rate; 2793221651Sbschmidt tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 2794221651Sbschmidt tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 2795221651Sbschmidt tap->wt_hwqueue = index; 2796221651Sbschmidt if (le16toh(txwi->phy) & RT2860_PHY_SHPRE) 2797221651Sbschmidt tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 2798221651Sbschmidt 2799221651Sbschmidt ieee80211_radiotap_tx(vap, m); 2800221651Sbschmidt } 2801221651Sbschmidt 2802221651Sbschmidt DPRINTFN(11, "sending frame len=%u/%u @ index %d\n", 2803221651Sbschmidt m->m_pkthdr.len, size, index); 2804221651Sbschmidt 2805221651Sbschmidt usbd_xfer_set_frame_len(xfer, 0, size); 2806221651Sbschmidt usbd_xfer_set_priv(xfer, data); 2807221651Sbschmidt 2808221651Sbschmidt usbd_transfer_submit(xfer); 2809221651Sbschmidt 2810221651Sbschmidt RUN_UNLOCK(sc); 2811221651Sbschmidt run_start(ifp); 2812221651Sbschmidt RUN_LOCK(sc); 2813221651Sbschmidt 2814221651Sbschmidt break; 2815221651Sbschmidt 2816221651Sbschmidt default: 2817221651Sbschmidt DPRINTF("USB transfer error, %s\n", 2818221651Sbschmidt usbd_errstr(error)); 2819221651Sbschmidt 2820221651Sbschmidt data = usbd_xfer_get_priv(xfer); 2821221651Sbschmidt 2822221651Sbschmidt ifp->if_oerrors++; 2823221651Sbschmidt 2824221651Sbschmidt if (data != NULL) { 2825221651Sbschmidt if(data->ni != NULL) 2826221651Sbschmidt vap = data->ni->ni_vap; 2827221651Sbschmidt run_tx_free(pq, data, error); 2828221651Sbschmidt usbd_xfer_set_priv(xfer, NULL); 2829221651Sbschmidt } 2830221651Sbschmidt if (vap == NULL) 2831221651Sbschmidt vap = TAILQ_FIRST(&ic->ic_vaps); 2832221651Sbschmidt 2833221651Sbschmidt if (error != USB_ERR_CANCELLED) { 2834221651Sbschmidt if (error == USB_ERR_TIMEOUT) { 2835221651Sbschmidt device_printf(sc->sc_dev, "device timeout\n"); 2836221651Sbschmidt uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 2837221651Sbschmidt DPRINTF("cmdq_store=%d\n", i); 2838221651Sbschmidt sc->cmdq[i].func = run_usb_timeout_cb; 2839221651Sbschmidt sc->cmdq[i].arg0 = vap; 2840221651Sbschmidt ieee80211_runtask(ic, &sc->cmdq_task); 2841221651Sbschmidt } 2842221651Sbschmidt 2843221651Sbschmidt /* 2844221651Sbschmidt * Try to clear stall first, also if other 2845221651Sbschmidt * errors occur, hence clearing stall 2846221651Sbschmidt * introduces a 50 ms delay: 2847221651Sbschmidt */ 2848221651Sbschmidt usbd_xfer_set_stall(xfer); 2849221651Sbschmidt goto tr_setup; 2850221651Sbschmidt } 2851221651Sbschmidt break; 2852221651Sbschmidt } 2853198429Srpaulo} 2854198429Srpaulo 2855198429Srpaulostatic void 2856206477Sbschmidtrun_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error) 2857178676Ssam{ 2858178676Ssam run_bulk_tx_callbackN(xfer, error, 0); 2859220728Sbschmidt} 2860178676Ssam 2861178676Ssamstatic void 2862178676Ssamrun_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error) 2863178676Ssam{ 2864178676Ssam run_bulk_tx_callbackN(xfer, error, 1); 2865198429Srpaulo} 2866198429Srpaulo 2867198429Srpaulostatic void 2868198429Srpaulorun_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error) 2869178676Ssam{ 2870178676Ssam run_bulk_tx_callbackN(xfer, error, 2); 2871198429Srpaulo} 2872178676Ssam 2873201209Srpaulostatic void 2874201209Srpaulorun_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error) 2875198429Srpaulo{ 2876198429Srpaulo run_bulk_tx_callbackN(xfer, error, 3); 2877178676Ssam} 2878178676Ssam 2879198439Srpaulostatic void 2880178676Ssamrun_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error) 2881178676Ssam{ 2882178676Ssam run_bulk_tx_callbackN(xfer, error, 4); 2883198429Srpaulo} 2884198429Srpaulo 2885178676Ssamstatic void 2886178676Ssamrun_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error) 2887198429Srpaulo{ 2888198429Srpaulo run_bulk_tx_callbackN(xfer, error, 5); 2889178676Ssam} 2890178676Ssam 2891198429Srpaulostatic void 2892198429Srpaulorun_set_tx_desc(struct run_softc *sc, struct run_tx_data *data) 2893198429Srpaulo{ 2894198429Srpaulo struct mbuf *m = data->m; 2895178676Ssam struct ieee80211com *ic = sc->sc_ifp->if_l2com; 2896178676Ssam struct ieee80211vap *vap = data->ni->ni_vap; 2897201209Srpaulo struct ieee80211_frame *wh; 2898201209Srpaulo struct rt2870_txd *txd; 2899201209Srpaulo struct rt2860_txwi *txwi; 2900201209Srpaulo uint16_t xferlen; 2901201209Srpaulo uint16_t mcs; 2902178676Ssam uint8_t ridx = data->ridx; 2903198429Srpaulo uint8_t pad; 2904220728Sbschmidt 2905178676Ssam /* get MCS code from rate index */ 2906178676Ssam mcs = rt2860_rates[ridx].mcs; 2907178676Ssam 2908178676Ssam xferlen = sizeof(*txwi) + m->m_pkthdr.len; 2909198429Srpaulo 2910178676Ssam /* roundup to 32-bit alignment */ 2911178676Ssam xferlen = (xferlen + 3) & ~3; 2912198429Srpaulo 2913198429Srpaulo txd = (struct rt2870_txd *)&data->desc; 2914178676Ssam txd->len = htole16(xferlen); 2915178676Ssam 2916202986Srpaulo wh = mtod(m, struct ieee80211_frame *); 2917178676Ssam 2918201209Srpaulo /* 2919201209Srpaulo * Ether both are true or both are false, the header 2920202986Srpaulo * are nicely aligned to 32-bit. So, no L2 padding. 2921201209Srpaulo */ 2922178676Ssam if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh)) 2923178676Ssam pad = 0; 2924178676Ssam else 2925178676Ssam pad = 2; 2926178676Ssam 2927178676Ssam /* setup TX Wireless Information */ 2928178676Ssam txwi = (struct rt2860_txwi *)(txd + 1); 2929220660Sbschmidt txwi->len = htole16(m->m_pkthdr.len - pad); 2930220660Sbschmidt if (rt2860_rates[ridx].phy == IEEE80211_T_DS) { 2931220660Sbschmidt txwi->phy = htole16(RT2860_PHY_CCK); 2932220660Sbschmidt if (ridx != RT2860_RIDX_CCK1 && 2933220660Sbschmidt (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 2934220660Sbschmidt mcs |= RT2860_PHY_SHPRE; 2935220660Sbschmidt } else 2936220660Sbschmidt txwi->phy = htole16(RT2860_PHY_OFDM); 2937220660Sbschmidt txwi->phy |= htole16(mcs); 2938201209Srpaulo 2939178676Ssam /* check if RTS/CTS or CTS-to-self protection is required */ 2940178676Ssam if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 2941198429Srpaulo (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold || 2942198429Srpaulo ((ic->ic_flags & IEEE80211_F_USEPROT) && 2943178676Ssam rt2860_rates[ridx].phy == IEEE80211_T_OFDM))) 2944178676Ssam txwi->txop |= RT2860_TX_TXOP_HT; 2945178676Ssam else 2946198429Srpaulo txwi->txop |= RT2860_TX_TXOP_BACKOFF; 2947201209Srpaulo 2948201209Srpaulo if (vap->iv_opmode != IEEE80211_M_STA && !IEEE80211_QOS_HAS_SEQ(wh)) 2949178676Ssam txwi->xflags |= RT2860_TX_NSEQ; 2950178676Ssam} 2951178676Ssam 2952178676Ssam/* This function must be called locked */ 2953178676Ssamstatic int 2954178676Ssamrun_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) 2955178676Ssam{ 2956198429Srpaulo struct ieee80211com *ic = sc->sc_ifp->if_l2com; 2957178676Ssam struct ieee80211vap *vap = ni->ni_vap; 2958178676Ssam struct ieee80211_frame *wh; 2959178676Ssam struct ieee80211_channel *chan; 2960201209Srpaulo const struct ieee80211_txparam *tp; 2961178676Ssam struct run_node *rn = (void *)ni; 2962178676Ssam struct run_tx_data *data; 2963198429Srpaulo struct rt2870_txd *txd; 2964198429Srpaulo struct rt2860_txwi *txwi; 2965178676Ssam uint16_t qos; 2966178676Ssam uint16_t dur; 2967198429Srpaulo uint16_t qid; 2968198429Srpaulo uint8_t type; 2969178676Ssam uint8_t tid; 2970178676Ssam uint8_t ridx; 2971178676Ssam uint8_t ctl_ridx; 2972178676Ssam uint8_t qflags; 2973178676Ssam uint8_t xflags = 0; 2974178676Ssam int hasqos; 2975178676Ssam 2976201209Srpaulo RUN_LOCK_ASSERT(sc, MA_OWNED); 2977201209Srpaulo 2978178676Ssam wh = mtod(m, struct ieee80211_frame *); 2979178676Ssam 2980178676Ssam type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 2981178676Ssam 2982198429Srpaulo /* 2983198429Srpaulo * There are 7 bulk endpoints: 1 for RX 2984178676Ssam * and 6 for TX (4 EDCAs + HCCA + Prio). 2985178676Ssam * Update 03-14-2009: some devices like the Planex GW-US300MiniS 2986178676Ssam * seem to have only 4 TX bulk endpoints (Fukaumi Naoki). 2987201209Srpaulo */ 2988201209Srpaulo if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) { 2989178676Ssam uint8_t *frm; 2990178676Ssam 2991178676Ssam if(IEEE80211_HAS_ADDR4(wh)) 2992178676Ssam frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos; 2993178676Ssam else 2994198429Srpaulo frm =((struct ieee80211_qosframe *)wh)->i_qos; 2995198429Srpaulo 2996178676Ssam qos = le16toh(*(const uint16_t *)frm); 2997178676Ssam tid = qos & IEEE80211_QOS_TID; 2998178676Ssam qid = TID_TO_WME_AC(tid); 2999201209Srpaulo } else { 3000201209Srpaulo qos = 0; 3001178676Ssam tid = 0; 3002178676Ssam qid = WME_AC_BE; 3003178676Ssam } 3004178676Ssam qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA; 3005201209Srpaulo 3006191746Sthompsa DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n", 3007201209Srpaulo qos, qid, tid, qflags); 3008178676Ssam 3009178676Ssam chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan; 3010198429Srpaulo tp = &vap->iv_txparms[ieee80211_chan2mode(chan)]; 3011220674Sbschmidt 3012198429Srpaulo /* pickup a rate index */ 3013198429Srpaulo if (IEEE80211_IS_MULTICAST(wh->i_addr1) || 3014198429Srpaulo type != IEEE80211_FC0_TYPE_DATA) { 3015201209Srpaulo ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? 3016198429Srpaulo RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; 3017198429Srpaulo ctl_ridx = rt2860_rates[ridx].ctl_ridx; 3018178676Ssam } else { 3019198429Srpaulo if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) 3020178676Ssam ridx = rn->fix_ridx; 3021178676Ssam else 3022178676Ssam ridx = rn->amrr_ridx; 3023198429Srpaulo ctl_ridx = rt2860_rates[ridx].ctl_ridx; 3024178676Ssam } 3025198429Srpaulo 3026178676Ssam if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 3027178676Ssam (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) != 3028198429Srpaulo IEEE80211_QOS_ACKPOLICY_NOACK)) { 3029198429Srpaulo xflags |= RT2860_TX_ACK; 3030198429Srpaulo if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 3031198429Srpaulo dur = rt2860_rates[ctl_ridx].sp_ack_dur; 3032206477Sbschmidt else 3033198429Srpaulo dur = rt2860_rates[ctl_ridx].lp_ack_dur; 3034198429Srpaulo *(uint16_t *)wh->i_dur = htole16(dur); 3035198429Srpaulo } 3036198429Srpaulo 3037198429Srpaulo /* reserve slots for mgmt packets, just in case */ 3038198429Srpaulo if (sc->sc_epq[qid].tx_nfree < 3) { 3039198429Srpaulo DPRINTFN(10, "tx ring %d is full\n", qid); 3040198429Srpaulo return (-1); 3041198429Srpaulo } 3042220728Sbschmidt 3043198429Srpaulo data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh); 3044198429Srpaulo STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next); 3045198429Srpaulo sc->sc_epq[qid].tx_nfree--; 3046198429Srpaulo 3047198429Srpaulo txd = (struct rt2870_txd *)&data->desc; 3048206477Sbschmidt txd->flags = qflags; 3049191746Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 3050191746Sthompsa txwi->xflags = xflags; 3051191746Sthompsa if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 3052191746Sthompsa txwi->wcid = 0; 3053198429Srpaulo } else { 3054191746Sthompsa txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 3055191746Sthompsa 1 : RUN_AID2WCID(ni->ni_associd); 3056191746Sthompsa } 3057191746Sthompsa /* clear leftover garbage bits */ 3058198429Srpaulo txwi->flags = 0; 3059198429Srpaulo txwi->txop = 0; 3060191746Sthompsa 3061191746Sthompsa data->m = m; 3062191746Sthompsa data->ni = ni; 3063191746Sthompsa data->ridx = ridx; 3064191746Sthompsa 3065198429Srpaulo run_set_tx_desc(sc, data); 3066198429Srpaulo 3067198429Srpaulo /* 3068198429Srpaulo * The chip keeps track of 2 kind of Tx stats, 3069198429Srpaulo * * TX_STAT_FIFO, for per WCID stats, and 3070206477Sbschmidt * * TX_STA_CNT0 for all-TX-in-one stats. 3071201209Srpaulo * 3072191746Sthompsa * To use FIFO stats, we need to store MCS into the driver-private 3073198429Srpaulo * PacketID field. So that, we can tell whose stats when we read them. 3074198429Srpaulo * We add 1 to the MCS because setting the PacketID field to 0 means 3075191746Sthompsa * that we don't want feedback in TX_STAT_FIFO. 3076191746Sthompsa * And, that's what we want for STA mode, since TX_STA_CNT0 does the job. 3077191746Sthompsa * 3078201209Srpaulo * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx(). 3079201209Srpaulo */ 3080201209Srpaulo if (sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP || 3081198429Srpaulo vap->iv_opmode == IEEE80211_M_MBSS) { 3082198429Srpaulo uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf; 3083198429Srpaulo txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT); 3084220728Sbschmidt 3085220726Sbschmidt /* 3086220726Sbschmidt * Unlike PCI based devices, we don't get any interrupt from 3087198429Srpaulo * USB devices, so we simulate FIFO-is-full interrupt here. 3088198429Srpaulo * Ralink recomends to drain FIFO stats every 100 ms, but 16 slots 3089198429Srpaulo * quickly get fulled. To prevent overflow, increment a counter on 3090220726Sbschmidt * every FIFO stat request, so we know how many slots are left. 3091198429Srpaulo * We do this only in HOSTAP or multiple vap mode since FIFO stats 3092198429Srpaulo * are used only in those modes. 3093198429Srpaulo * We just drain stats. AMRR gets updated every 1 sec by 3094198429Srpaulo * run_ratectl_cb() via callout. 3095198429Srpaulo * Call it early. Otherwise overflow. 3096198429Srpaulo */ 3097198429Srpaulo if (sc->fifo_cnt++ == 10) { 3098198429Srpaulo /* 3099220726Sbschmidt * With multiple vaps or if_bridge, if_start() is called 3100198429Srpaulo * with a non-sleepable lock, tcpinp. So, need to defer. 3101198429Srpaulo */ 3102198429Srpaulo uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); 3103198429Srpaulo DPRINTFN(6, "cmdq_store=%d\n", i); 3104198429Srpaulo sc->cmdq[i].func = run_drain_fifo; 3105198429Srpaulo sc->cmdq[i].arg0 = sc; 3106198429Srpaulo ieee80211_runtask(ic, &sc->cmdq_task); 3107198429Srpaulo } 3108198429Srpaulo } 3109198429Srpaulo 3110198429Srpaulo STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next); 3111198429Srpaulo 3112198429Srpaulo usbd_transfer_start(sc->sc_xfer[qid]); 3113198429Srpaulo 3114198429Srpaulo DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n", m->m_pkthdr.len + 3115198429Srpaulo (int)(sizeof (struct rt2870_txd) + sizeof (struct rt2860_rxwi)), 3116198429Srpaulo rt2860_rates[ridx].rate, qid); 3117198429Srpaulo 3118198429Srpaulo return (0); 3119220728Sbschmidt} 3120198429Srpaulo 3121198429Srpaulostatic int 3122198429Srpaulorun_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) 3123198429Srpaulo{ 3124198429Srpaulo struct ifnet *ifp = sc->sc_ifp; 3125191746Sthompsa struct ieee80211com *ic = ifp->if_l2com; 3126191746Sthompsa struct run_node *rn = (void *)ni; 3127206477Sbschmidt struct run_tx_data *data; 3128178676Ssam struct ieee80211_frame *wh; 3129178676Ssam struct rt2870_txd *txd; 3130178676Ssam struct rt2860_txwi *txwi; 3131198429Srpaulo uint16_t dur; 3132201209Srpaulo uint8_t ridx = rn->mgt_ridx; 3133178676Ssam uint8_t type; 3134178676Ssam uint8_t xflags = 0; 3135178676Ssam uint8_t wflags = 0; 3136198429Srpaulo 3137201209Srpaulo RUN_LOCK_ASSERT(sc, MA_OWNED); 3138178676Ssam 3139201209Srpaulo wh = mtod(m, struct ieee80211_frame *); 3140201209Srpaulo 3141201209Srpaulo type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3142201209Srpaulo 3143201209Srpaulo /* tell hardware to add timestamp for probe responses */ 3144201209Srpaulo if ((wh->i_fc[0] & 3145201209Srpaulo (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == 3146201209Srpaulo (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) 3147201209Srpaulo wflags |= RT2860_TX_TS; 3148206444Sbschmidt else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 3149206444Sbschmidt xflags |= RT2860_TX_ACK; 3150206444Sbschmidt 3151206444Sbschmidt dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate, 3152201209Srpaulo ic->ic_flags & IEEE80211_F_SHPREAMBLE); 3153201209Srpaulo *(uint16_t *)wh->i_dur = htole16(dur); 3154201209Srpaulo } 3155201209Srpaulo 3156201209Srpaulo if (sc->sc_epq[0].tx_nfree == 0) { 3157201209Srpaulo /* let caller free mbuf */ 3158201209Srpaulo ifp->if_drv_flags |= IFF_DRV_OACTIVE; 3159201209Srpaulo return (EIO); 3160178676Ssam } 3161198429Srpaulo data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3162198429Srpaulo STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3163201209Srpaulo sc->sc_epq[0].tx_nfree--; 3164198429Srpaulo 3165178676Ssam txd = (struct rt2870_txd *)&data->desc; 3166198429Srpaulo txd->flags = RT2860_TX_QSEL_EDCA; 3167198429Srpaulo txwi = (struct rt2860_txwi *)(txd + 1); 3168201209Srpaulo txwi->wcid = 0xff; 3169201209Srpaulo txwi->flags = wflags; 3170178676Ssam txwi->xflags = xflags; 3171198429Srpaulo txwi->txop = 0; /* clear leftover garbage bits */ 3172191746Sthompsa 3173201209Srpaulo data->m = m; 3174198429Srpaulo data->ni = ni; 3175198429Srpaulo data->ridx = ridx; 3176198429Srpaulo 3177198429Srpaulo run_set_tx_desc(sc, data); 3178198429Srpaulo 3179198429Srpaulo DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len + 3180220724Sbschmidt (int)(sizeof (struct rt2870_txd) + sizeof (struct rt2860_rxwi)), 3181220724Sbschmidt rt2860_rates[ridx].rate); 3182220725Sbschmidt 3183201209Srpaulo STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3184201209Srpaulo 3185201209Srpaulo usbd_transfer_start(sc->sc_xfer[0]); 3186178676Ssam 3187178676Ssam return (0); 3188201209Srpaulo} 3189201209Srpaulo 3190201209Srpaulostatic int 3191201209Srpaulorun_sendprot(struct run_softc *sc, 3192201209Srpaulo const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) 3193201209Srpaulo{ 3194201209Srpaulo struct ieee80211com *ic = ni->ni_ic; 3195201209Srpaulo struct ieee80211_frame *wh; 3196201209Srpaulo struct run_tx_data *data; 3197201209Srpaulo struct rt2870_txd *txd; 3198201209Srpaulo struct rt2860_txwi *txwi; 3199201209Srpaulo struct mbuf *mprot; 3200201209Srpaulo int ridx; 3201201209Srpaulo int protrate; 3202201209Srpaulo int ackrate; 3203178676Ssam int pktlen; 3204201209Srpaulo int isshort; 3205201209Srpaulo uint16_t dur; 3206201209Srpaulo uint8_t type; 3207198429Srpaulo uint8_t wflags = 0; 3208201209Srpaulo uint8_t xflags = 0; 3209198429Srpaulo 3210198429Srpaulo RUN_LOCK_ASSERT(sc, MA_OWNED); 3211198429Srpaulo 3212198429Srpaulo KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, 3213198429Srpaulo ("protection %d", prot)); 3214198429Srpaulo 3215198429Srpaulo wh = mtod(m, struct ieee80211_frame *); 3216201209Srpaulo pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; 3217198429Srpaulo type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3218201209Srpaulo 3219201209Srpaulo protrate = ieee80211_ctl_rate(ic->ic_rt, rate); 3220198429Srpaulo ackrate = ieee80211_ack_rate(ic->ic_rt, rate); 3221178676Ssam 3222178676Ssam isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; 3223178676Ssam dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort) 3224198429Srpaulo + ieee80211_ack_duration(ic->ic_rt, rate, isshort); 3225198429Srpaulo wflags = RT2860_TX_FRAG; 3226220725Sbschmidt 3227198429Srpaulo /* check that there are free slots before allocating the mbuf */ 3228206477Sbschmidt if (sc->sc_epq[0].tx_nfree == 0) { 3229198429Srpaulo /* let caller free mbuf */ 3230198429Srpaulo sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 3231178676Ssam return (ENOBUFS); 3232198429Srpaulo } 3233178676Ssam 3234198429Srpaulo if (prot == IEEE80211_PROT_RTSCTS) { 3235198439Srpaulo /* NB: CTS is the same size as an ACK */ 3236198439Srpaulo dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); 3237201209Srpaulo xflags |= RT2860_TX_ACK; 3238198429Srpaulo mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); 3239198439Srpaulo } else { 3240198439Srpaulo mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); 3241198439Srpaulo } 3242198429Srpaulo if (mprot == NULL) { 3243198429Srpaulo sc->sc_ifp->if_oerrors++; 3244206477Sbschmidt DPRINTF("could not allocate mbuf\n"); 3245198429Srpaulo return (ENOBUFS); 3246198429Srpaulo } 3247198429Srpaulo 3248198429Srpaulo data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3249198429Srpaulo STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3250198429Srpaulo sc->sc_epq[0].tx_nfree--; 3251198439Srpaulo 3252198439Srpaulo txd = (struct rt2870_txd *)&data->desc; 3253198439Srpaulo txd->flags = RT2860_TX_QSEL_EDCA; 3254198429Srpaulo txwi = (struct rt2860_txwi *)(txd + 1); 3255198439Srpaulo txwi->wcid = 0xff; 3256198439Srpaulo txwi->flags = wflags; 3257198439Srpaulo txwi->xflags = xflags; 3258198429Srpaulo txwi->txop = 0; /* clear leftover garbage bits */ 3259198429Srpaulo 3260206475Sbschmidt data->m = mprot; 3261206477Sbschmidt data->ni = ieee80211_ref_node(ni); 3262198429Srpaulo 3263198429Srpaulo for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 3264198429Srpaulo if (rt2860_rates[ridx].rate == protrate) 3265198429Srpaulo break; 3266198429Srpaulo data->ridx = ridx; 3267198439Srpaulo 3268198439Srpaulo run_set_tx_desc(sc, data); 3269198439Srpaulo 3270198429Srpaulo DPRINTFN(1, "sending prot len=%u rate=%u\n", 3271198439Srpaulo m->m_pkthdr.len, rate); 3272206443Sbschmidt 3273198439Srpaulo STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3274198429Srpaulo 3275206475Sbschmidt usbd_transfer_start(sc->sc_xfer[0]); 3276198429Srpaulo 3277206477Sbschmidt return (0); 3278220720Sbschmidt} 3279178676Ssam 3280221651Sbschmidtstatic int 3281198429Srpaulorun_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, 3282178676Ssam const struct ieee80211_bpf_params *params) 3283178676Ssam{ 3284198429Srpaulo struct ieee80211com *ic = ni->ni_ic; 3285220720Sbschmidt struct ieee80211_frame *wh; 3286178676Ssam struct run_tx_data *data; 3287178676Ssam struct rt2870_txd *txd; 3288178676Ssam struct rt2860_txwi *txwi; 3289178676Ssam uint8_t type; 3290178676Ssam uint8_t ridx; 3291198429Srpaulo uint8_t rate; 3292220700Sbschmidt uint8_t opflags = 0; 3293178676Ssam uint8_t xflags = 0; 3294220720Sbschmidt int error; 3295178676Ssam 3296220723Sbschmidt RUN_LOCK_ASSERT(sc, MA_OWNED); 3297220723Sbschmidt 3298220720Sbschmidt KASSERT(params != NULL, ("no raw xmit params")); 3299178676Ssam 3300178676Ssam wh = mtod(m, struct ieee80211_frame *); 3301178676Ssam type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 3302198429Srpaulo 3303198429Srpaulo rate = params->ibp_rate0; 3304178676Ssam if (!ieee80211_isratevalid(ic->ic_rt, rate)) { 3305178676Ssam /* let caller free mbuf */ 3306220720Sbschmidt return (EINVAL); 3307220720Sbschmidt } 3308220720Sbschmidt 3309220720Sbschmidt if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) 3310220720Sbschmidt xflags |= RT2860_TX_ACK; 3311220720Sbschmidt if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { 3312220720Sbschmidt error = run_sendprot(sc, m, ni, 3313220720Sbschmidt params->ibp_flags & IEEE80211_BPF_RTS ? 3314220720Sbschmidt IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, 3315220720Sbschmidt rate); 3316221651Sbschmidt if (error) { 3317221651Sbschmidt /* let caller free mbuf */ 3318221651Sbschmidt return error; 3319221651Sbschmidt } 3320221651Sbschmidt opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS; 3321221651Sbschmidt } 3322221651Sbschmidt 3323221651Sbschmidt if (sc->sc_epq[0].tx_nfree == 0) { 3324221651Sbschmidt /* let caller free mbuf */ 3325221651Sbschmidt sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 3326198429Srpaulo DPRINTF("sending raw frame, but tx ring is full\n"); 3327198429Srpaulo return (EIO); 3328198429Srpaulo } 3329198429Srpaulo data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 3330201209Srpaulo STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 3331178676Ssam sc->sc_epq[0].tx_nfree--; 3332178676Ssam 3333198429Srpaulo txd = (struct rt2870_txd *)&data->desc; 3334178676Ssam txd->flags = RT2860_TX_QSEL_EDCA; 3335178676Ssam txwi = (struct rt2860_txwi *)(txd + 1); 3336178676Ssam txwi->wcid = 0xff; 3337178676Ssam txwi->xflags = xflags; 3338206358Srpaulo txwi->txop = opflags; 3339206358Srpaulo txwi->flags = 0; /* clear leftover garbage bits */ 3340178676Ssam 3341178676Ssam data->m = m; 3342221648Sbschmidt data->ni = ni; 3343178676Ssam for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 3344198429Srpaulo if (rt2860_rates[ridx].rate == rate) 3345178676Ssam break; 3346220725Sbschmidt data->ridx = ridx; 3347198429Srpaulo 3348178676Ssam run_set_tx_desc(sc, data); 3349198429Srpaulo 3350178676Ssam DPRINTFN(10, "sending raw frame len=%u rate=%u\n", 3351178676Ssam m->m_pkthdr.len, rate); 3352220725Sbschmidt 3353198429Srpaulo STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 3354198429Srpaulo 3355198429Srpaulo usbd_transfer_start(sc->sc_xfer[0]); 3356178676Ssam 3357192468Ssam return (0); 3358178676Ssam} 3359178676Ssam 3360178676Ssamstatic int 3361221648Sbschmidtrun_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 3362178676Ssam const struct ieee80211_bpf_params *params) 3363178676Ssam{ 3364178676Ssam struct ifnet *ifp = ni->ni_ic->ic_ifp; 3365198429Srpaulo struct run_softc *sc = ifp->if_softc; 3366178676Ssam int error = 0; 3367178676Ssam 3368198429Srpaulo RUN_LOCK(sc); 3369198429Srpaulo 3370198429Srpaulo /* prevent management frames from being sent if we're not ready */ 3371198429Srpaulo if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 3372198429Srpaulo error = ENETDOWN; 3373198429Srpaulo goto done; 3374198429Srpaulo } 3375198429Srpaulo 3376198429Srpaulo if (params == NULL) { 3377198429Srpaulo /* tx mgt packet */ 3378198429Srpaulo if ((error = run_tx_mgt(sc, m, ni)) != 0) { 3379198429Srpaulo ifp->if_oerrors++; 3380220720Sbschmidt DPRINTF("mgt tx failed\n"); 3381220720Sbschmidt goto done; 3382220720Sbschmidt } 3383220720Sbschmidt } else { 3384220720Sbschmidt /* tx raw packet with param */ 3385220720Sbschmidt if ((error = run_tx_param(sc, m, ni, params)) != 0) { 3386198429Srpaulo ifp->if_oerrors++; 3387198429Srpaulo DPRINTF("tx with param failed\n"); 3388198429Srpaulo goto done; 3389198429Srpaulo } 3390178676Ssam } 3391198429Srpaulo 3392198429Srpaulo ifp->if_opackets++; 3393178676Ssam 3394198429Srpaulodone: 3395198429Srpaulo RUN_UNLOCK(sc); 3396198429Srpaulo 3397198429Srpaulo if (error != 0) { 3398198429Srpaulo if(m != NULL) 3399178676Ssam m_freem(m); 3400201209Srpaulo ieee80211_free_node(ni); 3401178676Ssam } 3402198429Srpaulo 3403178676Ssam return (error); 3404198429Srpaulo} 3405178676Ssam 3406198429Srpaulostatic void 3407198429Srpaulorun_start(struct ifnet *ifp) 3408198429Srpaulo{ 3409198429Srpaulo struct run_softc *sc = ifp->if_softc; 3410198429Srpaulo struct ieee80211_node *ni; 3411198429Srpaulo struct mbuf *m; 3412198429Srpaulo 3413198429Srpaulo RUN_LOCK(sc); 3414201209Srpaulo 3415178676Ssam if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 3416198429Srpaulo RUN_UNLOCK(sc); 3417198429Srpaulo return; 3418220728Sbschmidt } 3419198429Srpaulo 3420198429Srpaulo for (;;) { 3421198429Srpaulo /* send data frames */ 3422178676Ssam IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 3423178676Ssam if (m == NULL) 3424178676Ssam break; 3425198429Srpaulo 3426178676Ssam ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 3427178676Ssam if (run_tx(sc, m, ni) != 0) { 3428178676Ssam IFQ_DRV_PREPEND(&ifp->if_snd, m); 3429178676Ssam ifp->if_drv_flags |= IFF_DRV_OACTIVE; 3430198429Srpaulo break; 3431178676Ssam } 3432198429Srpaulo } 3433178676Ssam 3434198429Srpaulo RUN_UNLOCK(sc); 3435178676Ssam} 3436178676Ssam 3437201209Srpaulostatic int 3438178676Ssamrun_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 3439178676Ssam{ 3440178676Ssam struct run_softc *sc = ifp->if_softc; 3441178676Ssam struct ieee80211com *ic = sc->sc_ifp->if_l2com; 3442178676Ssam struct ifreq *ifr = (struct ifreq *) data; 3443198429Srpaulo int startall = 0; 3444220720Sbschmidt int error = 0; 3445201209Srpaulo 3446201209Srpaulo switch (cmd) { 3447178676Ssam case SIOCSIFFLAGS: 3448221648Sbschmidt RUN_LOCK(sc); 3449220728Sbschmidt if (ifp->if_flags & IFF_UP) { 3450201209Srpaulo if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)){ 3451201209Srpaulo startall = 1; 3452198429Srpaulo run_init_locked(sc); 3453201209Srpaulo } else 3454221648Sbschmidt run_update_promisc_locked(ifp); 3455201209Srpaulo } else { 3456220715Sbschmidt if (ifp->if_drv_flags & IFF_DRV_RUNNING && 3457201209Srpaulo (ic->ic_nrunning == 0 || sc->rvp_cnt <= 1)) { 3458201209Srpaulo run_stop(sc); 3459198429Srpaulo } 3460201209Srpaulo } 3461201209Srpaulo RUN_UNLOCK(sc); 3462178676Ssam if (startall) 3463198429Srpaulo ieee80211_start_all(ic); 3464178676Ssam break; 3465178676Ssam case SIOCGIFMEDIA: 3466198429Srpaulo error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); 3467198429Srpaulo break; 3468198429Srpaulo case SIOCGIFADDR: 3469198429Srpaulo error = ether_ioctl(ifp, cmd, data); 3470198429Srpaulo break; 3471220700Sbschmidt default: 3472220700Sbschmidt error = EINVAL; 3473220700Sbschmidt break; 3474220700Sbschmidt } 3475220700Sbschmidt 3476220700Sbschmidt return (error); 3477220700Sbschmidt} 3478220700Sbschmidt 3479178676Ssamstatic void 3480220700Sbschmidtrun_set_agc(struct run_softc *sc, uint8_t agc) 3481220700Sbschmidt{ 3482220700Sbschmidt uint8_t bbp; 3483220700Sbschmidt 3484220700Sbschmidt if (sc->mac_ver == 0x3572) { 3485220700Sbschmidt run_bbp_read(sc, 27, &bbp); 3486220700Sbschmidt bbp &= ~(0x3 << 5); 3487220700Sbschmidt run_bbp_write(sc, 27, bbp | 0 << 5); /* select Rx0 */ 3488220700Sbschmidt run_bbp_write(sc, 66, agc); 3489220700Sbschmidt run_bbp_write(sc, 27, bbp | 1 << 5); /* select Rx1 */ 3490220700Sbschmidt run_bbp_write(sc, 66, agc); 3491220700Sbschmidt } else 3492178676Ssam run_bbp_write(sc, 66, agc); 3493178676Ssam} 3494220700Sbschmidt 3495198429Srpaulostatic void 3496178676Ssamrun_select_chan_group(struct run_softc *sc, int group) 3497178676Ssam{ 3498178676Ssam uint32_t tmp; 3499178676Ssam uint8_t agc; 3500198429Srpaulo 3501178676Ssam run_bbp_write(sc, 62, 0x37 - sc->lna[group]); 3502178676Ssam run_bbp_write(sc, 63, 0x37 - sc->lna[group]); 3503178676Ssam run_bbp_write(sc, 64, 0x37 - sc->lna[group]); 3504198429Srpaulo run_bbp_write(sc, 86, 0x00); 3505178676Ssam 3506198429Srpaulo if (group == 0) { 3507220700Sbschmidt if (sc->ext_2ghz_lna) { 3508220700Sbschmidt run_bbp_write(sc, 82, 0x62); 3509220700Sbschmidt run_bbp_write(sc, 75, 0x46); 3510198429Srpaulo } else { 3511201209Srpaulo run_bbp_write(sc, 82, 0x84); 3512201209Srpaulo run_bbp_write(sc, 75, 0x50); 3513198429Srpaulo } 3514198429Srpaulo } else { 3515220700Sbschmidt if (sc->mac_ver == 0x3572) 3516178676Ssam run_bbp_write(sc, 82, 0x94); 3517220700Sbschmidt else 3518220700Sbschmidt run_bbp_write(sc, 82, 0xf2); 3519220700Sbschmidt if (sc->ext_5ghz_lna) 3520220700Sbschmidt run_bbp_write(sc, 75, 0x46); 3521178676Ssam else 3522178676Ssam run_bbp_write(sc, 75, 0x50); 3523201209Srpaulo } 3524201209Srpaulo 3525198429Srpaulo run_read(sc, RT2860_TX_BAND_CFG, &tmp); 3526198429Srpaulo tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P); 3527198429Srpaulo tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P; 3528178676Ssam run_write(sc, RT2860_TX_BAND_CFG, tmp); 3529198429Srpaulo 3530220728Sbschmidt /* enable appropriate Power Amplifiers and Low Noise Amplifiers */ 3531178676Ssam tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN; 3532198429Srpaulo if (sc->nrxchains > 1) 3533178676Ssam tmp |= RT2860_LNA_PE1_EN; 3534198429Srpaulo if (group == 0) { /* 2GHz */ 3535178676Ssam tmp |= RT2860_PA_PE_G0_EN; 3536198429Srpaulo if (sc->ntxchains > 1) 3537198429Srpaulo tmp |= RT2860_PA_PE_G1_EN; 3538198429Srpaulo } else { /* 5GHz */ 3539178676Ssam tmp |= RT2860_PA_PE_A0_EN; 3540178676Ssam if (sc->ntxchains > 1) 3541178676Ssam tmp |= RT2860_PA_PE_A1_EN; 3542178676Ssam } 3543178676Ssam if (sc->mac_ver == 0x3572) { 3544201209Srpaulo run_rt3070_rf_write(sc, 8, 0x00); 3545220720Sbschmidt run_write(sc, RT2860_TX_PIN_CFG, tmp); 3546178676Ssam run_rt3070_rf_write(sc, 8, 0x80); 3547221651Sbschmidt } else 3548178676Ssam run_write(sc, RT2860_TX_PIN_CFG, tmp); 3549198429Srpaulo 3550198429Srpaulo /* set initial AGC value */ 3551198429Srpaulo if (group == 0) { /* 2GHz band */ 3552198429Srpaulo if (sc->mac_ver >= 0x3070) 3553198429Srpaulo agc = 0x1c + sc->lna[0] * 2; 3554220720Sbschmidt else 3555178676Ssam agc = 0x2e + sc->lna[0]; 3556178676Ssam } else { /* 5GHz band */ 3557220700Sbschmidt if (sc->mac_ver == 0x3572) 3558220700Sbschmidt agc = 0x22 + (sc->lna[group] * 5) / 3; 3559198429Srpaulo else 3560198429Srpaulo agc = 0x32 + (sc->lna[group] * 5) / 3; 3561220720Sbschmidt } 3562201209Srpaulo run_set_agc(sc, agc); 3563178676Ssam} 3564198429Srpaulo 3565178676Ssamstatic void 3566201209Srpaulorun_rt2870_set_chan(struct run_softc *sc, uint32_t chan) 3567198429Srpaulo{ 3568198429Srpaulo const struct rfprog *rfprog = rt2860_rf2850; 3569198429Srpaulo uint32_t r2, r3, r4; 3570220720Sbschmidt int8_t txpow1, txpow2; 3571220720Sbschmidt int i; 3572220720Sbschmidt 3573178676Ssam /* find the settings for this channel (we know it exists) */ 3574178676Ssam for (i = 0; rfprog[i].chan != chan; i++); 3575178676Ssam 3576198429Srpaulo r2 = rfprog[i].r2; 3577198429Srpaulo if (sc->ntxchains == 1) 3578221648Sbschmidt r2 |= 1 << 12; /* 1T: disable Tx chain 2 */ 3579221648Sbschmidt if (sc->nrxchains == 1) 3580198429Srpaulo r2 |= 1 << 15 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 3581201209Srpaulo else if (sc->nrxchains == 2) 3582198429Srpaulo r2 |= 1 << 4; /* 2R: disable Rx chain 3 */ 3583198429Srpaulo 3584198429Srpaulo /* use Tx power values from EEPROM */ 3585201209Srpaulo txpow1 = sc->txpow1[i]; 3586198429Srpaulo txpow2 = sc->txpow2[i]; 3587201209Srpaulo if (chan > 14) { 3588198429Srpaulo if (txpow1 >= 0) 3589198429Srpaulo txpow1 = txpow1 << 1 | 1; 3590198429Srpaulo else 3591198429Srpaulo txpow1 = (7 + txpow1) << 1; 3592198429Srpaulo if (txpow2 >= 0) 3593198429Srpaulo txpow2 = txpow2 << 1 | 1; 3594198429Srpaulo else 3595201209Srpaulo txpow2 = (7 + txpow2) << 1; 3596198429Srpaulo } 3597198429Srpaulo r3 = rfprog[i].r3 | txpow1 << 7; 3598198429Srpaulo r4 = rfprog[i].r4 | sc->freq << 13 | txpow2 << 4; 3599198429Srpaulo 3600198429Srpaulo run_rt2870_rf_write(sc, RT2860_RF1, rfprog[i].r1); 3601198429Srpaulo run_rt2870_rf_write(sc, RT2860_RF2, r2); 3602198429Srpaulo run_rt2870_rf_write(sc, RT2860_RF3, r3); 3603198429Srpaulo run_rt2870_rf_write(sc, RT2860_RF4, r4); 3604198429Srpaulo 3605198429Srpaulo run_delay(sc, 10); 3606198429Srpaulo 3607198429Srpaulo run_rt2870_rf_write(sc, RT2860_RF1, rfprog[i].r1); 3608198429Srpaulo run_rt2870_rf_write(sc, RT2860_RF2, r2); 3609198429Srpaulo run_rt2870_rf_write(sc, RT2860_RF3, r3 | 1); 3610198429Srpaulo run_rt2870_rf_write(sc, RT2860_RF4, r4); 3611198429Srpaulo 3612198429Srpaulo run_delay(sc, 10); 3613198429Srpaulo 3614198429Srpaulo run_rt2870_rf_write(sc, RT2860_RF1, rfprog[i].r1); 3615198429Srpaulo run_rt2870_rf_write(sc, RT2860_RF2, r2); 3616198429Srpaulo run_rt2870_rf_write(sc, RT2860_RF3, r3); 3617198429Srpaulo run_rt2870_rf_write(sc, RT2860_RF4, r4); 3618198429Srpaulo} 3619198429Srpaulo 3620220725Sbschmidtstatic void 3621198429Srpaulorun_rt3070_set_chan(struct run_softc *sc, uint32_t chan) 3622198429Srpaulo{ 3623198429Srpaulo int8_t txpow1, txpow2; 3624198429Srpaulo uint8_t rf; 3625198429Srpaulo int i; 3626198429Srpaulo 3627198429Srpaulo /* RT3070 is 2GHz only */ 3628198429Srpaulo KASSERT(chan >= 1 && chan <= 14, ("wrong channel selected\n")); 3629198429Srpaulo 3630198429Srpaulo /* find the settings for this channel (we know it exists) */ 3631198429Srpaulo for (i = 0; rt2860_rf2850[i].chan != chan; i++); 3632198429Srpaulo 3633201209Srpaulo /* use Tx power values from EEPROM */ 3634198429Srpaulo txpow1 = sc->txpow1[i]; 3635198429Srpaulo txpow2 = sc->txpow2[i]; 3636198429Srpaulo 3637198429Srpaulo run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n); 3638198429Srpaulo run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k); 3639198429Srpaulo run_rt3070_rf_read(sc, 6, &rf); 3640198429Srpaulo rf = (rf & ~0x03) | rt3070_freqs[i].r; 3641198429Srpaulo run_rt3070_rf_write(sc, 6, rf); 3642198429Srpaulo 3643198429Srpaulo /* set Tx0 power */ 3644198429Srpaulo run_rt3070_rf_read(sc, 12, &rf); 3645201209Srpaulo rf = (rf & ~0x1f) | txpow1; 3646198429Srpaulo run_rt3070_rf_write(sc, 12, rf); 3647198429Srpaulo 3648198429Srpaulo /* set Tx1 power */ 3649198429Srpaulo run_rt3070_rf_read(sc, 13, &rf); 3650220728Sbschmidt rf = (rf & ~0x1f) | txpow2; 3651198429Srpaulo run_rt3070_rf_write(sc, 13, rf); 3652198429Srpaulo 3653198429Srpaulo run_rt3070_rf_read(sc, 1, &rf); 3654221648Sbschmidt rf &= ~0xfc; 3655221648Sbschmidt if (sc->ntxchains == 1) 3656221648Sbschmidt rf |= 1 << 7 | 1 << 5; /* 1T: disable Tx chains 2 & 3 */ 3657221648Sbschmidt else if (sc->ntxchains == 2) 3658201209Srpaulo rf |= 1 << 7; /* 2T: disable Tx chain 3 */ 3659201209Srpaulo if (sc->nrxchains == 1) 3660201209Srpaulo rf |= 1 << 6 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 3661221648Sbschmidt else if (sc->nrxchains == 2) 3662198429Srpaulo rf |= 1 << 6; /* 2R: disable Rx chain 3 */ 3663220694Sbschmidt run_rt3070_rf_write(sc, 1, rf); 3664220694Sbschmidt 3665198429Srpaulo /* set RF offset */ 3666198429Srpaulo run_rt3070_rf_read(sc, 23, &rf); 3667198429Srpaulo rf = (rf & ~0x7f) | sc->freq; 3668198429Srpaulo run_rt3070_rf_write(sc, 23, rf); 3669198429Srpaulo 3670201209Srpaulo /* program RF filter */ 3671198429Srpaulo run_rt3070_rf_read(sc, 24, &rf); /* Tx */ 3672198429Srpaulo rf = (rf & ~0x3f) | sc->rf24_20mhz; 3673198429Srpaulo run_rt3070_rf_write(sc, 24, rf); 3674220700Sbschmidt run_rt3070_rf_read(sc, 31, &rf); /* Rx */ 3675220700Sbschmidt rf = (rf & ~0x3f) | sc->rf24_20mhz; 3676220700Sbschmidt run_rt3070_rf_write(sc, 31, rf); 3677220700Sbschmidt 3678220700Sbschmidt /* enable RF tuning */ 3679220700Sbschmidt run_rt3070_rf_read(sc, 7, &rf); 3680220700Sbschmidt run_rt3070_rf_write(sc, 7, rf | 0x01); 3681220700Sbschmidt} 3682178676Ssam 3683220700Sbschmidtstatic void 3684220700Sbschmidtrun_rt3572_set_chan(struct run_softc *sc, u_int chan) 3685220700Sbschmidt{ 3686220700Sbschmidt int8_t txpow1, txpow2; 3687220700Sbschmidt uint32_t tmp; 3688220700Sbschmidt uint8_t rf; 3689220700Sbschmidt int i; 3690220700Sbschmidt 3691220700Sbschmidt /* find the settings for this channel (we know it exists) */ 3692220700Sbschmidt for (i = 0; rt2860_rf2850[i].chan != chan; i++); 3693220700Sbschmidt 3694220700Sbschmidt /* use Tx power values from EEPROM */ 3695178676Ssam txpow1 = sc->txpow1[i]; 3696178676Ssam txpow2 = sc->txpow2[i]; 3697220700Sbschmidt 3698201209Srpaulo if (chan <= 14) { 3699178676Ssam run_bbp_write(sc, 25, sc->bbp25); 3700178676Ssam run_bbp_write(sc, 26, sc->bbp26); 3701178676Ssam } else { 3702178676Ssam /* enable IQ phase correction */ 3703201209Srpaulo run_bbp_write(sc, 25, 0x09); 3704178676Ssam run_bbp_write(sc, 26, 0xff); 3705178676Ssam } 3706178676Ssam 3707201209Srpaulo run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n); 3708178676Ssam run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k); 3709198429Srpaulo run_rt3070_rf_read(sc, 6, &rf); 3710220700Sbschmidt rf = (rf & ~0x0f) | rt3070_freqs[i].r; 3711220700Sbschmidt rf |= (chan <= 14) ? 0x08 : 0x04; 3712220700Sbschmidt run_rt3070_rf_write(sc, 6, rf); 3713198429Srpaulo 3714201209Srpaulo /* set PLL mode */ 3715201209Srpaulo run_rt3070_rf_read(sc, 5, &rf); 3716198429Srpaulo rf &= ~(0x08 | 0x04); 3717198429Srpaulo rf |= (chan <= 14) ? 0x04 : 0x08; 3718220700Sbschmidt run_rt3070_rf_write(sc, 5, rf); 3719178676Ssam 3720220700Sbschmidt /* set Tx power for chain 0 */ 3721220700Sbschmidt if (chan <= 14) 3722220700Sbschmidt rf = 0x60 | txpow1; 3723220700Sbschmidt else 3724178676Ssam rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3); 3725178676Ssam run_rt3070_rf_write(sc, 12, rf); 3726201209Srpaulo 3727201209Srpaulo /* set Tx power for chain 1 */ 3728201209Srpaulo if (chan <= 14) 3729201209Srpaulo rf = 0x60 | txpow2; 3730201209Srpaulo else 3731201209Srpaulo rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3); 3732198429Srpaulo run_rt3070_rf_write(sc, 13, rf); 3733220728Sbschmidt 3734178676Ssam /* set Tx/Rx streams */ 3735198429Srpaulo run_rt3070_rf_read(sc, 1, &rf); 3736178676Ssam rf &= ~0xfc; 3737198429Srpaulo if (sc->ntxchains == 1) 3738178676Ssam rf |= 1 << 7 | 1 << 5; /* 1T: disable Tx chains 2 & 3 */ 3739198429Srpaulo else if (sc->ntxchains == 2) 3740198429Srpaulo rf |= 1 << 7; /* 2T: disable Tx chain 3 */ 3741198429Srpaulo if (sc->nrxchains == 1) 3742178676Ssam rf |= 1 << 6 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 3743178676Ssam else if (sc->nrxchains == 2) 3744178676Ssam rf |= 1 << 6; /* 2R: disable Rx chain 3 */ 3745178676Ssam run_rt3070_rf_write(sc, 1, rf); 3746178676Ssam 3747178676Ssam /* set RF offset */ 3748220720Sbschmidt run_rt3070_rf_read(sc, 23, &rf); 3749178676Ssam rf = (rf & ~0x7f) | sc->freq; 3750178676Ssam run_rt3070_rf_write(sc, 23, rf); 3751178676Ssam 3752178676Ssam /* program RF filter */ 3753198429Srpaulo rf = sc->rf24_20mhz; 3754178676Ssam run_rt3070_rf_write(sc, 24, rf); /* Tx */ 3755178676Ssam run_rt3070_rf_write(sc, 31, rf); /* Rx */ 3756178676Ssam 3757178676Ssam /* enable RF tuning */ 3758178676Ssam run_rt3070_rf_read(sc, 7, &rf); 3759178676Ssam rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14); 3760178676Ssam run_rt3070_rf_write(sc, 7, rf); 3761178676Ssam 3762178676Ssam /* TSSI */ 3763178676Ssam rf = (chan <= 14) ? 0xc3 : 0xc0; 3764178676Ssam run_rt3070_rf_write(sc, 9, rf); 3765178676Ssam 3766178676Ssam /* set loop filter 1 */ 3767220720Sbschmidt run_rt3070_rf_write(sc, 10, 0xf1); 3768178676Ssam /* set loop filter 2 */ 3769178676Ssam run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00); 3770178676Ssam 3771178676Ssam /* set tx_mx2_ic */ 3772178676Ssam run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43); 3773220720Sbschmidt /* set tx_mx1_ic */ 3774178676Ssam if (chan <= 14) 3775178676Ssam rf = 0x48 | sc->txmixgain_2ghz; 3776178676Ssam else 3777178676Ssam rf = 0x78 | sc->txmixgain_5ghz; 3778178676Ssam run_rt3070_rf_write(sc, 16, rf); 3779178676Ssam 3780220667Sbschmidt /* set tx_lo1 */ 3781220667Sbschmidt run_rt3070_rf_write(sc, 17, 0x23); 3782178676Ssam /* set tx_lo2 */ 3783178676Ssam if (chan <= 14) 3784178676Ssam rf = 0x93; 3785178676Ssam else if (chan <= 64) 3786206477Sbschmidt rf = 0xb7; 3787198429Srpaulo else if (chan <= 128) 3788198429Srpaulo rf = 0x74; 3789198429Srpaulo else 3790198429Srpaulo rf = 0x72; 3791198429Srpaulo run_rt3070_rf_write(sc, 19, rf); 3792198429Srpaulo 3793198429Srpaulo /* set rx_lo1 */ 3794198429Srpaulo if (chan <= 14) 3795198429Srpaulo rf = 0xb3; 3796206477Sbschmidt else if (chan <= 64) 3797198429Srpaulo rf = 0xf6; 3798198429Srpaulo else if (chan <= 128) 3799198429Srpaulo rf = 0xf4; 3800198429Srpaulo else 3801198429Srpaulo rf = 0xf3; 3802198429Srpaulo run_rt3070_rf_write(sc, 20, rf); 3803198429Srpaulo 3804198429Srpaulo /* set pfd_delay */ 3805220720Sbschmidt if (chan <= 14) 3806220720Sbschmidt rf = 0x15; 3807220720Sbschmidt else if (chan <= 64) 3808220720Sbschmidt rf = 0x3d; 3809198429Srpaulo else 3810198429Srpaulo rf = 0x01; 3811198429Srpaulo run_rt3070_rf_write(sc, 25, rf); 3812198429Srpaulo 3813198429Srpaulo /* set rx_lo2 */ 3814198429Srpaulo run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87); 3815198429Srpaulo /* set ldo_rf_vc */ 3816198429Srpaulo run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01); 3817198429Srpaulo /* set drv_cc */ 3818220720Sbschmidt run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f); 3819220720Sbschmidt 3820198429Srpaulo run_read(sc, RT2860_GPIO_CTRL, &tmp); 3821220720Sbschmidt tmp &= ~0x8080; 3822198429Srpaulo if (chan <= 14) 3823198429Srpaulo tmp |= 0x80; 3824198429Srpaulo run_write(sc, RT2860_GPIO_CTRL, tmp); 3825198429Srpaulo 3826198429Srpaulo /* enable RF tuning */ 3827178676Ssam run_rt3070_rf_read(sc, 7, &rf); 3828220667Sbschmidt run_rt3070_rf_write(sc, 7, rf | 0x01); 3829178676Ssam 3830220667Sbschmidt run_delay(sc, 2); 3831220667Sbschmidt} 3832220667Sbschmidt 3833178676Ssamstatic void 3834220667Sbschmidtrun_set_rx_antenna(struct run_softc *sc, int aux) 3835220667Sbschmidt{ 3836220667Sbschmidt uint32_t tmp; 3837220667Sbschmidt 3838220668Sbschmidt if (aux) { 3839220668Sbschmidt run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0); 3840220667Sbschmidt run_read(sc, RT2860_GPIO_CTRL, &tmp); 3841220667Sbschmidt run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08); 3842220667Sbschmidt } else { 3843220667Sbschmidt run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1); 3844178676Ssam run_read(sc, RT2860_GPIO_CTRL, &tmp); 3845220667Sbschmidt run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808); 3846178676Ssam } 3847178676Ssam} 3848206477Sbschmidt 3849178676Ssamstatic int 3850178676Ssamrun_set_chan(struct run_softc *sc, struct ieee80211_channel *c) 3851178676Ssam{ 3852178676Ssam struct ieee80211com *ic = sc->sc_ifp->if_l2com; 3853201209Srpaulo uint32_t chan, group; 3854178676Ssam 3855201209Srpaulo chan = ieee80211_chan2ieee(ic, c); 3856178676Ssam if (chan == 0 || chan == IEEE80211_CHAN_ANY) 3857178676Ssam return (EINVAL); 3858220723Sbschmidt 3859220723Sbschmidt if (sc->mac_ver == 0x3572) 3860220723Sbschmidt run_rt3572_set_chan(sc, chan); 3861178676Ssam else if (sc->mac_ver >= 0x3070) 3862178704Sthompsa run_rt3070_set_chan(sc, chan); 3863178676Ssam else 3864178676Ssam run_rt2870_set_chan(sc, chan); 3865178676Ssam 3866201209Srpaulo /* determine channel group */ 3867201209Srpaulo if (chan <= 14) 3868201209Srpaulo group = 0; 3869201209Srpaulo else if (chan <= 64) 3870178676Ssam group = 1; 3871178676Ssam else if (chan <= 128) 3872178676Ssam group = 2; 3873178676Ssam else 3874178676Ssam group = 3; 3875178704Sthompsa 3876178704Sthompsa /* XXX necessary only when group has changed! */ 3877178704Sthompsa run_select_chan_group(sc, group); 3878201209Srpaulo 3879201209Srpaulo run_delay(sc, 10); 3880178676Ssam 3881178676Ssam return (0); 3882178676Ssam} 3883178676Ssam 3884178704Sthompsastatic void 3885178704Sthompsarun_set_channel(struct ieee80211com *ic) 3886178704Sthompsa{ 3887178676Ssam struct run_softc *sc = ic->ic_ifp->if_softc; 3888178676Ssam 3889178676Ssam RUN_LOCK(sc); 3890178676Ssam run_set_chan(sc, ic->ic_curchan); 3891178676Ssam RUN_UNLOCK(sc); 3892178676Ssam 3893178676Ssam return; 3894206477Sbschmidt} 3895178676Ssam 3896178676Ssamstatic void 3897221651Sbschmidtrun_scan_start(struct ieee80211com *ic) 3898178676Ssam{ 3899178676Ssam struct run_softc *sc = ic->ic_ifp->if_softc; 3900198429Srpaulo uint32_t tmp; 3901178676Ssam 3902198439Srpaulo RUN_LOCK(sc); 3903178676Ssam 3904198439Srpaulo /* abort TSF synchronization */ 3905178676Ssam run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 3906221650Sbschmidt run_write(sc, RT2860_BCN_TIME_CFG, 3907221650Sbschmidt tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 3908178676Ssam RT2860_TBTT_TIMER_EN)); 3909178676Ssam run_set_bssid(sc, sc->sc_ifp->if_broadcastaddr); 3910198429Srpaulo 3911198429Srpaulo RUN_UNLOCK(sc); 3912178676Ssam 3913198439Srpaulo return; 3914198439Srpaulo} 3915198439Srpaulo 3916198439Srpaulostatic void 3917201209Srpaulorun_scan_end(struct ieee80211com *ic) 3918198439Srpaulo{ 3919198439Srpaulo struct run_softc *sc = ic->ic_ifp->if_softc; 3920198439Srpaulo 3921201209Srpaulo RUN_LOCK(sc); 3922198439Srpaulo 3923198439Srpaulo run_enable_tsf_sync(sc); 3924198439Srpaulo /* XXX keep local copy */ 3925198439Srpaulo run_set_bssid(sc, sc->sc_bssid); 3926198439Srpaulo 3927198439Srpaulo RUN_UNLOCK(sc); 3928198439Srpaulo 3929198439Srpaulo return; 3930198439Srpaulo} 3931198439Srpaulo 3932198439Srpaulo/* 3933178676Ssam * Could be called from ieee80211_node_timeout() 3934178676Ssam * (non-sleepable thread) 3935178676Ssam */ 3936178676Ssamstatic void 3937178676Ssamrun_update_beacon(struct ieee80211vap *vap, int item) 3938178676Ssam{ 3939198429Srpaulo struct ieee80211com *ic = vap->iv_ic; 3940198429Srpaulo struct run_softc *sc = ic->ic_ifp->if_softc; 3941198429Srpaulo struct run_vap *rvp = RUN_VAP(vap); 3942178676Ssam int mcast = 0; 3943178676Ssam uint32_t i; 3944178676Ssam 3945178676Ssam KASSERT(vap != NULL, ("no beacon")); 3946178676Ssam 3947198439Srpaulo switch (item) { 3948201209Srpaulo case IEEE80211_BEACON_ERP: 3949198439Srpaulo run_updateslot(ic->ic_ifp); 3950198439Srpaulo break; 3951201209Srpaulo case IEEE80211_BEACON_HTINFO: 3952198439Srpaulo run_updateprot(ic); 3953198439Srpaulo break; 3954198439Srpaulo case IEEE80211_BEACON_TIM: 3955198439Srpaulo mcast = 1; /*TODO*/ 3956198439Srpaulo break; 3957198429Srpaulo default: 3958220728Sbschmidt break; 3959198429Srpaulo } 3960198429Srpaulo 3961178676Ssam setbit(rvp->bo.bo_flags, item); 3962198429Srpaulo ieee80211_beacon_update(vap->iv_bss, &rvp->bo, rvp->beacon_mbuf, mcast); 3963178676Ssam 3964198439Srpaulo i = RUN_CMDQ_GET(&sc->cmdq_store); 3965178676Ssam DPRINTF("cmdq_store=%d\n", i); 3966178676Ssam sc->cmdq[i].func = run_update_beacon_cb; 3967206477Sbschmidt sc->cmdq[i].arg0 = vap; 3968198429Srpaulo ieee80211_runtask(ic, &sc->cmdq_task); 3969198429Srpaulo 3970198429Srpaulo return; 3971198429Srpaulo} 3972198429Srpaulo 3973198429Srpaulostatic void 3974198429Srpaulorun_update_beacon_cb(void *arg) 3975198429Srpaulo{ 3976198429Srpaulo struct ieee80211vap *vap = arg; 3977198429Srpaulo struct run_vap *rvp = RUN_VAP(vap); 3978198429Srpaulo struct ieee80211com *ic = vap->iv_ic; 3979198429Srpaulo struct run_softc *sc = ic->ic_ifp->if_softc; 3980198429Srpaulo struct rt2860_txwi txwi; 3981198429Srpaulo struct mbuf *m; 3982198429Srpaulo uint8_t ridx; 3983198429Srpaulo 3984198429Srpaulo if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC) 3985198429Srpaulo return; 3986206477Sbschmidt if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) 3987198429Srpaulo return; 3988198429Srpaulo 3989198429Srpaulo /* 3990198429Srpaulo * No need to call ieee80211_beacon_update(), run_update_beacon() 3991198429Srpaulo * is taking care of apropriate calls. 3992198429Srpaulo */ 3993206477Sbschmidt if (rvp->beacon_mbuf == NULL) { 3994220715Sbschmidt rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss, 3995178676Ssam &rvp->bo); 3996220715Sbschmidt if (rvp->beacon_mbuf == NULL) 3997220715Sbschmidt return; 3998198429Srpaulo } 3999220715Sbschmidt m = rvp->beacon_mbuf; 4000221648Sbschmidt 4001178676Ssam memset(&txwi, 0, sizeof txwi); 4002198429Srpaulo txwi.wcid = 0xff; 4003201209Srpaulo txwi.len = htole16(m->m_pkthdr.len); 4004178676Ssam /* send beacons at the lowest available rate */ 4005198429Srpaulo ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? 4006220715Sbschmidt RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; 4007198429Srpaulo txwi.phy = htole16(rt2860_rates[ridx].mcs); 4008201209Srpaulo if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM) 4009221651Sbschmidt txwi.phy |= htole16(RT2860_PHY_OFDM); 4010198429Srpaulo txwi.txop = RT2860_TX_TXOP_HT; 4011198429Srpaulo txwi.flags = RT2860_TX_TS; 4012198429Srpaulo txwi.xflags = RT2860_TX_NSEQ; 4013220715Sbschmidt 4014221649Sbschmidt run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id), 4015221649Sbschmidt (uint8_t *)&txwi, sizeof txwi); 4016221649Sbschmidt run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id) + sizeof txwi, 4017221649Sbschmidt mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1); /* roundup len */ 4018178676Ssam 4019221649Sbschmidt return; 4020221649Sbschmidt} 4021221649Sbschmidt 4022221649Sbschmidtstatic void 4023221648Sbschmidtrun_updateprot(struct ieee80211com *ic) 4024221648Sbschmidt{ 4025221649Sbschmidt struct run_softc *sc = ic->ic_ifp->if_softc; 4026221649Sbschmidt uint32_t i; 4027221649Sbschmidt 4028221649Sbschmidt i = RUN_CMDQ_GET(&sc->cmdq_store); 4029220715Sbschmidt DPRINTF("cmdq_store=%d\n", i); 4030220715Sbschmidt sc->cmdq[i].func = run_updateprot_cb; 4031220715Sbschmidt sc->cmdq[i].arg0 = ic; 4032178676Ssam ieee80211_runtask(ic, &sc->cmdq_task); 4033220715Sbschmidt} 4034178676Ssam 4035178676Ssamstatic void 4036178676Ssamrun_updateprot_cb(void *arg) 4037198429Srpaulo{ 4038178676Ssam struct ieee80211com *ic = arg; 4039206477Sbschmidt struct run_softc *sc = ic->ic_ifp->if_softc; 4040201209Srpaulo uint32_t tmp; 4041178676Ssam 4042220728Sbschmidt tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL; 4043198429Srpaulo /* setup protection frame rate (MCS code) */ 4044220715Sbschmidt tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ? 4045178676Ssam rt2860_rates[RT2860_RIDX_OFDM6].mcs : 4046220715Sbschmidt rt2860_rates[RT2860_RIDX_CCK11].mcs; 4047220715Sbschmidt 4048220715Sbschmidt /* CCK frames don't require protection */ 4049178676Ssam run_write(sc, RT2860_CCK_PROT_CFG, tmp); 4050178676Ssam if (ic->ic_flags & IEEE80211_F_USEPROT) { 4051198429Srpaulo if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) 4052220728Sbschmidt tmp |= RT2860_PROT_CTRL_RTS_CTS; 4053198429Srpaulo else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) 4054220728Sbschmidt tmp |= RT2860_PROT_CTRL_CTS; 4055198429Srpaulo } 4056178676Ssam run_write(sc, RT2860_OFDM_PROT_CFG, tmp); 4057220715Sbschmidt} 4058220715Sbschmidt 4059220715Sbschmidtstatic void 4060220715Sbschmidtrun_usb_timeout_cb(void *arg) 4061220728Sbschmidt{ 4062220715Sbschmidt struct ieee80211vap *vap = arg; 4063220715Sbschmidt struct run_softc *sc = vap->iv_ic->ic_ifp->if_softc; 4064220715Sbschmidt 4065220715Sbschmidt RUN_LOCK_ASSERT(sc, MA_OWNED); 4066220715Sbschmidt 4067220715Sbschmidt if(vap->iv_state == IEEE80211_S_RUN && 4068220715Sbschmidt vap->iv_opmode != IEEE80211_M_STA) 4069220715Sbschmidt run_reset_livelock(sc); 4070221648Sbschmidt else if (vap->iv_state == IEEE80211_S_SCAN) { 4071220715Sbschmidt DPRINTF("timeout caused by scan\n"); 4072221648Sbschmidt /* cancel bgscan */ 4073221648Sbschmidt ieee80211_cancel_scan(vap); 4074220715Sbschmidt } else 4075220715Sbschmidt DPRINTF("timeout by unknown cause\n"); 4076221648Sbschmidt} 4077220715Sbschmidt 4078220715Sbschmidtstatic void 4079178676Ssamrun_reset_livelock(struct run_softc *sc) 4080178676Ssam{ 4081206477Sbschmidt uint32_t tmp; 4082220721Sbschmidt 4083178676Ssam RUN_LOCK_ASSERT(sc, MA_OWNED); 4084178676Ssam 4085178676Ssam /* 4086178676Ssam * In IBSS or HostAP modes (when the hardware sends beacons), the MAC 4087220721Sbschmidt * can run into a livelock and start sending CTS-to-self frames like 4088178676Ssam * crazy if protection is enabled. Reset MAC/BBP for a while 4089178676Ssam */ 4090178676Ssam run_read(sc, RT2860_DEBUG, &tmp); 4091220721Sbschmidt DPRINTFN(3, "debug reg %08x\n", tmp); 4092220721Sbschmidt if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) { 4093220721Sbschmidt DPRINTF("CTS-to-self livelock detected\n"); 4094220721Sbschmidt run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST); 4095220721Sbschmidt run_delay(sc, 1); 4096220721Sbschmidt run_write(sc, RT2860_MAC_SYS_CTRL, 4097220721Sbschmidt RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 4098220721Sbschmidt } 4099178676Ssam} 4100201209Srpaulo 4101178676Ssamstatic void 4102220725Sbschmidtrun_update_promisc_locked(struct ifnet *ifp) 4103178676Ssam{ 4104201209Srpaulo struct run_softc *sc = ifp->if_softc; 4105178676Ssam uint32_t tmp; 4106178676Ssam 4107178676Ssam run_read(sc, RT2860_RX_FILTR_CFG, &tmp); 4108178676Ssam 4109201209Srpaulo tmp |= RT2860_DROP_UC_NOME; 4110201209Srpaulo if (ifp->if_flags & IFF_PROMISC) 4111201209Srpaulo tmp &= ~RT2860_DROP_UC_NOME; 4112201209Srpaulo 4113201209Srpaulo run_write(sc, RT2860_RX_FILTR_CFG, tmp); 4114201209Srpaulo 4115206477Sbschmidt DPRINTF("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ? 4116178676Ssam "entering" : "leaving"); 4117178676Ssam} 4118178676Ssam 4119178676Ssamstatic void 4120198429Srpaulorun_update_promisc(struct ifnet *ifp) 4121198429Srpaulo{ 4122198429Srpaulo struct run_softc *sc = ifp->if_softc; 4123178676Ssam 4124198429Srpaulo if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 4125178676Ssam return; 4126178676Ssam 4127198429Srpaulo RUN_LOCK(sc); 4128178676Ssam run_update_promisc_locked(ifp); 4129178676Ssam RUN_UNLOCK(sc); 4130178676Ssam} 4131201209Srpaulo 4132201209Srpaulostatic void 4133178676Ssamrun_enable_tsf_sync(struct run_softc *sc) 4134206477Sbschmidt{ 4135178676Ssam struct ieee80211com *ic = sc->sc_ifp->if_l2com; 4136178676Ssam struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 4137178676Ssam uint32_t tmp; 4138201209Srpaulo 4139178676Ssam DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id, ic->ic_opmode); 4140198429Srpaulo 4141178676Ssam run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 4142201209Srpaulo tmp &= ~0x1fffff; 4143201209Srpaulo tmp |= vap->iv_bss->ni_intval * 16; 4144201209Srpaulo tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN; 4145201209Srpaulo 4146201209Srpaulo if (ic->ic_opmode == IEEE80211_M_STA) { 4147201209Srpaulo /* 4148178676Ssam * Local TSF is always updated with remote TSF on beacon 4149201209Srpaulo * reception. 4150220726Sbschmidt */ 4151178676Ssam tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT; 4152178676Ssam } else if (ic->ic_opmode == IEEE80211_M_IBSS) { 4153178676Ssam tmp |= RT2860_BCN_TX_EN; 4154206477Sbschmidt /* 4155198429Srpaulo * Local TSF is updated with remote TSF on beacon reception 4156178676Ssam * only if the remote TSF is greater than local TSF. 4157198429Srpaulo */ 4158178676Ssam tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT; 4159178676Ssam } else if (ic->ic_opmode == IEEE80211_M_HOSTAP || 4160198429Srpaulo ic->ic_opmode == IEEE80211_M_MBSS) { 4161198429Srpaulo tmp |= RT2860_BCN_TX_EN; 4162198429Srpaulo /* SYNC with nobody */ 4163198429Srpaulo tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT; 4164178676Ssam } else { 4165198429Srpaulo DPRINTF("Enabling TSF failed. undefined opmode\n"); 4166220634Sbschmidt return; 4167198429Srpaulo } 4168198429Srpaulo 4169178676Ssam run_write(sc, RT2860_BCN_TIME_CFG, tmp); 4170198429Srpaulo} 4171198429Srpaulo 4172178676Ssamstatic void 4173198429Srpaulorun_enable_mrr(struct run_softc *sc) 4174178676Ssam{ 4175178676Ssam#define CCK(mcs) (mcs) 4176206477Sbschmidt#define OFDM(mcs) (1 << 3 | (mcs)) 4177198429Srpaulo run_write(sc, RT2860_LG_FBK_CFG0, 4178178676Ssam OFDM(6) << 28 | /* 54->48 */ 4179201882Skeramida OFDM(5) << 24 | /* 48->36 */ 4180201882Skeramida OFDM(4) << 20 | /* 36->24 */ 4181201882Skeramida OFDM(3) << 16 | /* 24->18 */ 4182220725Sbschmidt OFDM(2) << 12 | /* 18->12 */ 4183178676Ssam OFDM(1) << 8 | /* 12-> 9 */ 4184178676Ssam OFDM(0) << 4 | /* 9-> 6 */ 4185198429Srpaulo OFDM(0)); /* 6-> 6 */ 4186198429Srpaulo 4187198429Srpaulo run_write(sc, RT2860_LG_FBK_CFG1, 4188201882Skeramida CCK(2) << 12 | /* 11->5.5 */ 4189178676Ssam CCK(1) << 8 | /* 5.5-> 2 */ 4190178676Ssam CCK(0) << 4 | /* 2-> 1 */ 4191178676Ssam CCK(0)); /* 1-> 1 */ 4192178676Ssam#undef OFDM 4193198429Srpaulo#undef CCK 4194178676Ssam} 4195178676Ssam 4196178676Ssamstatic void 4197206477Sbschmidtrun_set_txpreamble(struct run_softc *sc) 4198201882Skeramida{ 4199201882Skeramida struct ieee80211com *ic = sc->sc_ifp->if_l2com; 4200178676Ssam uint32_t tmp; 4201198429Srpaulo 4202178676Ssam run_read(sc, RT2860_AUTO_RSP_CFG, &tmp); 4203178676Ssam if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 4204198429Srpaulo tmp |= RT2860_CCK_SHORT_EN; 4205178676Ssam else 4206178676Ssam tmp &= ~RT2860_CCK_SHORT_EN; 4207178676Ssam run_write(sc, RT2860_AUTO_RSP_CFG, tmp); 4208178676Ssam} 4209178676Ssam 4210198429Srpaulostatic void 4211198429Srpaulorun_set_basicrates(struct run_softc *sc) 4212220723Sbschmidt{ 4213178676Ssam struct ieee80211com *ic = sc->sc_ifp->if_l2com; 4214178676Ssam 4215198429Srpaulo /* set basic rates mask */ 4216178676Ssam if (ic->ic_curmode == IEEE80211_MODE_11B) 4217220687Sbschmidt run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003); 4218220687Sbschmidt else if (ic->ic_curmode == IEEE80211_MODE_11A) 4219201209Srpaulo run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150); 4220201209Srpaulo else /* 11g */ 4221178676Ssam run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f); 4222178676Ssam} 4223178676Ssam 4224178676Ssamstatic void 4225178676Ssamrun_set_leds(struct run_softc *sc, uint16_t which) 4226178676Ssam{ 4227178676Ssam (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS, 4228198429Srpaulo which | (sc->leds & 0x7f)); 4229198429Srpaulo} 4230178676Ssam 4231178676Ssamstatic void 4232198429Srpaulorun_set_bssid(struct run_softc *sc, const uint8_t *bssid) 4233198429Srpaulo{ 4234178676Ssam run_write(sc, RT2860_MAC_BSSID_DW0, 4235178676Ssam bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24); 4236198429Srpaulo run_write(sc, RT2860_MAC_BSSID_DW1, 4237178676Ssam bssid[4] | bssid[5] << 8); 4238178676Ssam} 4239178676Ssam 4240178676Ssamstatic void 4241178676Ssamrun_set_macaddr(struct run_softc *sc, const uint8_t *addr) 4242178676Ssam{ 4243178676Ssam run_write(sc, RT2860_MAC_ADDR_DW0, 4244178676Ssam addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24); 4245178676Ssam run_write(sc, RT2860_MAC_ADDR_DW1, 4246201209Srpaulo addr[4] | addr[5] << 8 | 0xff << 16); 4247178676Ssam} 4248178676Ssam 4249178676Ssamstatic void 4250178676Ssamrun_updateslot(struct ifnet *ifp) 4251178676Ssam{ 4252178676Ssam struct run_softc *sc = ifp->if_softc; 4253178676Ssam struct ieee80211com *ic = ifp->if_l2com; 4254178676Ssam uint32_t i; 4255178676Ssam 4256178676Ssam i = RUN_CMDQ_GET(&sc->cmdq_store); 4257178676Ssam DPRINTF("cmdq_store=%d\n", i); 4258178676Ssam sc->cmdq[i].func = run_updateslot_cb; 4259178676Ssam sc->cmdq[i].arg0 = ifp; 4260201209Srpaulo ieee80211_runtask(ic, &sc->cmdq_task); 4261178676Ssam 4262178676Ssam return; 4263178676Ssam} 4264178676Ssam 4265198429Srpaulo/* ARGSUSED */ 4266198429Srpaulostatic void 4267178676Ssamrun_updateslot_cb(void *arg) 4268178676Ssam{ 4269178676Ssam struct ifnet *ifp = arg; 4270178676Ssam struct run_softc *sc = ifp->if_softc; 4271198429Srpaulo struct ieee80211com *ic = ifp->if_l2com; 4272178676Ssam uint32_t tmp; 4273178676Ssam 4274178676Ssam run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp); 4275178676Ssam tmp &= ~0xff; 4276178676Ssam tmp |= (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; 4277178676Ssam run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp); 4278178676Ssam} 4279178676Ssam 4280178676Ssamstatic void 4281178676Ssamrun_update_mcast(struct ifnet *ifp) 4282178676Ssam{ 4283178676Ssam /* h/w filter supports getting everything or nothing */ 4284178676Ssam ifp->if_flags |= IFF_ALLMULTI; 4285178676Ssam} 4286178676Ssam 4287178676Ssamstatic int8_t 4288198429Srpaulorun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain) 4289178676Ssam{ 4290178676Ssam struct ieee80211com *ic = sc->sc_ifp->if_l2com; 4291178676Ssam struct ieee80211_channel *c = ic->ic_curchan; 4292178676Ssam int delta; 4293178676Ssam 4294178676Ssam if (IEEE80211_IS_CHAN_5GHZ(c)) { 4295201209Srpaulo uint32_t chan = ieee80211_chan2ieee(ic, c); 4296198429Srpaulo delta = sc->rssi_5ghz[rxchain]; 4297198429Srpaulo 4298198429Srpaulo /* determine channel group */ 4299178676Ssam if (chan <= 64) 4300198429Srpaulo delta -= sc->lna[1]; 4301178676Ssam else if (chan <= 128) 4302198429Srpaulo delta -= sc->lna[2]; 4303198429Srpaulo else 4304198429Srpaulo delta -= sc->lna[3]; 4305198429Srpaulo } else 4306198429Srpaulo delta = sc->rssi_2ghz[rxchain] - sc->lna[0]; 4307198429Srpaulo 4308198429Srpaulo return (-12 - delta - rssi); 4309198429Srpaulo} 4310198429Srpaulo 4311178676Ssamstatic int 4312201209Srpaulorun_bbp_init(struct run_softc *sc) 4313178676Ssam{ 4314178676Ssam int i, error, ntries; 4315178676Ssam uint8_t bbp0; 4316178676Ssam 4317178676Ssam /* wait for BBP to wake up */ 4318178676Ssam for (ntries = 0; ntries < 20; ntries++) { 4319178676Ssam if ((error = run_bbp_read(sc, 0, &bbp0)) != 0) 4320178676Ssam return error; 4321178676Ssam if (bbp0 != 0 && bbp0 != 0xff) 4322178676Ssam break; 4323178676Ssam } 4324178676Ssam if (ntries == 20) 4325198429Srpaulo return (ETIMEDOUT); 4326178676Ssam 4327178676Ssam /* initialize BBP registers to default values */ 4328198429Srpaulo for (i = 0; i < N(rt2860_def_bbp); i++) { 4329198429Srpaulo run_bbp_write(sc, rt2860_def_bbp[i].reg, 4330178676Ssam rt2860_def_bbp[i].val); 4331178676Ssam } 4332178676Ssam 4333178676Ssam /* fix BBP84 for RT2860E */ 4334178676Ssam if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101) 4335178676Ssam run_bbp_write(sc, 84, 0x19); 4336178676Ssam 4337178676Ssam if (sc->mac_ver >= 0x3070) { 4338178676Ssam run_bbp_write(sc, 79, 0x13); 4339178676Ssam run_bbp_write(sc, 80, 0x05); 4340178676Ssam run_bbp_write(sc, 81, 0x33); 4341178676Ssam } else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) { 4342178676Ssam run_bbp_write(sc, 69, 0x16); 4343178676Ssam run_bbp_write(sc, 73, 0x12); 4344178676Ssam } 4345178676Ssam return (0); 4346178676Ssam} 4347206477Sbschmidt 4348201882Skeramidastatic int 4349201882Skeramidarun_rt3070_rf_init(struct run_softc *sc) 4350198429Srpaulo{ 4351198429Srpaulo uint32_t tmp; 4352198429Srpaulo uint8_t rf, target, bbp4; 4353198429Srpaulo int i; 4354198429Srpaulo 4355198429Srpaulo run_rt3070_rf_read(sc, 30, &rf); 4356198429Srpaulo /* toggle RF R30 bit 7 */ 4357198429Srpaulo run_rt3070_rf_write(sc, 30, rf | 0x80); 4358198429Srpaulo run_delay(sc, 10); 4359198429Srpaulo run_rt3070_rf_write(sc, 30, rf & ~0x80); 4360198429Srpaulo 4361198429Srpaulo /* initialize RF registers to default value */ 4362198429Srpaulo if (sc->mac_ver == 0x3572) { 4363198429Srpaulo for (i = 0; i < N(rt3572_def_rf); i++) { 4364198429Srpaulo run_rt3070_rf_write(sc, rt3572_def_rf[i].reg, 4365178676Ssam rt3572_def_rf[i].val); 4366198429Srpaulo } 4367178676Ssam } else { 4368206477Sbschmidt for (i = 0; i < N(rt3070_def_rf); i++) { 4369198429Srpaulo run_rt3070_rf_write(sc, rt3070_def_rf[i].reg, 4370178676Ssam rt3070_def_rf[i].val); 4371198429Srpaulo } 4372198429Srpaulo } 4373198429Srpaulo 4374178676Ssam if (sc->mac_ver == 0x3070) { 4375201209Srpaulo /* change voltage from 1.2V to 1.35V for RT3070 */ 4376198429Srpaulo run_read(sc, RT3070_LDO_CFG0, &tmp); 4377178676Ssam tmp = (tmp & ~0x0f000000) | 0x0d000000; 4378178676Ssam run_write(sc, RT3070_LDO_CFG0, tmp); 4379220689Sbschmidt 4380220689Sbschmidt } else if (sc->mac_ver == 0x3071) { 4381220689Sbschmidt run_rt3070_rf_read(sc, 6, &rf); 4382220689Sbschmidt run_rt3070_rf_write(sc, 6, rf | 0x40); 4383220689Sbschmidt run_rt3070_rf_write(sc, 31, 0x14); 4384220689Sbschmidt 4385198429Srpaulo run_read(sc, RT3070_LDO_CFG0, &tmp); 4386220724Sbschmidt tmp &= ~0x1f000000; 4387220724Sbschmidt if (sc->mac_rev < 0x0211) 4388220724Sbschmidt tmp |= 0x0d000000; /* 1.3V */ 4389178676Ssam else 4390178676Ssam tmp |= 0x01000000; /* 1.2V */ 4391178676Ssam run_write(sc, RT3070_LDO_CFG0, tmp); 4392178676Ssam 4393206477Sbschmidt /* patch LNA_PE_G1 */ 4394198429Srpaulo run_read(sc, RT3070_GPIO_SWITCH, &tmp); 4395198429Srpaulo run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20); 4396198429Srpaulo 4397220723Sbschmidt } else if (sc->mac_ver == 0x3572) { 4398198429Srpaulo run_rt3070_rf_read(sc, 6, &rf); 4399198429Srpaulo run_rt3070_rf_write(sc, 6, rf | 0x40); 4400198429Srpaulo 4401198429Srpaulo /* increase voltage from 1.2V to 1.35V */ 4402198429Srpaulo run_read(sc, RT3070_LDO_CFG0, &tmp); 4403198429Srpaulo tmp = (tmp & ~0x1f000000) | 0x0d000000; 4404198429Srpaulo run_write(sc, RT3070_LDO_CFG0, tmp); 4405198429Srpaulo 4406220724Sbschmidt if (sc->mac_rev < 0x0211 || !sc->patch_dac) { 4407220724Sbschmidt run_delay(sc, 1); /* wait for 1msec */ 4408201822Strasz /* decrease voltage back to 1.2V */ 4409198429Srpaulo tmp = (tmp & ~0x1f000000) | 0x01000000; 4410198429Srpaulo run_write(sc, RT3070_LDO_CFG0, tmp); 4411198429Srpaulo } 4412198429Srpaulo } 4413178676Ssam 4414198429Srpaulo /* select 20MHz bandwidth */ 4415178676Ssam run_rt3070_rf_read(sc, 31, &rf); 4416206477Sbschmidt run_rt3070_rf_write(sc, 31, rf & ~0x20); 4417178676Ssam 4418178676Ssam /* calibrate filter for 20MHz bandwidth */ 4419178676Ssam sc->rf24_20mhz = 0x1f; /* default value */ 4420178676Ssam target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13; 4421178676Ssam run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz); 4422178676Ssam 4423198429Srpaulo /* select 40MHz bandwidth */ 4424198429Srpaulo run_bbp_read(sc, 4, &bbp4); 4425198429Srpaulo run_bbp_write(sc, 4, (bbp4 & ~0x08) | 0x10); 4426198429Srpaulo run_rt3070_rf_read(sc, 31, &rf); 4427178676Ssam run_rt3070_rf_write(sc, 31, rf | 0x20); 4428198429Srpaulo 4429178676Ssam /* calibrate filter for 40MHz bandwidth */ 4430178676Ssam sc->rf24_40mhz = 0x2f; /* default value */ 4431178676Ssam target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15; 4432178676Ssam run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz); 4433198429Srpaulo 4434178676Ssam /* go back to 20MHz bandwidth */ 4435206477Sbschmidt run_bbp_read(sc, 4, &bbp4); 4436198429Srpaulo run_bbp_write(sc, 4, bbp4 & ~0x18); 4437178676Ssam 4438178676Ssam if (sc->mac_ver == 0x3572) { 4439178676Ssam /* save default BBP registers 25 and 26 values */ 4440178676Ssam run_bbp_read(sc, 25, &sc->bbp25); 4441178676Ssam run_bbp_read(sc, 26, &sc->bbp26); 4442178676Ssam } else if (sc->mac_rev < 0x0211) 4443178676Ssam run_rt3070_rf_write(sc, 27, 0x03); 4444178676Ssam 4445178676Ssam run_read(sc, RT3070_OPT_14, &tmp); 4446220725Sbschmidt run_write(sc, RT3070_OPT_14, tmp | 1); 4447178676Ssam 4448178676Ssam if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) { 4449198429Srpaulo run_rt3070_rf_read(sc, 17, &rf); 4450220659Sbschmidt rf &= ~RT3070_TX_LO1; 4451198429Srpaulo if ((sc->mac_ver == 0x3070 || 4452178676Ssam (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) && 4453178676Ssam !sc->ext_2ghz_lna) 4454178676Ssam rf |= 0x20; /* fix for long range Rx issue */ 4455201209Srpaulo if (sc->txmixgain_2ghz >= 1) 4456201209Srpaulo rf = (rf & ~0x7) | sc->txmixgain_2ghz; 4457178676Ssam run_rt3070_rf_write(sc, 17, rf); 4458178676Ssam } 4459178676Ssam 4460206477Sbschmidt if (sc->mac_rev == 0x3071) { 4461198429Srpaulo run_rt3070_rf_read(sc, 1, &rf); 4462198429Srpaulo rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD); 4463201209Srpaulo rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD; 4464201209Srpaulo run_rt3070_rf_write(sc, 1, rf); 4465198429Srpaulo 4466198429Srpaulo run_rt3070_rf_read(sc, 15, &rf); 4467220725Sbschmidt run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2); 4468198429Srpaulo 4469201209Srpaulo run_rt3070_rf_read(sc, 20, &rf); 4470201209Srpaulo run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1); 4471201209Srpaulo 4472201209Srpaulo run_rt3070_rf_read(sc, 21, &rf); 4473201209Srpaulo run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2); 4474201209Srpaulo } 4475198429Srpaulo 4476198429Srpaulo if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) { 4477178676Ssam /* fix Tx to Rx IQ glitch by raising RF voltage */ 4478178676Ssam run_rt3070_rf_read(sc, 27, &rf); 4479178676Ssam rf &= ~0x77; 4480206477Sbschmidt if (sc->mac_rev < 0x0211) 4481178676Ssam rf |= 0x03; 4482178676Ssam run_rt3070_rf_write(sc, 27, rf); 4483220728Sbschmidt } 4484178676Ssam return (0); 4485198429Srpaulo} 4486178676Ssam 4487178676Ssamstatic int 4488198429Srpaulorun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target, 4489178676Ssam uint8_t *val) 4490178676Ssam{ 4491178676Ssam uint8_t rf22, rf24; 4492198429Srpaulo uint8_t bbp55_pb, bbp55_sb, delta; 4493201209Srpaulo int ntries; 4494201209Srpaulo 4495206444Sbschmidt /* program filter */ 4496201209Srpaulo run_rt3070_rf_read(sc, 24, &rf24); 4497198429Srpaulo rf24 = (rf24 & 0xc0) | init; /* initial filter value */ 4498201209Srpaulo run_rt3070_rf_write(sc, 24, rf24); 4499201209Srpaulo 4500178676Ssam /* enable baseband loopback mode */ 4501198429Srpaulo run_rt3070_rf_read(sc, 22, &rf22); 4502220726Sbschmidt run_rt3070_rf_write(sc, 22, rf22 | 0x01); 4503178676Ssam 4504178676Ssam /* set power and frequency of passband test tone */ 4505198429Srpaulo run_bbp_write(sc, 24, 0x00); 4506220728Sbschmidt for (ntries = 0; ntries < 100; ntries++) { 4507198429Srpaulo /* transmit test tone */ 4508198429Srpaulo run_bbp_write(sc, 25, 0x90); 4509198429Srpaulo run_delay(sc, 10); 4510198429Srpaulo /* read received power */ 4511220724Sbschmidt run_bbp_read(sc, 55, &bbp55_pb); 4512220724Sbschmidt if (bbp55_pb != 0) 4513198429Srpaulo break; 4514178676Ssam } 4515178676Ssam if (ntries == 100) 4516178676Ssam return ETIMEDOUT; 4517178676Ssam 4518178676Ssam /* set power and frequency of stopband test tone */ 4519198429Srpaulo run_bbp_write(sc, 24, 0x06); 4520178676Ssam for (ntries = 0; ntries < 100; ntries++) { 4521206477Sbschmidt /* transmit test tone */ 4522198429Srpaulo run_bbp_write(sc, 25, 0x90); 4523178676Ssam run_delay(sc, 10); 4524178676Ssam /* read received power */ 4525220728Sbschmidt run_bbp_read(sc, 55, &bbp55_sb); 4526178676Ssam 4527198429Srpaulo delta = bbp55_pb - bbp55_sb; 4528198429Srpaulo if (delta > target) 4529178676Ssam break; 4530198429Srpaulo 4531178676Ssam /* reprogram filter */ 4532178676Ssam rf24++; 4533178676Ssam run_rt3070_rf_write(sc, 24, rf24); 4534178676Ssam } 4535198429Srpaulo if (ntries < 100) { 4536178676Ssam if (rf24 != init) 4537178676Ssam rf24--; /* backtrack */ 4538178676Ssam *val = rf24; 4539198429Srpaulo run_rt3070_rf_write(sc, 24, rf24); 4540198429Srpaulo } 4541198429Srpaulo 4542178676Ssam /* restore initial state */ 4543198429Srpaulo run_bbp_write(sc, 24, 0x00); 4544210110Sbschmidt 4545178676Ssam /* disable baseband loopback mode */ 4546210110Sbschmidt run_rt3070_rf_read(sc, 22, &rf22); 4547210110Sbschmidt run_rt3070_rf_write(sc, 22, rf22 & ~0x01); 4548210110Sbschmidt 4549210110Sbschmidt return (0); 4550210110Sbschmidt} 4551210110Sbschmidt 4552198429Srpaulostatic void 4553201209Srpaulorun_rt3070_rf_setup(struct run_softc *sc) 4554201209Srpaulo{ 4555178676Ssam uint8_t bbp, rf; 4556220728Sbschmidt int i; 4557198429Srpaulo 4558198429Srpaulo if (sc->mac_ver == 0x3572) { 4559198429Srpaulo /* enable DC filter */ 4560198429Srpaulo if (sc->mac_rev >= 0x0201) 4561201209Srpaulo run_bbp_write(sc, 103, 0xc0); 4562220728Sbschmidt 4563198429Srpaulo run_bbp_read(sc, 138, &bbp); 4564198429Srpaulo if (sc->ntxchains == 1) 4565198429Srpaulo bbp |= 0x20; /* turn off DAC1 */ 4566198429Srpaulo if (sc->nrxchains == 1) 4567198429Srpaulo bbp &= ~0x02; /* turn off ADC1 */ 4568198429Srpaulo run_bbp_write(sc, 138, bbp); 4569198429Srpaulo 4570198429Srpaulo if (sc->mac_rev >= 0x0211) { 4571198429Srpaulo /* improve power consumption */ 4572198429Srpaulo run_bbp_read(sc, 31, &bbp); 4573206477Sbschmidt run_bbp_write(sc, 31, bbp & ~0x03); 4574198429Srpaulo } 4575198429Srpaulo 4576198429Srpaulo run_rt3070_rf_read(sc, 16, &rf); 4577198429Srpaulo rf = (rf & ~0x07) | sc->txmixgain_2ghz; 4578198429Srpaulo run_rt3070_rf_write(sc, 16, rf); 4579198429Srpaulo 4580198429Srpaulo } else if (sc->mac_ver == 0x3071) { 4581198429Srpaulo /* enable DC filter */ 4582198429Srpaulo if (sc->mac_rev >= 0x0201) 4583198429Srpaulo run_bbp_write(sc, 103, 0xc0); 4584198429Srpaulo 4585198429Srpaulo run_bbp_read(sc, 138, &bbp); 4586206477Sbschmidt if (sc->ntxchains == 1) 4587198429Srpaulo bbp |= 0x20; /* turn off DAC1 */ 4588198429Srpaulo if (sc->nrxchains == 1) 4589198429Srpaulo bbp &= ~0x02; /* turn off ADC1 */ 4590198429Srpaulo run_bbp_write(sc, 138, bbp); 4591198429Srpaulo 4592220866Sbschmidt if (sc->mac_rev >= 0x0211) { 4593198429Srpaulo /* improve power consumption */ 4594198429Srpaulo run_bbp_read(sc, 31, &bbp); 4595198429Srpaulo run_bbp_write(sc, 31, bbp & ~0x03); 4596198429Srpaulo } 4597198429Srpaulo 4598198429Srpaulo run_write(sc, RT2860_TX_SW_CFG1, 0); 4599198429Srpaulo if (sc->mac_rev < 0x0211) { 4600206477Sbschmidt run_write(sc, RT2860_TX_SW_CFG2, 4601198429Srpaulo sc->patch_dac ? 0x2c : 0x0f); 4602198429Srpaulo } else 4603198429Srpaulo run_write(sc, RT2860_TX_SW_CFG2, 0); 4604198429Srpaulo 4605198429Srpaulo } else if (sc->mac_ver == 0x3070) { 4606198429Srpaulo if (sc->mac_rev >= 0x0201) { 4607198429Srpaulo /* enable DC filter */ 4608201209Srpaulo run_bbp_write(sc, 103, 0xc0); 4609178676Ssam 4610201209Srpaulo /* improve power consumption */ 4611198429Srpaulo run_bbp_read(sc, 31, &bbp); 4612178676Ssam run_bbp_write(sc, 31, bbp & ~0x03); 4613178676Ssam } 4614198429Srpaulo 4615198429Srpaulo if (sc->mac_rev < 0x0211) { 4616178676Ssam run_write(sc, RT2860_TX_SW_CFG1, 0); 4617201209Srpaulo run_write(sc, RT2860_TX_SW_CFG2, 0x2c); 4618198429Srpaulo } else 4619198429Srpaulo run_write(sc, RT2860_TX_SW_CFG2, 0); 4620198429Srpaulo } 4621198429Srpaulo 4622198429Srpaulo /* initialize RF registers from ROM for >=RT3071*/ 4623198429Srpaulo if (sc->mac_ver >= 0x3071) { 4624198429Srpaulo for (i = 0; i < 10; i++) { 4625178676Ssam if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff) 4626178676Ssam continue; 4627178676Ssam run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val); 4628198429Srpaulo } 4629201209Srpaulo } 4630198429Srpaulo} 4631178676Ssam 4632178676Ssamstatic int 4633206477Sbschmidtrun_txrx_enable(struct run_softc *sc) 4634198429Srpaulo{ 4635198429Srpaulo struct ieee80211com *ic = sc->sc_ifp->if_l2com; 4636198429Srpaulo uint32_t tmp; 4637198429Srpaulo int error, ntries; 4638220723Sbschmidt 4639198429Srpaulo run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN); 4640206444Sbschmidt for (ntries = 0; ntries < 200; ntries++) { 4641206444Sbschmidt if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0) 4642198429Srpaulo return error; 4643198429Srpaulo if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 4644220866Sbschmidt break; 4645198429Srpaulo run_delay(sc, 50); 4646198429Srpaulo } 4647201209Srpaulo if (ntries == 200) 4648201209Srpaulo return ETIMEDOUT; 4649201209Srpaulo 4650201209Srpaulo run_delay(sc, 50); 4651201209Srpaulo 4652201209Srpaulo tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE; 4653201209Srpaulo run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 4654206444Sbschmidt 4655198429Srpaulo /* enable Rx bulk aggregation (set timeout and limit) */ 4656198429Srpaulo tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN | 4657198429Srpaulo RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2); 4658198429Srpaulo run_write(sc, RT2860_USB_DMA_CFG, tmp); 4659198429Srpaulo 4660198429Srpaulo /* set Rx filter */ 4661198429Srpaulo tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR; 4662198429Srpaulo if (ic->ic_opmode != IEEE80211_M_MONITOR) { 4663201209Srpaulo tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL | 4664198429Srpaulo RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK | 4665198429Srpaulo RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV | 4666198429Srpaulo RT2860_DROP_CFACK | RT2860_DROP_CFEND; 4667178676Ssam if (ic->ic_opmode == IEEE80211_M_STA) 4668198429Srpaulo tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL; 4669178676Ssam } 4670178676Ssam run_write(sc, RT2860_RX_FILTR_CFG, tmp); 4671206477Sbschmidt 4672178676Ssam run_write(sc, RT2860_MAC_SYS_CTRL, 4673178676Ssam RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 4674198429Srpaulo 4675178676Ssam return (0); 4676178676Ssam} 4677178676Ssam 4678178676Ssamstatic void 4679178676Ssamrun_init_locked(struct run_softc *sc) 4680178676Ssam{ 4681178676Ssam struct ifnet *ifp = sc->sc_ifp; 4682198429Srpaulo struct ieee80211com *ic = ifp->if_l2com; 4683178676Ssam uint32_t tmp; 4684178676Ssam uint8_t bbp1, bbp3; 4685178676Ssam int i; 4686178676Ssam int ridx; 4687178676Ssam int ntries; 4688178676Ssam 4689178676Ssam if (ic->ic_nrunning > 1) 4690178676Ssam return; 4691201209Srpaulo 4692178676Ssam run_stop(sc); 4693178676Ssam 4694178676Ssam if (run_load_microcode(sc) != 0) { 4695198439Srpaulo device_printf(sc->sc_dev, "could not load 8051 microcode\n"); 4696198429Srpaulo goto fail; 4697178676Ssam } 4698198429Srpaulo 4699220726Sbschmidt for (ntries = 0; ntries < 100; ntries++) { 4700178676Ssam if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0) 4701178676Ssam goto fail; 4702198429Srpaulo if (tmp != 0 && tmp != 0xffffffff) 4703178676Ssam break; 4704178676Ssam run_delay(sc, 10); 4705220634Sbschmidt } 4706178676Ssam if (ntries == 100) 4707198429Srpaulo goto fail; 4708178676Ssam 4709178676Ssam for (i = 0; i != RUN_EP_QUEUES; i++) 4710178676Ssam run_setup_tx_list(sc, &sc->sc_epq[i]); 4711178676Ssam 4712198429Srpaulo run_set_macaddr(sc, IF_LLADDR(ifp)); 4713178676Ssam 4714178676Ssam for (ntries = 0; ntries < 100; ntries++) { 4715198429Srpaulo if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 4716198429Srpaulo goto fail; 4717198429Srpaulo if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 4718198429Srpaulo break; 4719178676Ssam run_delay(sc, 10); 4720178676Ssam } 4721198429Srpaulo if (ntries == 100) { 4722178676Ssam device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); 4723178676Ssam goto fail; 4724198429Srpaulo } 4725198429Srpaulo tmp &= 0xff0; 4726198429Srpaulo tmp |= RT2860_TX_WB_DDONE; 4727198429Srpaulo run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 4728178676Ssam 4729178676Ssam /* turn off PME_OEN to solve high-current issue */ 4730198429Srpaulo run_read(sc, RT2860_SYS_CTRL, &tmp); 4731178676Ssam run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN); 4732178676Ssam 4733198429Srpaulo run_write(sc, RT2860_MAC_SYS_CTRL, 4734198429Srpaulo RT2860_BBP_HRST | RT2860_MAC_SRST); 4735198429Srpaulo run_write(sc, RT2860_USB_DMA_CFG, 0); 4736178676Ssam 4737178676Ssam if (run_reset(sc) != 0) { 4738178676Ssam device_printf(sc->sc_dev, "could not reset chipset\n"); 4739198429Srpaulo goto fail; 4740178676Ssam } 4741178676Ssam 4742198429Srpaulo run_write(sc, RT2860_MAC_SYS_CTRL, 0); 4743178676Ssam 4744198429Srpaulo /* init Tx power for all Tx rates (from EEPROM) */ 4745178676Ssam for (ridx = 0; ridx < 5; ridx++) { 4746178676Ssam if (sc->txpow20mhz[ridx] == 0xffffffff) 4747198429Srpaulo continue; 4748198429Srpaulo run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]); 4749198429Srpaulo } 4750178676Ssam 4751178676Ssam for (i = 0; i < N(rt2870_def_mac); i++) 4752178676Ssam run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val); 4753198429Srpaulo run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273); 4754178676Ssam run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344); 4755178676Ssam run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa); 4756198429Srpaulo 4757178676Ssam if (sc->mac_ver >= 0x3070) { 4758178676Ssam /* set delay of PA_PE assertion to 1us (unit of 0.25us) */ 4759198429Srpaulo run_write(sc, RT2860_TX_SW_CFG0, 4760178676Ssam 4 << RT2860_DLY_PAPE_EN_SHIFT); 4761178676Ssam } 4762220634Sbschmidt 4763178676Ssam /* wait while MAC is busy */ 4764198429Srpaulo for (ntries = 0; ntries < 100; ntries++) { 4765178676Ssam if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0) 4766178676Ssam goto fail; 4767178676Ssam if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY))) 4768178676Ssam break; 4769198429Srpaulo run_delay(sc, 10); 4770178676Ssam } 4771178676Ssam if (ntries == 100) 4772178676Ssam goto fail; 4773178676Ssam 4774178676Ssam /* clear Host to MCU mailbox */ 4775198429Srpaulo run_write(sc, RT2860_H2M_BBPAGENT, 0); 4776178676Ssam run_write(sc, RT2860_H2M_MAILBOX, 0); 4777178676Ssam run_delay(sc, 10); 4778198429Srpaulo 4779178676Ssam if (run_bbp_init(sc) != 0) { 4780198429Srpaulo device_printf(sc->sc_dev, "could not initialize BBP\n"); 4781198429Srpaulo goto fail; 4782178676Ssam } 4783178676Ssam 4784198429Srpaulo /* abort TSF synchronization */ 4785178676Ssam run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 4786198429Srpaulo tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 4787178676Ssam RT2860_TBTT_TIMER_EN); 4788178676Ssam run_write(sc, RT2860_BCN_TIME_CFG, tmp); 4789198429Srpaulo 4790178676Ssam /* clear RX WCID search table */ 4791178676Ssam run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512); 4792178676Ssam /* clear WCID attribute table */ 4793178676Ssam run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32); 4794178676Ssam 4795198429Srpaulo /* hostapd sets a key before init. So, don't clear it. */ 4796198429Srpaulo if (sc->cmdq_key_set != RUN_CMDQ_GO) { 4797220726Sbschmidt /* clear shared key table */ 4798198429Srpaulo run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32); 4799198429Srpaulo /* clear shared key mode */ 4800198429Srpaulo run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4); 4801178676Ssam } 4802178676Ssam 4803198429Srpaulo run_read(sc, RT2860_US_CYC_CNT, &tmp); 4804178676Ssam tmp = (tmp & ~0xff) | 0x1e; 4805178676Ssam run_write(sc, RT2860_US_CYC_CNT, tmp); 4806178676Ssam 4807178676Ssam if (sc->mac_rev != 0x0101) 4808178676Ssam run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f); 4809178676Ssam 4810198429Srpaulo run_write(sc, RT2860_WMM_TXOP0_CFG, 0); 4811198429Srpaulo run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96); 4812178676Ssam 4813178676Ssam /* write vendor-specific BBP values (from EEPROM) */ 4814178676Ssam for (i = 0; i < 10; i++) { 4815178676Ssam if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff) 4816178676Ssam continue; 4817178676Ssam run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val); 4818198429Srpaulo } 4819198429Srpaulo 4820178676Ssam /* select Main antenna for 1T1R devices */ 4821178676Ssam if (sc->rf_rev == RT3070_RF_3020) 4822206477Sbschmidt run_set_rx_antenna(sc, 0); 4823178676Ssam 4824178676Ssam /* send LEDs operating mode to microcontroller */ 4825178676Ssam (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]); 4826220729Sbschmidt (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]); 4827220729Sbschmidt (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]); 4828178676Ssam 4829178676Ssam if (sc->mac_ver >= 0x3070) 4830220729Sbschmidt run_rt3070_rf_init(sc); 4831178676Ssam 4832198429Srpaulo /* disable non-existing Rx chains */ 4833220726Sbschmidt run_bbp_read(sc, 3, &bbp3); 4834220726Sbschmidt bbp3 &= ~(1 << 3 | 1 << 4); 4835220726Sbschmidt if (sc->nrxchains == 2) 4836220726Sbschmidt bbp3 |= 1 << 3; 4837220726Sbschmidt else if (sc->nrxchains == 3) 4838220726Sbschmidt bbp3 |= 1 << 4; 4839198429Srpaulo run_bbp_write(sc, 3, bbp3); 4840220726Sbschmidt 4841220726Sbschmidt /* disable non-existing Tx chains */ 4842220726Sbschmidt run_bbp_read(sc, 1, &bbp1); 4843198429Srpaulo if (sc->ntxchains == 1) 4844220726Sbschmidt bbp1 &= ~(1 << 3 | 1 << 4); 4845220726Sbschmidt run_bbp_write(sc, 1, bbp1); 4846178676Ssam 4847202986Srpaulo if (sc->mac_ver >= 0x3070) 4848178676Ssam run_rt3070_rf_setup(sc); 4849198429Srpaulo 4850198429Srpaulo /* select default channel */ 4851198429Srpaulo run_set_chan(sc, ic->ic_curchan); 4852220729Sbschmidt 4853220729Sbschmidt /* setup initial protection mode */ 4854220729Sbschmidt run_updateprot_cb(ic); 4855220729Sbschmidt 4856220729Sbschmidt /* turn radio LED on */ 4857220729Sbschmidt run_set_leds(sc, RT2860_LED_RADIO); 4858220729Sbschmidt 4859220729Sbschmidt ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 4860220729Sbschmidt ifp->if_drv_flags |= IFF_DRV_RUNNING; 4861220729Sbschmidt sc->cmdq_run = RUN_CMDQ_GO; 4862220729Sbschmidt 4863220729Sbschmidt for (i = 0; i != RUN_N_XFER; i++) 4864220729Sbschmidt usbd_xfer_set_stall(sc->sc_xfer[i]); 4865220729Sbschmidt 4866220729Sbschmidt usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]); 4867178676Ssam 4868178676Ssam if (run_txrx_enable(sc) != 0) 4869198429Srpaulo goto fail; 4870198429Srpaulo 4871198429Srpaulo return; 4872198429Srpaulo 4873206477Sbschmidtfail: 4874198429Srpaulo run_stop(sc); 4875198429Srpaulo} 4876220723Sbschmidt 4877198429Srpaulostatic void 4878198429Srpaulorun_init(void *arg) 4879220721Sbschmidt{ 4880198429Srpaulo struct run_softc *sc = arg; 4881198429Srpaulo struct ifnet *ifp = sc->sc_ifp; 4882198429Srpaulo struct ieee80211com *ic = ifp->if_l2com; 4883198429Srpaulo 4884198429Srpaulo RUN_LOCK(sc); 4885198429Srpaulo run_init_locked(sc); 4886198429Srpaulo RUN_UNLOCK(sc); 4887198429Srpaulo 4888198429Srpaulo if (ifp->if_drv_flags & IFF_DRV_RUNNING) 4889198429Srpaulo ieee80211_start_all(ic); 4890198429Srpaulo} 4891198429Srpaulo 4892198429Srpaulostatic void 4893198429Srpaulorun_stop(void *arg) 4894198429Srpaulo{ 4895201209Srpaulo struct run_softc *sc = (struct run_softc *)arg; 4896220721Sbschmidt struct ifnet *ifp = sc->sc_ifp; 4897220721Sbschmidt uint32_t tmp; 4898198429Srpaulo int i; 4899198429Srpaulo int ntries; 4900198429Srpaulo 4901198429Srpaulo RUN_LOCK_ASSERT(sc, MA_OWNED); 4902198429Srpaulo 4903198429Srpaulo if (ifp->if_drv_flags & IFF_DRV_RUNNING) 4904198429Srpaulo run_set_leds(sc, 0); /* turn all LEDs off */ 4905198429Srpaulo 4906198429Srpaulo ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 4907198429Srpaulo 4908198429Srpaulo sc->ratectl_run = RUN_RATECTL_OFF; 4909198429Srpaulo sc->cmdq_run = sc->cmdq_key_set; 4910198429Srpaulo 4911198429Srpaulo RUN_UNLOCK(sc); 4912198429Srpaulo 4913198429Srpaulo for(i = 0; i < RUN_N_XFER; i++) 4914198429Srpaulo usbd_transfer_drain(sc->sc_xfer[i]); 4915198429Srpaulo 4916198429Srpaulo RUN_LOCK(sc); 4917198429Srpaulo 4918198429Srpaulo if (sc->rx_m != NULL) { 4919198429Srpaulo m_free(sc->rx_m); 4920198429Srpaulo sc->rx_m = NULL; 4921198429Srpaulo } 4922198429Srpaulo 4923198429Srpaulo /* disable Tx/Rx */ 4924206477Sbschmidt run_read(sc, RT2860_MAC_SYS_CTRL, &tmp); 4925220662Sbschmidt tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 4926220662Sbschmidt run_write(sc, RT2860_MAC_SYS_CTRL, tmp); 4927220662Sbschmidt 4928220662Sbschmidt /* wait for pending Tx to complete */ 4929220662Sbschmidt for (ntries = 0; ntries < 100; ntries++) { 4930220662Sbschmidt if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0) { 4931220662Sbschmidt DPRINTF("Cannot read Tx queue count\n"); 4932220662Sbschmidt break; 4933220662Sbschmidt } 4934220662Sbschmidt if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0) { 4935220662Sbschmidt DPRINTF("All Tx cleared\n"); 4936220662Sbschmidt break; 4937220662Sbschmidt } 4938220662Sbschmidt run_delay(sc, 10); 4939220891Sbschmidt } 4940220891Sbschmidt if (ntries >= 100) 4941220891Sbschmidt DPRINTF("There are still pending Tx\n"); 4942220891Sbschmidt run_delay(sc, 10); 4943220891Sbschmidt run_write(sc, RT2860_USB_DMA_CFG, 0); 4944220891Sbschmidt 4945220891Sbschmidt run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST); 4946220891Sbschmidt run_write(sc, RT2860_MAC_SYS_CTRL, 0); 4947220891Sbschmidt 4948220891Sbschmidt for (i = 0; i != RUN_EP_QUEUES; i++) 4949220891Sbschmidt run_unsetup_tx_list(sc, &sc->sc_epq[i]); 4950220891Sbschmidt 4951220891Sbschmidt return; 4952220891Sbschmidt} 4953220891Sbschmidt 4954220891Sbschmidtstatic void 4955220891Sbschmidtrun_delay(struct run_softc *sc, unsigned int ms) 4956220891Sbschmidt{ 4957220891Sbschmidt usb_pause_mtx(mtx_owned(&sc->sc_mtx) ? 4958220891Sbschmidt &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms)); 4959220891Sbschmidt} 4960220891Sbschmidt 4961220891Sbschmidtstatic device_method_t run_methods[] = { 4962220891Sbschmidt /* Device interface */ 4963220891Sbschmidt DEVMETHOD(device_probe, run_match), 4964220891Sbschmidt DEVMETHOD(device_attach, run_attach), 4965220891Sbschmidt DEVMETHOD(device_detach, run_detach), 4966220891Sbschmidt 4967220891Sbschmidt { 0, 0 } 4968220891Sbschmidt}; 4969220891Sbschmidt 4970220891Sbschmidtstatic driver_t run_driver = { 4971220891Sbschmidt .name = "run", 4972220891Sbschmidt .methods = run_methods, 4973220891Sbschmidt .size = sizeof(struct run_softc) 4974220891Sbschmidt}; 4975220891Sbschmidt 4976220891Sbschmidtstatic devclass_t run_devclass; 4977220891Sbschmidt 4978220891SbschmidtDRIVER_MODULE(run, uhub, run_driver, run_devclass, NULL, 0); 4979220891SbschmidtMODULE_DEPEND(run, wlan, 1, 1, 1); 4980220891SbschmidtMODULE_DEPEND(run, usb, 1, 1, 1); 4981220891SbschmidtMODULE_DEPEND(run, firmware, 1, 1, 1); 4982220891SbschmidtMODULE_VERSION(run, 1); 4983220891Sbschmidt