if_run.c revision 207554
1203134Sthompsa/* $FreeBSD: head/sys/dev/usb/wlan/if_run.c 207554 2010-05-03 07:32:50Z sobomax $ */ 2203134Sthompsa 3203134Sthompsa/*- 4205042Sthompsa * Copyright (c) 2008,2010 Damien Bergamini <damien.bergamini@free.fr> 5205042Sthompsa * ported to FreeBSD by Akinori Furukoshi <moonlightakkiy@yahoo.ca> 6205042Sthompsa * USB Consulting, Hans Petter Selasky <hselasky@freebsd.org> 7203134Sthompsa * 8203134Sthompsa * Permission to use, copy, modify, and distribute this software for any 9203134Sthompsa * purpose with or without fee is hereby granted, provided that the above 10203134Sthompsa * copyright notice and this permission notice appear in all copies. 11203134Sthompsa * 12203134Sthompsa * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13203134Sthompsa * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14203134Sthompsa * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15203134Sthompsa * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16203134Sthompsa * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17203134Sthompsa * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18203134Sthompsa * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19203134Sthompsa */ 20203134Sthompsa 21203134Sthompsa#include <sys/cdefs.h> 22203134Sthompsa__FBSDID("$FreeBSD: head/sys/dev/usb/wlan/if_run.c 207554 2010-05-03 07:32:50Z sobomax $"); 23203134Sthompsa 24203134Sthompsa/*- 25203134Sthompsa * Ralink Technology RT2700U/RT2800U/RT3000U chipset driver. 26203134Sthompsa * http://www.ralinktech.com/ 27203134Sthompsa */ 28203134Sthompsa 29203134Sthompsa#include <sys/param.h> 30203134Sthompsa#include <sys/sockio.h> 31203134Sthompsa#include <sys/sysctl.h> 32203134Sthompsa#include <sys/lock.h> 33203134Sthompsa#include <sys/mutex.h> 34203134Sthompsa#include <sys/mbuf.h> 35203134Sthompsa#include <sys/kernel.h> 36203134Sthompsa#include <sys/socket.h> 37203134Sthompsa#include <sys/systm.h> 38203134Sthompsa#include <sys/malloc.h> 39203134Sthompsa#include <sys/module.h> 40203134Sthompsa#include <sys/bus.h> 41203134Sthompsa#include <sys/endian.h> 42203134Sthompsa#include <sys/systm.h> 43203134Sthompsa#include <sys/linker.h> 44203134Sthompsa#include <sys/firmware.h> 45203134Sthompsa#include <sys/kdb.h> 46203134Sthompsa 47203134Sthompsa#include <machine/bus.h> 48203134Sthompsa#include <machine/resource.h> 49203134Sthompsa#include <sys/rman.h> 50203134Sthompsa 51203134Sthompsa#include <net/bpf.h> 52203134Sthompsa#include <net/if.h> 53203134Sthompsa#include <net/if_arp.h> 54203134Sthompsa#include <net/ethernet.h> 55203134Sthompsa#include <net/if_dl.h> 56203134Sthompsa#include <net/if_media.h> 57203134Sthompsa#include <net/if_types.h> 58203134Sthompsa 59203134Sthompsa#include <netinet/in.h> 60203134Sthompsa#include <netinet/in_systm.h> 61203134Sthompsa#include <netinet/in_var.h> 62203134Sthompsa#include <netinet/if_ether.h> 63203134Sthompsa#include <netinet/ip.h> 64203134Sthompsa 65203134Sthompsa#include <net80211/ieee80211_var.h> 66203134Sthompsa#include <net80211/ieee80211_regdomain.h> 67203134Sthompsa#include <net80211/ieee80211_radiotap.h> 68206358Srpaulo#include <net80211/ieee80211_ratectl.h> 69203134Sthompsa 70203134Sthompsa#include <dev/usb/usb.h> 71203134Sthompsa#include <dev/usb/usbdi.h> 72203134Sthompsa#include "usbdevs.h" 73203134Sthompsa 74203134Sthompsa#define USB_DEBUG_VAR run_debug 75203134Sthompsa#include <dev/usb/usb_debug.h> 76203134Sthompsa 77203134Sthompsa#include "if_runreg.h" /* shared with ral(4) */ 78203134Sthompsa#include "if_runvar.h" 79203134Sthompsa 80203134Sthompsa#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) 81203134Sthompsa 82207077Sthompsa#ifdef USB_DEBUG 83203134Sthompsa#define RUN_DEBUG 84203134Sthompsa#endif 85203134Sthompsa 86203134Sthompsa#ifdef RUN_DEBUG 87203134Sthompsaint run_debug = 0; 88203134SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, run, CTLFLAG_RW, 0, "USB run"); 89203134SthompsaSYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RW, &run_debug, 0, 90203134Sthompsa "run debug level"); 91203134Sthompsa#endif 92203134Sthompsa 93203134Sthompsa#define IEEE80211_HAS_ADDR4(wh) \ 94203134Sthompsa (((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) 95203134Sthompsa 96203134Sthompsastatic const struct usb_device_id run_devs[] = { 97203134Sthompsa { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT2770) }, 98203134Sthompsa { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT2870) }, 99203134Sthompsa { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT3070) }, 100203134Sthompsa { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT3071) }, 101203134Sthompsa { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT3072) }, 102203134Sthompsa { USB_VP(USB_VENDOR_ABOCOM2, USB_PRODUCT_ABOCOM2_RT2870_1) }, 103203134Sthompsa { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT2770) }, 104203134Sthompsa { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT2870_1) }, 105203134Sthompsa { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT2870_2) }, 106203134Sthompsa { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT2870_3) }, 107203134Sthompsa { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT2870_4) }, 108203134Sthompsa { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT2870_5) }, 109205042Sthompsa { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT3070) }, 110203134Sthompsa { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT3070_1) }, 111203134Sthompsa { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT3070_2) }, 112203134Sthompsa { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT3070_3) }, 113203134Sthompsa { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT3070_4) }, 114205042Sthompsa { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT3070_5) }, 115203134Sthompsa { USB_VP(USB_VENDOR_AIRTIES, USB_PRODUCT_AIRTIES_RT3070) }, 116205042Sthompsa { USB_VP(USB_VENDOR_ALLWIN, USB_PRODUCT_ALLWIN_RT2070) }, 117205042Sthompsa { USB_VP(USB_VENDOR_ALLWIN, USB_PRODUCT_ALLWIN_RT2770) }, 118205042Sthompsa { USB_VP(USB_VENDOR_ALLWIN, USB_PRODUCT_ALLWIN_RT2870) }, 119205042Sthompsa { USB_VP(USB_VENDOR_ALLWIN, USB_PRODUCT_ALLWIN_RT3070) }, 120205042Sthompsa { USB_VP(USB_VENDOR_ALLWIN, USB_PRODUCT_ALLWIN_RT3071) }, 121205042Sthompsa { USB_VP(USB_VENDOR_ALLWIN, USB_PRODUCT_ALLWIN_RT3072) }, 122205042Sthompsa { USB_VP(USB_VENDOR_ALLWIN, USB_PRODUCT_ALLWIN_RT3572) }, 123203134Sthompsa { USB_VP(USB_VENDOR_AMIGO, USB_PRODUCT_AMIGO_RT2870_1) }, 124203134Sthompsa { USB_VP(USB_VENDOR_AMIGO, USB_PRODUCT_AMIGO_RT2870_2) }, 125203134Sthompsa { USB_VP(USB_VENDOR_AMIT, USB_PRODUCT_AMIT_CGWLUSB2GNR) }, 126203134Sthompsa { USB_VP(USB_VENDOR_AMIT, USB_PRODUCT_AMIT_RT2870_1) }, 127203134Sthompsa { USB_VP(USB_VENDOR_AMIT2, USB_PRODUCT_AMIT2_RT2870) }, 128203134Sthompsa { USB_VP(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_RT2870_1) }, 129203134Sthompsa { USB_VP(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_RT2870_2) }, 130203134Sthompsa { USB_VP(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_RT2870_3) }, 131203134Sthompsa { USB_VP(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_RT2870_4) }, 132203134Sthompsa { USB_VP(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_RT2870_5) }, 133205042Sthompsa { USB_VP(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_USBN13) }, 134205042Sthompsa { USB_VP(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_RT3070_1) }, 135203134Sthompsa { USB_VP(USB_VENDOR_ASUS2, USB_PRODUCT_ASUS2_USBN11) }, 136203134Sthompsa { USB_VP(USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RT2870_1) }, 137203134Sthompsa { USB_VP(USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RT2870_2) }, 138203134Sthompsa { USB_VP(USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RT3070_1) }, 139203134Sthompsa { USB_VP(USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RT3070_2) }, 140203134Sthompsa { USB_VP(USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RT3070_3) }, 141203134Sthompsa { USB_VP(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D8053V3) }, 142203134Sthompsa { USB_VP(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D8055) }, 143203134Sthompsa { USB_VP(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F6D4050V1) }, 144203134Sthompsa { USB_VP(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_RT2870_1) }, 145203134Sthompsa { USB_VP(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_RT2870_2) }, 146205042Sthompsa { USB_VP(USB_VENDOR_CISCOLINKSYS2, USB_PRODUCT_CISCOLINKSYS2_RT3070) }, 147205042Sthompsa { USB_VP(USB_VENDOR_CISCOLINKSYS3, USB_PRODUCT_CISCOLINKSYS2_RT3070) }, 148203134Sthompsa { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_RT2870_1) }, 149203134Sthompsa { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_RT2870_2) }, 150203134Sthompsa { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_RT2870_3) }, 151203134Sthompsa { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_RT2870_4) }, 152203134Sthompsa { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_RT2870_5) }, 153203134Sthompsa { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_RT2870_6) }, 154203134Sthompsa { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_RT2870_7) }, 155203134Sthompsa { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_RT2870_8) }, 156205042Sthompsa { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_RT3070_1) }, 157205042Sthompsa { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_RT3070_2) }, 158203134Sthompsa { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_VIGORN61) }, 159203134Sthompsa { USB_VP(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_CGWLUSB300GNM) }, 160203134Sthompsa { USB_VP(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_RT2870_1) }, 161203134Sthompsa { USB_VP(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_RT2870_2) }, 162203134Sthompsa { USB_VP(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_RT2870_3) }, 163203134Sthompsa { USB_VP(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_RT3070) }, 164203134Sthompsa { USB_VP(USB_VENDOR_CYBERTAN, USB_PRODUCT_CYBERTAN_RT2870) }, 165203134Sthompsa { USB_VP(USB_VENDOR_DLINK, USB_PRODUCT_DLINK_RT2870) }, 166203134Sthompsa { USB_VP(USB_VENDOR_DLINK, USB_PRODUCT_DLINK_RT3072) }, 167203134Sthompsa { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DWA130) }, 168203134Sthompsa { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_RT2870_1) }, 169203134Sthompsa { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_RT2870_2) }, 170203134Sthompsa { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_RT3070_1) }, 171203134Sthompsa { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_RT3070_2) }, 172203134Sthompsa { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_RT3070_3) }, 173203134Sthompsa { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_RT3070_4) }, 174205042Sthompsa { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_RT3070_5) }, 175203134Sthompsa { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_RT3072) }, 176205042Sthompsa { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_RT3072_1) }, 177203134Sthompsa { USB_VP(USB_VENDOR_EDIMAX, USB_PRODUCT_EDIMAX_EW7717) }, 178203134Sthompsa { USB_VP(USB_VENDOR_EDIMAX, USB_PRODUCT_EDIMAX_EW7718) }, 179203134Sthompsa { USB_VP(USB_VENDOR_EDIMAX, USB_PRODUCT_EDIMAX_RT2870_1) }, 180203134Sthompsa { USB_VP(USB_VENDOR_ENCORE, USB_PRODUCT_ENCORE_RT3070_1) }, 181203134Sthompsa { USB_VP(USB_VENDOR_ENCORE, USB_PRODUCT_ENCORE_RT3070_2) }, 182203134Sthompsa { USB_VP(USB_VENDOR_ENCORE, USB_PRODUCT_ENCORE_RT3070_3) }, 183203134Sthompsa { USB_VP(USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNWB31N) }, 184203134Sthompsa { USB_VP(USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNWB32L) }, 185203134Sthompsa { USB_VP(USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_RT2870_1) }, 186203134Sthompsa { USB_VP(USB_VENDOR_GIGASET, USB_PRODUCT_GIGASET_RT3070_1) }, 187203134Sthompsa { USB_VP(USB_VENDOR_GIGASET, USB_PRODUCT_GIGASET_RT3070_2) }, 188203134Sthompsa { USB_VP(USB_VENDOR_GUILLEMOT, USB_PRODUCT_GUILLEMOT_HWNU300) }, 189203134Sthompsa { USB_VP(USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_HWUN2) }, 190203134Sthompsa { USB_VP(USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_RT2870_1) }, 191203134Sthompsa { USB_VP(USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_RT2870_2) }, 192203134Sthompsa { USB_VP(USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_RT3070) }, 193203134Sthompsa { USB_VP(USB_VENDOR_IODATA, USB_PRODUCT_IODATA_RT3072_1) }, 194203134Sthompsa { USB_VP(USB_VENDOR_IODATA, USB_PRODUCT_IODATA_RT3072_2) }, 195203134Sthompsa { USB_VP(USB_VENDOR_IODATA, USB_PRODUCT_IODATA_RT3072_3) }, 196203134Sthompsa { USB_VP(USB_VENDOR_IODATA, USB_PRODUCT_IODATA_RT3072_4) }, 197205042Sthompsa { USB_VP(USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_RT3070) }, 198203134Sthompsa { USB_VP(USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_WUSB100) }, 199203134Sthompsa { USB_VP(USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_WUSB54GCV3) }, 200203134Sthompsa { USB_VP(USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_WUSB600N) }, 201203134Sthompsa { USB_VP(USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_WUSB600NV2) }, 202203134Sthompsa { USB_VP(USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_RT2870_1) }, 203203134Sthompsa { USB_VP(USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_RT2870_2) }, 204203134Sthompsa { USB_VP(USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_RT2870_3) }, 205205042Sthompsa { USB_VP(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_RT2870_1) }, 206205042Sthompsa { USB_VP(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_RT2870_2) }, 207203134Sthompsa { USB_VP(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_WLIUCAG300N) }, 208203134Sthompsa { USB_VP(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_WLIUCG300N) }, 209203134Sthompsa { USB_VP(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_WLIUCGN) }, 210205042Sthompsa { USB_VP(USB_VENDOR_MOTOROLA4, USB_PRODUCT_MOTOROLA4_RT2770) }, 211205042Sthompsa { USB_VP(USB_VENDOR_MOTOROLA4, USB_PRODUCT_MOTOROLA4_RT3070) }, 212203134Sthompsa { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT3070_1) }, 213203134Sthompsa { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT3070_2) }, 214203134Sthompsa { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT3070_3) }, 215203134Sthompsa { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT3070_4) }, 216203134Sthompsa { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT3070_5) }, 217203134Sthompsa { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT3070_6) }, 218203134Sthompsa { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT3070_7) }, 219205042Sthompsa { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT3070_8) }, 220205042Sthompsa { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT3070_9) }, 221205042Sthompsa { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT3070_10) }, 222205042Sthompsa { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT3070_11) }, 223205042Sthompsa { USB_VP(USB_VENDOR_OVISLINK, USB_PRODUCT_OVISLINK_RT3072) }, 224203134Sthompsa { USB_VP(USB_VENDOR_PARA, USB_PRODUCT_PARA_RT3070) }, 225203134Sthompsa { USB_VP(USB_VENDOR_PEGATRON, USB_PRODUCT_PEGATRON_RT2870) }, 226203134Sthompsa { USB_VP(USB_VENDOR_PEGATRON, USB_PRODUCT_PEGATRON_RT3070) }, 227203134Sthompsa { USB_VP(USB_VENDOR_PEGATRON, USB_PRODUCT_PEGATRON_RT3070_2) }, 228205042Sthompsa { USB_VP(USB_VENDOR_PEGATRON, USB_PRODUCT_PEGATRON_RT3070_3) }, 229203134Sthompsa { USB_VP(USB_VENDOR_PHILIPS, USB_PRODUCT_PHILIPS_RT2870) }, 230203134Sthompsa { USB_VP(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUS300MINIS) }, 231203134Sthompsa { USB_VP(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUSMICRON) }, 232203134Sthompsa { USB_VP(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_RT2870) }, 233203134Sthompsa { USB_VP(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_RT3070) }, 234203134Sthompsa { USB_VP(USB_VENDOR_QCOM, USB_PRODUCT_QCOM_RT2870) }, 235203134Sthompsa { USB_VP(USB_VENDOR_QUANTA, USB_PRODUCT_QUANTA_RT3070) }, 236203134Sthompsa { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2070) }, 237203134Sthompsa { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2770) }, 238203134Sthompsa { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2870) }, 239203134Sthompsa { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT3070) }, 240203134Sthompsa { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT3071) }, 241203134Sthompsa { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT3072) }, 242205042Sthompsa { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT3370) }, 243203134Sthompsa { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT3572) }, 244205042Sthompsa { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT8070) }, 245203134Sthompsa { USB_VP(USB_VENDOR_SAMSUNG2, USB_PRODUCT_SAMSUNG2_RT2870_1) }, 246203134Sthompsa { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT2870_1) }, 247203134Sthompsa { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT2870_2) }, 248203134Sthompsa { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT2870_3) }, 249203134Sthompsa { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT2870_4) }, 250203134Sthompsa { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT3070) }, 251203134Sthompsa { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT3071) }, 252203134Sthompsa { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT3072_1) }, 253203134Sthompsa { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT3072_2) }, 254203134Sthompsa { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT3072_3) }, 255203134Sthompsa { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT3072_4) }, 256203134Sthompsa { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT3072_5) }, 257203134Sthompsa { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT2770) }, 258203134Sthompsa { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT2870_1) }, 259203134Sthompsa { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT2870_2) }, 260203134Sthompsa { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT2870_3) }, 261203134Sthompsa { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT2870_4) }, 262203134Sthompsa { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3070) }, 263203134Sthompsa { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3070_2) }, 264203134Sthompsa { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3070_3) }, 265203134Sthompsa { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3070_4) }, 266205042Sthompsa { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3071) }, 267203134Sthompsa { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3072_1) }, 268203134Sthompsa { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3072_2) }, 269203134Sthompsa { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3072_3) }, 270203134Sthompsa { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3072_4) }, 271203134Sthompsa { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3072_5) }, 272203134Sthompsa { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3072_6) }, 273203134Sthompsa { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_WL608) }, 274203134Sthompsa { USB_VP(USB_VENDOR_SPARKLAN, USB_PRODUCT_SPARKLAN_RT2870_1) }, 275203134Sthompsa { USB_VP(USB_VENDOR_SPARKLAN, USB_PRODUCT_SPARKLAN_RT3070) }, 276205042Sthompsa { USB_VP(USB_VENDOR_SWEEX2, USB_PRODUCT_SWEEX2_LW153) }, 277203134Sthompsa { USB_VP(USB_VENDOR_SWEEX2, USB_PRODUCT_SWEEX2_LW303) }, 278203134Sthompsa { USB_VP(USB_VENDOR_SWEEX2, USB_PRODUCT_SWEEX2_LW313) }, 279205042Sthompsa { USB_VP(USB_VENDOR_TOSHIBA, USB_PRODUCT_TOSHIBA_RT3070) }, 280203134Sthompsa { USB_VP(USB_VENDOR_UMEDIA, USB_PRODUCT_UMEDIA_RT2870_1) }, 281203134Sthompsa { USB_VP(USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_RT2870_1) }, 282203134Sthompsa { USB_VP(USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_RT2870_2) }, 283203134Sthompsa { USB_VP(USB_VENDOR_ZINWELL, USB_PRODUCT_ZINWELL_RT2870_1) }, 284203134Sthompsa { USB_VP(USB_VENDOR_ZINWELL, USB_PRODUCT_ZINWELL_RT2870_2) }, 285203134Sthompsa { USB_VP(USB_VENDOR_ZINWELL, USB_PRODUCT_ZINWELL_RT3070) }, 286203134Sthompsa { USB_VP(USB_VENDOR_ZINWELL, USB_PRODUCT_ZINWELL_RT3072_1) }, 287203134Sthompsa { USB_VP(USB_VENDOR_ZINWELL, USB_PRODUCT_ZINWELL_RT3072_2) }, 288203134Sthompsa { USB_VP(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_RT2870_1) }, 289205042Sthompsa { USB_VP(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_RT2870_2) }, 290203134Sthompsa}; 291203134Sthompsa 292203134SthompsaMODULE_DEPEND(run, wlan, 1, 1, 1); 293203134SthompsaMODULE_DEPEND(run, usb, 1, 1, 1); 294203134SthompsaMODULE_DEPEND(run, firmware, 1, 1, 1); 295203134Sthompsa 296203134Sthompsastatic device_probe_t run_match; 297203134Sthompsastatic device_attach_t run_attach; 298203134Sthompsastatic device_detach_t run_detach; 299203134Sthompsa 300203134Sthompsastatic usb_callback_t run_bulk_rx_callback; 301203134Sthompsastatic usb_callback_t run_bulk_tx_callback0; 302203134Sthompsastatic usb_callback_t run_bulk_tx_callback1; 303203134Sthompsastatic usb_callback_t run_bulk_tx_callback2; 304203134Sthompsastatic usb_callback_t run_bulk_tx_callback3; 305203134Sthompsastatic usb_callback_t run_bulk_tx_callback4; 306203134Sthompsastatic usb_callback_t run_bulk_tx_callback5; 307203134Sthompsa 308203134Sthompsastatic void run_bulk_tx_callbackN(struct usb_xfer *xfer, 309203134Sthompsa usb_error_t error, unsigned int index); 310203134Sthompsastatic struct ieee80211vap *run_vap_create(struct ieee80211com *, 311203134Sthompsa const char name[IFNAMSIZ], int unit, int opmode, int flags, 312203134Sthompsa const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t 313203134Sthompsa mac[IEEE80211_ADDR_LEN]); 314203134Sthompsastatic void run_vap_delete(struct ieee80211vap *); 315203134Sthompsastatic void run_setup_tx_list(struct run_softc *, 316203134Sthompsa struct run_endpoint_queue *); 317203134Sthompsastatic void run_unsetup_tx_list(struct run_softc *, 318203134Sthompsa struct run_endpoint_queue *); 319203134Sthompsastatic int run_load_microcode(struct run_softc *); 320203134Sthompsastatic int run_reset(struct run_softc *); 321203134Sthompsastatic usb_error_t run_do_request(struct run_softc *, 322203134Sthompsa struct usb_device_request *, void *); 323203134Sthompsastatic int run_read(struct run_softc *, uint16_t, uint32_t *); 324203134Sthompsastatic int run_read_region_1(struct run_softc *, uint16_t, uint8_t *, int); 325203134Sthompsastatic int run_write_2(struct run_softc *, uint16_t, uint16_t); 326203134Sthompsastatic int run_write(struct run_softc *, uint16_t, uint32_t); 327203134Sthompsastatic int run_write_region_1(struct run_softc *, uint16_t, 328203134Sthompsa const uint8_t *, int); 329203134Sthompsastatic int run_set_region_4(struct run_softc *, uint16_t, uint32_t, int); 330203134Sthompsastatic int run_efuse_read_2(struct run_softc *, uint16_t, uint16_t *); 331203134Sthompsastatic int run_eeprom_read_2(struct run_softc *, uint16_t, uint16_t *); 332203134Sthompsastatic int run_rt2870_rf_write(struct run_softc *, uint8_t, uint32_t); 333203134Sthompsastatic int run_rt3070_rf_read(struct run_softc *, uint8_t, uint8_t *); 334203134Sthompsastatic int run_rt3070_rf_write(struct run_softc *, uint8_t, uint8_t); 335203134Sthompsastatic int run_bbp_read(struct run_softc *, uint8_t, uint8_t *); 336203134Sthompsastatic int run_bbp_write(struct run_softc *, uint8_t, uint8_t); 337203134Sthompsastatic int run_mcu_cmd(struct run_softc *, uint8_t, uint16_t); 338203134Sthompsastatic const char *run_get_rf(int); 339203134Sthompsastatic int run_read_eeprom(struct run_softc *); 340203134Sthompsastatic struct ieee80211_node *run_node_alloc(struct ieee80211vap *, 341203134Sthompsa const uint8_t mac[IEEE80211_ADDR_LEN]); 342203134Sthompsastatic int run_media_change(struct ifnet *); 343203134Sthompsastatic int run_newstate(struct ieee80211vap *, enum ieee80211_state, int); 344203134Sthompsastatic int run_wme_update(struct ieee80211com *); 345203134Sthompsastatic void run_wme_update_cb(void *, int); 346203134Sthompsastatic void run_key_update_begin(struct ieee80211vap *); 347203134Sthompsastatic void run_key_update_end(struct ieee80211vap *); 348203134Sthompsastatic int run_key_set(struct ieee80211vap *, const struct ieee80211_key *, 349203134Sthompsa const uint8_t mac[IEEE80211_ADDR_LEN]); 350203134Sthompsastatic int run_key_delete(struct ieee80211vap *, 351203134Sthompsa const struct ieee80211_key *); 352206358Srpaulostatic void run_ratectl_start(struct run_softc *, struct ieee80211_node *); 353206358Srpaulostatic void run_ratectl_to(void *); 354206358Srpaulostatic void run_ratectl_cb(void *, int); 355203134Sthompsastatic void run_iter_func(void *, struct ieee80211_node *); 356203134Sthompsastatic void run_newassoc(struct ieee80211_node *, int); 357203134Sthompsastatic void run_rx_frame(struct run_softc *, struct mbuf *, uint32_t); 358203134Sthompsastatic void run_tx_free(struct run_endpoint_queue *pq, 359203134Sthompsa struct run_tx_data *, int); 360203134Sthompsastatic void run_set_tx_desc(struct run_softc *, struct run_tx_data *, 361203134Sthompsa uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t); 362203134Sthompsastatic int run_tx(struct run_softc *, struct mbuf *, 363203134Sthompsa struct ieee80211_node *); 364203134Sthompsastatic int run_tx_mgt(struct run_softc *, struct mbuf *, 365203134Sthompsa struct ieee80211_node *); 366203134Sthompsastatic int run_sendprot(struct run_softc *, const struct mbuf *, 367203134Sthompsa struct ieee80211_node *, int, int); 368203134Sthompsastatic int run_tx_param(struct run_softc *, struct mbuf *, 369203134Sthompsa struct ieee80211_node *, 370203134Sthompsa const struct ieee80211_bpf_params *); 371203134Sthompsastatic int run_raw_xmit(struct ieee80211_node *, struct mbuf *, 372203134Sthompsa const struct ieee80211_bpf_params *); 373203134Sthompsastatic void run_start(struct ifnet *); 374203134Sthompsastatic int run_ioctl(struct ifnet *, u_long, caddr_t); 375205042Sthompsastatic void run_set_agc(struct run_softc *, uint8_t); 376203134Sthompsastatic void run_select_chan_group(struct run_softc *, int); 377203134Sthompsastatic void run_set_rx_antenna(struct run_softc *, int); 378203134Sthompsastatic void run_rt2870_set_chan(struct run_softc *, u_int); 379203134Sthompsastatic void run_rt3070_set_chan(struct run_softc *, u_int); 380205042Sthompsastatic void run_rt3572_set_chan(struct run_softc *, u_int); 381203134Sthompsastatic int run_set_chan(struct run_softc *, struct ieee80211_channel *); 382203134Sthompsastatic void run_set_channel(struct ieee80211com *); 383203134Sthompsastatic void run_scan_start(struct ieee80211com *); 384203134Sthompsastatic void run_scan_end(struct ieee80211com *); 385203134Sthompsastatic uint8_t run_rate2mcs(uint8_t); 386203134Sthompsastatic void run_update_beacon(struct ieee80211vap *, int); 387203134Sthompsastatic void run_update_beacon_locked(struct ieee80211vap *, int); 388203134Sthompsastatic void run_updateprot(struct ieee80211com *); 389203134Sthompsastatic void run_usb_timeout_cb(void *, int); 390203134Sthompsastatic void run_reset_livelock(struct run_softc *); 391203134Sthompsastatic void run_enable_tsf_sync(struct run_softc *); 392203134Sthompsastatic void run_enable_mrr(struct run_softc *); 393203134Sthompsastatic void run_set_txpreamble(struct run_softc *); 394203134Sthompsastatic void run_set_basicrates(struct run_softc *); 395203134Sthompsastatic void run_set_leds(struct run_softc *, uint16_t); 396203134Sthompsastatic void run_set_bssid(struct run_softc *, const uint8_t *); 397203134Sthompsastatic void run_set_macaddr(struct run_softc *, const uint8_t *); 398203134Sthompsastatic void run_updateslot(struct ifnet *); 399203134Sthompsastatic int8_t run_rssi2dbm(struct run_softc *, uint8_t, uint8_t); 400203134Sthompsastatic void run_update_promisc_locked(struct ifnet *); 401203134Sthompsastatic void run_update_promisc(struct ifnet *); 402203134Sthompsastatic int run_bbp_init(struct run_softc *); 403203134Sthompsastatic int run_rt3070_rf_init(struct run_softc *); 404203134Sthompsastatic int run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t, 405203134Sthompsa uint8_t *); 406205042Sthompsastatic void run_rt3070_rf_setup(struct run_softc *); 407203134Sthompsastatic int run_txrx_enable(struct run_softc *); 408203134Sthompsastatic void run_init(void *); 409203134Sthompsastatic void run_init_locked(struct run_softc *); 410203134Sthompsastatic void run_stop(void *); 411203134Sthompsastatic void run_delay(struct run_softc *, unsigned int); 412203134Sthompsa 413203134Sthompsastatic const struct { 414203134Sthompsa uint32_t reg; 415203134Sthompsa uint32_t val; 416203134Sthompsa} rt2870_def_mac[] = { 417203134Sthompsa RT2870_DEF_MAC 418203134Sthompsa}; 419203134Sthompsa 420203134Sthompsastatic const struct { 421203134Sthompsa uint8_t reg; 422203134Sthompsa uint8_t val; 423203134Sthompsa} rt2860_def_bbp[] = { 424203134Sthompsa RT2860_DEF_BBP 425203134Sthompsa}; 426203134Sthompsa 427203134Sthompsastatic const struct rfprog { 428203134Sthompsa uint8_t chan; 429203134Sthompsa uint32_t r1, r2, r3, r4; 430203134Sthompsa} rt2860_rf2850[] = { 431203134Sthompsa RT2860_RF2850 432203134Sthompsa}; 433203134Sthompsa 434203134Sthompsastruct { 435203134Sthompsa uint8_t n, r, k; 436205042Sthompsa} rt3070_freqs[] = { 437205042Sthompsa RT3070_RF3052 438203134Sthompsa}; 439203134Sthompsa 440203134Sthompsastatic const struct { 441203134Sthompsa uint8_t reg; 442203134Sthompsa uint8_t val; 443203134Sthompsa} rt3070_def_rf[] = { 444203134Sthompsa RT3070_DEF_RF 445205042Sthompsa},rt3572_def_rf[] = { 446205042Sthompsa RT3572_DEF_RF 447203134Sthompsa}; 448203134Sthompsa 449203134Sthompsastatic const struct usb_config run_config[RUN_N_XFER] = { 450203134Sthompsa [RUN_BULK_TX_BE] = { 451203134Sthompsa .type = UE_BULK, 452203134Sthompsa .endpoint = UE_ADDR_ANY, 453203134Sthompsa .ep_index = 0, 454203134Sthompsa .direction = UE_DIR_OUT, 455203134Sthompsa .bufsize = RUN_MAX_TXSZ, 456203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 457203134Sthompsa .callback = run_bulk_tx_callback0, 458203134Sthompsa .timeout = 5000, /* ms */ 459203134Sthompsa }, 460203134Sthompsa [RUN_BULK_TX_BK] = { 461203134Sthompsa .type = UE_BULK, 462203134Sthompsa .endpoint = UE_ADDR_ANY, 463203134Sthompsa .direction = UE_DIR_OUT, 464203134Sthompsa .ep_index = 1, 465203134Sthompsa .bufsize = RUN_MAX_TXSZ, 466203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 467203134Sthompsa .callback = run_bulk_tx_callback1, 468203134Sthompsa .timeout = 5000, /* ms */ 469203134Sthompsa }, 470203134Sthompsa [RUN_BULK_TX_VI] = { 471203134Sthompsa .type = UE_BULK, 472203134Sthompsa .endpoint = UE_ADDR_ANY, 473203134Sthompsa .direction = UE_DIR_OUT, 474203134Sthompsa .ep_index = 2, 475203134Sthompsa .bufsize = RUN_MAX_TXSZ, 476203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 477203134Sthompsa .callback = run_bulk_tx_callback2, 478203134Sthompsa .timeout = 5000, /* ms */ 479203134Sthompsa }, 480203134Sthompsa [RUN_BULK_TX_VO] = { 481203134Sthompsa .type = UE_BULK, 482203134Sthompsa .endpoint = UE_ADDR_ANY, 483203134Sthompsa .direction = UE_DIR_OUT, 484203134Sthompsa .ep_index = 3, 485203134Sthompsa .bufsize = RUN_MAX_TXSZ, 486203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 487203134Sthompsa .callback = run_bulk_tx_callback3, 488203134Sthompsa .timeout = 5000, /* ms */ 489203134Sthompsa }, 490203134Sthompsa [RUN_BULK_TX_HCCA] = { 491203134Sthompsa .type = UE_BULK, 492203134Sthompsa .endpoint = UE_ADDR_ANY, 493203134Sthompsa .direction = UE_DIR_OUT, 494203134Sthompsa .ep_index = 4, 495203134Sthompsa .bufsize = RUN_MAX_TXSZ, 496203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 497203134Sthompsa .callback = run_bulk_tx_callback4, 498203134Sthompsa .timeout = 5000, /* ms */ 499203134Sthompsa }, 500203134Sthompsa [RUN_BULK_TX_PRIO] = { 501203134Sthompsa .type = UE_BULK, 502203134Sthompsa .endpoint = UE_ADDR_ANY, 503203134Sthompsa .direction = UE_DIR_OUT, 504203134Sthompsa .ep_index = 5, 505203134Sthompsa .bufsize = RUN_MAX_TXSZ, 506203134Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 507203134Sthompsa .callback = run_bulk_tx_callback5, 508203134Sthompsa .timeout = 5000, /* ms */ 509203134Sthompsa }, 510203134Sthompsa [RUN_BULK_RX] = { 511203134Sthompsa .type = UE_BULK, 512203134Sthompsa .endpoint = UE_ADDR_ANY, 513203134Sthompsa .direction = UE_DIR_IN, 514203134Sthompsa .bufsize = RUN_MAX_RXSZ, 515203134Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 516203134Sthompsa .callback = run_bulk_rx_callback, 517203134Sthompsa } 518203134Sthompsa}; 519203134Sthompsa 520203134Sthompsaint 521203134Sthompsarun_match(device_t self) 522203134Sthompsa{ 523203134Sthompsa struct usb_attach_arg *uaa = device_get_ivars(self); 524203134Sthompsa 525203134Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 526203134Sthompsa return (ENXIO); 527203134Sthompsa if (uaa->info.bConfigIndex != 0) 528203134Sthompsa return (ENXIO); 529203134Sthompsa if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX) 530203134Sthompsa return (ENXIO); 531203134Sthompsa 532203134Sthompsa return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa)); 533203134Sthompsa} 534203134Sthompsa 535203134Sthompsastatic int 536203134Sthompsarun_attach(device_t self) 537203134Sthompsa{ 538203134Sthompsa struct run_softc *sc = device_get_softc(self); 539203134Sthompsa struct usb_attach_arg *uaa = device_get_ivars(self); 540203134Sthompsa struct ieee80211com *ic; 541203134Sthompsa struct ifnet *ifp; 542205042Sthompsa uint32_t ver; 543203134Sthompsa int i, ntries, error; 544203134Sthompsa uint8_t iface_index, bands; 545203134Sthompsa 546203134Sthompsa device_set_usb_desc(self); 547203134Sthompsa sc->sc_udev = uaa->device; 548203134Sthompsa sc->sc_dev = self; 549203134Sthompsa 550203134Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), 551203134Sthompsa MTX_NETWORK_LOCK, MTX_DEF); 552203134Sthompsa 553203134Sthompsa iface_index = RT2860_IFACE_INDEX; 554203134Sthompsa error = usbd_transfer_setup(uaa->device, &iface_index, 555203134Sthompsa sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx); 556203134Sthompsa if (error) { 557205042Sthompsa device_printf(self, "could not allocate USB transfers, " 558203134Sthompsa "err=%s\n", usbd_errstr(error)); 559203134Sthompsa goto detach; 560203134Sthompsa } 561203134Sthompsa 562203134Sthompsa RUN_LOCK(sc); 563203134Sthompsa 564203134Sthompsa /* wait for the chip to settle */ 565203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 566205042Sthompsa if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0){ 567203134Sthompsa RUN_UNLOCK(sc); 568203134Sthompsa goto detach; 569203134Sthompsa } 570205042Sthompsa if (ver != 0 && ver != 0xffffffff) 571203134Sthompsa break; 572203134Sthompsa run_delay(sc, 10); 573203134Sthompsa } 574203134Sthompsa if (ntries == 100) { 575203138Sthompsa device_printf(sc->sc_dev, 576203138Sthompsa "timeout waiting for NIC to initialize\n"); 577203134Sthompsa RUN_UNLOCK(sc); 578203134Sthompsa goto detach; 579203134Sthompsa } 580205042Sthompsa sc->mac_ver = ver >> 16; 581205042Sthompsa sc->mac_rev = ver & 0xffff; 582203134Sthompsa 583203134Sthompsa /* retrieve RF rev. no and various other things from EEPROM */ 584203134Sthompsa run_read_eeprom(sc); 585203134Sthompsa 586203138Sthompsa device_printf(sc->sc_dev, 587203138Sthompsa "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n", 588205042Sthompsa sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev), 589203138Sthompsa sc->ntxchains, sc->nrxchains, ether_sprintf(sc->sc_bssid)); 590203134Sthompsa 591203134Sthompsa if ((error = run_load_microcode(sc)) != 0) { 592203138Sthompsa device_printf(sc->sc_dev, "could not load 8051 microcode\n"); 593203134Sthompsa RUN_UNLOCK(sc); 594203134Sthompsa goto detach; 595203134Sthompsa } 596203134Sthompsa 597203134Sthompsa RUN_UNLOCK(sc); 598203134Sthompsa 599203134Sthompsa ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); 600203134Sthompsa if(ifp == NULL){ 601203138Sthompsa device_printf(sc->sc_dev, "can not if_alloc()\n"); 602203134Sthompsa goto detach; 603203134Sthompsa } 604203134Sthompsa ic = ifp->if_l2com; 605203134Sthompsa 606203134Sthompsa ifp->if_softc = sc; 607203134Sthompsa if_initname(ifp, "run", device_get_unit(sc->sc_dev)); 608203134Sthompsa ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 609203134Sthompsa ifp->if_init = run_init; 610203134Sthompsa ifp->if_ioctl = run_ioctl; 611203134Sthompsa ifp->if_start = run_start; 612207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 613207554Ssobomax ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 614203134Sthompsa IFQ_SET_READY(&ifp->if_snd); 615203134Sthompsa 616203134Sthompsa ic->ic_ifp = ifp; 617203134Sthompsa ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 618203134Sthompsa ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 619203134Sthompsa#if 0 620203134Sthompsa ic->ic_state = IEEE80211_S_INIT; 621203134Sthompsa#endif 622203134Sthompsa /* set device capabilities */ 623203134Sthompsa ic->ic_caps = 624203134Sthompsa IEEE80211_C_STA | /* station mode supported */ 625203134Sthompsa IEEE80211_C_MONITOR | /* monitor mode supported */ 626203134Sthompsa IEEE80211_C_IBSS | 627203134Sthompsa IEEE80211_C_HOSTAP | 628203134Sthompsa IEEE80211_C_SHPREAMBLE | /* short preamble supported */ 629203134Sthompsa IEEE80211_C_SHSLOT | /* short slot time supported */ 630203134Sthompsa IEEE80211_C_WME | /* WME */ 631203134Sthompsa IEEE80211_C_WPA; /* WPA1|WPA2(RSN) */ 632203134Sthompsa 633203134Sthompsa ic->ic_cryptocaps = 634203134Sthompsa IEEE80211_CRYPTO_WEP | 635203134Sthompsa IEEE80211_CRYPTO_AES_CCM | 636203134Sthompsa IEEE80211_CRYPTO_TKIPMIC | 637203134Sthompsa IEEE80211_CRYPTO_TKIP; 638203134Sthompsa 639203134Sthompsa ic->ic_flags |= IEEE80211_F_DATAPAD; 640203134Sthompsa ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; 641203134Sthompsa 642203134Sthompsa bands = 0; 643203134Sthompsa setbit(&bands, IEEE80211_MODE_11B); 644203134Sthompsa setbit(&bands, IEEE80211_MODE_11G); 645203134Sthompsa ieee80211_init_channels(ic, NULL, &bands); 646203134Sthompsa 647203134Sthompsa /* 648203134Sthompsa * Do this by own because h/w supports 649203134Sthompsa * more channels than ieee80211_init_channels() 650203134Sthompsa */ 651205042Sthompsa if (sc->rf_rev == RT2860_RF_2750 || 652205042Sthompsa sc->rf_rev == RT2860_RF_2850 || 653205042Sthompsa sc->rf_rev == RT3070_RF_3052) { 654203134Sthompsa /* set supported .11a rates */ 655203134Sthompsa for (i = 14; i < nitems(rt2860_rf2850); i++) { 656203134Sthompsa uint8_t chan = rt2860_rf2850[i].chan; 657203134Sthompsa ic->ic_channels[ic->ic_nchans].ic_freq = 658203134Sthompsa ieee80211_ieee2mhz(chan, IEEE80211_CHAN_A); 659203134Sthompsa ic->ic_channels[ic->ic_nchans].ic_ieee = chan; 660203134Sthompsa ic->ic_channels[ic->ic_nchans].ic_flags = IEEE80211_CHAN_A; 661203134Sthompsa ic->ic_channels[ic->ic_nchans].ic_extieee = 0; 662203134Sthompsa ic->ic_nchans++; 663203134Sthompsa } 664203134Sthompsa } 665203134Sthompsa 666203134Sthompsa ieee80211_ifattach(ic, sc->sc_bssid); 667203134Sthompsa 668203134Sthompsa ic->ic_scan_start = run_scan_start; 669203134Sthompsa ic->ic_scan_end = run_scan_end; 670203134Sthompsa ic->ic_set_channel = run_set_channel; 671203134Sthompsa ic->ic_node_alloc = run_node_alloc; 672203134Sthompsa ic->ic_newassoc = run_newassoc; 673203134Sthompsa //ic->ic_updateslot = run_updateslot; 674203134Sthompsa ic->ic_wme.wme_update = run_wme_update; 675203134Sthompsa ic->ic_raw_xmit = run_raw_xmit; 676203134Sthompsa ic->ic_update_promisc = run_update_promisc; 677203134Sthompsa 678203134Sthompsa ic->ic_vap_create = run_vap_create; 679203134Sthompsa ic->ic_vap_delete = run_vap_delete; 680203134Sthompsa 681203134Sthompsa ieee80211_radiotap_attach(ic, 682203134Sthompsa &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), 683203134Sthompsa RUN_TX_RADIOTAP_PRESENT, 684203134Sthompsa &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 685203134Sthompsa RUN_RX_RADIOTAP_PRESENT); 686203134Sthompsa 687203134Sthompsa if (bootverbose) 688203134Sthompsa ieee80211_announce(ic); 689203134Sthompsa 690203134Sthompsa return 0; 691203134Sthompsa 692203134Sthompsadetach: 693203134Sthompsa run_detach(self); 694203134Sthompsa return(ENXIO); 695203134Sthompsa} 696203134Sthompsa 697203134Sthompsastatic int 698203134Sthompsarun_detach(device_t self) 699203134Sthompsa{ 700203134Sthompsa struct run_softc *sc = device_get_softc(self); 701203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 702203134Sthompsa struct ieee80211com *ic; 703203134Sthompsa int i; 704203134Sthompsa 705203134Sthompsa /* stop all USB transfers */ 706203134Sthompsa usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER); 707203134Sthompsa 708203134Sthompsa RUN_LOCK(sc); 709203134Sthompsa /* free TX list, if any */ 710203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 711203134Sthompsa run_unsetup_tx_list(sc, &sc->sc_epq[i]); 712203134Sthompsa RUN_UNLOCK(sc); 713203134Sthompsa 714203134Sthompsa if (ifp) { 715203134Sthompsa ic = ifp->if_l2com; 716203134Sthompsa ieee80211_ifdetach(ic); 717203134Sthompsa if_free(ifp); 718203134Sthompsa } 719203134Sthompsa 720203134Sthompsa mtx_destroy(&sc->sc_mtx); 721203134Sthompsa 722203134Sthompsa return (0); 723203134Sthompsa} 724203134Sthompsa 725203134Sthompsastatic struct ieee80211vap * 726203134Sthompsarun_vap_create(struct ieee80211com *ic, 727203134Sthompsa const char name[IFNAMSIZ], int unit, int opmode, int flags, 728203134Sthompsa const uint8_t bssid[IEEE80211_ADDR_LEN], 729203134Sthompsa const uint8_t mac[IEEE80211_ADDR_LEN]) 730203134Sthompsa{ 731203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 732203134Sthompsa struct run_vap *rvp; 733203134Sthompsa struct ieee80211vap *vap; 734203134Sthompsa 735203134Sthompsa if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ 736203134Sthompsa return NULL; 737203134Sthompsa sc->sc_rvp = rvp = (struct run_vap *) malloc(sizeof(struct run_vap), 738203134Sthompsa M_80211_VAP, M_NOWAIT | M_ZERO); 739203134Sthompsa if (rvp == NULL) 740203134Sthompsa return NULL; 741203134Sthompsa vap = &rvp->vap; 742203134Sthompsa /* enable s/w bmiss handling for sta mode */ 743203134Sthompsa ieee80211_vap_setup(ic, vap, name, unit, opmode, 744203134Sthompsa flags | IEEE80211_CLONE_NOBEACONS, bssid, mac); 745203134Sthompsa 746203134Sthompsa vap->iv_key_update_begin = run_key_update_begin; 747203134Sthompsa vap->iv_key_update_end = run_key_update_end; 748203134Sthompsa vap->iv_key_delete = run_key_delete; 749203134Sthompsa vap->iv_key_set = run_key_set; 750203134Sthompsa vap->iv_update_beacon = run_update_beacon; 751203134Sthompsa 752203134Sthompsa /* override state transition machine */ 753203134Sthompsa rvp->newstate = vap->iv_newstate; 754203134Sthompsa vap->iv_newstate = run_newstate; 755203134Sthompsa 756206358Srpaulo TASK_INIT(&rvp->ratectl_task, 0, run_ratectl_cb, rvp); 757203134Sthompsa TASK_INIT(&sc->wme_task, 0, run_wme_update_cb, ic); 758203134Sthompsa TASK_INIT(&sc->usb_timeout_task, 0, run_usb_timeout_cb, sc); 759206358Srpaulo callout_init((struct callout *)&rvp->ratectl_ch, 1); 760206358Srpaulo ieee80211_ratectl_init(vap); 761206358Srpaulo ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */); 762203134Sthompsa 763203134Sthompsa /* complete setup */ 764203134Sthompsa ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status); 765203134Sthompsa ic->ic_opmode = opmode; 766203134Sthompsa return vap; 767203134Sthompsa} 768203134Sthompsa 769203134Sthompsastatic void 770203134Sthompsarun_vap_delete(struct ieee80211vap *vap) 771203134Sthompsa{ 772203134Sthompsa struct run_vap *rvp = RUN_VAP(vap); 773203134Sthompsa struct ifnet *ifp; 774203134Sthompsa struct ieee80211com *ic; 775203134Sthompsa struct run_softc *sc; 776203134Sthompsa 777203134Sthompsa if(vap == NULL) 778203134Sthompsa return; 779203134Sthompsa 780203134Sthompsa ic = vap->iv_ic; 781203134Sthompsa ifp = ic->ic_ifp; 782203134Sthompsa 783203134Sthompsa sc = ifp->if_softc; 784203134Sthompsa 785205042Sthompsa RUN_LOCK(sc); 786206358Srpaulo sc->sc_rvp->ratectl_run = RUN_RATECTL_OFF; 787205042Sthompsa RUN_UNLOCK(sc); 788203134Sthompsa 789205042Sthompsa /* drain them all */ 790206358Srpaulo usb_callout_drain(&sc->sc_rvp->ratectl_ch); 791206358Srpaulo ieee80211_draintask(ic, &sc->sc_rvp->ratectl_task); 792205042Sthompsa ieee80211_draintask(ic, &sc->wme_task); 793205042Sthompsa ieee80211_draintask(ic, &sc->usb_timeout_task); 794205042Sthompsa 795206358Srpaulo ieee80211_ratectl_deinit(vap); 796203134Sthompsa ieee80211_vap_detach(vap); 797203134Sthompsa free(rvp, M_80211_VAP); 798203134Sthompsa sc->sc_rvp = NULL; 799203134Sthompsa} 800203134Sthompsa 801203134Sthompsastatic void 802203134Sthompsarun_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq) 803203134Sthompsa{ 804203134Sthompsa struct run_tx_data *data; 805203134Sthompsa 806203134Sthompsa memset(pq, 0, sizeof(*pq)); 807203134Sthompsa 808203134Sthompsa STAILQ_INIT(&pq->tx_qh); 809203134Sthompsa STAILQ_INIT(&pq->tx_fh); 810203134Sthompsa 811203134Sthompsa for (data = &pq->tx_data[0]; 812203134Sthompsa data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) { 813203134Sthompsa data->sc = sc; 814203134Sthompsa STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); 815203134Sthompsa } 816203134Sthompsa pq->tx_nfree = RUN_TX_RING_COUNT; 817203134Sthompsa} 818203134Sthompsa 819203134Sthompsastatic void 820203134Sthompsarun_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq) 821203134Sthompsa{ 822203134Sthompsa struct run_tx_data *data; 823203134Sthompsa 824203134Sthompsa /* make sure any subsequent use of the queues will fail */ 825203134Sthompsa pq->tx_nfree = 0; 826203134Sthompsa STAILQ_INIT(&pq->tx_fh); 827203134Sthompsa STAILQ_INIT(&pq->tx_qh); 828203134Sthompsa 829203134Sthompsa /* free up all node references and mbufs */ 830203134Sthompsa for (data = &pq->tx_data[0]; 831203134Sthompsa data < &pq->tx_data[RUN_TX_RING_COUNT]; data++){ 832203134Sthompsa if (data->m != NULL) { 833203134Sthompsa m_freem(data->m); 834203134Sthompsa data->m = NULL; 835203134Sthompsa } 836203134Sthompsa if (data->ni != NULL) { 837203134Sthompsa ieee80211_free_node(data->ni); 838203134Sthompsa data->ni = NULL; 839203134Sthompsa } 840203134Sthompsa } 841203134Sthompsa} 842203134Sthompsa 843203134Sthompsaint 844203134Sthompsarun_load_microcode(struct run_softc *sc) 845203134Sthompsa{ 846203134Sthompsa usb_device_request_t req; 847203137Sthompsa const struct firmware *fw; 848203134Sthompsa const u_char *base; 849203134Sthompsa uint32_t tmp; 850203134Sthompsa int ntries, error; 851203134Sthompsa const uint64_t *temp; 852203134Sthompsa uint64_t bytes; 853203134Sthompsa 854205042Sthompsa RUN_UNLOCK(sc); 855203137Sthompsa fw = firmware_get("runfw"); 856205042Sthompsa RUN_LOCK(sc); 857203137Sthompsa if(fw == NULL){ 858203138Sthompsa device_printf(sc->sc_dev, 859203138Sthompsa "failed loadfirmware of file %s\n", "runfw"); 860203134Sthompsa return ENOENT; 861203134Sthompsa } 862203134Sthompsa 863203137Sthompsa if (fw->datasize != 8192) { 864203138Sthompsa device_printf(sc->sc_dev, 865203138Sthompsa "invalid firmware size (should be 8KB)\n"); 866203137Sthompsa error = EINVAL; 867203137Sthompsa goto fail; 868203134Sthompsa } 869203134Sthompsa 870203134Sthompsa /* 871203134Sthompsa * RT3071/RT3072 use a different firmware 872203134Sthompsa * run-rt2870 (8KB) contains both, 873203134Sthompsa * first half (4KB) is for rt2870, 874203134Sthompsa * last half is for rt3071. 875203134Sthompsa */ 876203137Sthompsa base = fw->data; 877205042Sthompsa if ((sc->mac_ver) != 0x2860 && 878205042Sthompsa (sc->mac_ver) != 0x2872 && 879205042Sthompsa (sc->mac_ver) != 0x3070){ 880203134Sthompsa base += 4096; 881205042Sthompsa } 882203134Sthompsa 883203134Sthompsa /* cheap sanity check */ 884203137Sthompsa temp = fw->data; 885203134Sthompsa bytes = *temp; 886203137Sthompsa if(bytes != be64toh(0xffffff0210280210)) { 887203138Sthompsa device_printf(sc->sc_dev, "firmware checksum failed\n"); 888203137Sthompsa error = EINVAL; 889203137Sthompsa goto fail; 890203137Sthompsa } 891203134Sthompsa 892203134Sthompsa run_read(sc, RT2860_ASIC_VER_ID, &tmp); 893203134Sthompsa /* write microcode image */ 894203134Sthompsa run_write_region_1(sc, RT2870_FW_BASE, base, 4096); 895203134Sthompsa run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff); 896203134Sthompsa run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff); 897203134Sthompsa 898203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 899203134Sthompsa req.bRequest = RT2870_RESET; 900203134Sthompsa USETW(req.wValue, 8); 901203134Sthompsa USETW(req.wIndex, 0); 902203134Sthompsa USETW(req.wLength, 0); 903203137Sthompsa if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)) != 0) { 904203138Sthompsa device_printf(sc->sc_dev, "firmware reset failed\n"); 905203137Sthompsa goto fail; 906203137Sthompsa } 907203134Sthompsa 908203134Sthompsa run_delay(sc, 10); 909203134Sthompsa 910203134Sthompsa run_write(sc, RT2860_H2M_MAILBOX, 0); 911205042Sthompsa if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0) 912203137Sthompsa goto fail; 913203134Sthompsa 914203134Sthompsa /* wait until microcontroller is ready */ 915203134Sthompsa for (ntries = 0; ntries < 1000; ntries++) { 916203137Sthompsa if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0) { 917203137Sthompsa goto fail; 918203137Sthompsa } 919203134Sthompsa if (tmp & RT2860_MCU_READY) 920203134Sthompsa break; 921203134Sthompsa run_delay(sc, 10); 922203134Sthompsa } 923203134Sthompsa if (ntries == 1000) { 924203138Sthompsa device_printf(sc->sc_dev, 925203138Sthompsa "timeout waiting for MCU to initialize\n"); 926203137Sthompsa error = ETIMEDOUT; 927203137Sthompsa goto fail; 928203134Sthompsa } 929205042Sthompsa device_printf(sc->sc_dev, "firmware %s loaded\n", 930205042Sthompsa (base == fw->data) ? "RT2870" : "RT3071"); 931203134Sthompsa 932203137Sthompsafail: 933203137Sthompsa firmware_put(fw, FIRMWARE_UNLOAD); 934203137Sthompsa return (error); 935203134Sthompsa} 936203134Sthompsa 937203134Sthompsaint 938203134Sthompsarun_reset(struct run_softc *sc) 939203134Sthompsa{ 940203134Sthompsa usb_device_request_t req; 941203134Sthompsa 942203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 943203134Sthompsa req.bRequest = RT2870_RESET; 944203134Sthompsa USETW(req.wValue, 1); 945203134Sthompsa USETW(req.wIndex, 0); 946203134Sthompsa USETW(req.wLength, 0); 947203134Sthompsa return usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL); 948203134Sthompsa} 949203134Sthompsa 950203134Sthompsastatic usb_error_t 951203134Sthompsarun_do_request(struct run_softc *sc, 952203134Sthompsa struct usb_device_request *req, void *data) 953203134Sthompsa{ 954203134Sthompsa usb_error_t err; 955203134Sthompsa int ntries = 10; 956203134Sthompsa 957203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 958203134Sthompsa 959203134Sthompsa while (ntries--) { 960203134Sthompsa err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, 961203134Sthompsa req, data, 0, NULL, 250 /* ms */); 962203134Sthompsa if (err == 0) 963203134Sthompsa break; 964203134Sthompsa DPRINTFN(1, "Control request failed, %s (retrying)\n", 965203134Sthompsa usbd_errstr(err)); 966203134Sthompsa run_delay(sc, 10); 967203134Sthompsa } 968203134Sthompsa return (err); 969203134Sthompsa} 970203134Sthompsa 971203134Sthompsastatic int 972203134Sthompsarun_read(struct run_softc *sc, uint16_t reg, uint32_t *val) 973203134Sthompsa{ 974203134Sthompsa uint32_t tmp; 975203134Sthompsa int error; 976203134Sthompsa 977203134Sthompsa error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp); 978203134Sthompsa if (error == 0) 979203134Sthompsa *val = le32toh(tmp); 980203134Sthompsa else 981203134Sthompsa *val = 0xffffffff; 982203134Sthompsa return error; 983203134Sthompsa} 984203134Sthompsa 985203134Sthompsastatic int 986203134Sthompsarun_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len) 987203134Sthompsa{ 988203134Sthompsa usb_device_request_t req; 989203134Sthompsa 990203134Sthompsa req.bmRequestType = UT_READ_VENDOR_DEVICE; 991203134Sthompsa req.bRequest = RT2870_READ_REGION_1; 992203134Sthompsa USETW(req.wValue, 0); 993203134Sthompsa USETW(req.wIndex, reg); 994203134Sthompsa USETW(req.wLength, len); 995203134Sthompsa 996203134Sthompsa return run_do_request(sc, &req, buf); 997203134Sthompsa} 998203134Sthompsa 999203134Sthompsastatic int 1000203134Sthompsarun_write_2(struct run_softc *sc, uint16_t reg, uint16_t val) 1001203134Sthompsa{ 1002203134Sthompsa usb_device_request_t req; 1003203134Sthompsa 1004203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1005203134Sthompsa req.bRequest = RT2870_WRITE_2; 1006203134Sthompsa USETW(req.wValue, val); 1007203134Sthompsa USETW(req.wIndex, reg); 1008203134Sthompsa USETW(req.wLength, 0); 1009203134Sthompsa 1010203134Sthompsa return run_do_request(sc, &req, NULL); 1011203134Sthompsa} 1012203134Sthompsa 1013203134Sthompsastatic int 1014203134Sthompsarun_write(struct run_softc *sc, uint16_t reg, uint32_t val) 1015203134Sthompsa{ 1016203134Sthompsa int error; 1017203134Sthompsa 1018203134Sthompsa if ((error = run_write_2(sc, reg, val & 0xffff)) == 0) 1019203134Sthompsa error = run_write_2(sc, reg + 2, val >> 16); 1020203134Sthompsa return error; 1021203134Sthompsa} 1022203134Sthompsa 1023203134Sthompsastatic int 1024203134Sthompsarun_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf, 1025203134Sthompsa int len) 1026203134Sthompsa{ 1027203134Sthompsa#if 1 1028203134Sthompsa int i, error = 0; 1029203134Sthompsa /* 1030203134Sthompsa * NB: the WRITE_REGION_1 command is not stable on RT2860. 1031203134Sthompsa * We thus issue multiple WRITE_2 commands instead. 1032203134Sthompsa */ 1033203134Sthompsa KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n")); 1034203134Sthompsa for (i = 0; i < len && error == 0; i += 2) 1035203134Sthompsa error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8); 1036203134Sthompsa return error; 1037203134Sthompsa#else 1038203134Sthompsa usb_device_request_t req; 1039203134Sthompsa 1040203134Sthompsa req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1041203134Sthompsa req.bRequest = RT2870_WRITE_REGION_1; 1042203134Sthompsa USETW(req.wValue, 0); 1043203134Sthompsa USETW(req.wIndex, reg); 1044203134Sthompsa USETW(req.wLength, len); 1045203134Sthompsa return run_do_request(sc, &req, buf); 1046203134Sthompsa#endif 1047203134Sthompsa} 1048203134Sthompsa 1049203134Sthompsastatic int 1050203134Sthompsarun_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len) 1051203134Sthompsa{ 1052203134Sthompsa int i, error = 0; 1053203134Sthompsa 1054203134Sthompsa KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n")); 1055203134Sthompsa for (i = 0; i < len && error == 0; i += 4) 1056203134Sthompsa error = run_write(sc, reg + i, val); 1057203134Sthompsa return error; 1058203134Sthompsa} 1059203134Sthompsa 1060203134Sthompsa/* Read 16-bit from eFUSE ROM (RT3070 only.) */ 1061203134Sthompsastatic int 1062203134Sthompsarun_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val) 1063203134Sthompsa{ 1064203134Sthompsa uint32_t tmp; 1065203134Sthompsa uint16_t reg; 1066203134Sthompsa int error, ntries; 1067203134Sthompsa 1068203134Sthompsa if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0) 1069203134Sthompsa return error; 1070203134Sthompsa 1071203134Sthompsa addr *= 2; 1072203134Sthompsa /*- 1073203134Sthompsa * Read one 16-byte block into registers EFUSE_DATA[0-3]: 1074203134Sthompsa * DATA0: F E D C 1075203134Sthompsa * DATA1: B A 9 8 1076203134Sthompsa * DATA2: 7 6 5 4 1077203134Sthompsa * DATA3: 3 2 1 0 1078203134Sthompsa */ 1079203134Sthompsa tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK); 1080203134Sthompsa tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK; 1081203134Sthompsa run_write(sc, RT3070_EFUSE_CTRL, tmp); 1082203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1083203134Sthompsa if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0) 1084203134Sthompsa return error; 1085203134Sthompsa if (!(tmp & RT3070_EFSROM_KICK)) 1086203134Sthompsa break; 1087203134Sthompsa run_delay(sc, 2); 1088203134Sthompsa } 1089203134Sthompsa if (ntries == 100) 1090203134Sthompsa return ETIMEDOUT; 1091203134Sthompsa 1092203134Sthompsa if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) { 1093203134Sthompsa *val = 0xffff; /* address not found */ 1094203134Sthompsa return 0; 1095203134Sthompsa } 1096203134Sthompsa /* determine to which 32-bit register our 16-bit word belongs */ 1097203134Sthompsa reg = RT3070_EFUSE_DATA3 - (addr & 0xc); 1098203134Sthompsa if ((error = run_read(sc, reg, &tmp)) != 0) 1099203134Sthompsa return error; 1100203134Sthompsa 1101203134Sthompsa *val = (addr & 2) ? tmp >> 16 : tmp & 0xffff; 1102203134Sthompsa return 0; 1103203134Sthompsa} 1104203134Sthompsa 1105203134Sthompsastatic int 1106203134Sthompsarun_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val) 1107203134Sthompsa{ 1108203134Sthompsa usb_device_request_t req; 1109203134Sthompsa uint16_t tmp; 1110203134Sthompsa int error; 1111203134Sthompsa 1112203134Sthompsa addr *= 2; 1113203134Sthompsa req.bmRequestType = UT_READ_VENDOR_DEVICE; 1114203134Sthompsa req.bRequest = RT2870_EEPROM_READ; 1115203134Sthompsa USETW(req.wValue, 0); 1116203134Sthompsa USETW(req.wIndex, addr); 1117203134Sthompsa USETW(req.wLength, sizeof tmp); 1118203134Sthompsa 1119203134Sthompsa error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp); 1120203134Sthompsa if (error == 0) 1121203134Sthompsa *val = le16toh(tmp); 1122203134Sthompsa else 1123203134Sthompsa *val = 0xffff; 1124203134Sthompsa return error; 1125203134Sthompsa} 1126203134Sthompsa 1127203134Sthompsastatic __inline int 1128203134Sthompsarun_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val) 1129203134Sthompsa{ 1130203134Sthompsa /* either eFUSE ROM or EEPROM */ 1131203134Sthompsa return sc->sc_srom_read(sc, addr, val); 1132203134Sthompsa} 1133203134Sthompsa 1134203134Sthompsastatic int 1135203134Sthompsarun_rt2870_rf_write(struct run_softc *sc, uint8_t reg, uint32_t val) 1136203134Sthompsa{ 1137203134Sthompsa uint32_t tmp; 1138203134Sthompsa int error, ntries; 1139203134Sthompsa 1140203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1141203134Sthompsa if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0) 1142203134Sthompsa return error; 1143203134Sthompsa if (!(tmp & RT2860_RF_REG_CTRL)) 1144203134Sthompsa break; 1145203134Sthompsa } 1146203134Sthompsa if (ntries == 10) 1147203134Sthompsa return ETIMEDOUT; 1148203134Sthompsa 1149203134Sthompsa /* RF registers are 24-bit on the RT2860 */ 1150203134Sthompsa tmp = RT2860_RF_REG_CTRL | 24 << RT2860_RF_REG_WIDTH_SHIFT | 1151203134Sthompsa (val & 0x3fffff) << 2 | (reg & 3); 1152203134Sthompsa return run_write(sc, RT2860_RF_CSR_CFG0, tmp); 1153203134Sthompsa} 1154203134Sthompsa 1155203134Sthompsastatic int 1156203134Sthompsarun_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val) 1157203134Sthompsa{ 1158203134Sthompsa uint32_t tmp; 1159203134Sthompsa int error, ntries; 1160203134Sthompsa 1161203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1162203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1163203134Sthompsa return error; 1164203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1165203134Sthompsa break; 1166203134Sthompsa } 1167203134Sthompsa if (ntries == 100) 1168203134Sthompsa return ETIMEDOUT; 1169203134Sthompsa 1170203134Sthompsa tmp = RT3070_RF_KICK | reg << 8; 1171203134Sthompsa if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0) 1172203134Sthompsa return error; 1173203134Sthompsa 1174203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1175203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1176203134Sthompsa return error; 1177203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1178203134Sthompsa break; 1179203134Sthompsa } 1180203134Sthompsa if (ntries == 100) 1181203134Sthompsa return ETIMEDOUT; 1182203134Sthompsa 1183203134Sthompsa *val = tmp & 0xff; 1184203134Sthompsa return 0; 1185203134Sthompsa} 1186203134Sthompsa 1187203134Sthompsastatic int 1188203134Sthompsarun_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val) 1189203134Sthompsa{ 1190203134Sthompsa uint32_t tmp; 1191203134Sthompsa int error, ntries; 1192203134Sthompsa 1193203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1194203134Sthompsa if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0) 1195203134Sthompsa return error; 1196203134Sthompsa if (!(tmp & RT3070_RF_KICK)) 1197203134Sthompsa break; 1198203134Sthompsa } 1199203134Sthompsa if (ntries == 10) 1200203134Sthompsa return ETIMEDOUT; 1201203134Sthompsa 1202203134Sthompsa tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val; 1203203134Sthompsa return run_write(sc, RT3070_RF_CSR_CFG, tmp); 1204203134Sthompsa} 1205203134Sthompsa 1206203134Sthompsastatic int 1207203134Sthompsarun_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val) 1208203134Sthompsa{ 1209203134Sthompsa uint32_t tmp; 1210203134Sthompsa int ntries, error; 1211203134Sthompsa 1212203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1213203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1214203134Sthompsa return error; 1215203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1216203134Sthompsa break; 1217203134Sthompsa } 1218203134Sthompsa if (ntries == 10) 1219203134Sthompsa return ETIMEDOUT; 1220203134Sthompsa 1221203134Sthompsa tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8; 1222203134Sthompsa if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0) 1223203134Sthompsa return error; 1224203134Sthompsa 1225203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1226203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1227203134Sthompsa return error; 1228203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1229203134Sthompsa break; 1230203134Sthompsa } 1231203134Sthompsa if (ntries == 10) 1232203134Sthompsa return ETIMEDOUT; 1233203134Sthompsa 1234203134Sthompsa *val = tmp & 0xff; 1235203134Sthompsa return 0; 1236203134Sthompsa} 1237203134Sthompsa 1238203134Sthompsastatic int 1239203134Sthompsarun_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val) 1240203134Sthompsa{ 1241203134Sthompsa uint32_t tmp; 1242203134Sthompsa int ntries, error; 1243203134Sthompsa 1244203134Sthompsa for (ntries = 0; ntries < 10; ntries++) { 1245203134Sthompsa if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0) 1246203134Sthompsa return error; 1247203134Sthompsa if (!(tmp & RT2860_BBP_CSR_KICK)) 1248203134Sthompsa break; 1249203134Sthompsa } 1250203134Sthompsa if (ntries == 10) 1251203134Sthompsa return ETIMEDOUT; 1252203134Sthompsa 1253203134Sthompsa tmp = RT2860_BBP_CSR_KICK | reg << 8 | val; 1254203134Sthompsa return run_write(sc, RT2860_BBP_CSR_CFG, tmp); 1255203134Sthompsa} 1256203134Sthompsa 1257203134Sthompsa/* 1258203134Sthompsa * Send a command to the 8051 microcontroller unit. 1259203134Sthompsa */ 1260203134Sthompsastatic int 1261203134Sthompsarun_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg) 1262203134Sthompsa{ 1263203134Sthompsa uint32_t tmp; 1264203134Sthompsa int error, ntries; 1265203134Sthompsa 1266203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 1267203134Sthompsa if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0) 1268203134Sthompsa return error; 1269203134Sthompsa if (!(tmp & RT2860_H2M_BUSY)) 1270203134Sthompsa break; 1271203134Sthompsa } 1272203134Sthompsa if (ntries == 100) 1273203134Sthompsa return ETIMEDOUT; 1274203134Sthompsa 1275203134Sthompsa tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg; 1276203134Sthompsa if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0) 1277203134Sthompsa error = run_write(sc, RT2860_HOST_CMD, cmd); 1278203134Sthompsa return error; 1279203134Sthompsa} 1280203134Sthompsa 1281203134Sthompsa/* 1282203134Sthompsa * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word. 1283203134Sthompsa * Used to adjust per-rate Tx power registers. 1284203134Sthompsa */ 1285203134Sthompsastatic __inline uint32_t 1286203134Sthompsab4inc(uint32_t b32, int8_t delta) 1287203134Sthompsa{ 1288203134Sthompsa int8_t i, b4; 1289203134Sthompsa 1290203134Sthompsa for (i = 0; i < 8; i++) { 1291203134Sthompsa b4 = b32 & 0xf; 1292203134Sthompsa b4 += delta; 1293203134Sthompsa if (b4 < 0) 1294203134Sthompsa b4 = 0; 1295203134Sthompsa else if (b4 > 0xf) 1296203134Sthompsa b4 = 0xf; 1297203134Sthompsa b32 = b32 >> 4 | b4 << 28; 1298203134Sthompsa } 1299203134Sthompsa return b32; 1300203134Sthompsa} 1301203134Sthompsa 1302203134Sthompsastatic const char * 1303203134Sthompsarun_get_rf(int rev) 1304203134Sthompsa{ 1305203134Sthompsa switch (rev) { 1306203134Sthompsa case RT2860_RF_2820: return "RT2820"; 1307203134Sthompsa case RT2860_RF_2850: return "RT2850"; 1308203134Sthompsa case RT2860_RF_2720: return "RT2720"; 1309203134Sthompsa case RT2860_RF_2750: return "RT2750"; 1310203134Sthompsa case RT3070_RF_3020: return "RT3020"; 1311203134Sthompsa case RT3070_RF_2020: return "RT2020"; 1312203134Sthompsa case RT3070_RF_3021: return "RT3021"; 1313203134Sthompsa case RT3070_RF_3022: return "RT3022"; 1314203134Sthompsa case RT3070_RF_3052: return "RT3052"; 1315203134Sthompsa } 1316203134Sthompsa return "unknown"; 1317203134Sthompsa} 1318203134Sthompsa 1319203134Sthompsaint 1320203134Sthompsarun_read_eeprom(struct run_softc *sc) 1321203134Sthompsa{ 1322203134Sthompsa int8_t delta_2ghz, delta_5ghz; 1323203134Sthompsa uint32_t tmp; 1324203134Sthompsa uint16_t val; 1325203134Sthompsa int ridx, ant, i; 1326203134Sthompsa 1327203134Sthompsa /* check whether the ROM is eFUSE ROM or EEPROM */ 1328203134Sthompsa sc->sc_srom_read = run_eeprom_read_2; 1329205042Sthompsa if (sc->mac_ver >= 0x3070) { 1330203134Sthompsa run_read(sc, RT3070_EFUSE_CTRL, &tmp); 1331203134Sthompsa DPRINTF("EFUSE_CTRL=0x%08x\n", tmp); 1332203134Sthompsa if (tmp & RT3070_SEL_EFUSE) 1333203134Sthompsa sc->sc_srom_read = run_efuse_read_2; 1334203134Sthompsa } 1335203134Sthompsa 1336203134Sthompsa /* read ROM version */ 1337203134Sthompsa run_srom_read(sc, RT2860_EEPROM_VERSION, &val); 1338203134Sthompsa DPRINTF("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8); 1339203134Sthompsa 1340203134Sthompsa /* read MAC address */ 1341203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC01, &val); 1342203134Sthompsa sc->sc_bssid[0] = val & 0xff; 1343203134Sthompsa sc->sc_bssid[1] = val >> 8; 1344203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC23, &val); 1345203134Sthompsa sc->sc_bssid[2] = val & 0xff; 1346203134Sthompsa sc->sc_bssid[3] = val >> 8; 1347203134Sthompsa run_srom_read(sc, RT2860_EEPROM_MAC45, &val); 1348203134Sthompsa sc->sc_bssid[4] = val & 0xff; 1349203134Sthompsa sc->sc_bssid[5] = val >> 8; 1350203134Sthompsa 1351205042Sthompsa /* read vender BBP settings */ 1352205042Sthompsa for (i = 0; i < 10; i++) { 1353203134Sthompsa run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val); 1354203134Sthompsa sc->bbp[i].val = val & 0xff; 1355203134Sthompsa sc->bbp[i].reg = val >> 8; 1356203134Sthompsa DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg, sc->bbp[i].val); 1357203134Sthompsa } 1358205042Sthompsa if (sc->mac_ver >= 0x3071) { 1359205042Sthompsa /* read vendor RF settings */ 1360205042Sthompsa for (i = 0; i < 10; i++) { 1361205042Sthompsa run_srom_read(sc, RT3071_EEPROM_RF_BASE + i, &val); 1362205042Sthompsa sc->rf[i].val = val & 0xff; 1363205042Sthompsa sc->rf[i].reg = val >> 8; 1364205042Sthompsa DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg, 1365205042Sthompsa sc->rf[i].val); 1366205042Sthompsa } 1367205042Sthompsa } 1368203134Sthompsa 1369203134Sthompsa /* read RF frequency offset from EEPROM */ 1370203134Sthompsa run_srom_read(sc, RT2860_EEPROM_FREQ_LEDS, &val); 1371203134Sthompsa sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0; 1372203134Sthompsa DPRINTF("EEPROM freq offset %d\n", sc->freq & 0xff); 1373203134Sthompsa 1374205042Sthompsa if (val >> 8 != 0xff) { 1375203134Sthompsa /* read LEDs operating mode */ 1376205042Sthompsa sc->leds = val >> 8; 1377203134Sthompsa run_srom_read(sc, RT2860_EEPROM_LED1, &sc->led[0]); 1378203134Sthompsa run_srom_read(sc, RT2860_EEPROM_LED2, &sc->led[1]); 1379203134Sthompsa run_srom_read(sc, RT2860_EEPROM_LED3, &sc->led[2]); 1380203134Sthompsa } else { 1381203134Sthompsa /* broken EEPROM, use default settings */ 1382203134Sthompsa sc->leds = 0x01; 1383203134Sthompsa sc->led[0] = 0x5555; 1384203134Sthompsa sc->led[1] = 0x2221; 1385203134Sthompsa sc->led[2] = 0x5627; /* differs from RT2860 */ 1386203134Sthompsa } 1387203134Sthompsa DPRINTF("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n", 1388203134Sthompsa sc->leds, sc->led[0], sc->led[1], sc->led[2]); 1389203134Sthompsa 1390203134Sthompsa /* read RF information */ 1391203134Sthompsa run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val); 1392203134Sthompsa if (val == 0xffff) { 1393203134Sthompsa DPRINTF("invalid EEPROM antenna info, using default\n"); 1394205042Sthompsa if (sc->mac_ver == 0x3572) { 1395205042Sthompsa /* default to RF3052 2T2R */ 1396205042Sthompsa sc->rf_rev = RT3070_RF_3052; 1397205042Sthompsa sc->ntxchains = 2; 1398205042Sthompsa sc->nrxchains = 2; 1399205042Sthompsa } else if (sc->mac_ver >= 0x3070) { 1400203134Sthompsa /* default to RF3020 1T1R */ 1401203134Sthompsa sc->rf_rev = RT3070_RF_3020; 1402203134Sthompsa sc->ntxchains = 1; 1403203134Sthompsa sc->nrxchains = 1; 1404203134Sthompsa } else { 1405203134Sthompsa /* default to RF2820 1T2R */ 1406203134Sthompsa sc->rf_rev = RT2860_RF_2820; 1407203134Sthompsa sc->ntxchains = 1; 1408203134Sthompsa sc->nrxchains = 2; 1409203134Sthompsa } 1410203134Sthompsa } else { 1411203134Sthompsa sc->rf_rev = (val >> 8) & 0xf; 1412203134Sthompsa sc->ntxchains = (val >> 4) & 0xf; 1413203134Sthompsa sc->nrxchains = val & 0xf; 1414203134Sthompsa } 1415203134Sthompsa DPRINTF("EEPROM RF rev=0x%02x chains=%dT%dR\n", 1416203134Sthompsa sc->rf_rev, sc->ntxchains, sc->nrxchains); 1417203134Sthompsa 1418203134Sthompsa run_srom_read(sc, RT2860_EEPROM_CONFIG, &val); 1419203134Sthompsa DPRINTF("EEPROM CFG 0x%04x\n", val); 1420205042Sthompsa /* check if driver should patch the DAC issue */ 1421205042Sthompsa if ((val >> 8) != 0xff) 1422205042Sthompsa sc->patch_dac = (val >> 15) & 1; 1423203134Sthompsa if ((val & 0xff) != 0xff) { 1424203134Sthompsa sc->ext_5ghz_lna = (val >> 3) & 1; 1425203134Sthompsa sc->ext_2ghz_lna = (val >> 2) & 1; 1426205042Sthompsa /* check if RF supports automatic Tx access gain control */ 1427203134Sthompsa sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1; 1428205042Sthompsa /* check if we have a hardware radio switch */ 1429205042Sthompsa sc->rfswitch = val & 1; 1430203134Sthompsa } 1431203134Sthompsa 1432203134Sthompsa /* read power settings for 2GHz channels */ 1433203134Sthompsa for (i = 0; i < 14; i += 2) { 1434203134Sthompsa run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val); 1435203134Sthompsa sc->txpow1[i + 0] = (int8_t)(val & 0xff); 1436203134Sthompsa sc->txpow1[i + 1] = (int8_t)(val >> 8); 1437203134Sthompsa 1438203134Sthompsa run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val); 1439203134Sthompsa sc->txpow2[i + 0] = (int8_t)(val & 0xff); 1440203134Sthompsa sc->txpow2[i + 1] = (int8_t)(val >> 8); 1441203134Sthompsa } 1442203134Sthompsa /* fix broken Tx power entries */ 1443203134Sthompsa for (i = 0; i < 14; i++) { 1444203134Sthompsa if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31) 1445203134Sthompsa sc->txpow1[i] = 5; 1446203134Sthompsa if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31) 1447203134Sthompsa sc->txpow2[i] = 5; 1448203134Sthompsa DPRINTF("chan %d: power1=%d, power2=%d\n", 1449203134Sthompsa rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]); 1450203134Sthompsa } 1451203134Sthompsa /* read power settings for 5GHz channels */ 1452205042Sthompsa for (i = 0; i < 40; i += 2) { 1453203134Sthompsa run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val); 1454203134Sthompsa sc->txpow1[i + 14] = (int8_t)(val & 0xff); 1455203134Sthompsa sc->txpow1[i + 15] = (int8_t)(val >> 8); 1456203134Sthompsa 1457203134Sthompsa run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val); 1458203134Sthompsa sc->txpow2[i + 14] = (int8_t)(val & 0xff); 1459203134Sthompsa sc->txpow2[i + 15] = (int8_t)(val >> 8); 1460203134Sthompsa } 1461203134Sthompsa /* fix broken Tx power entries */ 1462205042Sthompsa for (i = 0; i < 40; i++) { 1463203134Sthompsa if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15) 1464203134Sthompsa sc->txpow1[14 + i] = 5; 1465203134Sthompsa if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15) 1466203134Sthompsa sc->txpow2[14 + i] = 5; 1467203134Sthompsa DPRINTF("chan %d: power1=%d, power2=%d\n", 1468203134Sthompsa rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i], 1469203134Sthompsa sc->txpow2[14 + i]); 1470203134Sthompsa } 1471203134Sthompsa 1472203134Sthompsa /* read Tx power compensation for each Tx rate */ 1473203134Sthompsa run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val); 1474203134Sthompsa delta_2ghz = delta_5ghz = 0; 1475203134Sthompsa if ((val & 0xff) != 0xff && (val & 0x80)) { 1476203134Sthompsa delta_2ghz = val & 0xf; 1477203134Sthompsa if (!(val & 0x40)) /* negative number */ 1478203134Sthompsa delta_2ghz = -delta_2ghz; 1479203134Sthompsa } 1480203134Sthompsa val >>= 8; 1481203134Sthompsa if ((val & 0xff) != 0xff && (val & 0x80)) { 1482203134Sthompsa delta_5ghz = val & 0xf; 1483203134Sthompsa if (!(val & 0x40)) /* negative number */ 1484203134Sthompsa delta_5ghz = -delta_5ghz; 1485203134Sthompsa } 1486203134Sthompsa DPRINTF("power compensation=%d (2GHz), %d (5GHz)\n", 1487203134Sthompsa delta_2ghz, delta_5ghz); 1488203134Sthompsa 1489203134Sthompsa for (ridx = 0; ridx < 5; ridx++) { 1490203134Sthompsa uint32_t reg; 1491203134Sthompsa 1492203134Sthompsa run_srom_read(sc, RT2860_EEPROM_RPWR + ridx, &val); 1493203134Sthompsa reg = (uint32_t)val << 16; 1494203134Sthompsa run_srom_read(sc, RT2860_EEPROM_RPWR + ridx + 1, &val); 1495203134Sthompsa reg |= val; 1496203134Sthompsa 1497203134Sthompsa sc->txpow20mhz[ridx] = reg; 1498203134Sthompsa sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz); 1499203134Sthompsa sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz); 1500203134Sthompsa 1501203134Sthompsa DPRINTF("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, " 1502203134Sthompsa "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx], 1503203134Sthompsa sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]); 1504203134Sthompsa } 1505203134Sthompsa 1506203134Sthompsa /* read RSSI offsets and LNA gains from EEPROM */ 1507203134Sthompsa run_srom_read(sc, RT2860_EEPROM_RSSI1_2GHZ, &val); 1508203134Sthompsa sc->rssi_2ghz[0] = val & 0xff; /* Ant A */ 1509203134Sthompsa sc->rssi_2ghz[1] = val >> 8; /* Ant B */ 1510203134Sthompsa run_srom_read(sc, RT2860_EEPROM_RSSI2_2GHZ, &val); 1511205042Sthompsa if (sc->mac_ver >= 0x3070) { 1512205042Sthompsa /* 1513205042Sthompsa * On RT3070 chips (limited to 2 Rx chains), this ROM 1514205042Sthompsa * field contains the Tx mixer gain for the 2GHz band. 1515205042Sthompsa */ 1516205042Sthompsa if ((val & 0xff) != 0xff) 1517205042Sthompsa sc->txmixgain_2ghz = val & 0x7; 1518205042Sthompsa DPRINTF("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz); 1519205042Sthompsa } else 1520205042Sthompsa sc->rssi_2ghz[2] = val & 0xff; /* Ant C */ 1521203134Sthompsa sc->lna[2] = val >> 8; /* channel group 2 */ 1522203134Sthompsa 1523203134Sthompsa run_srom_read(sc, RT2860_EEPROM_RSSI1_5GHZ, &val); 1524203134Sthompsa sc->rssi_5ghz[0] = val & 0xff; /* Ant A */ 1525203134Sthompsa sc->rssi_5ghz[1] = val >> 8; /* Ant B */ 1526203134Sthompsa run_srom_read(sc, RT2860_EEPROM_RSSI2_5GHZ, &val); 1527205042Sthompsa if (sc->mac_ver == 0x3572) { 1528205042Sthompsa /* 1529205042Sthompsa * On RT3572 chips (limited to 2 Rx chains), this ROM 1530205042Sthompsa * field contains the Tx mixer gain for the 5GHz band. 1531205042Sthompsa */ 1532205042Sthompsa if ((val & 0xff) != 0xff) 1533205042Sthompsa sc->txmixgain_5ghz = val & 0x7; 1534205042Sthompsa DPRINTF("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz); 1535205042Sthompsa } else 1536205042Sthompsa sc->rssi_5ghz[2] = val & 0xff; /* Ant C */ 1537203134Sthompsa sc->lna[3] = val >> 8; /* channel group 3 */ 1538203134Sthompsa 1539203134Sthompsa run_srom_read(sc, RT2860_EEPROM_LNA, &val); 1540203134Sthompsa sc->lna[0] = val & 0xff; /* channel group 0 */ 1541203134Sthompsa sc->lna[1] = val >> 8; /* channel group 1 */ 1542203134Sthompsa 1543203134Sthompsa /* fix broken 5GHz LNA entries */ 1544203134Sthompsa if (sc->lna[2] == 0 || sc->lna[2] == 0xff) { 1545203134Sthompsa DPRINTF("invalid LNA for channel group %d\n", 2); 1546203134Sthompsa sc->lna[2] = sc->lna[1]; 1547203134Sthompsa } 1548203134Sthompsa if (sc->lna[3] == 0 || sc->lna[3] == 0xff) { 1549203134Sthompsa DPRINTF("invalid LNA for channel group %d\n", 3); 1550203134Sthompsa sc->lna[3] = sc->lna[1]; 1551203134Sthompsa } 1552203134Sthompsa 1553203134Sthompsa /* fix broken RSSI offset entries */ 1554203134Sthompsa for (ant = 0; ant < 3; ant++) { 1555203134Sthompsa if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) { 1556203134Sthompsa DPRINTF("invalid RSSI%d offset: %d (2GHz)\n", 1557203134Sthompsa ant + 1, sc->rssi_2ghz[ant]); 1558203134Sthompsa sc->rssi_2ghz[ant] = 0; 1559203134Sthompsa } 1560203134Sthompsa if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) { 1561203134Sthompsa DPRINTF("invalid RSSI%d offset: %d (5GHz)\n", 1562203134Sthompsa ant + 1, sc->rssi_5ghz[ant]); 1563203134Sthompsa sc->rssi_5ghz[ant] = 0; 1564203134Sthompsa } 1565203134Sthompsa } 1566203134Sthompsa return 0; 1567203134Sthompsa} 1568203134Sthompsa 1569203134Sthompsastruct ieee80211_node * 1570203134Sthompsarun_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) 1571203134Sthompsa{ 1572203134Sthompsa return malloc(sizeof (struct run_node), M_DEVBUF, M_NOWAIT | M_ZERO); 1573203134Sthompsa} 1574203134Sthompsa 1575203134Sthompsastatic int 1576203134Sthompsarun_media_change(struct ifnet *ifp) 1577203134Sthompsa{ 1578203134Sthompsa const struct ieee80211_txparam *tp; 1579203134Sthompsa struct run_softc *sc = ifp->if_softc; 1580203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 1581203134Sthompsa struct ieee80211vap *vap = &sc->sc_rvp->vap; 1582203134Sthompsa uint8_t rate, ridx; 1583203134Sthompsa int error; 1584203134Sthompsa 1585203134Sthompsa RUN_LOCK(sc); 1586203134Sthompsa 1587203134Sthompsa error = ieee80211_media_change(ifp); 1588203134Sthompsa if (error != ENETRESET) 1589203134Sthompsa RUN_UNLOCK(sc); 1590203134Sthompsa return error; 1591203134Sthompsa 1592203134Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 1593203134Sthompsa if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 1594203134Sthompsa rate = ic->ic_sup_rates[ic->ic_curmode]. 1595203134Sthompsa rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL; 1596203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 1597203134Sthompsa if (rt2860_rates[ridx].rate == rate) 1598203134Sthompsa break; 1599203134Sthompsa sc->fixed_ridx = ridx; 1600203134Sthompsa } 1601203134Sthompsa 1602203134Sthompsa if ((ifp->if_flags & IFF_UP) && 1603203134Sthompsa (ifp->if_drv_flags & IFF_DRV_RUNNING)){ 1604203134Sthompsa run_init_locked(sc); 1605203134Sthompsa } 1606203134Sthompsa 1607203134Sthompsa RUN_UNLOCK(sc); 1608203134Sthompsa 1609203134Sthompsa return 0; 1610203134Sthompsa} 1611203134Sthompsa 1612203134Sthompsastatic int 1613203134Sthompsarun_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 1614203134Sthompsa{ 1615203134Sthompsa const struct ieee80211_txparam *tp; 1616203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 1617203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 1618203134Sthompsa struct run_vap *rvp = RUN_VAP(vap); 1619203134Sthompsa enum ieee80211_state ostate; 1620203134Sthompsa struct ieee80211_node *ni; 1621203134Sthompsa uint32_t tmp; 1622203134Sthompsa uint8_t wcid; 1623203134Sthompsa 1624203134Sthompsa ostate = vap->iv_state; 1625203134Sthompsa DPRINTF("%s -> %s\n", 1626203134Sthompsa ieee80211_state_name[ostate], 1627203134Sthompsa ieee80211_state_name[nstate]); 1628203134Sthompsa 1629203134Sthompsa IEEE80211_UNLOCK(ic); 1630203134Sthompsa RUN_LOCK(sc); 1631203134Sthompsa 1632206358Srpaulo sc->sc_rvp->ratectl_run = RUN_RATECTL_OFF; 1633206358Srpaulo usb_callout_stop(&rvp->ratectl_ch); 1634203134Sthompsa 1635203134Sthompsa if (ostate == IEEE80211_S_RUN) { 1636203134Sthompsa /* turn link LED off */ 1637203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO); 1638203134Sthompsa } 1639203134Sthompsa 1640203134Sthompsa switch (nstate) { 1641203134Sthompsa case IEEE80211_S_INIT: 1642203134Sthompsa if (ostate == IEEE80211_S_RUN) { 1643203134Sthompsa /* abort TSF synchronization */ 1644203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 1645203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, 1646203134Sthompsa tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 1647203134Sthompsa RT2860_TBTT_TIMER_EN)); 1648203134Sthompsa } 1649203134Sthompsa break; 1650203134Sthompsa 1651203134Sthompsa case IEEE80211_S_RUN: 1652203134Sthompsa ni = vap->iv_bss; 1653203134Sthompsa 1654203134Sthompsa if (vap->iv_opmode != IEEE80211_M_MONITOR) { 1655203134Sthompsa run_updateslot(ic->ic_ifp); 1656203134Sthompsa run_enable_mrr(sc); 1657203134Sthompsa run_set_txpreamble(sc); 1658203134Sthompsa run_set_basicrates(sc); 1659203134Sthompsa IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); 1660203134Sthompsa run_set_bssid(sc, ni->ni_bssid); 1661203134Sthompsa } 1662203134Sthompsa 1663203134Sthompsa if (vap->iv_opmode == IEEE80211_M_STA) { 1664203134Sthompsa /* add BSS entry to the WCID table */ 1665203134Sthompsa wcid = RUN_AID2WCID(ni->ni_associd); 1666203134Sthompsa run_write_region_1(sc, RT2860_WCID_ENTRY(wcid), 1667203134Sthompsa ni->ni_macaddr, IEEE80211_ADDR_LEN); 1668203134Sthompsa } 1669203134Sthompsa 1670203134Sthompsa if (vap->iv_opmode == IEEE80211_M_HOSTAP || 1671203134Sthompsa vap->iv_opmode == IEEE80211_M_IBSS) 1672203134Sthompsa run_update_beacon_locked(vap, 0); 1673203134Sthompsa 1674203134Sthompsa if (vap->iv_opmode != IEEE80211_M_MONITOR) { 1675203134Sthompsa run_enable_tsf_sync(sc); 1676203134Sthompsa } /* else tsf */ 1677203134Sthompsa 1678203134Sthompsa /* enable automatic rate adaptation */ 1679203134Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 1680203134Sthompsa if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) 1681206358Srpaulo run_ratectl_start(sc, ni); 1682203134Sthompsa 1683203134Sthompsa /* turn link LED on */ 1684203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO | 1685203134Sthompsa (IEEE80211_IS_CHAN_2GHZ(vap->iv_bss->ni_chan) ? 1686203134Sthompsa RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ)); 1687203134Sthompsa 1688203134Sthompsa break; 1689203134Sthompsa default: 1690203134Sthompsa DPRINTFN(6, "undefined case\n"); 1691203134Sthompsa break; 1692203134Sthompsa } 1693203134Sthompsa 1694203134Sthompsa RUN_UNLOCK(sc); 1695203134Sthompsa IEEE80211_LOCK(ic); 1696203134Sthompsa 1697203134Sthompsa return(rvp->newstate(vap, nstate, arg)); 1698203134Sthompsa} 1699203134Sthompsa 1700203134Sthompsa/* another taskqueue, so usbd_do_request() can go sleep */ 1701203134Sthompsastatic int 1702203134Sthompsarun_wme_update(struct ieee80211com *ic) 1703203134Sthompsa{ 1704203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 1705203134Sthompsa 1706203134Sthompsa ieee80211_runtask(ic, &sc->wme_task); 1707203134Sthompsa 1708203134Sthompsa /* return whatever, upper layer desn't care anyway */ 1709203134Sthompsa return 0; 1710203134Sthompsa} 1711203134Sthompsa 1712203134Sthompsa/* ARGSUSED */ 1713203134Sthompsastatic void 1714203134Sthompsarun_wme_update_cb(void *arg, int pending) 1715203134Sthompsa{ 1716203134Sthompsa struct ieee80211com *ic = arg; 1717203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 1718203134Sthompsa struct ieee80211_wme_state *wmesp = &ic->ic_wme; 1719203134Sthompsa int aci, error = 0; 1720203134Sthompsa 1721203134Sthompsa RUN_LOCK(sc); 1722203134Sthompsa 1723203134Sthompsa /* update MAC TX configuration registers */ 1724203134Sthompsa for (aci = 0; aci < WME_NUM_AC; aci++) { 1725203134Sthompsa error = run_write(sc, RT2860_EDCA_AC_CFG(aci), 1726203134Sthompsa wmesp->wme_params[aci].wmep_logcwmax << 16 | 1727203134Sthompsa wmesp->wme_params[aci].wmep_logcwmin << 12 | 1728203134Sthompsa wmesp->wme_params[aci].wmep_aifsn << 8 | 1729203134Sthompsa wmesp->wme_params[aci].wmep_txopLimit); 1730203134Sthompsa if(error) goto err; 1731203134Sthompsa } 1732203134Sthompsa 1733203134Sthompsa /* update SCH/DMA registers too */ 1734203134Sthompsa error = run_write(sc, RT2860_WMM_AIFSN_CFG, 1735203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_aifsn << 12 | 1736203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_aifsn << 8 | 1737203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_aifsn << 4 | 1738203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_aifsn); 1739203134Sthompsa if(error) goto err; 1740203134Sthompsa error = run_write(sc, RT2860_WMM_CWMIN_CFG, 1741203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_logcwmin << 12 | 1742203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_logcwmin << 8 | 1743203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_logcwmin << 4 | 1744203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_logcwmin); 1745203134Sthompsa if(error) goto err; 1746203134Sthompsa error = run_write(sc, RT2860_WMM_CWMAX_CFG, 1747203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_logcwmax << 12 | 1748203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_logcwmax << 8 | 1749203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_logcwmax << 4 | 1750203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_logcwmax); 1751203134Sthompsa if(error) goto err; 1752203134Sthompsa error = run_write(sc, RT2860_WMM_TXOP0_CFG, 1753203134Sthompsa wmesp->wme_params[WME_AC_BK].wmep_txopLimit << 16 | 1754203134Sthompsa wmesp->wme_params[WME_AC_BE].wmep_txopLimit); 1755203134Sthompsa if(error) goto err; 1756203134Sthompsa error = run_write(sc, RT2860_WMM_TXOP1_CFG, 1757203134Sthompsa wmesp->wme_params[WME_AC_VO].wmep_txopLimit << 16 | 1758203134Sthompsa wmesp->wme_params[WME_AC_VI].wmep_txopLimit); 1759203134Sthompsa 1760203134Sthompsaerr: 1761203134Sthompsa if(error) 1762203134Sthompsa DPRINTF("WME update failed\n"); 1763203134Sthompsa 1764203134Sthompsa RUN_UNLOCK(sc); 1765203134Sthompsa return; 1766203134Sthompsa} 1767203134Sthompsa 1768203134Sthompsastatic void 1769203134Sthompsarun_key_update_begin(struct ieee80211vap *vap) 1770203134Sthompsa{ 1771203134Sthompsa /* 1772203134Sthompsa * Because run_key_delete() needs special attention 1773203134Sthompsa * on lock related operation, lock handling is being done 1774203134Sthompsa * differently in run_key_set and _delete. 1775203134Sthompsa * 1776203134Sthompsa * So, we don't use key_update_begin and _end. 1777203134Sthompsa */ 1778203134Sthompsa} 1779203134Sthompsa 1780203134Sthompsastatic void 1781203134Sthompsarun_key_update_end(struct ieee80211vap *vap) 1782203134Sthompsa{ 1783203134Sthompsa /* null */ 1784203134Sthompsa} 1785203134Sthompsa 1786203134Sthompsa/* 1787203134Sthompsa * return 0 on error 1788203134Sthompsa */ 1789203134Sthompsastatic int 1790203134Sthompsarun_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, 1791203134Sthompsa const uint8_t mac[IEEE80211_ADDR_LEN]) 1792203134Sthompsa{ 1793203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 1794203134Sthompsa struct ifnet *ifp = ic->ic_ifp; 1795203134Sthompsa struct run_softc *sc = ifp->if_softc; 1796203134Sthompsa struct ieee80211_node *ni; 1797203134Sthompsa uint32_t attr; 1798203134Sthompsa uint16_t base, associd; 1799203134Sthompsa uint8_t mode, wcid, txmic, rxmic, iv[8]; 1800203134Sthompsa int error = 0; 1801203134Sthompsa 1802203134Sthompsa RUN_LOCK(sc); 1803203134Sthompsa 1804203134Sthompsa if(vap->iv_opmode == IEEE80211_M_HOSTAP){ 1805203134Sthompsa ni = ieee80211_find_vap_node(&ic->ic_sta, vap, mac); 1806203134Sthompsa associd = (ni != NULL) ? ni->ni_associd : 0; 1807203134Sthompsa if(ni != NULL) 1808203134Sthompsa ieee80211_free_node(ni); 1809203134Sthompsa txmic = 24; 1810203134Sthompsa rxmic = 16; 1811203134Sthompsa } else { 1812203134Sthompsa ni = vap->iv_bss; 1813203134Sthompsa associd = (ni != NULL) ? ni->ni_associd : 0; 1814203134Sthompsa txmic = 16; 1815203134Sthompsa rxmic = 24; 1816203134Sthompsa } 1817203134Sthompsa 1818203134Sthompsa /* map net80211 cipher to RT2860 security mode */ 1819203134Sthompsa switch (k->wk_cipher->ic_cipher) { 1820203134Sthompsa case IEEE80211_CIPHER_WEP: 1821203134Sthompsa if(k->wk_keylen < 8) 1822203134Sthompsa mode = RT2860_MODE_WEP40; 1823203134Sthompsa else 1824203134Sthompsa mode = RT2860_MODE_WEP104; 1825203134Sthompsa break; 1826203134Sthompsa case IEEE80211_CIPHER_TKIP: 1827203134Sthompsa mode = RT2860_MODE_TKIP; 1828203134Sthompsa break; 1829203134Sthompsa case IEEE80211_CIPHER_AES_CCM: 1830203134Sthompsa mode = RT2860_MODE_AES_CCMP; 1831203134Sthompsa break; 1832203134Sthompsa default: 1833203134Sthompsa DPRINTF("undefined case\n"); 1834203134Sthompsa goto fail; 1835203134Sthompsa } 1836203134Sthompsa 1837203134Sthompsa DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s\n", 1838203134Sthompsa associd, k->wk_keyix, mode, 1839203134Sthompsa (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise"); 1840203134Sthompsa 1841203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 1842203134Sthompsa wcid = 0; /* NB: update WCID0 for group keys */ 1843203134Sthompsa base = RT2860_SKEY(0, k->wk_keyix); 1844203134Sthompsa } else { 1845203134Sthompsa wcid = RUN_AID2WCID(associd); 1846203134Sthompsa base = RT2860_PKEY(wcid); 1847203134Sthompsa } 1848203134Sthompsa 1849203134Sthompsa if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) { 1850203134Sthompsa if(run_write_region_1(sc, base, k->wk_key, 16)) 1851203134Sthompsa goto fail; 1852203134Sthompsa if(run_write_region_1(sc, base + 16, &k->wk_key[txmic], 8)) /* wk_txmic */ 1853203134Sthompsa goto fail; 1854203134Sthompsa if(run_write_region_1(sc, base + 24, &k->wk_key[rxmic], 8)) /* wk_rxmic */ 1855203134Sthompsa goto fail; 1856203134Sthompsa } else { 1857203134Sthompsa /* roundup len to 16-bit: XXX fix write_region_1() instead */ 1858203134Sthompsa if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1)) 1859203134Sthompsa goto fail; 1860203134Sthompsa } 1861203134Sthompsa 1862203134Sthompsa if (!(k->wk_flags & IEEE80211_KEY_GROUP) || 1863203134Sthompsa (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) { 1864203134Sthompsa /* set initial packet number in IV+EIV */ 1865203134Sthompsa if (k->wk_cipher == IEEE80211_CIPHER_WEP){ 1866203134Sthompsa memset(iv, 0, sizeof iv); 1867203134Sthompsa iv[3] = sc->sc_rvp->vap.iv_def_txkey << 6; 1868203134Sthompsa } else { 1869203134Sthompsa if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) { 1870203134Sthompsa iv[0] = k->wk_keytsc >> 8; 1871203134Sthompsa iv[1] = (iv[0] | 0x20) & 0x7f; 1872203134Sthompsa iv[2] = k->wk_keytsc; 1873203134Sthompsa } else /* CCMP */ { 1874203134Sthompsa iv[0] = k->wk_keytsc; 1875203134Sthompsa iv[1] = k->wk_keytsc >> 8; 1876203134Sthompsa iv[2] = 0; 1877203134Sthompsa } 1878203134Sthompsa iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV; 1879203134Sthompsa iv[4] = k->wk_keytsc >> 16; 1880203134Sthompsa iv[5] = k->wk_keytsc >> 24; 1881203134Sthompsa iv[6] = k->wk_keytsc >> 32; 1882203134Sthompsa iv[7] = k->wk_keytsc >> 40; 1883203134Sthompsa } 1884203134Sthompsa if(run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8)) 1885203134Sthompsa goto fail; 1886203134Sthompsa } 1887203134Sthompsa 1888203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 1889203134Sthompsa /* install group key */ 1890203134Sthompsa if(run_read(sc, RT2860_SKEY_MODE_0_7, &attr)) 1891203134Sthompsa goto fail; 1892203134Sthompsa attr &= ~(0xf << (k->wk_keyix * 4)); 1893203134Sthompsa attr |= mode << (k->wk_keyix * 4); 1894203134Sthompsa if(run_write(sc, RT2860_SKEY_MODE_0_7, attr)) 1895203134Sthompsa goto fail; 1896203134Sthompsa } else { 1897203134Sthompsa /* install pairwise key */ 1898203134Sthompsa if(run_read(sc, RT2860_WCID_ATTR(wcid), &attr)) 1899203134Sthompsa goto fail; 1900203134Sthompsa attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN; 1901203134Sthompsa if(run_write(sc, RT2860_WCID_ATTR(wcid), attr)) 1902203134Sthompsa goto fail; 1903203134Sthompsa } 1904203134Sthompsa 1905203134Sthompsa /* TODO create a pass-thru key entry? */ 1906203134Sthompsa 1907203134Sthompsafail: 1908203134Sthompsa RUN_UNLOCK(sc); 1909203134Sthompsa return (error? 0 : 1); 1910203134Sthompsa} 1911203134Sthompsa 1912203134Sthompsa/* 1913203134Sthompsa * return 0 on error 1914203134Sthompsa */ 1915203134Sthompsastatic int 1916203134Sthompsarun_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) 1917203134Sthompsa{ 1918203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 1919203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 1920203134Sthompsa struct ieee80211_node *ni = vap->iv_bss; 1921203134Sthompsa struct ieee80211_node_table *nt = &ic->ic_sta; 1922203134Sthompsa uint32_t attr; 1923203134Sthompsa uint8_t wcid; 1924203134Sthompsa int error = 0; 1925203134Sthompsa uint8_t nislocked, cislocked; 1926203134Sthompsa 1927203134Sthompsa if((nislocked = IEEE80211_NODE_IS_LOCKED(nt))) 1928203134Sthompsa IEEE80211_NODE_UNLOCK(nt); 1929203134Sthompsa if((cislocked = mtx_owned(&ic->ic_comlock.mtx))) 1930203134Sthompsa IEEE80211_UNLOCK(ic); 1931203134Sthompsa RUN_LOCK(sc); 1932203134Sthompsa 1933203134Sthompsa if (k->wk_flags & IEEE80211_KEY_GROUP) { 1934203134Sthompsa /* remove group key */ 1935203134Sthompsa if(run_read(sc, RT2860_SKEY_MODE_0_7, &attr)) 1936203134Sthompsa goto fail; 1937203134Sthompsa attr &= ~(0xf << (k->wk_keyix * 4)); 1938203134Sthompsa if(run_write(sc, RT2860_SKEY_MODE_0_7, attr)) 1939203134Sthompsa goto fail; 1940203134Sthompsa } else { 1941203134Sthompsa /* remove pairwise key */ 1942203134Sthompsa wcid = RUN_AID2WCID((ni != NULL) ? ni->ni_associd : 0); 1943203134Sthompsa if(run_read(sc, RT2860_WCID_ATTR(wcid), &attr)) 1944203134Sthompsa goto fail; 1945203134Sthompsa attr &= ~0xf; 1946203134Sthompsa if(run_write(sc, RT2860_WCID_ATTR(wcid), attr)) 1947203134Sthompsa goto fail; 1948203134Sthompsa } 1949203134Sthompsa 1950203134Sthompsafail: 1951203134Sthompsa RUN_UNLOCK(sc); 1952203134Sthompsa if(cislocked) 1953203134Sthompsa IEEE80211_LOCK(ic); 1954203134Sthompsa if(nislocked) 1955203134Sthompsa IEEE80211_NODE_LOCK(nt); 1956203134Sthompsa 1957203134Sthompsa return (error? 0 : 1); 1958203134Sthompsa} 1959203134Sthompsa 1960203134Sthompsastatic void 1961206358Srpaulorun_ratectl_start(struct run_softc *sc, struct ieee80211_node *ni) 1962203134Sthompsa{ 1963203134Sthompsa struct ieee80211vap *vap = ni->ni_vap; 1964203134Sthompsa struct run_vap *rvp = RUN_VAP(vap); 1965203134Sthompsa uint32_t sta[3]; 1966203134Sthompsa 1967203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 1968203134Sthompsa 1969203134Sthompsa /* read statistic counters (clear on read) and update AMRR state */ 1970203134Sthompsa run_read_region_1(sc, RT2860_TX_STA_CNT0, 1971203134Sthompsa (uint8_t *)sta, sizeof sta); 1972203134Sthompsa 1973206358Srpaulo ieee80211_ratectl_node_init(ni); 1974203134Sthompsa 1975203134Sthompsa /* start at lowest available bit-rate, AMRR will raise */ 1976203134Sthompsa ni->ni_txrate = 2; 1977203134Sthompsa 1978203134Sthompsa /* start calibration timer */ 1979206358Srpaulo rvp->ratectl_run = RUN_RATECTL_ON; 1980206358Srpaulo usb_callout_reset(&rvp->ratectl_ch, hz, run_ratectl_to, rvp); 1981203134Sthompsa} 1982203134Sthompsa 1983203134Sthompsastatic void 1984206358Srpaulorun_ratectl_to(void *arg) 1985203134Sthompsa{ 1986203134Sthompsa struct run_vap *rvp = arg; 1987203134Sthompsa 1988203134Sthompsa /* do it in a process context, so it can go sleep */ 1989206358Srpaulo ieee80211_runtask(rvp->vap.iv_ic, &rvp->ratectl_task); 1990203134Sthompsa /* next timeout will be rescheduled in the callback task */ 1991203134Sthompsa} 1992203134Sthompsa 1993203134Sthompsa/* ARGSUSED */ 1994203134Sthompsastatic void 1995206358Srpaulorun_ratectl_cb(void *arg, int pending) 1996203134Sthompsa{ 1997203134Sthompsa struct run_vap *rvp = arg; 1998203134Sthompsa struct ieee80211vap *vap = &rvp->vap; 1999203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 2000203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 2001203134Sthompsa 2002203134Sthompsa if (ic->ic_opmode == IEEE80211_M_STA) 2003203134Sthompsa run_iter_func(rvp, vap->iv_bss); 2004203134Sthompsa else { 2005203134Sthompsa /* 2006203134Sthompsa * run_reset_livelock() doesn't do anything with AMRR, 2007203134Sthompsa * but Ralink wants us to call it every 1 sec. So, we 2008203134Sthompsa * piggyback here rather than creating another callout. 2009203134Sthompsa * Livelock may occur only in HOSTAP or IBSS mode 2010203134Sthompsa * (when h/w is sending beacons). 2011203134Sthompsa */ 2012203134Sthompsa RUN_LOCK(sc); 2013203134Sthompsa run_reset_livelock(sc); 2014203134Sthompsa RUN_UNLOCK(sc); 2015203134Sthompsa ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, rvp); 2016203134Sthompsa } 2017203134Sthompsa 2018206358Srpaulo if(rvp->ratectl_run == RUN_RATECTL_ON) 2019206358Srpaulo usb_callout_reset(&rvp->ratectl_ch, hz, run_ratectl_to, rvp); 2020203134Sthompsa} 2021203134Sthompsa 2022203134Sthompsa 2023203134Sthompsastatic void 2024203134Sthompsarun_iter_func(void *arg, struct ieee80211_node *ni) 2025203134Sthompsa{ 2026203134Sthompsa struct run_vap *rvp = arg; 2027203134Sthompsa struct ieee80211com *ic = rvp->vap.iv_ic; 2028203134Sthompsa struct ifnet *ifp = ic->ic_ifp; 2029203134Sthompsa struct run_softc *sc = ifp->if_softc; 2030203134Sthompsa struct ieee80211_node_table *nt = &ic->ic_sta; 2031203134Sthompsa uint32_t sta[3], stat; 2032203134Sthompsa int error; 2033203134Sthompsa uint8_t wcid, mcs, pid; 2034206358Srpaulo struct ieee80211vap *vap = ni->ni_vap; 2035206358Srpaulo int txcnt = 0, success = 0, retrycnt = 0; 2036203134Sthompsa 2037203134Sthompsa if(ic->ic_opmode != IEEE80211_M_STA) 2038203134Sthompsa IEEE80211_NODE_ITERATE_UNLOCK(nt); 2039203134Sthompsa 2040203134Sthompsa RUN_LOCK(sc); 2041203134Sthompsa 2042203134Sthompsa if(ic->ic_opmode != IEEE80211_M_STA){ 2043203134Sthompsa /* drain Tx status FIFO (maxsize = 16) */ 2044203134Sthompsa run_read(sc, RT2860_TX_STAT_FIFO, &stat); 2045203134Sthompsa while (stat & RT2860_TXQ_VLD) { 2046203134Sthompsa DPRINTFN(4, "tx stat 0x%08x\n", stat); 2047203134Sthompsa 2048203134Sthompsa wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff; 2049203134Sthompsa 2050203134Sthompsa /* if no ACK was requested, no feedback is available */ 2051203134Sthompsa if (!(stat & RT2860_TXQ_ACKREQ) || wcid == 0xff) 2052203134Sthompsa continue; 2053203134Sthompsa 2054203134Sthompsa /* update per-STA AMRR stats */ 2055203134Sthompsa if (stat & RT2860_TXQ_OK) { 2056203134Sthompsa /* 2057203134Sthompsa * Check if there were retries, ie if the Tx 2058203134Sthompsa * success rate is different from the requested 2059203134Sthompsa * rate. Note that it works only because we do 2060203134Sthompsa * not allow rate fallback from OFDM to CCK. 2061203134Sthompsa */ 2062203134Sthompsa mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f; 2063203134Sthompsa pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf; 2064203134Sthompsa if (mcs + 1 != pid) 2065206358Srpaulo retrycnt = 1; 2066206358Srpaulo ieee80211_ratectl_tx_complete(vap, ni, 2067206358Srpaulo IEEE80211_RATECTL_TX_SUCCESS, 2068206358Srpaulo &retrycnt, NULL); 2069203134Sthompsa } else { 2070206358Srpaulo retrycnt = 1; 2071206358Srpaulo ieee80211_ratectl_tx_complete(vap, ni, 2072206358Srpaulo IEEE80211_RATECTL_TX_SUCCESS, 2073206358Srpaulo &retrycnt, NULL); 2074203134Sthompsa ifp->if_oerrors++; 2075203134Sthompsa } 2076203134Sthompsa run_read_region_1(sc, RT2860_TX_STAT_FIFO, 2077203134Sthompsa (uint8_t *)&stat, sizeof stat); 2078203134Sthompsa } 2079203134Sthompsa } else { 2080203134Sthompsa /* read statistic counters (clear on read) and update AMRR state */ 2081203134Sthompsa error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta, 2082203134Sthompsa sizeof sta); 2083203134Sthompsa if (error != 0) 2084203134Sthompsa goto skip; 2085203134Sthompsa 2086203134Sthompsa DPRINTFN(3, "retrycnt=%d txcnt=%d failcnt=%d\n", 2087203134Sthompsa le32toh(sta[1]) >> 16, le32toh(sta[1]) & 0xffff, 2088203134Sthompsa le32toh(sta[0]) & 0xffff); 2089203134Sthompsa 2090203134Sthompsa /* count failed TX as errors */ 2091203134Sthompsa ifp->if_oerrors += le32toh(sta[0]) & 0xffff; 2092203134Sthompsa 2093206358Srpaulo retrycnt = 2094203134Sthompsa (le32toh(sta[0]) & 0xffff) + /* failed TX count */ 2095203134Sthompsa (le32toh(sta[1]) >> 16); /* TX retransmission count */ 2096203134Sthompsa 2097206358Srpaulo txcnt = 2098206358Srpaulo retrycnt + 2099203134Sthompsa (le32toh(sta[1]) & 0xffff); /* successful TX count */ 2100203134Sthompsa 2101206358Srpaulo success = 2102203134Sthompsa (le32toh(sta[1]) >> 16) + 2103203134Sthompsa (le32toh(sta[1]) & 0xffff); 2104206358Srpaulo ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, 2105206358Srpaulo &retrycnt); 2106203134Sthompsa } 2107203134Sthompsa 2108206358Srpaulo ieee80211_ratectl_rate(ni, NULL, 0); 2109203134Sthompsa 2110203134Sthompsaskip:; 2111203134Sthompsa RUN_UNLOCK(sc); 2112203134Sthompsa 2113203134Sthompsa if(ic->ic_opmode != IEEE80211_M_STA) 2114203134Sthompsa IEEE80211_NODE_ITERATE_LOCK(nt); 2115203134Sthompsa} 2116203134Sthompsa 2117203134Sthompsastatic void 2118203134Sthompsarun_newassoc(struct ieee80211_node *ni, int isnew) 2119203134Sthompsa{ 2120203134Sthompsa struct run_node *rn = (void *)ni; 2121203134Sthompsa struct ieee80211_rateset *rs = &ni->ni_rates; 2122203134Sthompsa uint8_t rate; 2123203134Sthompsa int ridx, i, j; 2124203134Sthompsa 2125203134Sthompsa DPRINTF("new assoc isnew=%d addr=%s\n", 2126203134Sthompsa isnew, ether_sprintf(ni->ni_macaddr)); 2127203134Sthompsa 2128203134Sthompsa for (i = 0; i < rs->rs_nrates; i++) { 2129203134Sthompsa rate = rs->rs_rates[i] & IEEE80211_RATE_VAL; 2130203134Sthompsa /* convert 802.11 rate to hardware rate index */ 2131203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2132203134Sthompsa if (rt2860_rates[ridx].rate == rate) 2133203134Sthompsa break; 2134203134Sthompsa rn->ridx[i] = ridx; 2135203134Sthompsa /* determine rate of control response frames */ 2136203134Sthompsa for (j = i; j >= 0; j--) { 2137203134Sthompsa if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) && 2138203134Sthompsa rt2860_rates[rn->ridx[i]].phy == 2139203134Sthompsa rt2860_rates[rn->ridx[j]].phy) 2140203134Sthompsa break; 2141203134Sthompsa } 2142203134Sthompsa if (j >= 0) { 2143203134Sthompsa rn->ctl_ridx[i] = rn->ridx[j]; 2144203134Sthompsa } else { 2145203134Sthompsa /* no basic rate found, use mandatory one */ 2146203134Sthompsa rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx; 2147203134Sthompsa } 2148203134Sthompsa DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n", 2149203134Sthompsa rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]); 2150203134Sthompsa } 2151203134Sthompsa} 2152203134Sthompsa 2153203134Sthompsa/* 2154203134Sthompsa * Return the Rx chain with the highest RSSI for a given frame. 2155203134Sthompsa */ 2156203134Sthompsastatic __inline uint8_t 2157203134Sthompsarun_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi) 2158203134Sthompsa{ 2159203134Sthompsa uint8_t rxchain = 0; 2160203134Sthompsa 2161203134Sthompsa if (sc->nrxchains > 1) { 2162203134Sthompsa if (rxwi->rssi[1] > rxwi->rssi[rxchain]) 2163203134Sthompsa rxchain = 1; 2164203134Sthompsa if (sc->nrxchains > 2) 2165203134Sthompsa if (rxwi->rssi[2] > rxwi->rssi[rxchain]) 2166203134Sthompsa rxchain = 2; 2167203134Sthompsa } 2168203134Sthompsa return rxchain; 2169203134Sthompsa} 2170203134Sthompsa 2171203134Sthompsastatic void 2172203134Sthompsarun_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) 2173203134Sthompsa{ 2174203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 2175203134Sthompsa struct ieee80211vap *vap = &sc->sc_rvp->vap; 2176203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 2177203134Sthompsa struct ieee80211_frame *wh; 2178203134Sthompsa struct ieee80211_node *ni; 2179203134Sthompsa struct rt2870_rxd *rxd; 2180203134Sthompsa struct rt2860_rxwi *rxwi; 2181203134Sthompsa uint32_t flags; 2182203134Sthompsa uint16_t len, phy; 2183203134Sthompsa uint8_t ant, rssi; 2184203134Sthompsa int8_t nf; 2185203134Sthompsa 2186203134Sthompsa rxwi = mtod(m, struct rt2860_rxwi *); 2187203134Sthompsa len = le16toh(rxwi->len) & 0xfff; 2188203134Sthompsa if (__predict_false(len > dmalen)) { 2189203134Sthompsa m_freem(m); 2190203134Sthompsa ifp->if_ierrors++; 2191203134Sthompsa DPRINTF("bad RXWI length %u > %u\n", len, dmalen); 2192203134Sthompsa return; 2193203134Sthompsa } 2194203134Sthompsa /* Rx descriptor is located at the end */ 2195203134Sthompsa rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen); 2196203134Sthompsa flags = le32toh(rxd->flags); 2197203134Sthompsa 2198203134Sthompsa if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) { 2199203134Sthompsa m_freem(m); 2200203134Sthompsa ifp->if_ierrors++; 2201203134Sthompsa DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV"); 2202203134Sthompsa return; 2203203134Sthompsa } 2204203134Sthompsa 2205203134Sthompsa m->m_data += sizeof(struct rt2860_rxwi); 2206203134Sthompsa m->m_pkthdr.len = m->m_len -= sizeof(struct rt2860_rxwi); 2207203134Sthompsa 2208203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 2209203134Sthompsa 2210203134Sthompsa if (wh->i_fc[1] & IEEE80211_FC1_WEP){ 2211203134Sthompsa wh->i_fc[1] &= ~IEEE80211_FC1_WEP; 2212203134Sthompsa m->m_flags |= M_WEP; 2213203134Sthompsa } 2214203134Sthompsa 2215203134Sthompsa if (flags & RT2860_RX_L2PAD){ 2216203134Sthompsa DPRINTFN(8, "received RT2860_RX_L2PAD frame\n"); 2217203134Sthompsa len += 2; 2218203134Sthompsa } 2219203134Sthompsa 2220203134Sthompsa if (__predict_false(flags & RT2860_RX_MICERR)) { 2221203134Sthompsa /* report MIC failures to net80211 for TKIP */ 2222203134Sthompsa ieee80211_notify_michael_failure(vap, wh, rxwi->keyidx); 2223203134Sthompsa m_freem(m); 2224203134Sthompsa ifp->if_ierrors++; 2225203134Sthompsa DPRINTF("MIC error. Someone is lying.\n"); 2226203134Sthompsa return; 2227203134Sthompsa } 2228203134Sthompsa 2229203134Sthompsa ant = run_maxrssi_chain(sc, rxwi); 2230203134Sthompsa rssi = rxwi->rssi[ant]; 2231203134Sthompsa nf = run_rssi2dbm(sc, rssi, ant); 2232203134Sthompsa 2233203134Sthompsa m->m_pkthdr.rcvif = ifp; 2234203134Sthompsa m->m_pkthdr.len = m->m_len = len; 2235203134Sthompsa 2236203134Sthompsa ni = ieee80211_find_rxnode(ic, 2237203134Sthompsa mtod(m, struct ieee80211_frame_min *)); 2238203134Sthompsa if (ni != NULL) { 2239203134Sthompsa (void)ieee80211_input(ni, m, rssi, nf); 2240203134Sthompsa ieee80211_free_node(ni); 2241203134Sthompsa } else { 2242203134Sthompsa (void)ieee80211_input_all(ic, m, rssi, nf); 2243203134Sthompsa } 2244203134Sthompsa 2245203134Sthompsa if(__predict_false(ieee80211_radiotap_active(ic))){ 2246203134Sthompsa struct run_rx_radiotap_header *tap = &sc->sc_rxtap; 2247203134Sthompsa 2248203134Sthompsa tap->wr_flags = 0; 2249203134Sthompsa tap->wr_chan_freq = htole16(ic->ic_bsschan->ic_freq); 2250203134Sthompsa tap->wr_chan_flags = htole16(ic->ic_bsschan->ic_flags); 2251203134Sthompsa tap->wr_antsignal = rssi; 2252203134Sthompsa tap->wr_antenna = ant; 2253203134Sthompsa tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant); 2254203134Sthompsa tap->wr_rate = 2; /* in case it can't be found below */ 2255203134Sthompsa phy = le16toh(rxwi->phy); 2256203134Sthompsa switch (phy & RT2860_PHY_MODE) { 2257203134Sthompsa case RT2860_PHY_CCK: 2258203134Sthompsa switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) { 2259203134Sthompsa case 0: tap->wr_rate = 2; break; 2260203134Sthompsa case 1: tap->wr_rate = 4; break; 2261203134Sthompsa case 2: tap->wr_rate = 11; break; 2262203134Sthompsa case 3: tap->wr_rate = 22; break; 2263203134Sthompsa } 2264203134Sthompsa if (phy & RT2860_PHY_SHPRE) 2265203134Sthompsa tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 2266203134Sthompsa break; 2267203134Sthompsa case RT2860_PHY_OFDM: 2268203134Sthompsa switch (phy & RT2860_PHY_MCS) { 2269203134Sthompsa case 0: tap->wr_rate = 12; break; 2270203134Sthompsa case 1: tap->wr_rate = 18; break; 2271203134Sthompsa case 2: tap->wr_rate = 24; break; 2272203134Sthompsa case 3: tap->wr_rate = 36; break; 2273203134Sthompsa case 4: tap->wr_rate = 48; break; 2274203134Sthompsa case 5: tap->wr_rate = 72; break; 2275203134Sthompsa case 6: tap->wr_rate = 96; break; 2276203134Sthompsa case 7: tap->wr_rate = 108; break; 2277203134Sthompsa } 2278203134Sthompsa break; 2279203134Sthompsa } 2280203134Sthompsa } 2281203134Sthompsa} 2282203134Sthompsa 2283203134Sthompsastatic void 2284203134Sthompsarun_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) 2285203134Sthompsa{ 2286203134Sthompsa struct run_softc *sc = usbd_xfer_softc(xfer); 2287203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 2288203134Sthompsa struct mbuf *m = NULL; 2289203134Sthompsa struct mbuf *m0; 2290203134Sthompsa uint32_t dmalen; 2291203134Sthompsa int xferlen; 2292203134Sthompsa 2293203134Sthompsa usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL); 2294203134Sthompsa 2295203134Sthompsa switch (USB_GET_STATE(xfer)) { 2296203134Sthompsa case USB_ST_TRANSFERRED: 2297203134Sthompsa 2298203134Sthompsa DPRINTFN(15, "rx done, actlen=%d\n", xferlen); 2299203134Sthompsa 2300203134Sthompsa if (xferlen < sizeof (uint32_t) + 2301203134Sthompsa sizeof (struct rt2860_rxwi) + sizeof (struct rt2870_rxd)) { 2302203134Sthompsa DPRINTF("xfer too short %d\n", xferlen); 2303203134Sthompsa goto tr_setup; 2304203134Sthompsa } 2305203134Sthompsa 2306203134Sthompsa m = sc->rx_m; 2307203134Sthompsa sc->rx_m = NULL; 2308203134Sthompsa 2309203134Sthompsa /* FALLTHROUGH */ 2310203134Sthompsa case USB_ST_SETUP: 2311203134Sthompsatr_setup: 2312203134Sthompsa if (sc->rx_m == NULL) { 2313203134Sthompsa sc->rx_m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, 2314203134Sthompsa MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */); 2315203134Sthompsa } 2316203134Sthompsa if (sc->rx_m == NULL) { 2317203134Sthompsa DPRINTF("could not allocate mbuf - idle with stall\n"); 2318203134Sthompsa ifp->if_ierrors++; 2319203134Sthompsa usbd_xfer_set_stall(xfer); 2320203134Sthompsa usbd_xfer_set_frames(xfer, 0); 2321203134Sthompsa } else { 2322203134Sthompsa /* 2323203134Sthompsa * Directly loading a mbuf cluster into DMA to 2324203134Sthompsa * save some data copying. This works because 2325203134Sthompsa * there is only one cluster. 2326203134Sthompsa */ 2327203134Sthompsa usbd_xfer_set_frame_data(xfer, 0, 2328203134Sthompsa mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ); 2329203134Sthompsa usbd_xfer_set_frames(xfer, 1); 2330203134Sthompsa } 2331203134Sthompsa usbd_transfer_submit(xfer); 2332203134Sthompsa break; 2333203134Sthompsa 2334203134Sthompsa default: /* Error */ 2335203134Sthompsa if (error != USB_ERR_CANCELLED) { 2336203134Sthompsa /* try to clear stall first */ 2337203134Sthompsa usbd_xfer_set_stall(xfer); 2338203134Sthompsa 2339203134Sthompsa if (error == USB_ERR_TIMEOUT) 2340203134Sthompsa device_printf(sc->sc_dev, "device timeout\n"); 2341203134Sthompsa 2342203134Sthompsa ifp->if_ierrors++; 2343203134Sthompsa 2344203134Sthompsa goto tr_setup; 2345203134Sthompsa } 2346203134Sthompsa if(sc->rx_m != NULL){ 2347203134Sthompsa m_freem(sc->rx_m); 2348203134Sthompsa sc->rx_m = NULL; 2349203134Sthompsa } 2350203134Sthompsa break; 2351203134Sthompsa } 2352203134Sthompsa 2353203134Sthompsa if (m == NULL) 2354203134Sthompsa return; 2355203134Sthompsa 2356203134Sthompsa /* inputting all the frames must be last */ 2357203134Sthompsa 2358203134Sthompsa RUN_UNLOCK(sc); 2359203134Sthompsa 2360203134Sthompsa m->m_pkthdr.len = m->m_len = xferlen; 2361203134Sthompsa 2362203134Sthompsa /* HW can aggregate multiple 802.11 frames in a single USB xfer */ 2363203134Sthompsa for(;;) { 2364203134Sthompsa dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff; 2365203134Sthompsa 2366203134Sthompsa if ((dmalen == 0) || ((dmalen & 3) != 0)) { 2367203134Sthompsa DPRINTF("bad DMA length %u\n", dmalen); 2368203134Sthompsa break; 2369203134Sthompsa } 2370203134Sthompsa if ((dmalen + 8) > xferlen) { 2371203134Sthompsa DPRINTF("bad DMA length %u > %d\n", 2372203134Sthompsa dmalen + 8, xferlen); 2373203134Sthompsa break; 2374203134Sthompsa } 2375203134Sthompsa 2376203134Sthompsa /* If it is the last one or a single frame, we won't copy. */ 2377203134Sthompsa if((xferlen -= dmalen + 8) <= 8){ 2378203134Sthompsa /* trim 32-bit DMA-len header */ 2379203134Sthompsa m->m_data += 4; 2380203134Sthompsa m->m_pkthdr.len = m->m_len -= 4; 2381203134Sthompsa run_rx_frame(sc, m, dmalen); 2382203134Sthompsa break; 2383203134Sthompsa } 2384203134Sthompsa 2385203134Sthompsa /* copy aggregated frames to another mbuf */ 2386203134Sthompsa m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 2387203134Sthompsa if (__predict_false(m0 == NULL)) { 2388203134Sthompsa DPRINTF("could not allocate mbuf\n"); 2389203134Sthompsa ifp->if_ierrors++; 2390203134Sthompsa break; 2391203134Sthompsa } 2392203134Sthompsa m_copydata(m, 4 /* skip 32-bit DMA-len header */, 2393203134Sthompsa dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t)); 2394203134Sthompsa m0->m_pkthdr.len = m0->m_len = 2395203134Sthompsa dmalen + sizeof(struct rt2870_rxd); 2396203134Sthompsa run_rx_frame(sc, m0, dmalen); 2397203134Sthompsa 2398203134Sthompsa /* update data ptr */ 2399203134Sthompsa m->m_data += dmalen + 8; 2400203134Sthompsa m->m_pkthdr.len = m->m_len -= dmalen + 8; 2401203134Sthompsa } 2402203134Sthompsa 2403203134Sthompsa RUN_LOCK(sc); 2404203134Sthompsa} 2405203134Sthompsa 2406203134Sthompsastatic void 2407203134Sthompsarun_tx_free(struct run_endpoint_queue *pq, 2408203134Sthompsa struct run_tx_data *data, int txerr) 2409203134Sthompsa{ 2410203134Sthompsa if (data->m != NULL) { 2411203134Sthompsa if (data->m->m_flags & M_TXCB) 2412203134Sthompsa ieee80211_process_callback(data->ni, data->m, 2413203134Sthompsa txerr ? ETIMEDOUT : 0); 2414203134Sthompsa m_freem(data->m); 2415203134Sthompsa data->m = NULL; 2416203134Sthompsa 2417203134Sthompsa if(data->ni == NULL) { 2418203134Sthompsa DPRINTF("no node\n"); 2419203134Sthompsa } else { 2420203134Sthompsa ieee80211_free_node(data->ni); 2421203134Sthompsa data->ni = NULL; 2422203134Sthompsa } 2423203134Sthompsa } 2424203134Sthompsa 2425203134Sthompsa STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); 2426203134Sthompsa pq->tx_nfree++; 2427203134Sthompsa} 2428203134Sthompsa 2429203134Sthompsastatic void 2430203134Sthompsarun_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, unsigned int index) 2431203134Sthompsa{ 2432203134Sthompsa struct run_softc *sc = usbd_xfer_softc(xfer); 2433203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 2434203134Sthompsa struct run_tx_data *data; 2435203134Sthompsa struct ieee80211vap *vap = NULL; 2436203134Sthompsa struct usb_page_cache *pc; 2437203134Sthompsa struct run_endpoint_queue *pq = &sc->sc_epq[index]; 2438203134Sthompsa struct mbuf *m; 2439203134Sthompsa usb_frlength_t size; 2440203134Sthompsa unsigned int len; 2441203134Sthompsa int actlen; 2442203134Sthompsa int sumlen; 2443203134Sthompsa 2444203134Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 2445203134Sthompsa 2446203134Sthompsa switch (USB_GET_STATE(xfer)){ 2447203134Sthompsa case USB_ST_TRANSFERRED: 2448203134Sthompsa DPRINTFN(11, "transfer complete: %d " 2449203134Sthompsa "bytes @ index %d\n", actlen, index); 2450203134Sthompsa 2451203134Sthompsa data = usbd_xfer_get_priv(xfer); 2452203134Sthompsa 2453203134Sthompsa run_tx_free(pq, data, 0); 2454203134Sthompsa ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2455203134Sthompsa 2456203134Sthompsa usbd_xfer_set_priv(xfer, NULL); 2457203134Sthompsa 2458203134Sthompsa ifp->if_opackets++; 2459203134Sthompsa 2460203134Sthompsa /* FALLTHROUGH */ 2461203134Sthompsa case USB_ST_SETUP: 2462203134Sthompsatr_setup: 2463203134Sthompsa data = STAILQ_FIRST(&pq->tx_qh); 2464203134Sthompsa if(data == NULL) 2465203134Sthompsa break; 2466203134Sthompsa 2467203134Sthompsa STAILQ_REMOVE_HEAD(&pq->tx_qh, next); 2468203134Sthompsa 2469203134Sthompsa m = data->m; 2470203134Sthompsa if (m->m_pkthdr.len > RUN_MAX_TXSZ) { 2471203134Sthompsa DPRINTF("data overflow, %u bytes\n", 2472203134Sthompsa m->m_pkthdr.len); 2473203134Sthompsa 2474203134Sthompsa ifp->if_oerrors++; 2475203134Sthompsa 2476203134Sthompsa run_tx_free(pq, data, 1); 2477203134Sthompsa 2478203134Sthompsa goto tr_setup; 2479203134Sthompsa } 2480203134Sthompsa 2481203134Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 2482203134Sthompsa size = sizeof(data->desc); 2483203134Sthompsa usbd_copy_in(pc, 0, &data->desc, size); 2484203134Sthompsa usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len); 2485203134Sthompsa 2486203134Sthompsa vap = data->ni->ni_vap; 2487203134Sthompsa if (ieee80211_radiotap_active_vap(vap)) { 2488203134Sthompsa struct run_tx_radiotap_header *tap = &sc->sc_txtap; 2489203134Sthompsa 2490203134Sthompsa tap->wt_flags = 0; 2491203134Sthompsa tap->wt_rate = rt2860_rates[data->ridx].rate; 2492203134Sthompsa tap->wt_chan_freq = htole16(vap->iv_bss->ni_chan->ic_freq); 2493203134Sthompsa tap->wt_chan_flags = htole16(vap->iv_bss->ni_chan->ic_flags); 2494203134Sthompsa tap->wt_hwqueue = index; 2495203134Sthompsa if (data->mcs & RT2860_PHY_SHPRE) 2496203134Sthompsa tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 2497203134Sthompsa 2498203134Sthompsa ieee80211_radiotap_tx(vap, m); 2499203134Sthompsa } 2500203134Sthompsa 2501203134Sthompsa /* align end on a 4-bytes boundary */ 2502203134Sthompsa len = (size + m->m_pkthdr.len + 3) & ~3; 2503203134Sthompsa 2504203134Sthompsa DPRINTFN(11, "sending frame len=%u xferlen=%u @ index %d\n", 2505203134Sthompsa m->m_pkthdr.len, len, index); 2506203134Sthompsa 2507203134Sthompsa usbd_xfer_set_frame_len(xfer, 0, len); 2508203134Sthompsa usbd_xfer_set_priv(xfer, data); 2509203134Sthompsa 2510203134Sthompsa usbd_transfer_submit(xfer); 2511203134Sthompsa 2512203134Sthompsa RUN_UNLOCK(sc); 2513203134Sthompsa run_start(ifp); 2514203134Sthompsa RUN_LOCK(sc); 2515203134Sthompsa 2516203134Sthompsa break; 2517203134Sthompsa 2518203134Sthompsa default: 2519203134Sthompsa DPRINTF("USB transfer error, %s\n", 2520203134Sthompsa usbd_errstr(error)); 2521203134Sthompsa 2522203134Sthompsa data = usbd_xfer_get_priv(xfer); 2523203134Sthompsa 2524203134Sthompsa ifp->if_oerrors++; 2525203134Sthompsa 2526203134Sthompsa if (data != NULL) { 2527203134Sthompsa run_tx_free(pq, data, error); 2528203134Sthompsa usbd_xfer_set_priv(xfer, NULL); 2529203134Sthompsa } 2530203134Sthompsa 2531203134Sthompsa if (error != USB_ERR_CANCELLED) { 2532203134Sthompsa if (error == USB_ERR_TIMEOUT) { 2533203134Sthompsa device_printf(sc->sc_dev, "device timeout\n"); 2534203134Sthompsa ieee80211_runtask(ifp->if_l2com, &sc->usb_timeout_task); 2535203134Sthompsa } 2536203134Sthompsa 2537203134Sthompsa /* 2538203134Sthompsa * Try to clear stall first, also if other 2539203134Sthompsa * errors occur, hence clearing stall 2540203134Sthompsa * introduces a 50 ms delay: 2541203134Sthompsa */ 2542203134Sthompsa usbd_xfer_set_stall(xfer); 2543203134Sthompsa goto tr_setup; 2544203134Sthompsa } 2545203134Sthompsa break; 2546203134Sthompsa } 2547203134Sthompsa} 2548203134Sthompsa 2549203134Sthompsastatic void 2550203134Sthompsarun_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error) 2551203134Sthompsa{ 2552203134Sthompsa run_bulk_tx_callbackN(xfer, error, 0); 2553203134Sthompsa} 2554203134Sthompsa 2555203134Sthompsastatic void 2556203134Sthompsarun_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error) 2557203134Sthompsa{ 2558203134Sthompsa run_bulk_tx_callbackN(xfer, error, 1); 2559203134Sthompsa} 2560203134Sthompsa 2561203134Sthompsastatic void 2562203134Sthompsarun_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error) 2563203134Sthompsa{ 2564203134Sthompsa run_bulk_tx_callbackN(xfer, error, 2); 2565203134Sthompsa} 2566203134Sthompsa 2567203134Sthompsastatic void 2568203134Sthompsarun_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error) 2569203134Sthompsa{ 2570203134Sthompsa run_bulk_tx_callbackN(xfer, error, 3); 2571203134Sthompsa} 2572203134Sthompsa 2573203134Sthompsastatic void 2574203134Sthompsarun_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error) 2575203134Sthompsa{ 2576203134Sthompsa run_bulk_tx_callbackN(xfer, error, 4); 2577203134Sthompsa} 2578203134Sthompsa 2579203134Sthompsastatic void 2580203134Sthompsarun_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error) 2581203134Sthompsa{ 2582203134Sthompsa run_bulk_tx_callbackN(xfer, error, 5); 2583203134Sthompsa} 2584203134Sthompsa 2585203134Sthompsastatic void 2586203134Sthompsarun_set_tx_desc(struct run_softc *sc, struct run_tx_data *data, 2587203134Sthompsa uint8_t wflags, uint8_t xflags, uint8_t opflags, uint8_t dflags, 2588203134Sthompsa uint8_t type, uint8_t pad) 2589203134Sthompsa{ 2590203134Sthompsa struct mbuf *m = data->m; 2591203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 2592203134Sthompsa struct ieee80211vap *vap = &sc->sc_rvp->vap; 2593203134Sthompsa struct ieee80211_frame *wh; 2594203134Sthompsa struct rt2870_txd *txd; 2595203134Sthompsa struct rt2860_txwi *txwi; 2596203134Sthompsa int xferlen; 2597203134Sthompsa uint8_t mcs; 2598203134Sthompsa uint8_t ridx = data->ridx; 2599203134Sthompsa 2600203134Sthompsa /* get MCS code from rate index */ 2601203134Sthompsa data->mcs = mcs = rt2860_rates[ridx].mcs; 2602203134Sthompsa 2603203134Sthompsa xferlen = sizeof(*txwi) + m->m_pkthdr.len; 2604203134Sthompsa 2605203134Sthompsa /* roundup to 32-bit alignment */ 2606203134Sthompsa xferlen = (xferlen + 3) & ~3; 2607203134Sthompsa 2608203134Sthompsa txd = (struct rt2870_txd *)&data->desc; 2609203134Sthompsa txd->flags = dflags; 2610203134Sthompsa txd->len = htole16(xferlen); 2611203134Sthompsa 2612203134Sthompsa /* setup TX Wireless Information */ 2613203134Sthompsa txwi = (struct rt2860_txwi *)(txd + 1); 2614203134Sthompsa txwi->flags = wflags; 2615203134Sthompsa txwi->xflags = xflags; 2616203134Sthompsa txwi->wcid = (type == IEEE80211_FC0_TYPE_DATA) ? 2617203134Sthompsa RUN_AID2WCID(data->ni->ni_associd) : 0xff; 2618203134Sthompsa txwi->len = htole16(m->m_pkthdr.len - pad); 2619203134Sthompsa if (rt2860_rates[ridx].phy == IEEE80211_T_DS) { 2620203134Sthompsa txwi->phy = htole16(RT2860_PHY_CCK); 2621203134Sthompsa if (ridx != RT2860_RIDX_CCK1 && 2622203134Sthompsa (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 2623203134Sthompsa mcs |= RT2860_PHY_SHPRE; 2624203134Sthompsa } else 2625203134Sthompsa txwi->phy = htole16(RT2860_PHY_OFDM); 2626203134Sthompsa txwi->phy |= htole16(mcs); 2627203134Sthompsa 2628203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 2629203134Sthompsa 2630203134Sthompsa /* check if RTS/CTS or CTS-to-self protection is required */ 2631203134Sthompsa if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 2632203134Sthompsa (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold || 2633203134Sthompsa ((ic->ic_flags & IEEE80211_F_USEPROT) && 2634203134Sthompsa rt2860_rates[ridx].phy == IEEE80211_T_OFDM))) 2635203134Sthompsa txwi->txop = RT2860_TX_TXOP_HT | opflags; 2636203134Sthompsa else 2637203134Sthompsa txwi->txop = RT2860_TX_TXOP_BACKOFF | opflags; 2638203134Sthompsa} 2639203134Sthompsa 2640203134Sthompsa/* This function must be called locked */ 2641203134Sthompsastatic int 2642203134Sthompsarun_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) 2643203134Sthompsa{ 2644203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 2645203134Sthompsa struct ieee80211vap *vap = &sc->sc_rvp->vap; 2646203134Sthompsa struct ieee80211_frame *wh; 2647203134Sthompsa const struct ieee80211_txparam *tp; 2648203134Sthompsa struct run_tx_data *data; 2649203134Sthompsa uint16_t qos; 2650203134Sthompsa uint16_t dur; 2651203134Sthompsa uint8_t type; 2652203134Sthompsa uint8_t tid; 2653203134Sthompsa uint8_t qid; 2654203134Sthompsa uint8_t qflags; 2655203134Sthompsa uint8_t pad; 2656203134Sthompsa uint8_t xflags = 0; 2657203134Sthompsa int hasqos; 2658203134Sthompsa int ridx; 2659203134Sthompsa int ctl_ridx; 2660203134Sthompsa 2661203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2662203134Sthompsa 2663203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 2664203134Sthompsa 2665203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 2666203134Sthompsa 2667203134Sthompsa /* 2668203134Sthompsa * There are 7 bulk endpoints: 1 for RX 2669203134Sthompsa * and 6 for TX (4 EDCAs + HCCA + Prio). 2670203134Sthompsa * Update 03-14-2009: some devices like the Planex GW-US300MiniS 2671203134Sthompsa * seem to have only 4 TX bulk endpoints (Fukaumi Naoki). 2672203134Sthompsa */ 2673203134Sthompsa if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) { 2674203134Sthompsa uint8_t *frm; 2675203134Sthompsa 2676203134Sthompsa if(IEEE80211_HAS_ADDR4(wh)) 2677203134Sthompsa frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos; 2678203134Sthompsa else 2679203134Sthompsa frm =((struct ieee80211_qosframe *)wh)->i_qos; 2680203134Sthompsa 2681203134Sthompsa qos = le16toh(*(const uint16_t *)frm); 2682203134Sthompsa tid = qos & IEEE80211_QOS_TID; 2683203134Sthompsa qid = TID_TO_WME_AC(tid); 2684203134Sthompsa pad = 2; 2685203134Sthompsa } else { 2686203134Sthompsa qos = 0; 2687203134Sthompsa tid = 0; 2688203134Sthompsa qid = WME_AC_BE; 2689203134Sthompsa pad = 0; 2690203134Sthompsa } 2691203134Sthompsa qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA; 2692203134Sthompsa 2693203134Sthompsa DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n", 2694203134Sthompsa qos, qid, tid, qflags); 2695203134Sthompsa 2696203134Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; 2697203134Sthompsa 2698203134Sthompsa /* pickup a rate index */ 2699203134Sthompsa if (IEEE80211_IS_MULTICAST(wh->i_addr1) || 2700203134Sthompsa type != IEEE80211_FC0_TYPE_DATA) { 2701203134Sthompsa ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? 2702203134Sthompsa RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; 2703203134Sthompsa ctl_ridx = rt2860_rates[ridx].ctl_ridx; 2704203134Sthompsa } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 2705203134Sthompsa ridx = sc->fixed_ridx; 2706203134Sthompsa ctl_ridx = rt2860_rates[ridx].ctl_ridx; 2707203134Sthompsa } else { 2708203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++){ 2709203134Sthompsa if (rt2860_rates[ridx].rate == ni->ni_txrate) 2710203134Sthompsa break; 2711203134Sthompsa } 2712203134Sthompsa ctl_ridx = rt2860_rates[ridx].ctl_ridx; 2713203134Sthompsa } 2714203134Sthompsa 2715203134Sthompsa if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 2716203134Sthompsa (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) != 2717203134Sthompsa IEEE80211_QOS_ACKPOLICY_NOACK)) { 2718203134Sthompsa xflags |= RT2860_TX_ACK; 2719203134Sthompsa if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 2720203134Sthompsa dur = rt2860_rates[ridx].sp_ack_dur; 2721203134Sthompsa else 2722203134Sthompsa dur = rt2860_rates[ridx].lp_ack_dur; 2723205042Sthompsa *(uint16_t *)wh->i_dur = htole16(dur); 2724203134Sthompsa } 2725203134Sthompsa 2726203134Sthompsa /* reserve slots for mgmt packets, just in case */ 2727203134Sthompsa if (sc->sc_epq[qid].tx_nfree < 3) { 2728203134Sthompsa DPRINTFN(10, "tx ring %d is full\n", qid); 2729203134Sthompsa return (-1); 2730203134Sthompsa } 2731203134Sthompsa 2732203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh); 2733203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next); 2734203134Sthompsa sc->sc_epq[qid].tx_nfree--; 2735203134Sthompsa 2736203134Sthompsa data->m = m; 2737203134Sthompsa data->ni = ni; 2738203134Sthompsa data->ridx = ridx; 2739203134Sthompsa 2740203134Sthompsa run_set_tx_desc(sc, data, 0, xflags, 0, qflags, type, pad); 2741203134Sthompsa 2742203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next); 2743203134Sthompsa 2744203134Sthompsa usbd_transfer_start(sc->sc_xfer[qid]); 2745203134Sthompsa 2746203134Sthompsa DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n", m->m_pkthdr.len + 2747203134Sthompsa (int)(sizeof (struct rt2870_txd) + sizeof (struct rt2860_rxwi)), 2748203134Sthompsa rt2860_rates[ridx].rate, qid); 2749203134Sthompsa 2750203134Sthompsa return (0); 2751203134Sthompsa} 2752203134Sthompsa 2753203134Sthompsastatic int 2754203134Sthompsarun_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) 2755203134Sthompsa{ 2756203134Sthompsa const struct ieee80211_txparam *tp; 2757203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 2758203134Sthompsa struct ieee80211vap *vap = ni->ni_vap; 2759203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 2760203134Sthompsa struct run_tx_data *data; 2761203134Sthompsa struct ieee80211_frame *wh; 2762203134Sthompsa int ridx; 2763203134Sthompsa uint16_t dur; 2764203134Sthompsa uint8_t type; 2765203134Sthompsa uint8_t xflags = 0; 2766203134Sthompsa 2767203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2768203134Sthompsa 2769203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 2770203134Sthompsa 2771203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 2772203134Sthompsa tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 2773203134Sthompsa 2774203134Sthompsa if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 2775203134Sthompsa xflags |= RT2860_TX_ACK; 2776203134Sthompsa 2777203134Sthompsa dur = ieee80211_ack_duration(ic->ic_rt, tp->mgmtrate, 2778203134Sthompsa ic->ic_flags & IEEE80211_F_SHPREAMBLE); 2779203134Sthompsa *(uint16_t *)wh->i_dur = htole16(dur); 2780203134Sthompsa 2781203134Sthompsa /* tell hardware to add timestamp for probe responses */ 2782203134Sthompsa if ((wh->i_fc[0] & 2783203134Sthompsa (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == 2784203134Sthompsa (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) 2785203134Sthompsa xflags |= RT2860_TX_TS; 2786203134Sthompsa } 2787203134Sthompsa 2788203134Sthompsa if (sc->sc_epq[0].tx_nfree == 0) { 2789203134Sthompsa /* let caller free mbuf */ 2790203134Sthompsa ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2791203134Sthompsa return (EIO); 2792203134Sthompsa } 2793203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 2794203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 2795203134Sthompsa sc->sc_epq[0].tx_nfree--; 2796203134Sthompsa 2797203134Sthompsa data->m = m; 2798203134Sthompsa data->ni = ni; 2799203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2800203134Sthompsa if (rt2860_rates[ridx].rate == tp->mgmtrate) 2801203134Sthompsa break; 2802203134Sthompsa data->ridx = ridx; 2803203134Sthompsa 2804203134Sthompsa run_set_tx_desc(sc, data, 0, xflags, 0, RT2860_TX_QSEL_MGMT, 2805203134Sthompsa wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, 0); 2806203134Sthompsa 2807203134Sthompsa DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len + 2808203134Sthompsa (int)(sizeof (struct rt2870_txd) + sizeof (struct rt2860_rxwi)), 2809203134Sthompsa tp->mgmtrate); 2810203134Sthompsa 2811203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 2812203134Sthompsa 2813203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 2814203134Sthompsa 2815203134Sthompsa return (0); 2816203134Sthompsa} 2817203134Sthompsa 2818203134Sthompsastatic int 2819203134Sthompsarun_sendprot(struct run_softc *sc, 2820203134Sthompsa const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) 2821203134Sthompsa{ 2822203134Sthompsa struct ieee80211com *ic = ni->ni_ic; 2823203134Sthompsa struct ieee80211_frame *wh; 2824203134Sthompsa struct run_tx_data *data; 2825203134Sthompsa struct mbuf *mprot; 2826203134Sthompsa int ridx; 2827203134Sthompsa int protrate; 2828203134Sthompsa int ackrate; 2829203134Sthompsa int pktlen; 2830203134Sthompsa int isshort; 2831203134Sthompsa uint16_t dur; 2832203134Sthompsa uint8_t type; 2833203134Sthompsa uint8_t wflags; 2834203134Sthompsa uint8_t txflags = 0; 2835203134Sthompsa 2836203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2837203134Sthompsa 2838203134Sthompsa KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, 2839203134Sthompsa ("protection %d", prot)); 2840203134Sthompsa 2841203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 2842203134Sthompsa pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; 2843203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 2844203134Sthompsa 2845203134Sthompsa protrate = ieee80211_ctl_rate(ic->ic_rt, rate); 2846203134Sthompsa ackrate = ieee80211_ack_rate(ic->ic_rt, rate); 2847203134Sthompsa 2848203134Sthompsa isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; 2849203134Sthompsa dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort); 2850203134Sthompsa + ieee80211_ack_duration(ic->ic_rt, rate, isshort); 2851203134Sthompsa wflags = RT2860_TX_FRAG; 2852203134Sthompsa 2853203134Sthompsa /* check that there are free slots before allocating the mbuf */ 2854203134Sthompsa if (sc->sc_epq[0].tx_nfree == 0) { 2855203134Sthompsa /* let caller free mbuf */ 2856203134Sthompsa sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2857203134Sthompsa return (ENOBUFS); 2858203134Sthompsa } 2859203134Sthompsa 2860203134Sthompsa if (prot == IEEE80211_PROT_RTSCTS) { 2861203134Sthompsa /* NB: CTS is the same size as an ACK */ 2862203134Sthompsa dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); 2863203134Sthompsa txflags |= RT2860_TX_ACK; 2864203134Sthompsa mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); 2865203134Sthompsa } else { 2866203134Sthompsa mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); 2867203134Sthompsa } 2868203134Sthompsa if (mprot == NULL) { 2869203134Sthompsa sc->sc_ifp->if_oerrors++; 2870203134Sthompsa DPRINTF("could not allocate mbuf\n"); 2871203134Sthompsa return (ENOBUFS); 2872203134Sthompsa } 2873203134Sthompsa 2874203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 2875203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 2876203134Sthompsa sc->sc_epq[0].tx_nfree--; 2877203134Sthompsa 2878203134Sthompsa data->m = mprot; 2879203134Sthompsa data->ni = ieee80211_ref_node(ni); 2880203134Sthompsa 2881203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2882203134Sthompsa if (rt2860_rates[ridx].rate == protrate) 2883203134Sthompsa break; 2884203134Sthompsa data->ridx = ridx; 2885203134Sthompsa 2886203134Sthompsa run_set_tx_desc(sc, data, wflags, txflags, 0, 2887203134Sthompsa RT2860_TX_QSEL_EDCA, type, 0); 2888203134Sthompsa 2889203134Sthompsa DPRINTFN(1, "sending prot len=%u rate=%u\n", 2890203134Sthompsa m->m_pkthdr.len, rate); 2891203134Sthompsa 2892203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 2893203134Sthompsa 2894203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 2895203134Sthompsa 2896203134Sthompsa return (0); 2897203134Sthompsa} 2898203134Sthompsa 2899203134Sthompsastatic int 2900203134Sthompsarun_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, 2901203134Sthompsa const struct ieee80211_bpf_params *params) 2902203134Sthompsa{ 2903203134Sthompsa struct ieee80211com *ic = ni->ni_ic; 2904203134Sthompsa struct ieee80211_frame *wh; 2905203134Sthompsa struct run_tx_data *data; 2906203134Sthompsa uint8_t type; 2907203134Sthompsa uint8_t opflags; 2908203134Sthompsa uint8_t txflags; 2909203134Sthompsa int ridx; 2910203134Sthompsa int rate; 2911203134Sthompsa int error; 2912203134Sthompsa 2913203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 2914203134Sthompsa 2915203134Sthompsa KASSERT(params != NULL, ("no raw xmit params")); 2916203134Sthompsa 2917203134Sthompsa wh = mtod(m, struct ieee80211_frame *); 2918203134Sthompsa type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 2919203134Sthompsa 2920203134Sthompsa rate = params->ibp_rate0; 2921203134Sthompsa if (!ieee80211_isratevalid(ic->ic_rt, rate)) { 2922203134Sthompsa /* let caller free mbuf */ 2923203134Sthompsa return (EINVAL); 2924203134Sthompsa } 2925203134Sthompsa 2926203134Sthompsa opflags = 0; 2927203134Sthompsa txflags = 0; 2928203134Sthompsa if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) 2929203134Sthompsa txflags |= RT2860_TX_ACK; 2930203134Sthompsa if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { 2931203134Sthompsa error = run_sendprot(sc, m, ni, 2932203134Sthompsa params->ibp_flags & IEEE80211_BPF_RTS ? 2933203134Sthompsa IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, 2934203134Sthompsa rate); 2935203134Sthompsa if (error) { 2936203134Sthompsa /* let caller free mbuf */ 2937203134Sthompsa return (error); 2938203134Sthompsa } 2939203134Sthompsa opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS; 2940203134Sthompsa } 2941203134Sthompsa 2942203134Sthompsa if (sc->sc_epq[0].tx_nfree == 0) { 2943203134Sthompsa /* let caller free mbuf */ 2944203134Sthompsa sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2945203134Sthompsa DPRINTF("sending raw frame, but tx ring is full\n"); 2946203134Sthompsa return (EIO); 2947203134Sthompsa } 2948203134Sthompsa data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); 2949203134Sthompsa STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); 2950203134Sthompsa sc->sc_epq[0].tx_nfree--; 2951203134Sthompsa 2952203134Sthompsa data->m = m; 2953203134Sthompsa data->ni = ni; 2954203134Sthompsa for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) 2955203134Sthompsa if (rt2860_rates[ridx].rate == rate) 2956203134Sthompsa break; 2957203134Sthompsa data->ridx = ridx; 2958203134Sthompsa 2959203134Sthompsa run_set_tx_desc(sc, data, 0, txflags, opflags, 2960203134Sthompsa RT2860_TX_QSEL_EDCA, type, 0); 2961203134Sthompsa 2962203134Sthompsa DPRINTFN(10, "sending raw frame len=%u rate=%u\n", 2963203134Sthompsa m->m_pkthdr.len, rate); 2964203134Sthompsa 2965203134Sthompsa STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); 2966203134Sthompsa 2967203134Sthompsa usbd_transfer_start(sc->sc_xfer[0]); 2968203134Sthompsa 2969203134Sthompsa return (0); 2970203134Sthompsa} 2971203134Sthompsa 2972203134Sthompsastatic int 2973203134Sthompsarun_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 2974203134Sthompsa const struct ieee80211_bpf_params *params) 2975203134Sthompsa{ 2976203134Sthompsa struct ifnet *ifp = ni->ni_ic->ic_ifp; 2977203134Sthompsa struct run_softc *sc = ifp->if_softc; 2978203134Sthompsa int error; 2979203134Sthompsa 2980203134Sthompsa RUN_LOCK(sc); 2981203134Sthompsa 2982203134Sthompsa /* prevent management frames from being sent if we're not ready */ 2983203134Sthompsa if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2984203134Sthompsa error = ENETDOWN; 2985203134Sthompsa goto bad; 2986203134Sthompsa } 2987203134Sthompsa 2988203134Sthompsa if (params == NULL) { 2989203134Sthompsa /* tx mgt packet */ 2990203134Sthompsa if ((error = run_tx_mgt(sc, m, ni)) != 0){ 2991203134Sthompsa ifp->if_oerrors++; 2992203134Sthompsa DPRINTF("mgt tx failed\n"); 2993203134Sthompsa goto bad; 2994203134Sthompsa } 2995203134Sthompsa } else { 2996203134Sthompsa /* tx raw packet with param */ 2997203134Sthompsa if ((error = run_tx_param(sc, m, ni, params)) != 0){ 2998203134Sthompsa ifp->if_oerrors++; 2999203134Sthompsa DPRINTF("tx with param failed\n"); 3000203134Sthompsa goto bad; 3001203134Sthompsa } 3002203134Sthompsa } 3003203134Sthompsa 3004203134Sthompsa ifp->if_opackets++; 3005203134Sthompsa 3006203134Sthompsa RUN_UNLOCK(sc); 3007203134Sthompsa 3008203134Sthompsa return (0); 3009203134Sthompsa 3010203134Sthompsabad: 3011203134Sthompsa RUN_UNLOCK(sc); 3012203134Sthompsa if(m != NULL) 3013203134Sthompsa m_freem(m); 3014203134Sthompsa ieee80211_free_node(ni); 3015203134Sthompsa 3016203134Sthompsa return (error); 3017203134Sthompsa} 3018203134Sthompsa 3019203134Sthompsastatic void 3020203134Sthompsarun_start(struct ifnet *ifp) 3021203134Sthompsa{ 3022203134Sthompsa struct run_softc *sc = ifp->if_softc; 3023203134Sthompsa struct ieee80211_node *ni; 3024203134Sthompsa struct mbuf *m; 3025203134Sthompsa 3026203134Sthompsa RUN_LOCK(sc); 3027203134Sthompsa 3028203134Sthompsa if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 3029203134Sthompsa RUN_UNLOCK(sc); 3030203134Sthompsa return; 3031203134Sthompsa } 3032203134Sthompsa 3033203134Sthompsa for (;;) { 3034203134Sthompsa /* send data frames */ 3035203134Sthompsa IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 3036203134Sthompsa if (m == NULL) 3037203134Sthompsa break; 3038203134Sthompsa 3039203134Sthompsa ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 3040203134Sthompsa if (run_tx(sc, m, ni) != 0) { 3041203134Sthompsa IFQ_DRV_PREPEND(&ifp->if_snd, m); 3042203134Sthompsa ifp->if_drv_flags |= IFF_DRV_OACTIVE; 3043203134Sthompsa break; 3044203134Sthompsa } 3045203134Sthompsa } 3046203134Sthompsa 3047203134Sthompsa RUN_UNLOCK(sc); 3048203134Sthompsa} 3049203134Sthompsa 3050203134Sthompsastatic int 3051203134Sthompsarun_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 3052203134Sthompsa{ 3053203134Sthompsa struct run_softc *sc = ifp->if_softc; 3054203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 3055203134Sthompsa struct ifreq *ifr = (struct ifreq *) data; 3056203134Sthompsa int error = 0, startall = 0; 3057203134Sthompsa 3058203134Sthompsa switch (cmd) { 3059203134Sthompsa case SIOCSIFFLAGS: 3060203134Sthompsa RUN_LOCK(sc); 3061203134Sthompsa if (ifp->if_flags & IFF_UP) { 3062203134Sthompsa if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)){ 3063203134Sthompsa run_init_locked(sc); 3064203134Sthompsa startall = 1; 3065203134Sthompsa } else 3066203134Sthompsa run_update_promisc_locked(ifp); 3067203134Sthompsa } else { 3068203134Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING) 3069203134Sthompsa run_stop(sc); 3070203134Sthompsa } 3071203134Sthompsa RUN_UNLOCK(sc); 3072203134Sthompsa if(startall) 3073203134Sthompsa ieee80211_start_all(ic); 3074203134Sthompsa break; 3075203134Sthompsa case SIOCGIFMEDIA: 3076203134Sthompsa error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); 3077203134Sthompsa break; 3078203134Sthompsa case SIOCGIFADDR: 3079203134Sthompsa error = ether_ioctl(ifp, cmd, data); 3080203134Sthompsa break; 3081203134Sthompsa default: 3082203134Sthompsa error = EINVAL; 3083203134Sthompsa break; 3084203134Sthompsa } 3085203134Sthompsa 3086203134Sthompsa return (error); 3087203134Sthompsa} 3088203134Sthompsa 3089203134Sthompsastatic void 3090205042Sthompsarun_set_agc(struct run_softc *sc, uint8_t agc) 3091205042Sthompsa{ 3092205042Sthompsa uint8_t bbp; 3093205042Sthompsa 3094205042Sthompsa if (sc->mac_ver == 0x3572) { 3095205042Sthompsa run_bbp_read(sc, 27, &bbp); 3096205042Sthompsa bbp &= ~(0x3 << 5); 3097205042Sthompsa run_bbp_write(sc, 27, bbp | 0 << 5); /* select Rx0 */ 3098205042Sthompsa run_bbp_write(sc, 66, agc); 3099205042Sthompsa run_bbp_write(sc, 27, bbp | 1 << 5); /* select Rx1 */ 3100205042Sthompsa run_bbp_write(sc, 66, agc); 3101205042Sthompsa } else 3102205042Sthompsa run_bbp_write(sc, 66, agc); 3103205042Sthompsa} 3104205042Sthompsa 3105205042Sthompsastatic void 3106203134Sthompsarun_select_chan_group(struct run_softc *sc, int group) 3107203134Sthompsa{ 3108203134Sthompsa uint32_t tmp; 3109205042Sthompsa uint8_t agc; 3110203134Sthompsa 3111203134Sthompsa run_bbp_write(sc, 62, 0x37 - sc->lna[group]); 3112203134Sthompsa run_bbp_write(sc, 63, 0x37 - sc->lna[group]); 3113203134Sthompsa run_bbp_write(sc, 64, 0x37 - sc->lna[group]); 3114203134Sthompsa run_bbp_write(sc, 86, 0x00); 3115203134Sthompsa 3116203134Sthompsa if (group == 0) { 3117203134Sthompsa if (sc->ext_2ghz_lna) { 3118203134Sthompsa run_bbp_write(sc, 82, 0x62); 3119203134Sthompsa run_bbp_write(sc, 75, 0x46); 3120203134Sthompsa } else { 3121203134Sthompsa run_bbp_write(sc, 82, 0x84); 3122203134Sthompsa run_bbp_write(sc, 75, 0x50); 3123203134Sthompsa } 3124203134Sthompsa } else { 3125205042Sthompsa if (sc->mac_ver == 0x3572) 3126205042Sthompsa run_bbp_write(sc, 82, 0x94); 3127205042Sthompsa else 3128203134Sthompsa run_bbp_write(sc, 82, 0xf2); 3129205042Sthompsa if (sc->ext_5ghz_lna) 3130203134Sthompsa run_bbp_write(sc, 75, 0x46); 3131205042Sthompsa else 3132203134Sthompsa run_bbp_write(sc, 75, 0x50); 3133203134Sthompsa } 3134203134Sthompsa 3135203134Sthompsa run_read(sc, RT2860_TX_BAND_CFG, &tmp); 3136203134Sthompsa tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P); 3137203134Sthompsa tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P; 3138203134Sthompsa run_write(sc, RT2860_TX_BAND_CFG, tmp); 3139203134Sthompsa 3140203134Sthompsa /* enable appropriate Power Amplifiers and Low Noise Amplifiers */ 3141203134Sthompsa tmp = RT2860_RFTR_EN | RT2860_TRSW_EN; 3142203134Sthompsa if (group == 0) { /* 2GHz */ 3143203134Sthompsa tmp |= RT2860_PA_PE_G0_EN | RT2860_LNA_PE_G0_EN; 3144203134Sthompsa if (sc->ntxchains > 1) 3145203134Sthompsa tmp |= RT2860_PA_PE_G1_EN; 3146203134Sthompsa if (sc->nrxchains > 1) 3147203134Sthompsa tmp |= RT2860_LNA_PE_G1_EN; 3148203134Sthompsa } else { /* 5GHz */ 3149203134Sthompsa tmp |= RT2860_PA_PE_A0_EN | RT2860_LNA_PE_A0_EN; 3150203134Sthompsa if (sc->ntxchains > 1) 3151203134Sthompsa tmp |= RT2860_PA_PE_A1_EN; 3152203134Sthompsa if (sc->nrxchains > 1) 3153203134Sthompsa tmp |= RT2860_LNA_PE_A1_EN; 3154203134Sthompsa } 3155205042Sthompsa if (sc->mac_ver == 0x3572) { 3156205042Sthompsa run_rt3070_rf_write(sc, 8, 0x00); 3157205042Sthompsa run_write(sc, RT2860_TX_PIN_CFG, tmp); 3158205042Sthompsa run_rt3070_rf_write(sc, 8, 0x80); 3159205042Sthompsa } else 3160205042Sthompsa run_write(sc, RT2860_TX_PIN_CFG, tmp); 3161203134Sthompsa 3162203134Sthompsa /* set initial AGC value */ 3163205042Sthompsa if (group == 0) { /* 2GHz band */ 3164205042Sthompsa if (sc->mac_ver >= 0x3070) 3165205042Sthompsa agc = 0x1c + sc->lna[0] * 2; 3166205042Sthompsa else 3167205042Sthompsa agc = 0x2e + sc->lna[0]; 3168205042Sthompsa } else { /* 5GHz band */ 3169205042Sthompsa if (sc->mac_ver == 0x3572) 3170205042Sthompsa agc = 0x22 + (sc->lna[group] * 5) / 3; 3171205042Sthompsa else 3172205042Sthompsa agc = 0x32 + (sc->lna[group] * 5) / 3; 3173205042Sthompsa } 3174205042Sthompsa run_set_agc(sc, agc); 3175203134Sthompsa} 3176203134Sthompsa 3177203134Sthompsastatic void 3178203134Sthompsarun_rt2870_set_chan(struct run_softc *sc, uint32_t chan) 3179203134Sthompsa{ 3180203134Sthompsa const struct rfprog *rfprog = rt2860_rf2850; 3181203134Sthompsa uint32_t r2, r3, r4; 3182203134Sthompsa int8_t txpow1, txpow2; 3183203134Sthompsa int i; 3184203134Sthompsa 3185203134Sthompsa /* find the settings for this channel (we know it exists) */ 3186203134Sthompsa for (i = 0; rfprog[i].chan != chan; i++); 3187203134Sthompsa 3188203134Sthompsa r2 = rfprog[i].r2; 3189203134Sthompsa if (sc->ntxchains == 1) 3190203134Sthompsa r2 |= 1 << 12; /* 1T: disable Tx chain 2 */ 3191203134Sthompsa if (sc->nrxchains == 1) 3192203134Sthompsa r2 |= 1 << 15 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 3193203134Sthompsa else if (sc->nrxchains == 2) 3194203134Sthompsa r2 |= 1 << 4; /* 2R: disable Rx chain 3 */ 3195203134Sthompsa 3196203134Sthompsa /* use Tx power values from EEPROM */ 3197203134Sthompsa txpow1 = sc->txpow1[i]; 3198203134Sthompsa txpow2 = sc->txpow2[i]; 3199203134Sthompsa if (chan > 14) { 3200203134Sthompsa if (txpow1 >= 0) 3201203134Sthompsa txpow1 = txpow1 << 1; 3202203134Sthompsa else 3203203134Sthompsa txpow1 = (7 + txpow1) << 1 | 1; 3204203134Sthompsa if (txpow2 >= 0) 3205203134Sthompsa txpow2 = txpow2 << 1; 3206203134Sthompsa else 3207203134Sthompsa txpow2 = (7 + txpow2) << 1 | 1; 3208203134Sthompsa } 3209203134Sthompsa r3 = rfprog[i].r3 | txpow1 << 7; 3210203134Sthompsa r4 = rfprog[i].r4 | sc->freq << 13 | txpow2 << 4; 3211203134Sthompsa 3212203134Sthompsa run_rt2870_rf_write(sc, RT2860_RF1, rfprog[i].r1); 3213203134Sthompsa run_rt2870_rf_write(sc, RT2860_RF2, r2); 3214203134Sthompsa run_rt2870_rf_write(sc, RT2860_RF3, r3); 3215203134Sthompsa run_rt2870_rf_write(sc, RT2860_RF4, r4); 3216203134Sthompsa 3217203134Sthompsa run_delay(sc, 10); 3218203134Sthompsa 3219203134Sthompsa run_rt2870_rf_write(sc, RT2860_RF1, rfprog[i].r1); 3220203134Sthompsa run_rt2870_rf_write(sc, RT2860_RF2, r2); 3221203134Sthompsa run_rt2870_rf_write(sc, RT2860_RF3, r3 | 1); 3222203134Sthompsa run_rt2870_rf_write(sc, RT2860_RF4, r4); 3223203134Sthompsa 3224203134Sthompsa run_delay(sc, 10); 3225203134Sthompsa 3226203134Sthompsa run_rt2870_rf_write(sc, RT2860_RF1, rfprog[i].r1); 3227203134Sthompsa run_rt2870_rf_write(sc, RT2860_RF2, r2); 3228203134Sthompsa run_rt2870_rf_write(sc, RT2860_RF3, r3); 3229203134Sthompsa run_rt2870_rf_write(sc, RT2860_RF4, r4); 3230203134Sthompsa} 3231203134Sthompsa 3232203134Sthompsastatic void 3233203134Sthompsarun_rt3070_set_chan(struct run_softc *sc, uint32_t chan) 3234203134Sthompsa{ 3235203134Sthompsa int8_t txpow1, txpow2; 3236203134Sthompsa uint8_t rf; 3237205042Sthompsa int i; 3238203134Sthompsa 3239203134Sthompsa /* RT3070 is 2GHz only */ 3240203134Sthompsa KASSERT(chan >= 1 && chan <= 14, ("wrong channel selected\n")); 3241203134Sthompsa 3242205042Sthompsa /* find the settings for this channel (we know it exists) */ 3243205042Sthompsa for (i = 0; rt2860_rf2850[i].chan != chan; i++); 3244205042Sthompsa 3245203134Sthompsa /* use Tx power values from EEPROM */ 3246205042Sthompsa txpow1 = sc->txpow1[i]; 3247205042Sthompsa txpow2 = sc->txpow2[i]; 3248203134Sthompsa 3249205042Sthompsa run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n); 3250205042Sthompsa run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k); 3251203134Sthompsa run_rt3070_rf_read(sc, 6, &rf); 3252205042Sthompsa rf = (rf & ~0x03) | rt3070_freqs[i].r; 3253203134Sthompsa run_rt3070_rf_write(sc, 6, rf); 3254203134Sthompsa 3255203134Sthompsa /* set Tx0 power */ 3256203134Sthompsa run_rt3070_rf_read(sc, 12, &rf); 3257203134Sthompsa rf = (rf & ~0x1f) | txpow1; 3258203134Sthompsa run_rt3070_rf_write(sc, 12, rf); 3259203134Sthompsa 3260203134Sthompsa /* set Tx1 power */ 3261203134Sthompsa run_rt3070_rf_read(sc, 13, &rf); 3262203134Sthompsa rf = (rf & ~0x1f) | txpow2; 3263203134Sthompsa run_rt3070_rf_write(sc, 13, rf); 3264203134Sthompsa 3265203134Sthompsa run_rt3070_rf_read(sc, 1, &rf); 3266203134Sthompsa rf &= ~0xfc; 3267203134Sthompsa if (sc->ntxchains == 1) 3268203134Sthompsa rf |= 1 << 7 | 1 << 5; /* 1T: disable Tx chains 2 & 3 */ 3269203134Sthompsa else if (sc->ntxchains == 2) 3270203134Sthompsa rf |= 1 << 7; /* 2T: disable Tx chain 3 */ 3271203134Sthompsa if (sc->nrxchains == 1) 3272203134Sthompsa rf |= 1 << 6 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 3273203134Sthompsa else if (sc->nrxchains == 2) 3274203134Sthompsa rf |= 1 << 6; /* 2R: disable Rx chain 3 */ 3275203134Sthompsa run_rt3070_rf_write(sc, 1, rf); 3276203134Sthompsa 3277203134Sthompsa /* set RF offset */ 3278203134Sthompsa run_rt3070_rf_read(sc, 23, &rf); 3279203134Sthompsa rf = (rf & ~0x7f) | sc->freq; 3280203134Sthompsa run_rt3070_rf_write(sc, 23, rf); 3281203134Sthompsa 3282203134Sthompsa /* program RF filter */ 3283205042Sthompsa run_rt3070_rf_read(sc, 24, &rf); /* Tx */ 3284205042Sthompsa rf = (rf & ~0x3f) | sc->rf24_20mhz; 3285205042Sthompsa run_rt3070_rf_write(sc, 24, rf); 3286205042Sthompsa run_rt3070_rf_read(sc, 31, &rf); /* Rx */ 3287205042Sthompsa rf = (rf & ~0x3f) | sc->rf24_20mhz; 3288205042Sthompsa run_rt3070_rf_write(sc, 31, rf); 3289203134Sthompsa 3290203134Sthompsa /* enable RF tuning */ 3291203134Sthompsa run_rt3070_rf_read(sc, 7, &rf); 3292203134Sthompsa run_rt3070_rf_write(sc, 7, rf | 0x01); 3293203134Sthompsa} 3294203134Sthompsa 3295203134Sthompsastatic void 3296205042Sthompsarun_rt3572_set_chan(struct run_softc *sc, u_int chan) 3297205042Sthompsa{ 3298205042Sthompsa int8_t txpow1, txpow2; 3299205042Sthompsa uint32_t tmp; 3300205042Sthompsa uint8_t rf; 3301205042Sthompsa int i; 3302205042Sthompsa 3303205042Sthompsa /* find the settings for this channel (we know it exists) */ 3304205042Sthompsa for (i = 0; rt2860_rf2850[i].chan != chan; i++); 3305205042Sthompsa 3306205042Sthompsa /* use Tx power values from EEPROM */ 3307205042Sthompsa txpow1 = sc->txpow1[i]; 3308205042Sthompsa txpow2 = sc->txpow2[i]; 3309205042Sthompsa 3310205042Sthompsa if (chan <= 14) { 3311205042Sthompsa run_bbp_write(sc, 25, sc->bbp25); 3312205042Sthompsa run_bbp_write(sc, 26, sc->bbp26); 3313205042Sthompsa } else { 3314205042Sthompsa /* enable IQ phase correction */ 3315205042Sthompsa run_bbp_write(sc, 25, 0x09); 3316205042Sthompsa run_bbp_write(sc, 26, 0xff); 3317205042Sthompsa } 3318205042Sthompsa 3319205042Sthompsa run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n); 3320205042Sthompsa run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k); 3321205042Sthompsa run_rt3070_rf_read(sc, 6, &rf); 3322205042Sthompsa rf = (rf & ~0x0f) | rt3070_freqs[i].r; 3323205042Sthompsa rf |= (chan <= 14) ? 0x08 : 0x04; 3324205042Sthompsa run_rt3070_rf_write(sc, 6, rf); 3325205042Sthompsa 3326205042Sthompsa /* set PLL mode */ 3327205042Sthompsa run_rt3070_rf_read(sc, 5, &rf); 3328205042Sthompsa rf &= ~(0x08 | 0x04); 3329205042Sthompsa rf |= (chan <= 14) ? 0x04 : 0x08; 3330205042Sthompsa run_rt3070_rf_write(sc, 5, rf); 3331205042Sthompsa 3332205042Sthompsa /* set Tx power for chain 0 */ 3333205042Sthompsa if (chan <= 14) 3334205042Sthompsa rf = 0x60 | txpow1; 3335205042Sthompsa else 3336205042Sthompsa rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3); 3337205042Sthompsa run_rt3070_rf_write(sc, 12, rf); 3338205042Sthompsa 3339205042Sthompsa /* set Tx power for chain 1 */ 3340205042Sthompsa if (chan <= 14) 3341205042Sthompsa rf = 0x60 | txpow2; 3342205042Sthompsa else 3343205042Sthompsa rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3); 3344205042Sthompsa run_rt3070_rf_write(sc, 13, rf); 3345205042Sthompsa 3346205042Sthompsa /* set Tx/Rx streams */ 3347205042Sthompsa run_rt3070_rf_read(sc, 1, &rf); 3348205042Sthompsa rf &= ~0xfc; 3349205042Sthompsa if (sc->ntxchains == 1) 3350205042Sthompsa rf |= 1 << 7 | 1 << 5; /* 1T: disable Tx chains 2 & 3 */ 3351205042Sthompsa else if (sc->ntxchains == 2) 3352205042Sthompsa rf |= 1 << 7; /* 2T: disable Tx chain 3 */ 3353205042Sthompsa if (sc->nrxchains == 1) 3354205042Sthompsa rf |= 1 << 6 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 3355205042Sthompsa else if (sc->nrxchains == 2) 3356205042Sthompsa rf |= 1 << 6; /* 2R: disable Rx chain 3 */ 3357205042Sthompsa run_rt3070_rf_write(sc, 1, rf); 3358205042Sthompsa 3359205042Sthompsa /* set RF offset */ 3360205042Sthompsa run_rt3070_rf_read(sc, 23, &rf); 3361205042Sthompsa rf = (rf & ~0x7f) | sc->freq; 3362205042Sthompsa run_rt3070_rf_write(sc, 23, rf); 3363205042Sthompsa 3364205042Sthompsa /* program RF filter */ 3365205042Sthompsa rf = sc->rf24_20mhz; 3366205042Sthompsa run_rt3070_rf_write(sc, 24, rf); /* Tx */ 3367205042Sthompsa run_rt3070_rf_write(sc, 31, rf); /* Rx */ 3368205042Sthompsa 3369205042Sthompsa /* enable RF tuning */ 3370205042Sthompsa run_rt3070_rf_read(sc, 7, &rf); 3371205042Sthompsa rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14); 3372205042Sthompsa run_rt3070_rf_write(sc, 7, rf); 3373205042Sthompsa 3374205042Sthompsa /* TSSI */ 3375205042Sthompsa rf = (chan <= 14) ? 0xc3 : 0xc0; 3376205042Sthompsa run_rt3070_rf_write(sc, 9, rf); 3377205042Sthompsa 3378205042Sthompsa /* set loop filter 1 */ 3379205042Sthompsa run_rt3070_rf_write(sc, 10, 0xf1); 3380205042Sthompsa /* set loop filter 2 */ 3381205042Sthompsa run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00); 3382205042Sthompsa 3383205042Sthompsa /* set tx_mx2_ic */ 3384205042Sthompsa run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43); 3385205042Sthompsa /* set tx_mx1_ic */ 3386205042Sthompsa if (chan <= 14) 3387205042Sthompsa rf = 0x48 | sc->txmixgain_2ghz; 3388205042Sthompsa else 3389205042Sthompsa rf = 0x78 | sc->txmixgain_5ghz; 3390205042Sthompsa run_rt3070_rf_write(sc, 16, rf); 3391205042Sthompsa 3392205042Sthompsa /* set tx_lo1 */ 3393205042Sthompsa run_rt3070_rf_write(sc, 17, 0x23); 3394205042Sthompsa /* set tx_lo2 */ 3395205042Sthompsa if (chan <= 14) 3396205042Sthompsa rf = 0x93; 3397205042Sthompsa else if (chan <= 64) 3398205042Sthompsa rf = 0xb7; 3399205042Sthompsa else if (chan <= 128) 3400205042Sthompsa rf = 0x74; 3401205042Sthompsa else 3402205042Sthompsa rf = 0x72; 3403205042Sthompsa run_rt3070_rf_write(sc, 19, rf); 3404205042Sthompsa 3405205042Sthompsa /* set rx_lo1 */ 3406205042Sthompsa if (chan <= 14) 3407205042Sthompsa rf = 0xb3; 3408205042Sthompsa else if (chan <= 64) 3409205042Sthompsa rf = 0xf6; 3410205042Sthompsa else if (chan <= 128) 3411205042Sthompsa rf = 0xf4; 3412205042Sthompsa else 3413205042Sthompsa rf = 0xf3; 3414205042Sthompsa run_rt3070_rf_write(sc, 20, rf); 3415205042Sthompsa 3416205042Sthompsa /* set pfd_delay */ 3417205042Sthompsa if (chan <= 14) 3418205042Sthompsa rf = 0x15; 3419205042Sthompsa else if (chan <= 64) 3420205042Sthompsa rf = 0x3d; 3421205042Sthompsa else 3422205042Sthompsa rf = 0x01; 3423205042Sthompsa run_rt3070_rf_write(sc, 25, rf); 3424205042Sthompsa 3425205042Sthompsa /* set rx_lo2 */ 3426205042Sthompsa run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87); 3427205042Sthompsa /* set ldo_rf_vc */ 3428205042Sthompsa run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01); 3429205042Sthompsa /* set drv_cc */ 3430205042Sthompsa run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f); 3431205042Sthompsa 3432205042Sthompsa run_read(sc, RT2860_GPIO_CTRL, &tmp); 3433205042Sthompsa tmp &= ~0x8080; 3434205042Sthompsa if (chan <= 14) 3435205042Sthompsa tmp |= 0x80; 3436205042Sthompsa run_write(sc, RT2860_GPIO_CTRL, tmp); 3437205042Sthompsa 3438205042Sthompsa /* enable RF tuning */ 3439205042Sthompsa run_rt3070_rf_read(sc, 7, &rf); 3440205042Sthompsa run_rt3070_rf_write(sc, 7, rf | 0x01); 3441205042Sthompsa 3442205042Sthompsa run_delay(sc, 2); 3443205042Sthompsa} 3444205042Sthompsa 3445205042Sthompsastatic void 3446203134Sthompsarun_set_rx_antenna(struct run_softc *sc, int aux) 3447203134Sthompsa{ 3448203134Sthompsa uint32_t tmp; 3449203134Sthompsa 3450203134Sthompsa if (aux) { 3451205042Sthompsa run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0); 3452203134Sthompsa run_read(sc, RT2860_GPIO_CTRL, &tmp); 3453203134Sthompsa run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08); 3454203134Sthompsa } else { 3455205042Sthompsa run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1); 3456203134Sthompsa run_read(sc, RT2860_GPIO_CTRL, &tmp); 3457203134Sthompsa run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808); 3458203134Sthompsa } 3459203134Sthompsa} 3460203134Sthompsa 3461203134Sthompsastatic int 3462203134Sthompsarun_set_chan(struct run_softc *sc, struct ieee80211_channel *c) 3463203134Sthompsa{ 3464203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 3465203134Sthompsa uint32_t chan, group; 3466203134Sthompsa 3467203134Sthompsa chan = ieee80211_chan2ieee(ic, c); 3468203134Sthompsa if (chan == 0 || chan == IEEE80211_CHAN_ANY) 3469203134Sthompsa return EINVAL; 3470203134Sthompsa 3471205042Sthompsa if (sc->mac_ver == 0x3572) 3472205042Sthompsa run_rt3572_set_chan(sc, chan); 3473205042Sthompsa else if (sc->mac_ver >= 0x3070) 3474203134Sthompsa run_rt3070_set_chan(sc, chan); 3475203134Sthompsa else 3476203134Sthompsa run_rt2870_set_chan(sc, chan); 3477203134Sthompsa 3478203134Sthompsa /* determine channel group */ 3479203134Sthompsa if (chan <= 14) 3480203134Sthompsa group = 0; 3481203134Sthompsa else if (chan <= 64) 3482203134Sthompsa group = 1; 3483203134Sthompsa else if (chan <= 128) 3484203134Sthompsa group = 2; 3485203134Sthompsa else 3486203134Sthompsa group = 3; 3487203134Sthompsa 3488203134Sthompsa /* XXX necessary only when group has changed! */ 3489203134Sthompsa run_select_chan_group(sc, group); 3490203134Sthompsa 3491203134Sthompsa run_delay(sc, 10); 3492203134Sthompsa 3493203134Sthompsa return 0; 3494203134Sthompsa} 3495203134Sthompsa 3496203134Sthompsastatic void 3497203134Sthompsarun_set_channel(struct ieee80211com *ic) 3498203134Sthompsa{ 3499203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 3500203134Sthompsa 3501203134Sthompsa RUN_LOCK(sc); 3502203134Sthompsa run_set_chan(sc, ic->ic_curchan); 3503203134Sthompsa RUN_UNLOCK(sc); 3504203134Sthompsa 3505203134Sthompsa return; 3506203134Sthompsa} 3507203134Sthompsa 3508203134Sthompsastatic void 3509203134Sthompsarun_scan_start(struct ieee80211com *ic) 3510203134Sthompsa{ 3511203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 3512203134Sthompsa uint32_t tmp; 3513203134Sthompsa 3514203134Sthompsa RUN_LOCK(sc); 3515203134Sthompsa 3516203134Sthompsa /* abort TSF synchronization */ 3517203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 3518203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, 3519203134Sthompsa tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 3520203134Sthompsa RT2860_TBTT_TIMER_EN)); 3521203134Sthompsa run_set_bssid(sc, sc->sc_ifp->if_broadcastaddr); 3522203134Sthompsa 3523203134Sthompsa RUN_UNLOCK(sc); 3524203134Sthompsa 3525203134Sthompsa return; 3526203134Sthompsa} 3527203134Sthompsa 3528203134Sthompsastatic void 3529203134Sthompsarun_scan_end(struct ieee80211com *ic) 3530203134Sthompsa{ 3531203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 3532203134Sthompsa 3533203134Sthompsa RUN_LOCK(sc); 3534203134Sthompsa 3535203134Sthompsa run_enable_tsf_sync(sc); 3536203134Sthompsa /* XXX keep local copy */ 3537203134Sthompsa run_set_bssid(sc, sc->sc_bssid); 3538203134Sthompsa 3539203134Sthompsa RUN_UNLOCK(sc); 3540203134Sthompsa 3541203134Sthompsa return; 3542203134Sthompsa} 3543203134Sthompsa 3544203134Sthompsastatic uint8_t 3545203134Sthompsarun_rate2mcs(uint8_t rate) 3546203134Sthompsa{ 3547203134Sthompsa switch (rate) { 3548203134Sthompsa /* CCK rates */ 3549203134Sthompsa case 2: return 0; 3550203134Sthompsa case 4: return 1; 3551203134Sthompsa case 11: return 2; 3552203134Sthompsa case 22: return 3; 3553203134Sthompsa /* OFDM rates */ 3554203134Sthompsa case 12: return 0; 3555203134Sthompsa case 18: return 1; 3556203134Sthompsa case 24: return 2; 3557203134Sthompsa case 36: return 3; 3558203134Sthompsa case 48: return 4; 3559203134Sthompsa case 72: return 5; 3560203134Sthompsa case 96: return 6; 3561203134Sthompsa case 108: return 7; 3562203134Sthompsa } 3563203134Sthompsa return 0; /* shouldn't get here */ 3564203134Sthompsa} 3565203134Sthompsa 3566203134Sthompsastatic void 3567203134Sthompsarun_update_beacon_locked(struct ieee80211vap *vap, int item) 3568203134Sthompsa{ 3569203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 3570203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 3571203134Sthompsa struct rt2860_txwi txwi; 3572203134Sthompsa struct mbuf *m; 3573203134Sthompsa int rate; 3574203134Sthompsa 3575203134Sthompsa if ((m = ieee80211_beacon_alloc(vap->iv_bss, &RUN_VAP(vap)->bo)) == NULL) 3576203134Sthompsa return; 3577203134Sthompsa 3578203134Sthompsa memset(&txwi, 0, sizeof txwi); 3579203134Sthompsa txwi.wcid = 0xff; 3580203134Sthompsa txwi.len = htole16(m->m_pkthdr.len); 3581203134Sthompsa /* send beacons at the lowest available rate */ 3582203134Sthompsa rate = (ic->ic_curmode == IEEE80211_MODE_11A) ? 12 : 2; 3583203134Sthompsa txwi.phy = htole16(run_rate2mcs(rate)); 3584203134Sthompsa if (rate == 12) 3585203134Sthompsa txwi.phy |= htole16(RT2860_PHY_OFDM); 3586203134Sthompsa txwi.txop = RT2860_TX_TXOP_HT; 3587203134Sthompsa txwi.flags = RT2860_TX_TS; 3588203134Sthompsa 3589203134Sthompsa run_write_region_1(sc, RT2860_BCN_BASE(0), 3590203134Sthompsa (u_int8_t *)&txwi, sizeof txwi); 3591203134Sthompsa run_write_region_1(sc, RT2860_BCN_BASE(0) + sizeof txwi, 3592203134Sthompsa mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1); /* roundup len */ 3593203134Sthompsa 3594203134Sthompsa m_freem(m); 3595203134Sthompsa 3596203134Sthompsa return; 3597203134Sthompsa} 3598203134Sthompsa 3599203134Sthompsastatic void 3600203134Sthompsarun_update_beacon(struct ieee80211vap *vap, int item) 3601203134Sthompsa{ 3602203134Sthompsa struct ieee80211com *ic = vap->iv_ic; 3603203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 3604203134Sthompsa 3605203134Sthompsa IEEE80211_UNLOCK(ic); 3606203134Sthompsa RUN_LOCK(sc); 3607203134Sthompsa run_update_beacon_locked(vap, item); 3608203134Sthompsa RUN_UNLOCK(sc); 3609203134Sthompsa IEEE80211_LOCK(ic); 3610203134Sthompsa 3611203134Sthompsa return; 3612203134Sthompsa} 3613203134Sthompsa 3614203134Sthompsastatic void 3615203134Sthompsarun_updateprot(struct ieee80211com *ic) 3616203134Sthompsa{ 3617203134Sthompsa struct run_softc *sc = ic->ic_ifp->if_softc; 3618203134Sthompsa uint32_t tmp; 3619203134Sthompsa 3620203134Sthompsa tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL; 3621203134Sthompsa /* setup protection frame rate (MCS code) */ 3622203134Sthompsa tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ? 3623203134Sthompsa rt2860_rates[RT2860_RIDX_OFDM6].mcs : 3624203134Sthompsa rt2860_rates[RT2860_RIDX_CCK11].mcs; 3625203134Sthompsa 3626203134Sthompsa /* CCK frames don't require protection */ 3627203134Sthompsa run_write(sc, RT2860_CCK_PROT_CFG, tmp); 3628203134Sthompsa if (ic->ic_flags & IEEE80211_F_USEPROT) { 3629203134Sthompsa if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) 3630203134Sthompsa tmp |= RT2860_PROT_CTRL_RTS_CTS; 3631203134Sthompsa else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) 3632203134Sthompsa tmp |= RT2860_PROT_CTRL_CTS; 3633203134Sthompsa } 3634203134Sthompsa run_write(sc, RT2860_OFDM_PROT_CFG, tmp); 3635203134Sthompsa} 3636203134Sthompsa 3637203134Sthompsastatic void 3638203134Sthompsarun_usb_timeout_cb(void *arg, int pending) 3639203134Sthompsa{ 3640203134Sthompsa struct run_softc *sc = arg; 3641203134Sthompsa struct ieee80211vap *vap = &sc->sc_rvp->vap; 3642203134Sthompsa 3643205042Sthompsa RUN_LOCK(sc); 3644203134Sthompsa 3645203134Sthompsa if(vap->iv_state == IEEE80211_S_RUN && 3646203134Sthompsa vap->iv_opmode != IEEE80211_M_STA) 3647203134Sthompsa run_reset_livelock(sc); 3648203134Sthompsa else if(vap->iv_state == IEEE80211_S_SCAN){ 3649203134Sthompsa DPRINTF("timeout caused by scan\n"); 3650203134Sthompsa /* cancel bgscan */ 3651203134Sthompsa ieee80211_cancel_scan(vap); 3652203134Sthompsa } else 3653203134Sthompsa DPRINTF("timeout by unknown cause\n"); 3654205042Sthompsa 3655205042Sthompsa RUN_UNLOCK(sc); 3656203134Sthompsa} 3657203134Sthompsa 3658203134Sthompsastatic void 3659203134Sthompsarun_reset_livelock(struct run_softc *sc) 3660203134Sthompsa{ 3661203134Sthompsa uint32_t tmp; 3662203134Sthompsa 3663203134Sthompsa /* 3664203134Sthompsa * In IBSS or HostAP modes (when the hardware sends beacons), the MAC 3665203134Sthompsa * can run into a livelock and start sending CTS-to-self frames like 3666203134Sthompsa * crazy if protection is enabled. Reset MAC/BBP for a while 3667203134Sthompsa */ 3668203134Sthompsa run_read(sc, RT2860_DEBUG, &tmp); 3669203134Sthompsa if((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))){ 3670203134Sthompsa DPRINTF("CTS-to-self livelock detected\n"); 3671203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST); 3672203134Sthompsa run_delay(sc, 1); 3673203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 3674203134Sthompsa RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 3675203134Sthompsa } 3676203134Sthompsa} 3677203134Sthompsa 3678203134Sthompsastatic void 3679203134Sthompsarun_update_promisc_locked(struct ifnet *ifp) 3680203134Sthompsa{ 3681203134Sthompsa struct run_softc *sc = ifp->if_softc; 3682203134Sthompsa uint32_t tmp; 3683203134Sthompsa 3684203134Sthompsa run_read(sc, RT2860_RX_FILTR_CFG, &tmp); 3685203134Sthompsa 3686203134Sthompsa tmp |= RT2860_DROP_UC_NOME; 3687203134Sthompsa if (ifp->if_flags & IFF_PROMISC) 3688203134Sthompsa tmp &= ~RT2860_DROP_UC_NOME; 3689203134Sthompsa 3690203134Sthompsa run_write(sc, RT2860_RX_FILTR_CFG, tmp); 3691203134Sthompsa 3692203134Sthompsa DPRINTF("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ? 3693203134Sthompsa "entering" : "leaving"); 3694203134Sthompsa} 3695203134Sthompsa 3696203134Sthompsastatic void 3697203134Sthompsarun_update_promisc(struct ifnet *ifp) 3698203134Sthompsa{ 3699203134Sthompsa struct run_softc *sc = ifp->if_softc; 3700203134Sthompsa 3701203134Sthompsa if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 3702203134Sthompsa return; 3703203134Sthompsa 3704203134Sthompsa RUN_LOCK(sc); 3705203134Sthompsa run_update_promisc_locked(ifp); 3706203134Sthompsa RUN_UNLOCK(sc); 3707203134Sthompsa} 3708203134Sthompsa 3709203134Sthompsastatic void 3710203134Sthompsarun_enable_tsf_sync(struct run_softc *sc) 3711203134Sthompsa{ 3712203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 3713203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 3714203134Sthompsa struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 3715203134Sthompsa uint32_t tmp; 3716203134Sthompsa 3717203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 3718203134Sthompsa tmp &= ~0x1fffff; 3719203134Sthompsa tmp |= vap->iv_bss->ni_intval * 16; 3720203134Sthompsa tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN; 3721203134Sthompsa 3722203134Sthompsa if (vap->iv_opmode == IEEE80211_M_STA) { 3723203134Sthompsa /* 3724203134Sthompsa * Local TSF is always updated with remote TSF on beacon 3725203134Sthompsa * reception. 3726203134Sthompsa */ 3727203134Sthompsa tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT; 3728203134Sthompsa } else if (vap->iv_opmode == IEEE80211_M_IBSS) { 3729203134Sthompsa tmp |= RT2860_BCN_TX_EN; 3730203134Sthompsa /* 3731203134Sthompsa * Local TSF is updated with remote TSF on beacon reception 3732203134Sthompsa * only if the remote TSF is greater than local TSF. 3733203134Sthompsa */ 3734203134Sthompsa tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT; 3735203134Sthompsa } else if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 3736203134Sthompsa tmp |= RT2860_BCN_TX_EN; 3737203134Sthompsa /* SYNC with nobody */ 3738203134Sthompsa tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT; 3739203134Sthompsa } else 3740203134Sthompsa DPRINTF("Enabling TSF failed. undefined opmode\n"); 3741203134Sthompsa 3742203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, tmp); 3743203134Sthompsa} 3744203134Sthompsa 3745203134Sthompsastatic void 3746203134Sthompsarun_enable_mrr(struct run_softc *sc) 3747203134Sthompsa{ 3748203134Sthompsa#define CCK(mcs) (mcs) 3749203134Sthompsa#define OFDM(mcs) (1 << 3 | (mcs)) 3750203134Sthompsa run_write(sc, RT2860_LG_FBK_CFG0, 3751203134Sthompsa OFDM(6) << 28 | /* 54->48 */ 3752203134Sthompsa OFDM(5) << 24 | /* 48->36 */ 3753203134Sthompsa OFDM(4) << 20 | /* 36->24 */ 3754203134Sthompsa OFDM(3) << 16 | /* 24->18 */ 3755203134Sthompsa OFDM(2) << 12 | /* 18->12 */ 3756203134Sthompsa OFDM(1) << 8 | /* 12-> 9 */ 3757203134Sthompsa OFDM(0) << 4 | /* 9-> 6 */ 3758203134Sthompsa OFDM(0)); /* 6-> 6 */ 3759203134Sthompsa 3760203134Sthompsa run_write(sc, RT2860_LG_FBK_CFG1, 3761203134Sthompsa CCK(2) << 12 | /* 11->5.5 */ 3762203134Sthompsa CCK(1) << 8 | /* 5.5-> 2 */ 3763203134Sthompsa CCK(0) << 4 | /* 2-> 1 */ 3764203134Sthompsa CCK(0)); /* 1-> 1 */ 3765203134Sthompsa#undef OFDM 3766203134Sthompsa#undef CCK 3767203134Sthompsa} 3768203134Sthompsa 3769203134Sthompsastatic void 3770203134Sthompsarun_set_txpreamble(struct run_softc *sc) 3771203134Sthompsa{ 3772203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 3773203134Sthompsa uint32_t tmp; 3774203134Sthompsa 3775203134Sthompsa run_read(sc, RT2860_AUTO_RSP_CFG, &tmp); 3776203134Sthompsa if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 3777203134Sthompsa tmp |= RT2860_CCK_SHORT_EN; 3778203134Sthompsa else 3779203134Sthompsa tmp &= ~RT2860_CCK_SHORT_EN; 3780203134Sthompsa run_write(sc, RT2860_AUTO_RSP_CFG, tmp); 3781203134Sthompsa} 3782203134Sthompsa 3783203134Sthompsastatic void 3784203134Sthompsarun_set_basicrates(struct run_softc *sc) 3785203134Sthompsa{ 3786203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 3787203134Sthompsa 3788203134Sthompsa /* set basic rates mask */ 3789203134Sthompsa if (ic->ic_curmode == IEEE80211_MODE_11B) 3790203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003); 3791203134Sthompsa else if (ic->ic_curmode == IEEE80211_MODE_11A) 3792203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150); 3793203134Sthompsa else /* 11g */ 3794203134Sthompsa run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f); 3795203134Sthompsa} 3796203134Sthompsa 3797203134Sthompsastatic void 3798203134Sthompsarun_set_leds(struct run_softc *sc, uint16_t which) 3799203134Sthompsa{ 3800203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS, 3801203134Sthompsa which | (sc->leds & 0x7f)); 3802203134Sthompsa} 3803203134Sthompsa 3804203134Sthompsastatic void 3805203134Sthompsarun_set_bssid(struct run_softc *sc, const uint8_t *bssid) 3806203134Sthompsa{ 3807203134Sthompsa run_write(sc, RT2860_MAC_BSSID_DW0, 3808203134Sthompsa bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24); 3809203134Sthompsa run_write(sc, RT2860_MAC_BSSID_DW1, 3810203134Sthompsa bssid[4] | bssid[5] << 8); 3811203134Sthompsa} 3812203134Sthompsa 3813203134Sthompsastatic void 3814203134Sthompsarun_set_macaddr(struct run_softc *sc, const uint8_t *addr) 3815203134Sthompsa{ 3816203134Sthompsa run_write(sc, RT2860_MAC_ADDR_DW0, 3817203134Sthompsa addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24); 3818203134Sthompsa run_write(sc, RT2860_MAC_ADDR_DW1, 3819203134Sthompsa addr[4] | addr[5] << 8 | 0xff << 16); 3820203134Sthompsa} 3821203134Sthompsa 3822203134Sthompsa/* ARGSUSED */ 3823203134Sthompsastatic void 3824203134Sthompsarun_updateslot(struct ifnet *ifp) 3825203134Sthompsa{ 3826203134Sthompsa struct run_softc *sc = ifp->if_softc; 3827203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 3828203134Sthompsa uint32_t tmp; 3829203134Sthompsa 3830203134Sthompsa run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp); 3831203134Sthompsa tmp &= ~0xff; 3832203134Sthompsa tmp |= (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; 3833203134Sthompsa run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp); 3834203134Sthompsa} 3835203134Sthompsa 3836203134Sthompsastatic int8_t 3837203134Sthompsarun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain) 3838203134Sthompsa{ 3839203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 3840203134Sthompsa struct ieee80211_channel *c = ic->ic_curchan; 3841203134Sthompsa int delta; 3842203134Sthompsa 3843203134Sthompsa if (IEEE80211_IS_CHAN_5GHZ(c)) { 3844203134Sthompsa uint32_t chan = ieee80211_chan2ieee(ic, c); 3845203134Sthompsa delta = sc->rssi_5ghz[rxchain]; 3846203134Sthompsa 3847203134Sthompsa /* determine channel group */ 3848203134Sthompsa if (chan <= 64) 3849203134Sthompsa delta -= sc->lna[1]; 3850203134Sthompsa else if (chan <= 128) 3851203134Sthompsa delta -= sc->lna[2]; 3852203134Sthompsa else 3853203134Sthompsa delta -= sc->lna[3]; 3854203134Sthompsa } else 3855203134Sthompsa delta = sc->rssi_2ghz[rxchain] - sc->lna[0]; 3856203134Sthompsa 3857203134Sthompsa return -12 - delta - rssi; 3858203134Sthompsa} 3859203134Sthompsa 3860203134Sthompsastatic int 3861203134Sthompsarun_bbp_init(struct run_softc *sc) 3862203134Sthompsa{ 3863203134Sthompsa int i, error, ntries; 3864203134Sthompsa uint8_t bbp0; 3865203134Sthompsa 3866203134Sthompsa /* wait for BBP to wake up */ 3867203134Sthompsa for (ntries = 0; ntries < 20; ntries++) { 3868203134Sthompsa if ((error = run_bbp_read(sc, 0, &bbp0)) != 0) 3869203134Sthompsa return error; 3870203134Sthompsa if (bbp0 != 0 && bbp0 != 0xff) 3871203134Sthompsa break; 3872203134Sthompsa } 3873203134Sthompsa if (ntries == 20) 3874203134Sthompsa return ETIMEDOUT; 3875203134Sthompsa 3876203134Sthompsa /* initialize BBP registers to default values */ 3877203134Sthompsa for (i = 0; i < nitems(rt2860_def_bbp); i++) { 3878203134Sthompsa run_bbp_write(sc, rt2860_def_bbp[i].reg, 3879203134Sthompsa rt2860_def_bbp[i].val); 3880203134Sthompsa } 3881203134Sthompsa 3882203134Sthompsa /* fix BBP84 for RT2860E */ 3883205042Sthompsa if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101) 3884205042Sthompsa run_bbp_write(sc, 84, 0x19); 3885203134Sthompsa 3886205042Sthompsa if (sc->mac_ver >= 0x3070) { 3887203134Sthompsa run_bbp_write(sc, 79, 0x13); 3888203134Sthompsa run_bbp_write(sc, 80, 0x05); 3889203134Sthompsa run_bbp_write(sc, 81, 0x33); 3890205042Sthompsa } else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) { 3891203134Sthompsa run_bbp_write(sc, 69, 0x16); 3892203134Sthompsa run_bbp_write(sc, 73, 0x12); 3893203134Sthompsa } 3894203134Sthompsa return 0; 3895203134Sthompsa} 3896203134Sthompsa 3897203134Sthompsastatic int 3898203134Sthompsarun_rt3070_rf_init(struct run_softc *sc) 3899203134Sthompsa{ 3900203134Sthompsa uint32_t tmp; 3901205042Sthompsa uint8_t rf, target, bbp4; 3902203134Sthompsa int i; 3903203134Sthompsa 3904203134Sthompsa run_rt3070_rf_read(sc, 30, &rf); 3905203134Sthompsa /* toggle RF R30 bit 7 */ 3906203134Sthompsa run_rt3070_rf_write(sc, 30, rf | 0x80); 3907203134Sthompsa run_delay(sc, 10); 3908203134Sthompsa run_rt3070_rf_write(sc, 30, rf & ~0x80); 3909203134Sthompsa 3910203134Sthompsa /* initialize RF registers to default value */ 3911205042Sthompsa if (sc->mac_ver == 0x3572) { 3912205042Sthompsa for (i = 0; i < nitems(rt3572_def_rf); i++) { 3913205042Sthompsa run_rt3070_rf_write(sc, rt3572_def_rf[i].reg, 3914205042Sthompsa rt3572_def_rf[i].val); 3915205042Sthompsa } 3916205042Sthompsa } else { 3917205042Sthompsa for (i = 0; i < nitems(rt3070_def_rf); i++) { 3918205042Sthompsa run_rt3070_rf_write(sc, rt3070_def_rf[i].reg, 3919205042Sthompsa rt3070_def_rf[i].val); 3920205042Sthompsa } 3921203134Sthompsa } 3922205042Sthompsa 3923205042Sthompsa if (sc->mac_ver == 0x3070) { 3924203134Sthompsa /* change voltage from 1.2V to 1.35V for RT3070 */ 3925203134Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 3926203134Sthompsa tmp = (tmp & ~0x0f000000) | 0x0d000000; 3927203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 3928203134Sthompsa 3929205042Sthompsa } else if (sc->mac_ver == 0x3071) { 3930203134Sthompsa run_rt3070_rf_read(sc, 6, &rf); 3931203134Sthompsa run_rt3070_rf_write(sc, 6, rf | 0x40); 3932203134Sthompsa run_rt3070_rf_write(sc, 31, 0x14); 3933203134Sthompsa 3934203134Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 3935203134Sthompsa tmp &= ~0x1f000000; 3936205042Sthompsa if (sc->mac_rev < 0x0211) 3937205042Sthompsa tmp |= 0x0d000000; /* 1.3V */ 3938203134Sthompsa else 3939205042Sthompsa tmp |= 0x01000000; /* 1.2V */ 3940203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 3941203134Sthompsa 3942203134Sthompsa /* patch LNA_PE_G1 */ 3943203134Sthompsa run_read(sc, RT3070_GPIO_SWITCH, &tmp); 3944203134Sthompsa run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20); 3945205042Sthompsa } else if(sc->mac_ver == 0x3572){ 3946205042Sthompsa run_rt3070_rf_read(sc, 6, &rf); 3947205042Sthompsa run_rt3070_rf_write(sc, 6, rf | 0x40); 3948205042Sthompsa 3949205042Sthompsa if (sc->mac_rev < 0x0211){ 3950205042Sthompsa /* increase voltage from 1.2V to 1.35V */ 3951203134Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 3952203134Sthompsa tmp = (tmp & ~0x0f000000) | 0x0d000000; 3953203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 3954203134Sthompsa } else { 3955205042Sthompsa /* increase voltage from 1.2V to 1.35V */ 3956203134Sthompsa run_read(sc, RT3070_LDO_CFG0, &tmp); 3957203134Sthompsa tmp = (tmp & ~0x1f000000) | 0x0d000000; 3958203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 3959203134Sthompsa 3960203134Sthompsa run_delay(sc, 1); /* wait for 1msec */ 3961203134Sthompsa 3962205042Sthompsa /* decrease voltage back to 1.2V */ 3963203134Sthompsa tmp = (tmp & ~0x1f000000) | 0x01000000; 3964203134Sthompsa run_write(sc, RT3070_LDO_CFG0, tmp); 3965203134Sthompsa } 3966203134Sthompsa } 3967203134Sthompsa 3968203134Sthompsa /* select 20MHz bandwidth */ 3969203134Sthompsa run_rt3070_rf_read(sc, 31, &rf); 3970203134Sthompsa run_rt3070_rf_write(sc, 31, rf & ~0x20); 3971203134Sthompsa 3972203134Sthompsa /* calibrate filter for 20MHz bandwidth */ 3973203134Sthompsa sc->rf24_20mhz = 0x1f; /* default value */ 3974205042Sthompsa target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13; 3975205042Sthompsa run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz); 3976203134Sthompsa 3977203134Sthompsa /* select 40MHz bandwidth */ 3978203134Sthompsa run_bbp_read(sc, 4, &bbp4); 3979203134Sthompsa run_bbp_write(sc, 4, (bbp4 & ~0x08) | 0x10); 3980205042Sthompsa run_rt3070_rf_read(sc, 31, &rf); 3981205042Sthompsa run_rt3070_rf_write(sc, 31, rf | 0x20); 3982203134Sthompsa 3983203134Sthompsa /* calibrate filter for 40MHz bandwidth */ 3984203134Sthompsa sc->rf24_40mhz = 0x2f; /* default value */ 3985205042Sthompsa target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15; 3986205042Sthompsa run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz); 3987203134Sthompsa 3988203134Sthompsa /* go back to 20MHz bandwidth */ 3989203134Sthompsa run_bbp_read(sc, 4, &bbp4); 3990203134Sthompsa run_bbp_write(sc, 4, bbp4 & ~0x18); 3991203134Sthompsa 3992205042Sthompsa if (sc->mac_ver == 0x3572) { 3993205042Sthompsa /* save default BBP registers 25 and 26 values */ 3994205042Sthompsa run_bbp_read(sc, 25, &sc->bbp25); 3995205042Sthompsa run_bbp_read(sc, 26, &sc->bbp26); 3996205042Sthompsa } else if (sc->mac_rev < 0x0211) 3997203134Sthompsa run_rt3070_rf_write(sc, 27, 0x03); 3998203134Sthompsa 3999203134Sthompsa run_read(sc, RT3070_OPT_14, &tmp); 4000203134Sthompsa run_write(sc, RT3070_OPT_14, tmp | 1); 4001203134Sthompsa 4002205042Sthompsa if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) { 4003205042Sthompsa run_rt3070_rf_read(sc, 17, &rf); 4004205042Sthompsa rf &= ~RT3070_TX_LO1; 4005205042Sthompsa if ((sc->mac_ver == 0x3070 || 4006205042Sthompsa (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) && 4007205042Sthompsa !sc->ext_2ghz_lna) 4008205042Sthompsa rf |= 0x20; /* fix for long range Rx issue */ 4009205042Sthompsa if (sc->txmixgain_2ghz >= 1) 4010205042Sthompsa rf = (rf & ~0x7) | sc->txmixgain_2ghz; 4011205042Sthompsa run_rt3070_rf_write(sc, 17, rf); 4012205042Sthompsa } 4013205042Sthompsa 4014205042Sthompsa if (sc->mac_rev == 0x3071) { 4015203134Sthompsa run_rt3070_rf_read(sc, 1, &rf); 4016203134Sthompsa rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD); 4017203134Sthompsa rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD; 4018203134Sthompsa run_rt3070_rf_write(sc, 1, rf); 4019203134Sthompsa 4020203134Sthompsa run_rt3070_rf_read(sc, 15, &rf); 4021203134Sthompsa run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2); 4022203134Sthompsa 4023203134Sthompsa run_rt3070_rf_read(sc, 20, &rf); 4024203134Sthompsa run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1); 4025203134Sthompsa 4026203134Sthompsa run_rt3070_rf_read(sc, 21, &rf); 4027203134Sthompsa run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2); 4028205042Sthompsa } 4029203134Sthompsa 4030205042Sthompsa if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) { 4031205042Sthompsa /* fix Tx to Rx IQ glitch by raising RF voltage */ 4032203134Sthompsa run_rt3070_rf_read(sc, 27, &rf); 4033203134Sthompsa rf &= ~0x77; 4034205042Sthompsa if (sc->mac_rev < 0x0211) 4035203134Sthompsa rf |= 0x03; 4036203134Sthompsa run_rt3070_rf_write(sc, 27, rf); 4037203134Sthompsa } 4038203134Sthompsa return 0; 4039203134Sthompsa} 4040203134Sthompsa 4041203134Sthompsastatic int 4042203134Sthompsarun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target, 4043203134Sthompsa uint8_t *val) 4044203134Sthompsa{ 4045203134Sthompsa uint8_t rf22, rf24; 4046203134Sthompsa uint8_t bbp55_pb, bbp55_sb, delta; 4047203134Sthompsa int ntries; 4048203134Sthompsa 4049203134Sthompsa /* program filter */ 4050205042Sthompsa run_rt3070_rf_read(sc, 24, &rf24); 4051205042Sthompsa rf24 = (rf24 & 0xc0) | init; /* initial filter value */ 4052203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 4053203134Sthompsa 4054203134Sthompsa /* enable baseband loopback mode */ 4055203134Sthompsa run_rt3070_rf_read(sc, 22, &rf22); 4056203134Sthompsa run_rt3070_rf_write(sc, 22, rf22 | 0x01); 4057203134Sthompsa 4058203134Sthompsa /* set power and frequency of passband test tone */ 4059203134Sthompsa run_bbp_write(sc, 24, 0x00); 4060203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 4061203134Sthompsa /* transmit test tone */ 4062203134Sthompsa run_bbp_write(sc, 25, 0x90); 4063203134Sthompsa run_delay(sc, 10); 4064203134Sthompsa /* read received power */ 4065203134Sthompsa run_bbp_read(sc, 55, &bbp55_pb); 4066203134Sthompsa if (bbp55_pb != 0) 4067203134Sthompsa break; 4068203134Sthompsa } 4069203134Sthompsa if (ntries == 100) 4070203134Sthompsa return ETIMEDOUT; 4071203134Sthompsa 4072203134Sthompsa /* set power and frequency of stopband test tone */ 4073203134Sthompsa run_bbp_write(sc, 24, 0x06); 4074203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 4075203134Sthompsa /* transmit test tone */ 4076203134Sthompsa run_bbp_write(sc, 25, 0x90); 4077203134Sthompsa run_delay(sc, 10); 4078203134Sthompsa /* read received power */ 4079203134Sthompsa run_bbp_read(sc, 55, &bbp55_sb); 4080203134Sthompsa 4081203134Sthompsa delta = bbp55_pb - bbp55_sb; 4082203134Sthompsa if (delta > target) 4083203134Sthompsa break; 4084203134Sthompsa 4085203134Sthompsa /* reprogram filter */ 4086203134Sthompsa rf24++; 4087203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 4088203134Sthompsa } 4089203134Sthompsa if (ntries < 100) { 4090203134Sthompsa if (rf24 != init) 4091203134Sthompsa rf24--; /* backtrack */ 4092203134Sthompsa *val = rf24; 4093203134Sthompsa run_rt3070_rf_write(sc, 24, rf24); 4094203134Sthompsa } 4095203134Sthompsa 4096203134Sthompsa /* restore initial state */ 4097203134Sthompsa run_bbp_write(sc, 24, 0x00); 4098203134Sthompsa 4099203134Sthompsa /* disable baseband loopback mode */ 4100203134Sthompsa run_rt3070_rf_read(sc, 22, &rf22); 4101203134Sthompsa run_rt3070_rf_write(sc, 22, rf22 & ~0x01); 4102203134Sthompsa 4103203134Sthompsa return 0; 4104203134Sthompsa} 4105203134Sthompsa 4106205042Sthompsastatic void 4107205042Sthompsarun_rt3070_rf_setup(struct run_softc *sc) 4108205042Sthompsa{ 4109205042Sthompsa uint8_t bbp, rf; 4110205042Sthompsa int i; 4111205042Sthompsa 4112205042Sthompsa if (sc->mac_ver == 0x3572) { 4113205042Sthompsa /* enable DC filter */ 4114205042Sthompsa if (sc->mac_rev >= 0x0201) 4115205042Sthompsa run_bbp_write(sc, 103, 0xc0); 4116205042Sthompsa 4117205042Sthompsa run_bbp_read(sc, 138, &bbp); 4118205042Sthompsa if (sc->ntxchains == 1) 4119205042Sthompsa bbp |= 0x20; /* turn off DAC1 */ 4120205042Sthompsa if (sc->nrxchains == 1) 4121205042Sthompsa bbp &= ~0x02; /* turn off ADC1 */ 4122205042Sthompsa run_bbp_write(sc, 138, bbp); 4123205042Sthompsa 4124205042Sthompsa if (sc->mac_rev >= 0x0211) { 4125205042Sthompsa /* improve power consumption */ 4126205042Sthompsa run_bbp_read(sc, 31, &bbp); 4127205042Sthompsa run_bbp_write(sc, 31, bbp & ~0x03); 4128205042Sthompsa } 4129205042Sthompsa 4130205042Sthompsa run_rt3070_rf_read(sc, 16, &rf); 4131205042Sthompsa rf = (rf & ~0x07) | sc->txmixgain_2ghz; 4132205042Sthompsa run_rt3070_rf_write(sc, 16, rf); 4133205042Sthompsa 4134205042Sthompsa } else if (sc->mac_ver == 0x3071) { 4135205042Sthompsa /* enable DC filter */ 4136205042Sthompsa if (sc->mac_rev >= 0x0201) 4137205042Sthompsa run_bbp_write(sc, 103, 0xc0); 4138205042Sthompsa 4139205042Sthompsa run_bbp_read(sc, 138, &bbp); 4140205042Sthompsa if (sc->ntxchains == 1) 4141205042Sthompsa bbp |= 0x20; /* turn off DAC1 */ 4142205042Sthompsa if (sc->nrxchains == 1) 4143205042Sthompsa bbp &= ~0x02; /* turn off ADC1 */ 4144205042Sthompsa run_bbp_write(sc, 138, bbp); 4145205042Sthompsa 4146205042Sthompsa if (sc->mac_rev >= 0x0211) { 4147205042Sthompsa /* improve power consumption */ 4148205042Sthompsa run_bbp_read(sc, 31, &bbp); 4149205042Sthompsa run_bbp_write(sc, 31, bbp & ~0x03); 4150205042Sthompsa } 4151205042Sthompsa 4152205042Sthompsa run_write(sc, RT2860_TX_SW_CFG1, 0); 4153205042Sthompsa if (sc->mac_rev < 0x0211) { 4154205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 4155205042Sthompsa sc->patch_dac ? 0x2c : 0x0f); 4156205042Sthompsa } else 4157205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0); 4158205042Sthompsa 4159205042Sthompsa } else if (sc->mac_ver == 0x3070) { 4160205042Sthompsa if (sc->mac_rev >= 0x0201) { 4161205042Sthompsa /* enable DC filter */ 4162205042Sthompsa run_bbp_write(sc, 103, 0xc0); 4163205042Sthompsa 4164205042Sthompsa /* improve power consumption */ 4165205042Sthompsa run_bbp_read(sc, 31, &bbp); 4166205042Sthompsa run_bbp_write(sc, 31, bbp & ~0x03); 4167205042Sthompsa } 4168205042Sthompsa 4169205042Sthompsa if (sc->mac_rev < 0x0211) { 4170205042Sthompsa run_write(sc, RT2860_TX_SW_CFG1, 0); 4171205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0x2c); 4172205042Sthompsa } else 4173205042Sthompsa run_write(sc, RT2860_TX_SW_CFG2, 0); 4174205042Sthompsa } 4175205042Sthompsa 4176205042Sthompsa /* initialize RF registers from ROM for >=RT3071*/ 4177205042Sthompsa if (sc->mac_ver >= 0x3071) { 4178205042Sthompsa for (i = 0; i < 10; i++) { 4179205042Sthompsa if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff) 4180205042Sthompsa continue; 4181205042Sthompsa run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val); 4182205042Sthompsa } 4183205042Sthompsa } 4184205042Sthompsa} 4185205042Sthompsa 4186203134Sthompsastatic int 4187203134Sthompsarun_txrx_enable(struct run_softc *sc) 4188203134Sthompsa{ 4189203134Sthompsa struct ieee80211com *ic = sc->sc_ifp->if_l2com; 4190203134Sthompsa uint32_t tmp; 4191203134Sthompsa int error, ntries; 4192203134Sthompsa 4193203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN); 4194203134Sthompsa for (ntries = 0; ntries < 200; ntries++) { 4195203134Sthompsa if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0) 4196203134Sthompsa return error; 4197203134Sthompsa if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 4198203134Sthompsa break; 4199203134Sthompsa run_delay(sc, 50); 4200203134Sthompsa } 4201203134Sthompsa if (ntries == 200) 4202203134Sthompsa return ETIMEDOUT; 4203203134Sthompsa 4204203134Sthompsa run_delay(sc, 50); 4205203134Sthompsa 4206203134Sthompsa tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE; 4207203134Sthompsa run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 4208203134Sthompsa 4209203134Sthompsa /* enable Rx bulk aggregation (set timeout and limit) */ 4210203134Sthompsa tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN | 4211203134Sthompsa RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2); 4212203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, tmp); 4213203134Sthompsa 4214203134Sthompsa /* set Rx filter */ 4215203134Sthompsa tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR; 4216203134Sthompsa if (ic->ic_opmode != IEEE80211_M_MONITOR) { 4217203134Sthompsa tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL | 4218203134Sthompsa RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK | 4219203134Sthompsa RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV | 4220203134Sthompsa RT2860_DROP_CFACK | RT2860_DROP_CFEND; 4221203134Sthompsa if (ic->ic_opmode == IEEE80211_M_STA) 4222203134Sthompsa tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL; 4223203134Sthompsa } 4224203134Sthompsa run_write(sc, RT2860_RX_FILTR_CFG, tmp); 4225203134Sthompsa 4226203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 4227203134Sthompsa RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 4228203134Sthompsa 4229203134Sthompsa return 0; 4230203134Sthompsa} 4231203134Sthompsa 4232203134Sthompsastatic void 4233203134Sthompsarun_init_locked(struct run_softc *sc) 4234203134Sthompsa{ 4235203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 4236203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 4237203134Sthompsa uint32_t tmp; 4238203134Sthompsa uint8_t bbp1, bbp3; 4239203134Sthompsa int i; 4240203134Sthompsa int ridx; 4241203134Sthompsa int ntries; 4242203134Sthompsa 4243203134Sthompsa run_stop(sc); 4244203134Sthompsa 4245203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 4246203134Sthompsa if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0) 4247203134Sthompsa goto fail; 4248203134Sthompsa if (tmp != 0 && tmp != 0xffffffff) 4249203134Sthompsa break; 4250203134Sthompsa run_delay(sc, 10); 4251203134Sthompsa } 4252203134Sthompsa if (ntries == 100) 4253203134Sthompsa goto fail; 4254203134Sthompsa 4255203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 4256203134Sthompsa run_setup_tx_list(sc, &sc->sc_epq[i]); 4257203134Sthompsa 4258203134Sthompsa run_set_macaddr(sc, IF_LLADDR(ifp)); 4259203134Sthompsa 4260203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 4261203134Sthompsa if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0) 4262203134Sthompsa goto fail; 4263203134Sthompsa if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 4264203134Sthompsa break; 4265203134Sthompsa run_delay(sc, 10); 4266203134Sthompsa } 4267203134Sthompsa if (ntries == 100) { 4268203138Sthompsa device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); 4269203134Sthompsa goto fail; 4270203134Sthompsa } 4271203134Sthompsa tmp &= 0xff0; 4272203134Sthompsa tmp |= RT2860_TX_WB_DDONE; 4273203134Sthompsa run_write(sc, RT2860_WPDMA_GLO_CFG, tmp); 4274203134Sthompsa 4275203134Sthompsa /* turn off PME_OEN to solve high-current issue */ 4276203134Sthompsa run_read(sc, RT2860_SYS_CTRL, &tmp); 4277203134Sthompsa run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN); 4278203134Sthompsa 4279203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 4280203134Sthompsa RT2860_BBP_HRST | RT2860_MAC_SRST); 4281203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, 0); 4282203134Sthompsa 4283203134Sthompsa if (run_reset(sc) != 0) { 4284203138Sthompsa device_printf(sc->sc_dev, "could not reset chipset\n"); 4285203134Sthompsa goto fail; 4286203134Sthompsa } 4287203134Sthompsa 4288203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 0); 4289203134Sthompsa 4290203134Sthompsa /* init Tx power for all Tx rates (from EEPROM) */ 4291203134Sthompsa for (ridx = 0; ridx < 5; ridx++) { 4292203134Sthompsa if (sc->txpow20mhz[ridx] == 0xffffffff) 4293203134Sthompsa continue; 4294203134Sthompsa run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]); 4295203134Sthompsa } 4296203134Sthompsa 4297203134Sthompsa for (i = 0; i < nitems(rt2870_def_mac); i++) 4298203134Sthompsa run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val); 4299203134Sthompsa run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273); 4300203134Sthompsa run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344); 4301203134Sthompsa run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa); 4302203134Sthompsa 4303205042Sthompsa if (sc->mac_ver >= 0x3070) { 4304203134Sthompsa /* set delay of PA_PE assertion to 1us (unit of 0.25us) */ 4305203134Sthompsa run_write(sc, RT2860_TX_SW_CFG0, 4306203134Sthompsa 4 << RT2860_DLY_PAPE_EN_SHIFT); 4307203134Sthompsa } 4308203134Sthompsa 4309203134Sthompsa /* wait while MAC is busy */ 4310203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 4311203134Sthompsa if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0) 4312203134Sthompsa goto fail; 4313203134Sthompsa if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY))) 4314203134Sthompsa break; 4315203134Sthompsa run_delay(sc, 10); 4316203134Sthompsa } 4317203134Sthompsa if (ntries == 100) 4318203134Sthompsa goto fail; 4319203134Sthompsa 4320203134Sthompsa /* clear Host to MCU mailbox */ 4321203134Sthompsa run_write(sc, RT2860_H2M_BBPAGENT, 0); 4322203134Sthompsa run_write(sc, RT2860_H2M_MAILBOX, 0); 4323203134Sthompsa run_delay(sc, 10); 4324203134Sthompsa 4325203134Sthompsa if (run_bbp_init(sc) != 0) { 4326203138Sthompsa device_printf(sc->sc_dev, "could not initialize BBP\n"); 4327203134Sthompsa goto fail; 4328203134Sthompsa } 4329203134Sthompsa 4330203134Sthompsa /* abort TSF synchronization */ 4331203134Sthompsa run_read(sc, RT2860_BCN_TIME_CFG, &tmp); 4332203134Sthompsa tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 4333203134Sthompsa RT2860_TBTT_TIMER_EN); 4334203134Sthompsa run_write(sc, RT2860_BCN_TIME_CFG, tmp); 4335203134Sthompsa 4336203134Sthompsa /* clear RX WCID search table */ 4337203134Sthompsa run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512); 4338203134Sthompsa /* clear WCID attribute table */ 4339203134Sthompsa run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32); 4340203134Sthompsa /* clear shared key table */ 4341203134Sthompsa run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32); 4342203134Sthompsa /* clear shared key mode */ 4343203134Sthompsa run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4); 4344203134Sthompsa 4345203134Sthompsa run_read(sc, RT2860_US_CYC_CNT, &tmp); 4346203134Sthompsa tmp = (tmp & ~0xff) | 0x1e; 4347203134Sthompsa run_write(sc, RT2860_US_CYC_CNT, tmp); 4348203134Sthompsa 4349205042Sthompsa if (sc->mac_rev != 0x0101) 4350203134Sthompsa run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f); 4351203134Sthompsa 4352203134Sthompsa run_write(sc, RT2860_WMM_TXOP0_CFG, 0); 4353203134Sthompsa run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96); 4354203134Sthompsa 4355203134Sthompsa /* write vendor-specific BBP values (from EEPROM) */ 4356203134Sthompsa for (i = 0; i < 8; i++) { 4357203134Sthompsa if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff) 4358203134Sthompsa continue; 4359203134Sthompsa run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val); 4360203134Sthompsa } 4361203134Sthompsa 4362203134Sthompsa /* select Main antenna for 1T1R devices */ 4363203134Sthompsa if (sc->rf_rev == RT3070_RF_3020) 4364203134Sthompsa run_set_rx_antenna(sc, 0); 4365203134Sthompsa 4366203134Sthompsa /* send LEDs operating mode to microcontroller */ 4367203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]); 4368203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]); 4369203134Sthompsa (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]); 4370203134Sthompsa 4371205042Sthompsa if (sc->mac_ver >= 0x3070) 4372205042Sthompsa run_rt3070_rf_init(sc); 4373205042Sthompsa 4374203134Sthompsa /* disable non-existing Rx chains */ 4375203134Sthompsa run_bbp_read(sc, 3, &bbp3); 4376203134Sthompsa bbp3 &= ~(1 << 3 | 1 << 4); 4377203134Sthompsa if (sc->nrxchains == 2) 4378203134Sthompsa bbp3 |= 1 << 3; 4379203134Sthompsa else if (sc->nrxchains == 3) 4380203134Sthompsa bbp3 |= 1 << 4; 4381203134Sthompsa run_bbp_write(sc, 3, bbp3); 4382203134Sthompsa 4383203134Sthompsa /* disable non-existing Tx chains */ 4384203134Sthompsa run_bbp_read(sc, 1, &bbp1); 4385203134Sthompsa if (sc->ntxchains == 1) 4386203134Sthompsa bbp1 &= ~(1 << 3 | 1 << 4); 4387203134Sthompsa run_bbp_write(sc, 1, bbp1); 4388203134Sthompsa 4389205042Sthompsa if (sc->mac_ver >= 0x3070) 4390205042Sthompsa run_rt3070_rf_setup(sc); 4391203134Sthompsa 4392203134Sthompsa /* select default channel */ 4393203134Sthompsa run_set_chan(sc, ic->ic_curchan); 4394203134Sthompsa 4395203134Sthompsa /* setup initial protection mode */ 4396203134Sthompsa run_updateprot(ic); 4397203134Sthompsa 4398203134Sthompsa /* turn radio LED on */ 4399203134Sthompsa run_set_leds(sc, RT2860_LED_RADIO); 4400203134Sthompsa 4401203134Sthompsa ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 4402203134Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 4403203134Sthompsa 4404203134Sthompsa for(i = 0; i != RUN_N_XFER; i++) 4405203134Sthompsa usbd_xfer_set_stall(sc->sc_xfer[i]); 4406203134Sthompsa 4407203134Sthompsa usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]); 4408203134Sthompsa 4409203134Sthompsa if (run_txrx_enable(sc) != 0) 4410203134Sthompsa goto fail; 4411203134Sthompsa 4412203134Sthompsa return; 4413203134Sthompsa 4414203134Sthompsafail: 4415203134Sthompsa run_stop(sc); 4416203134Sthompsa} 4417203134Sthompsa 4418203134Sthompsastatic void 4419203134Sthompsarun_init(void *arg) 4420203134Sthompsa{ 4421203134Sthompsa struct run_softc *sc = arg; 4422203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 4423203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 4424203134Sthompsa 4425203134Sthompsa RUN_LOCK(sc); 4426203134Sthompsa run_init_locked(sc); 4427203134Sthompsa RUN_UNLOCK(sc); 4428203134Sthompsa 4429203134Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING) 4430203134Sthompsa ieee80211_start_all(ic); 4431203134Sthompsa} 4432203134Sthompsa 4433203134Sthompsastatic void 4434203134Sthompsarun_stop(void *arg) 4435203134Sthompsa{ 4436203134Sthompsa struct run_softc *sc = (struct run_softc *)arg; 4437203134Sthompsa struct ifnet *ifp = sc->sc_ifp; 4438203134Sthompsa struct ieee80211com *ic = ifp->if_l2com; 4439203134Sthompsa uint32_t tmp; 4440203134Sthompsa int i; 4441203134Sthompsa int ntries; 4442203134Sthompsa 4443203134Sthompsa RUN_LOCK_ASSERT(sc, MA_OWNED); 4444203134Sthompsa 4445205042Sthompsa if(sc->sc_rvp != NULL){ 4446206358Srpaulo sc->sc_rvp->ratectl_run = RUN_RATECTL_OFF; 4447205042Sthompsa if (ic->ic_flags & IEEE80211_F_SCAN) 4448205042Sthompsa ieee80211_cancel_scan(&sc->sc_rvp->vap); 4449205042Sthompsa } 4450203134Sthompsa 4451203134Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING) 4452203134Sthompsa run_set_leds(sc, 0); /* turn all LEDs off */ 4453203134Sthompsa 4454203134Sthompsa ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 4455203134Sthompsa 4456203134Sthompsa RUN_UNLOCK(sc); 4457203134Sthompsa 4458203134Sthompsa for(i = 0; i < RUN_N_XFER; i++) 4459203134Sthompsa usbd_transfer_drain(sc->sc_xfer[i]); 4460203134Sthompsa 4461203134Sthompsa RUN_LOCK(sc); 4462203134Sthompsa 4463203134Sthompsa if(sc->rx_m != NULL){ 4464203134Sthompsa m_free(sc->rx_m); 4465203134Sthompsa sc->rx_m = NULL; 4466203134Sthompsa } 4467203134Sthompsa 4468203134Sthompsa /* disable Tx/Rx */ 4469203134Sthompsa run_read(sc, RT2860_MAC_SYS_CTRL, &tmp); 4470203134Sthompsa tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 4471203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, tmp); 4472203134Sthompsa 4473203134Sthompsa /* wait for pending Tx to complete */ 4474203134Sthompsa for (ntries = 0; ntries < 100; ntries++) { 4475203134Sthompsa if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0){ 4476203134Sthompsa DPRINTF("Cannot read Tx queue count\n"); 4477203134Sthompsa break; 4478203134Sthompsa } 4479203134Sthompsa if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0){ 4480203134Sthompsa DPRINTF("All Tx cleared\n"); 4481203134Sthompsa break; 4482203134Sthompsa } 4483203134Sthompsa run_delay(sc, 10); 4484203134Sthompsa } 4485203134Sthompsa if(ntries >= 100) 4486203134Sthompsa DPRINTF("There are still pending Tx\n"); 4487203134Sthompsa run_delay(sc, 10); 4488203134Sthompsa run_write(sc, RT2860_USB_DMA_CFG, 0); 4489203134Sthompsa 4490203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST); 4491203134Sthompsa run_write(sc, RT2860_MAC_SYS_CTRL, 0); 4492203134Sthompsa 4493203134Sthompsa for (i = 0; i != RUN_EP_QUEUES; i++) 4494203134Sthompsa run_unsetup_tx_list(sc, &sc->sc_epq[i]); 4495203134Sthompsa 4496203134Sthompsa return; 4497203134Sthompsa} 4498203134Sthompsa 4499203134Sthompsastatic void 4500203134Sthompsarun_delay(struct run_softc *sc, unsigned int ms) 4501203134Sthompsa{ 4502203134Sthompsa usb_pause_mtx(mtx_owned(&sc->sc_mtx) ? 4503203134Sthompsa &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms)); 4504203134Sthompsa} 4505203134Sthompsa 4506203134Sthompsastatic device_method_t run_methods[] = { 4507203134Sthompsa /* Device interface */ 4508203134Sthompsa DEVMETHOD(device_probe, run_match), 4509203134Sthompsa DEVMETHOD(device_attach, run_attach), 4510203134Sthompsa DEVMETHOD(device_detach, run_detach), 4511203134Sthompsa 4512203134Sthompsa { 0, 0 } 4513203134Sthompsa}; 4514203134Sthompsa 4515203134Sthompsastatic driver_t run_driver = { 4516203134Sthompsa "run", 4517203134Sthompsa run_methods, 4518203134Sthompsa sizeof(struct run_softc) 4519203134Sthompsa}; 4520203134Sthompsa 4521203134Sthompsastatic devclass_t run_devclass; 4522203134Sthompsa 4523203134SthompsaDRIVER_MODULE(run, uhub, run_driver, run_devclass, NULL, 0); 4524