if_urtwn.c revision 292173
1251538Srpaulo/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ 2251538Srpaulo 3251538Srpaulo/*- 4251538Srpaulo * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> 5264912Skevlo * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> 6251538Srpaulo * 7251538Srpaulo * Permission to use, copy, modify, and distribute this software for any 8251538Srpaulo * purpose with or without fee is hereby granted, provided that the above 9251538Srpaulo * copyright notice and this permission notice appear in all copies. 10251538Srpaulo * 11251538Srpaulo * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12251538Srpaulo * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13251538Srpaulo * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14251538Srpaulo * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15251538Srpaulo * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16251538Srpaulo * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17251538Srpaulo * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18251538Srpaulo */ 19251538Srpaulo 20251538Srpaulo#include <sys/cdefs.h> 21251538Srpaulo__FBSDID("$FreeBSD: head/sys/dev/usb/wlan/if_urtwn.c 292173 2015-12-13 21:43:54Z avos $"); 22251538Srpaulo 23251538Srpaulo/* 24264912Skevlo * Driver for Realtek RTL8188CE-VAU/RTL8188CUS/RTL8188EU/RTL8188RU/RTL8192CU. 25251538Srpaulo */ 26251538Srpaulo 27288353Sadrian#include "opt_wlan.h" 28288353Sadrian 29251538Srpaulo#include <sys/param.h> 30251538Srpaulo#include <sys/sockio.h> 31251538Srpaulo#include <sys/sysctl.h> 32251538Srpaulo#include <sys/lock.h> 33251538Srpaulo#include <sys/mutex.h> 34291902Skevlo#include <sys/condvar.h> 35251538Srpaulo#include <sys/mbuf.h> 36251538Srpaulo#include <sys/kernel.h> 37251538Srpaulo#include <sys/socket.h> 38251538Srpaulo#include <sys/systm.h> 39251538Srpaulo#include <sys/malloc.h> 40251538Srpaulo#include <sys/module.h> 41251538Srpaulo#include <sys/bus.h> 42251538Srpaulo#include <sys/endian.h> 43251538Srpaulo#include <sys/linker.h> 44251538Srpaulo#include <sys/firmware.h> 45251538Srpaulo#include <sys/kdb.h> 46251538Srpaulo 47251538Srpaulo#include <machine/bus.h> 48251538Srpaulo#include <machine/resource.h> 49251538Srpaulo#include <sys/rman.h> 50251538Srpaulo 51251538Srpaulo#include <net/bpf.h> 52251538Srpaulo#include <net/if.h> 53257176Sglebius#include <net/if_var.h> 54251538Srpaulo#include <net/if_arp.h> 55251538Srpaulo#include <net/ethernet.h> 56251538Srpaulo#include <net/if_dl.h> 57251538Srpaulo#include <net/if_media.h> 58251538Srpaulo#include <net/if_types.h> 59251538Srpaulo 60251538Srpaulo#include <netinet/in.h> 61251538Srpaulo#include <netinet/in_systm.h> 62251538Srpaulo#include <netinet/in_var.h> 63251538Srpaulo#include <netinet/if_ether.h> 64251538Srpaulo#include <netinet/ip.h> 65251538Srpaulo 66251538Srpaulo#include <net80211/ieee80211_var.h> 67288088Sadrian#include <net80211/ieee80211_input.h> 68251538Srpaulo#include <net80211/ieee80211_regdomain.h> 69251538Srpaulo#include <net80211/ieee80211_radiotap.h> 70251538Srpaulo#include <net80211/ieee80211_ratectl.h> 71251538Srpaulo 72251538Srpaulo#include <dev/usb/usb.h> 73251538Srpaulo#include <dev/usb/usbdi.h> 74291902Skevlo#include <dev/usb/usb_device.h> 75251538Srpaulo#include "usbdevs.h" 76251538Srpaulo 77251538Srpaulo#define USB_DEBUG_VAR urtwn_debug 78251538Srpaulo#include <dev/usb/usb_debug.h> 79251538Srpaulo 80251538Srpaulo#include <dev/usb/wlan/if_urtwnreg.h> 81289167Sadrian#include <dev/usb/wlan/if_urtwnvar.h> 82251538Srpaulo 83251538Srpaulo#ifdef USB_DEBUG 84251538Srpaulostatic int urtwn_debug = 0; 85251538Srpaulo 86251538SrpauloSYSCTL_NODE(_hw_usb, OID_AUTO, urtwn, CTLFLAG_RW, 0, "USB urtwn"); 87276701ShselaskySYSCTL_INT(_hw_usb_urtwn, OID_AUTO, debug, CTLFLAG_RWTUN, &urtwn_debug, 0, 88251538Srpaulo "Debug level"); 89251538Srpaulo#endif 90251538Srpaulo 91288088Sadrian#define IEEE80211_HAS_ADDR4(wh) IEEE80211_IS_DSTODS(wh) 92251538Srpaulo 93251538Srpaulo/* various supported device vendors/products */ 94251596Srpaulostatic const STRUCT_USB_HOST_ID urtwn_devs[] = { 95251538Srpaulo#define URTWN_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } 96264912Skevlo#define URTWN_RTL8188E_DEV(v,p) \ 97264912Skevlo { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, URTWN_RTL8188E) } 98264912Skevlo#define URTWN_RTL8188E 1 99251538Srpaulo URTWN_DEV(ABOCOM, RTL8188CU_1), 100251538Srpaulo URTWN_DEV(ABOCOM, RTL8188CU_2), 101251538Srpaulo URTWN_DEV(ABOCOM, RTL8192CU), 102251538Srpaulo URTWN_DEV(ASUS, RTL8192CU), 103266721Skevlo URTWN_DEV(ASUS, USBN10NANO), 104251538Srpaulo URTWN_DEV(AZUREWAVE, RTL8188CE_1), 105251538Srpaulo URTWN_DEV(AZUREWAVE, RTL8188CE_2), 106251538Srpaulo URTWN_DEV(AZUREWAVE, RTL8188CU), 107251538Srpaulo URTWN_DEV(BELKIN, F7D2102), 108251538Srpaulo URTWN_DEV(BELKIN, RTL8188CU), 109251538Srpaulo URTWN_DEV(BELKIN, RTL8192CU), 110251538Srpaulo URTWN_DEV(CHICONY, RTL8188CUS_1), 111251538Srpaulo URTWN_DEV(CHICONY, RTL8188CUS_2), 112251538Srpaulo URTWN_DEV(CHICONY, RTL8188CUS_3), 113251538Srpaulo URTWN_DEV(CHICONY, RTL8188CUS_4), 114251538Srpaulo URTWN_DEV(CHICONY, RTL8188CUS_5), 115251538Srpaulo URTWN_DEV(COREGA, RTL8192CU), 116251538Srpaulo URTWN_DEV(DLINK, RTL8188CU), 117251538Srpaulo URTWN_DEV(DLINK, RTL8192CU_1), 118251538Srpaulo URTWN_DEV(DLINK, RTL8192CU_2), 119251538Srpaulo URTWN_DEV(DLINK, RTL8192CU_3), 120252196Skevlo URTWN_DEV(DLINK, DWA131B), 121251538Srpaulo URTWN_DEV(EDIMAX, EW7811UN), 122251538Srpaulo URTWN_DEV(EDIMAX, RTL8192CU), 123251538Srpaulo URTWN_DEV(FEIXUN, RTL8188CU), 124251538Srpaulo URTWN_DEV(FEIXUN, RTL8192CU), 125251538Srpaulo URTWN_DEV(GUILLEMOT, HWNUP150), 126251538Srpaulo URTWN_DEV(HAWKING, RTL8192CU), 127251538Srpaulo URTWN_DEV(HP3, RTL8188CU), 128251538Srpaulo URTWN_DEV(NETGEAR, WNA1000M), 129251538Srpaulo URTWN_DEV(NETGEAR, RTL8192CU), 130251538Srpaulo URTWN_DEV(NETGEAR4, RTL8188CU), 131251538Srpaulo URTWN_DEV(NOVATECH, RTL8188CU), 132251538Srpaulo URTWN_DEV(PLANEX2, RTL8188CU_1), 133251538Srpaulo URTWN_DEV(PLANEX2, RTL8188CU_2), 134251538Srpaulo URTWN_DEV(PLANEX2, RTL8188CU_3), 135251538Srpaulo URTWN_DEV(PLANEX2, RTL8188CU_4), 136251538Srpaulo URTWN_DEV(PLANEX2, RTL8188CUS), 137251538Srpaulo URTWN_DEV(PLANEX2, RTL8192CU), 138251538Srpaulo URTWN_DEV(REALTEK, RTL8188CE_0), 139251538Srpaulo URTWN_DEV(REALTEK, RTL8188CE_1), 140251538Srpaulo URTWN_DEV(REALTEK, RTL8188CTV), 141251538Srpaulo URTWN_DEV(REALTEK, RTL8188CU_0), 142251538Srpaulo URTWN_DEV(REALTEK, RTL8188CU_1), 143251538Srpaulo URTWN_DEV(REALTEK, RTL8188CU_2), 144282119Skevlo URTWN_DEV(REALTEK, RTL8188CU_3), 145251538Srpaulo URTWN_DEV(REALTEK, RTL8188CU_COMBO), 146251538Srpaulo URTWN_DEV(REALTEK, RTL8188CUS), 147251538Srpaulo URTWN_DEV(REALTEK, RTL8188RU_1), 148251538Srpaulo URTWN_DEV(REALTEK, RTL8188RU_2), 149272410Shselasky URTWN_DEV(REALTEK, RTL8188RU_3), 150251538Srpaulo URTWN_DEV(REALTEK, RTL8191CU), 151251538Srpaulo URTWN_DEV(REALTEK, RTL8192CE), 152251538Srpaulo URTWN_DEV(REALTEK, RTL8192CU), 153251538Srpaulo URTWN_DEV(SITECOMEU, RTL8188CU_1), 154251538Srpaulo URTWN_DEV(SITECOMEU, RTL8188CU_2), 155251538Srpaulo URTWN_DEV(SITECOMEU, RTL8192CU), 156251538Srpaulo URTWN_DEV(TRENDNET, RTL8188CU), 157251538Srpaulo URTWN_DEV(TRENDNET, RTL8192CU), 158251538Srpaulo URTWN_DEV(ZYXEL, RTL8192CU), 159264912Skevlo /* URTWN_RTL8188E */ 160273589Skevlo URTWN_RTL8188E_DEV(DLINK, DWA123D1), 161270191Skevlo URTWN_RTL8188E_DEV(DLINK, DWA125D1), 162273589Skevlo URTWN_RTL8188E_DEV(ELECOM, WDC150SU2M), 163264912Skevlo URTWN_RTL8188E_DEV(REALTEK, RTL8188ETV), 164264912Skevlo URTWN_RTL8188E_DEV(REALTEK, RTL8188EU), 165264912Skevlo#undef URTWN_RTL8188E_DEV 166251538Srpaulo#undef URTWN_DEV 167251538Srpaulo}; 168251538Srpaulo 169251538Srpaulostatic device_probe_t urtwn_match; 170251538Srpaulostatic device_attach_t urtwn_attach; 171251538Srpaulostatic device_detach_t urtwn_detach; 172251538Srpaulo 173251538Srpaulostatic usb_callback_t urtwn_bulk_tx_callback; 174251538Srpaulostatic usb_callback_t urtwn_bulk_rx_callback; 175251538Srpaulo 176288353Sadrianstatic void urtwn_drain_mbufq(struct urtwn_softc *sc); 177287197Sglebiusstatic usb_error_t urtwn_do_request(struct urtwn_softc *, 178287197Sglebius struct usb_device_request *, void *); 179251538Srpaulostatic struct ieee80211vap *urtwn_vap_create(struct ieee80211com *, 180251538Srpaulo const char [IFNAMSIZ], int, enum ieee80211_opmode, int, 181251538Srpaulo const uint8_t [IEEE80211_ADDR_LEN], 182251538Srpaulo const uint8_t [IEEE80211_ADDR_LEN]); 183251538Srpaulostatic void urtwn_vap_delete(struct ieee80211vap *); 184281069Srpaulostatic struct mbuf * urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int, 185251538Srpaulo int *); 186292167Savosstatic struct mbuf * urtwn_report_intr(struct usb_xfer *, struct urtwn_data *, 187251538Srpaulo int *, int8_t *); 188292167Savosstatic struct mbuf * urtwn_rxeof(struct urtwn_softc *, uint8_t *, int, 189292167Savos int *, int8_t *); 190292167Savosstatic void urtwn_r88e_ratectl_tx_complete(struct urtwn_softc *, 191292167Savos void *); 192289891Savosstatic void urtwn_txeof(struct urtwn_softc *, struct urtwn_data *, 193289891Savos int); 194281069Srpaulostatic int urtwn_alloc_list(struct urtwn_softc *, 195251538Srpaulo struct urtwn_data[], int, int); 196251538Srpaulostatic int urtwn_alloc_rx_list(struct urtwn_softc *); 197251538Srpaulostatic int urtwn_alloc_tx_list(struct urtwn_softc *); 198251538Srpaulostatic void urtwn_free_list(struct urtwn_softc *, 199251538Srpaulo struct urtwn_data data[], int); 200289066Skevlostatic void urtwn_free_rx_list(struct urtwn_softc *); 201289066Skevlostatic void urtwn_free_tx_list(struct urtwn_softc *); 202251538Srpaulostatic struct urtwn_data * _urtwn_getbuf(struct urtwn_softc *); 203251538Srpaulostatic struct urtwn_data * urtwn_getbuf(struct urtwn_softc *); 204291698Savosstatic usb_error_t urtwn_write_region_1(struct urtwn_softc *, uint16_t, 205251538Srpaulo uint8_t *, int); 206291698Savosstatic usb_error_t urtwn_write_1(struct urtwn_softc *, uint16_t, uint8_t); 207291698Savosstatic usb_error_t urtwn_write_2(struct urtwn_softc *, uint16_t, uint16_t); 208291698Savosstatic usb_error_t urtwn_write_4(struct urtwn_softc *, uint16_t, uint32_t); 209291698Savosstatic usb_error_t urtwn_read_region_1(struct urtwn_softc *, uint16_t, 210251538Srpaulo uint8_t *, int); 211251538Srpaulostatic uint8_t urtwn_read_1(struct urtwn_softc *, uint16_t); 212251538Srpaulostatic uint16_t urtwn_read_2(struct urtwn_softc *, uint16_t); 213251538Srpaulostatic uint32_t urtwn_read_4(struct urtwn_softc *, uint16_t); 214281069Srpaulostatic int urtwn_fw_cmd(struct urtwn_softc *, uint8_t, 215251538Srpaulo const void *, int); 216264912Skevlostatic void urtwn_r92c_rf_write(struct urtwn_softc *, int, 217264912Skevlo uint8_t, uint32_t); 218281069Srpaulostatic void urtwn_r88e_rf_write(struct urtwn_softc *, int, 219264912Skevlo uint8_t, uint32_t); 220251538Srpaulostatic uint32_t urtwn_rf_read(struct urtwn_softc *, int, uint8_t); 221281069Srpaulostatic int urtwn_llt_write(struct urtwn_softc *, uint32_t, 222251538Srpaulo uint32_t); 223291264Savosstatic int urtwn_efuse_read_next(struct urtwn_softc *, uint8_t *); 224291264Savosstatic int urtwn_efuse_read_data(struct urtwn_softc *, uint8_t *, 225291264Savos uint8_t, uint8_t); 226291264Savos#ifdef URTWN_DEBUG 227291264Savosstatic void urtwn_dump_rom_contents(struct urtwn_softc *, 228291264Savos uint8_t *, uint16_t); 229291264Savos#endif 230291264Savosstatic int urtwn_efuse_read(struct urtwn_softc *, uint8_t *, 231291264Savos uint16_t); 232291698Savosstatic int urtwn_efuse_switch_power(struct urtwn_softc *); 233251538Srpaulostatic int urtwn_read_chipid(struct urtwn_softc *); 234291264Savosstatic int urtwn_read_rom(struct urtwn_softc *); 235291264Savosstatic int urtwn_r88e_read_rom(struct urtwn_softc *); 236251538Srpaulostatic int urtwn_ra_init(struct urtwn_softc *); 237290631Savosstatic void urtwn_init_beacon(struct urtwn_softc *, 238290631Savos struct urtwn_vap *); 239290631Savosstatic int urtwn_setup_beacon(struct urtwn_softc *, 240290631Savos struct ieee80211_node *); 241290631Savosstatic void urtwn_update_beacon(struct ieee80211vap *, int); 242290631Savosstatic int urtwn_tx_beacon(struct urtwn_softc *sc, 243290631Savos struct urtwn_vap *); 244290651Savosstatic void urtwn_tsf_task_adhoc(void *, int); 245290631Savosstatic void urtwn_tsf_sync_enable(struct urtwn_softc *, 246290631Savos struct ieee80211vap *); 247251538Srpaulostatic void urtwn_set_led(struct urtwn_softc *, int, int); 248289811Savosstatic void urtwn_set_mode(struct urtwn_softc *, uint8_t); 249290651Savosstatic void urtwn_ibss_recv_mgmt(struct ieee80211_node *, 250290651Savos struct mbuf *, int, 251290651Savos const struct ieee80211_rx_stats *, int, int); 252281069Srpaulostatic int urtwn_newstate(struct ieee80211vap *, 253251538Srpaulo enum ieee80211_state, int); 254251538Srpaulostatic void urtwn_watchdog(void *); 255251538Srpaulostatic void urtwn_update_avgrssi(struct urtwn_softc *, int, int8_t); 256251538Srpaulostatic int8_t urtwn_get_rssi(struct urtwn_softc *, int, void *); 257264912Skevlostatic int8_t urtwn_r88e_get_rssi(struct urtwn_softc *, int, void *); 258290630Savosstatic int urtwn_tx_data(struct urtwn_softc *, 259251538Srpaulo struct ieee80211_node *, struct mbuf *, 260251538Srpaulo struct urtwn_data *); 261290630Savosstatic void urtwn_tx_start(struct urtwn_softc *, struct mbuf *, 262290630Savos uint8_t, struct urtwn_data *); 263287197Sglebiusstatic int urtwn_transmit(struct ieee80211com *, struct mbuf *); 264287197Sglebiusstatic void urtwn_start(struct urtwn_softc *); 265287197Sglebiusstatic void urtwn_parent(struct ieee80211com *); 266264912Skevlostatic int urtwn_r92c_power_on(struct urtwn_softc *); 267264912Skevlostatic int urtwn_r88e_power_on(struct urtwn_softc *); 268251538Srpaulostatic int urtwn_llt_init(struct urtwn_softc *); 269251538Srpaulostatic void urtwn_fw_reset(struct urtwn_softc *); 270264912Skevlostatic void urtwn_r88e_fw_reset(struct urtwn_softc *); 271281069Srpaulostatic int urtwn_fw_loadpage(struct urtwn_softc *, int, 272251538Srpaulo const uint8_t *, int); 273251538Srpaulostatic int urtwn_load_firmware(struct urtwn_softc *); 274291902Skevlostatic int urtwn_dma_init(struct urtwn_softc *); 275291698Savosstatic int urtwn_mac_init(struct urtwn_softc *); 276251538Srpaulostatic void urtwn_bb_init(struct urtwn_softc *); 277251538Srpaulostatic void urtwn_rf_init(struct urtwn_softc *); 278251538Srpaulostatic void urtwn_cam_init(struct urtwn_softc *); 279251538Srpaulostatic void urtwn_pa_bias_init(struct urtwn_softc *); 280251538Srpaulostatic void urtwn_rxfilter_init(struct urtwn_softc *); 281251538Srpaulostatic void urtwn_edca_init(struct urtwn_softc *); 282281069Srpaulostatic void urtwn_write_txpower(struct urtwn_softc *, int, 283251538Srpaulo uint16_t[]); 284251538Srpaulostatic void urtwn_get_txpower(struct urtwn_softc *, int, 285281069Srpaulo struct ieee80211_channel *, 286251538Srpaulo struct ieee80211_channel *, uint16_t[]); 287264912Skevlostatic void urtwn_r88e_get_txpower(struct urtwn_softc *, int, 288281069Srpaulo struct ieee80211_channel *, 289264912Skevlo struct ieee80211_channel *, uint16_t[]); 290251538Srpaulostatic void urtwn_set_txpower(struct urtwn_softc *, 291281069Srpaulo struct ieee80211_channel *, 292251538Srpaulo struct ieee80211_channel *); 293290048Savosstatic void urtwn_set_rx_bssid_all(struct urtwn_softc *, int); 294290048Savosstatic void urtwn_set_gain(struct urtwn_softc *, uint8_t); 295251538Srpaulostatic void urtwn_scan_start(struct ieee80211com *); 296251538Srpaulostatic void urtwn_scan_end(struct ieee80211com *); 297251538Srpaulostatic void urtwn_set_channel(struct ieee80211com *); 298292014Savosstatic int urtwn_wme_update(struct ieee80211com *); 299290564Savosstatic void urtwn_set_promisc(struct urtwn_softc *); 300290564Savosstatic void urtwn_update_promisc(struct ieee80211com *); 301289066Skevlostatic void urtwn_update_mcast(struct ieee80211com *); 302292167Savosstatic struct ieee80211_node *urtwn_r88e_node_alloc(struct ieee80211vap *, 303292167Savos const uint8_t mac[IEEE80211_ADDR_LEN]); 304292167Savosstatic void urtwn_r88e_newassoc(struct ieee80211_node *, int); 305292167Savosstatic void urtwn_r88e_node_free(struct ieee80211_node *); 306251538Srpaulostatic void urtwn_set_chan(struct urtwn_softc *, 307281069Srpaulo struct ieee80211_channel *, 308251538Srpaulo struct ieee80211_channel *); 309251538Srpaulostatic void urtwn_iq_calib(struct urtwn_softc *); 310251538Srpaulostatic void urtwn_lc_calib(struct urtwn_softc *); 311291698Savosstatic int urtwn_init(struct urtwn_softc *); 312287197Sglebiusstatic void urtwn_stop(struct urtwn_softc *); 313251538Srpaulostatic void urtwn_abort_xfers(struct urtwn_softc *); 314251538Srpaulostatic int urtwn_raw_xmit(struct ieee80211_node *, struct mbuf *, 315251538Srpaulo const struct ieee80211_bpf_params *); 316266472Shselaskystatic void urtwn_ms_delay(struct urtwn_softc *); 317251538Srpaulo 318251538Srpaulo/* Aliases. */ 319251538Srpaulo#define urtwn_bb_write urtwn_write_4 320251538Srpaulo#define urtwn_bb_read urtwn_read_4 321251538Srpaulo 322251538Srpaulostatic const struct usb_config urtwn_config[URTWN_N_TRANSFER] = { 323251538Srpaulo [URTWN_BULK_RX] = { 324251538Srpaulo .type = UE_BULK, 325251538Srpaulo .endpoint = UE_ADDR_ANY, 326251538Srpaulo .direction = UE_DIR_IN, 327251538Srpaulo .bufsize = URTWN_RXBUFSZ, 328251538Srpaulo .flags = { 329251538Srpaulo .pipe_bof = 1, 330251538Srpaulo .short_xfer_ok = 1 331251538Srpaulo }, 332251538Srpaulo .callback = urtwn_bulk_rx_callback, 333251538Srpaulo }, 334251538Srpaulo [URTWN_BULK_TX_BE] = { 335251538Srpaulo .type = UE_BULK, 336251538Srpaulo .endpoint = 0x03, 337251538Srpaulo .direction = UE_DIR_OUT, 338251538Srpaulo .bufsize = URTWN_TXBUFSZ, 339251538Srpaulo .flags = { 340251538Srpaulo .ext_buffer = 1, 341251538Srpaulo .pipe_bof = 1, 342251538Srpaulo .force_short_xfer = 1 343251538Srpaulo }, 344251538Srpaulo .callback = urtwn_bulk_tx_callback, 345251538Srpaulo .timeout = URTWN_TX_TIMEOUT, /* ms */ 346251538Srpaulo }, 347251538Srpaulo [URTWN_BULK_TX_BK] = { 348251538Srpaulo .type = UE_BULK, 349251538Srpaulo .endpoint = 0x03, 350251538Srpaulo .direction = UE_DIR_OUT, 351251538Srpaulo .bufsize = URTWN_TXBUFSZ, 352251538Srpaulo .flags = { 353251538Srpaulo .ext_buffer = 1, 354251538Srpaulo .pipe_bof = 1, 355251538Srpaulo .force_short_xfer = 1, 356251538Srpaulo }, 357251538Srpaulo .callback = urtwn_bulk_tx_callback, 358251538Srpaulo .timeout = URTWN_TX_TIMEOUT, /* ms */ 359251538Srpaulo }, 360251538Srpaulo [URTWN_BULK_TX_VI] = { 361251538Srpaulo .type = UE_BULK, 362251538Srpaulo .endpoint = 0x02, 363251538Srpaulo .direction = UE_DIR_OUT, 364251538Srpaulo .bufsize = URTWN_TXBUFSZ, 365251538Srpaulo .flags = { 366251538Srpaulo .ext_buffer = 1, 367251538Srpaulo .pipe_bof = 1, 368251538Srpaulo .force_short_xfer = 1 369251538Srpaulo }, 370251538Srpaulo .callback = urtwn_bulk_tx_callback, 371251538Srpaulo .timeout = URTWN_TX_TIMEOUT, /* ms */ 372251538Srpaulo }, 373251538Srpaulo [URTWN_BULK_TX_VO] = { 374251538Srpaulo .type = UE_BULK, 375251538Srpaulo .endpoint = 0x02, 376251538Srpaulo .direction = UE_DIR_OUT, 377251538Srpaulo .bufsize = URTWN_TXBUFSZ, 378251538Srpaulo .flags = { 379251538Srpaulo .ext_buffer = 1, 380251538Srpaulo .pipe_bof = 1, 381251538Srpaulo .force_short_xfer = 1 382251538Srpaulo }, 383251538Srpaulo .callback = urtwn_bulk_tx_callback, 384251538Srpaulo .timeout = URTWN_TX_TIMEOUT, /* ms */ 385251538Srpaulo }, 386251538Srpaulo}; 387251538Srpaulo 388292014Savosstatic const struct wme_to_queue { 389292014Savos uint16_t reg; 390292014Savos uint8_t qid; 391292014Savos} wme2queue[WME_NUM_AC] = { 392292014Savos { R92C_EDCA_BE_PARAM, URTWN_BULK_TX_BE}, 393292014Savos { R92C_EDCA_BK_PARAM, URTWN_BULK_TX_BK}, 394292014Savos { R92C_EDCA_VI_PARAM, URTWN_BULK_TX_VI}, 395292014Savos { R92C_EDCA_VO_PARAM, URTWN_BULK_TX_VO} 396292014Savos}; 397292014Savos 398251538Srpaulostatic int 399251538Srpaulourtwn_match(device_t self) 400251538Srpaulo{ 401251538Srpaulo struct usb_attach_arg *uaa = device_get_ivars(self); 402251538Srpaulo 403251538Srpaulo if (uaa->usb_mode != USB_MODE_HOST) 404251538Srpaulo return (ENXIO); 405251538Srpaulo if (uaa->info.bConfigIndex != URTWN_CONFIG_INDEX) 406251538Srpaulo return (ENXIO); 407251538Srpaulo if (uaa->info.bIfaceIndex != URTWN_IFACE_INDEX) 408251538Srpaulo return (ENXIO); 409251538Srpaulo 410251538Srpaulo return (usbd_lookup_id_by_uaa(urtwn_devs, sizeof(urtwn_devs), uaa)); 411251538Srpaulo} 412251538Srpaulo 413251538Srpaulostatic int 414251538Srpaulourtwn_attach(device_t self) 415251538Srpaulo{ 416251538Srpaulo struct usb_attach_arg *uaa = device_get_ivars(self); 417251538Srpaulo struct urtwn_softc *sc = device_get_softc(self); 418287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 419291902Skevlo uint8_t bands; 420251538Srpaulo int error; 421251538Srpaulo 422251538Srpaulo device_set_usb_desc(self); 423251538Srpaulo sc->sc_udev = uaa->device; 424251538Srpaulo sc->sc_dev = self; 425264912Skevlo if (USB_GET_DRIVER_INFO(uaa) == URTWN_RTL8188E) 426264912Skevlo sc->chip |= URTWN_CHIP_88E; 427251538Srpaulo 428251538Srpaulo mtx_init(&sc->sc_mtx, device_get_nameunit(self), 429251538Srpaulo MTX_NETWORK_LOCK, MTX_DEF); 430292167Savos URTWN_NT_LOCK_INIT(sc); 431251538Srpaulo callout_init(&sc->sc_watchdog_ch, 0); 432287197Sglebius mbufq_init(&sc->sc_snd, ifqmaxlen); 433251538Srpaulo 434291902Skevlo sc->sc_iface_index = URTWN_IFACE_INDEX; 435291902Skevlo error = usbd_transfer_setup(uaa->device, &sc->sc_iface_index, 436291902Skevlo sc->sc_xfer, urtwn_config, URTWN_N_TRANSFER, sc, &sc->sc_mtx); 437251538Srpaulo if (error) { 438251538Srpaulo device_printf(self, "could not allocate USB transfers, " 439251538Srpaulo "err=%s\n", usbd_errstr(error)); 440251538Srpaulo goto detach; 441251538Srpaulo } 442251538Srpaulo 443251538Srpaulo URTWN_LOCK(sc); 444251538Srpaulo 445251538Srpaulo error = urtwn_read_chipid(sc); 446251538Srpaulo if (error) { 447251538Srpaulo device_printf(sc->sc_dev, "unsupported test chip\n"); 448251538Srpaulo URTWN_UNLOCK(sc); 449251538Srpaulo goto detach; 450251538Srpaulo } 451251538Srpaulo 452251538Srpaulo /* Determine number of Tx/Rx chains. */ 453251538Srpaulo if (sc->chip & URTWN_CHIP_92C) { 454251538Srpaulo sc->ntxchains = (sc->chip & URTWN_CHIP_92C_1T2R) ? 1 : 2; 455251538Srpaulo sc->nrxchains = 2; 456251538Srpaulo } else { 457251538Srpaulo sc->ntxchains = 1; 458251538Srpaulo sc->nrxchains = 1; 459251538Srpaulo } 460251538Srpaulo 461264912Skevlo if (sc->chip & URTWN_CHIP_88E) 462291264Savos error = urtwn_r88e_read_rom(sc); 463264912Skevlo else 464291264Savos error = urtwn_read_rom(sc); 465291264Savos if (error != 0) { 466291264Savos device_printf(sc->sc_dev, "%s: cannot read rom, error %d\n", 467291264Savos __func__, error); 468291264Savos URTWN_UNLOCK(sc); 469291264Savos goto detach; 470291264Savos } 471264912Skevlo 472251538Srpaulo device_printf(sc->sc_dev, "MAC/BB RTL%s, RF 6052 %dT%dR\n", 473251538Srpaulo (sc->chip & URTWN_CHIP_92C) ? "8192CU" : 474264912Skevlo (sc->chip & URTWN_CHIP_88E) ? "8188EU" : 475251538Srpaulo (sc->board_type == R92C_BOARD_TYPE_HIGHPA) ? "8188RU" : 476251538Srpaulo (sc->board_type == R92C_BOARD_TYPE_MINICARD) ? "8188CE-VAU" : 477251538Srpaulo "8188CUS", sc->ntxchains, sc->nrxchains); 478251538Srpaulo 479251538Srpaulo URTWN_UNLOCK(sc); 480251538Srpaulo 481283537Sglebius ic->ic_softc = sc; 482283527Sglebius ic->ic_name = device_get_nameunit(self); 483251538Srpaulo ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 484251538Srpaulo ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 485251538Srpaulo 486251538Srpaulo /* set device capabilities */ 487251538Srpaulo ic->ic_caps = 488251538Srpaulo IEEE80211_C_STA /* station mode */ 489251538Srpaulo | IEEE80211_C_MONITOR /* monitor mode */ 490290651Savos | IEEE80211_C_IBSS /* adhoc mode */ 491290631Savos | IEEE80211_C_HOSTAP /* hostap mode */ 492251538Srpaulo | IEEE80211_C_SHPREAMBLE /* short preamble supported */ 493251538Srpaulo | IEEE80211_C_SHSLOT /* short slot time supported */ 494251538Srpaulo | IEEE80211_C_BGSCAN /* capable of bg scanning */ 495251538Srpaulo | IEEE80211_C_WPA /* 802.11i */ 496292014Savos | IEEE80211_C_WME /* 802.11e */ 497251538Srpaulo ; 498251538Srpaulo 499251538Srpaulo bands = 0; 500251538Srpaulo setbit(&bands, IEEE80211_MODE_11B); 501251538Srpaulo setbit(&bands, IEEE80211_MODE_11G); 502251538Srpaulo ieee80211_init_channels(ic, NULL, &bands); 503251538Srpaulo 504287197Sglebius ieee80211_ifattach(ic); 505251538Srpaulo ic->ic_raw_xmit = urtwn_raw_xmit; 506251538Srpaulo ic->ic_scan_start = urtwn_scan_start; 507251538Srpaulo ic->ic_scan_end = urtwn_scan_end; 508251538Srpaulo ic->ic_set_channel = urtwn_set_channel; 509287197Sglebius ic->ic_transmit = urtwn_transmit; 510287197Sglebius ic->ic_parent = urtwn_parent; 511251538Srpaulo ic->ic_vap_create = urtwn_vap_create; 512251538Srpaulo ic->ic_vap_delete = urtwn_vap_delete; 513292014Savos ic->ic_wme.wme_update = urtwn_wme_update; 514290564Savos ic->ic_update_promisc = urtwn_update_promisc; 515251538Srpaulo ic->ic_update_mcast = urtwn_update_mcast; 516292167Savos if (sc->chip & URTWN_CHIP_88E) { 517292167Savos ic->ic_node_alloc = urtwn_r88e_node_alloc; 518292167Savos ic->ic_newassoc = urtwn_r88e_newassoc; 519292167Savos sc->sc_node_free = ic->ic_node_free; 520292167Savos ic->ic_node_free = urtwn_r88e_node_free; 521292167Savos } 522251538Srpaulo 523281069Srpaulo ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, 524251538Srpaulo sizeof(sc->sc_txtap), URTWN_TX_RADIOTAP_PRESENT, 525251538Srpaulo &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 526251538Srpaulo URTWN_RX_RADIOTAP_PRESENT); 527251538Srpaulo 528251538Srpaulo if (bootverbose) 529251538Srpaulo ieee80211_announce(ic); 530251538Srpaulo 531251538Srpaulo return (0); 532251538Srpaulo 533251538Srpaulodetach: 534251538Srpaulo urtwn_detach(self); 535251538Srpaulo return (ENXIO); /* failure */ 536251538Srpaulo} 537251538Srpaulo 538251538Srpaulostatic int 539251538Srpaulourtwn_detach(device_t self) 540251538Srpaulo{ 541251538Srpaulo struct urtwn_softc *sc = device_get_softc(self); 542287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 543263153Skevlo unsigned int x; 544281069Srpaulo 545263153Skevlo /* Prevent further ioctls. */ 546263153Skevlo URTWN_LOCK(sc); 547263153Skevlo sc->sc_flags |= URTWN_DETACHED; 548263153Skevlo URTWN_UNLOCK(sc); 549251538Srpaulo 550291698Savos urtwn_stop(sc); 551291698Savos 552251538Srpaulo callout_drain(&sc->sc_watchdog_ch); 553251538Srpaulo 554288353Sadrian /* stop all USB transfers */ 555288353Sadrian usbd_transfer_unsetup(sc->sc_xfer, URTWN_N_TRANSFER); 556288353Sadrian 557263153Skevlo /* Prevent further allocations from RX/TX data lists. */ 558263153Skevlo URTWN_LOCK(sc); 559263153Skevlo STAILQ_INIT(&sc->sc_tx_active); 560263153Skevlo STAILQ_INIT(&sc->sc_tx_inactive); 561263153Skevlo STAILQ_INIT(&sc->sc_tx_pending); 562263153Skevlo 563263153Skevlo STAILQ_INIT(&sc->sc_rx_active); 564263153Skevlo STAILQ_INIT(&sc->sc_rx_inactive); 565263153Skevlo URTWN_UNLOCK(sc); 566263153Skevlo 567263153Skevlo /* drain USB transfers */ 568263153Skevlo for (x = 0; x != URTWN_N_TRANSFER; x++) 569263153Skevlo usbd_transfer_drain(sc->sc_xfer[x]); 570263153Skevlo 571263153Skevlo /* Free data buffers. */ 572263153Skevlo URTWN_LOCK(sc); 573263153Skevlo urtwn_free_tx_list(sc); 574263153Skevlo urtwn_free_rx_list(sc); 575263153Skevlo URTWN_UNLOCK(sc); 576263153Skevlo 577251538Srpaulo ieee80211_ifdetach(ic); 578292167Savos URTWN_NT_LOCK_DESTROY(sc); 579251538Srpaulo mtx_destroy(&sc->sc_mtx); 580251538Srpaulo 581251538Srpaulo return (0); 582251538Srpaulo} 583251538Srpaulo 584251538Srpaulostatic void 585289066Skevlourtwn_drain_mbufq(struct urtwn_softc *sc) 586251538Srpaulo{ 587289066Skevlo struct mbuf *m; 588289066Skevlo struct ieee80211_node *ni; 589289066Skevlo URTWN_ASSERT_LOCKED(sc); 590289066Skevlo while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { 591289066Skevlo ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 592289066Skevlo m->m_pkthdr.rcvif = NULL; 593289066Skevlo ieee80211_free_node(ni); 594289066Skevlo m_freem(m); 595251538Srpaulo } 596251538Srpaulo} 597251538Srpaulo 598251538Srpaulostatic usb_error_t 599251538Srpaulourtwn_do_request(struct urtwn_softc *sc, struct usb_device_request *req, 600251538Srpaulo void *data) 601251538Srpaulo{ 602251538Srpaulo usb_error_t err; 603251538Srpaulo int ntries = 10; 604251538Srpaulo 605251538Srpaulo URTWN_ASSERT_LOCKED(sc); 606251538Srpaulo 607251538Srpaulo while (ntries--) { 608251538Srpaulo err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, 609251538Srpaulo req, data, 0, NULL, 250 /* ms */); 610251538Srpaulo if (err == 0) 611251538Srpaulo break; 612251538Srpaulo 613251538Srpaulo DPRINTFN(1, "Control request failed, %s (retrying)\n", 614251538Srpaulo usbd_errstr(err)); 615251538Srpaulo usb_pause_mtx(&sc->sc_mtx, hz / 100); 616251538Srpaulo } 617251538Srpaulo return (err); 618251538Srpaulo} 619251538Srpaulo 620251538Srpaulostatic struct ieee80211vap * 621251538Srpaulourtwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, 622251538Srpaulo enum ieee80211_opmode opmode, int flags, 623251538Srpaulo const uint8_t bssid[IEEE80211_ADDR_LEN], 624251538Srpaulo const uint8_t mac[IEEE80211_ADDR_LEN]) 625251538Srpaulo{ 626290631Savos struct urtwn_softc *sc = ic->ic_softc; 627251538Srpaulo struct urtwn_vap *uvp; 628251538Srpaulo struct ieee80211vap *vap; 629251538Srpaulo 630251538Srpaulo if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ 631251538Srpaulo return (NULL); 632251538Srpaulo 633287197Sglebius uvp = malloc(sizeof(struct urtwn_vap), M_80211_VAP, M_WAITOK | M_ZERO); 634251538Srpaulo vap = &uvp->vap; 635251538Srpaulo /* enable s/w bmiss handling for sta mode */ 636251538Srpaulo 637281069Srpaulo if (ieee80211_vap_setup(ic, vap, name, unit, opmode, 638287197Sglebius flags | IEEE80211_CLONE_NOBEACONS, bssid) != 0) { 639257743Shselasky /* out of memory */ 640257743Shselasky free(uvp, M_80211_VAP); 641257743Shselasky return (NULL); 642257743Shselasky } 643257743Shselasky 644290651Savos if (opmode == IEEE80211_M_HOSTAP || opmode == IEEE80211_M_IBSS) 645290631Savos urtwn_init_beacon(sc, uvp); 646290631Savos 647251538Srpaulo /* override state transition machine */ 648251538Srpaulo uvp->newstate = vap->iv_newstate; 649251538Srpaulo vap->iv_newstate = urtwn_newstate; 650290631Savos vap->iv_update_beacon = urtwn_update_beacon; 651290651Savos if (opmode == IEEE80211_M_IBSS) { 652290651Savos uvp->recv_mgmt = vap->iv_recv_mgmt; 653290651Savos vap->iv_recv_mgmt = urtwn_ibss_recv_mgmt; 654290651Savos TASK_INIT(&uvp->tsf_task_adhoc, 0, urtwn_tsf_task_adhoc, vap); 655290651Savos } 656251538Srpaulo 657292167Savos if (URTWN_CHIP_HAS_RATECTL(sc)) 658292167Savos ieee80211_ratectl_init(vap); 659251538Srpaulo /* complete setup */ 660251538Srpaulo ieee80211_vap_attach(vap, ieee80211_media_change, 661287197Sglebius ieee80211_media_status, mac); 662251538Srpaulo ic->ic_opmode = opmode; 663251538Srpaulo return (vap); 664251538Srpaulo} 665251538Srpaulo 666251538Srpaulostatic void 667251538Srpaulourtwn_vap_delete(struct ieee80211vap *vap) 668251538Srpaulo{ 669290651Savos struct ieee80211com *ic = vap->iv_ic; 670292167Savos struct urtwn_softc *sc = ic->ic_softc; 671251538Srpaulo struct urtwn_vap *uvp = URTWN_VAP(vap); 672251538Srpaulo 673290651Savos if (uvp->bcn_mbuf != NULL) 674290651Savos m_freem(uvp->bcn_mbuf); 675290651Savos if (vap->iv_opmode == IEEE80211_M_IBSS) 676290651Savos ieee80211_draintask(ic, &uvp->tsf_task_adhoc); 677292167Savos if (URTWN_CHIP_HAS_RATECTL(sc)) 678292167Savos ieee80211_ratectl_deinit(vap); 679251538Srpaulo ieee80211_vap_detach(vap); 680251538Srpaulo free(uvp, M_80211_VAP); 681251538Srpaulo} 682251538Srpaulo 683251538Srpaulostatic struct mbuf * 684251538Srpaulourtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen, int *rssi_p) 685251538Srpaulo{ 686287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 687251538Srpaulo struct ieee80211_frame *wh; 688251538Srpaulo struct mbuf *m; 689251538Srpaulo struct r92c_rx_stat *stat; 690251538Srpaulo uint32_t rxdw0, rxdw3; 691251538Srpaulo uint8_t rate; 692251538Srpaulo int8_t rssi = 0; 693251538Srpaulo int infosz; 694251538Srpaulo 695251538Srpaulo /* 696251538Srpaulo * don't pass packets to the ieee80211 framework if the driver isn't 697251538Srpaulo * RUNNING. 698251538Srpaulo */ 699287197Sglebius if (!(sc->sc_flags & URTWN_RUNNING)) 700251538Srpaulo return (NULL); 701251538Srpaulo 702251538Srpaulo stat = (struct r92c_rx_stat *)buf; 703251538Srpaulo rxdw0 = le32toh(stat->rxdw0); 704251538Srpaulo rxdw3 = le32toh(stat->rxdw3); 705251538Srpaulo 706251538Srpaulo if (rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR)) { 707251538Srpaulo /* 708251538Srpaulo * This should not happen since we setup our Rx filter 709251538Srpaulo * to not receive these frames. 710251538Srpaulo */ 711287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 712251538Srpaulo return (NULL); 713251538Srpaulo } 714290022Savos if (pktlen < sizeof(struct ieee80211_frame_ack) || 715290022Savos pktlen > MCLBYTES) { 716287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 717271303Skevlo return (NULL); 718271303Skevlo } 719251538Srpaulo 720251538Srpaulo rate = MS(rxdw3, R92C_RXDW3_RATE); 721251538Srpaulo infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; 722251538Srpaulo 723251538Srpaulo /* Get RSSI from PHY status descriptor if present. */ 724251538Srpaulo if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) { 725281069Srpaulo if (sc->chip & URTWN_CHIP_88E) 726264912Skevlo rssi = urtwn_r88e_get_rssi(sc, rate, &stat[1]); 727264912Skevlo else 728264912Skevlo rssi = urtwn_get_rssi(sc, rate, &stat[1]); 729251538Srpaulo /* Update our average RSSI. */ 730251538Srpaulo urtwn_update_avgrssi(sc, rate, rssi); 731251538Srpaulo } 732251538Srpaulo 733260463Skevlo m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 734251538Srpaulo if (m == NULL) { 735251538Srpaulo device_printf(sc->sc_dev, "could not create RX mbuf\n"); 736251538Srpaulo return (NULL); 737251538Srpaulo } 738251538Srpaulo 739251538Srpaulo /* Finalize mbuf. */ 740251538Srpaulo wh = (struct ieee80211_frame *)((uint8_t *)&stat[1] + infosz); 741251538Srpaulo memcpy(mtod(m, uint8_t *), wh, pktlen); 742251538Srpaulo m->m_pkthdr.len = m->m_len = pktlen; 743251538Srpaulo 744251538Srpaulo if (ieee80211_radiotap_active(ic)) { 745251538Srpaulo struct urtwn_rx_radiotap_header *tap = &sc->sc_rxtap; 746251538Srpaulo 747251538Srpaulo tap->wr_flags = 0; 748251538Srpaulo /* Map HW rate index to 802.11 rate. */ 749251538Srpaulo if (!(rxdw3 & R92C_RXDW3_HT)) { 750289758Savos tap->wr_rate = ridx2rate[rate]; 751251538Srpaulo } else if (rate >= 12) { /* MCS0~15. */ 752251538Srpaulo /* Bit 7 set means HT MCS instead of rate. */ 753251538Srpaulo tap->wr_rate = 0x80 | (rate - 12); 754251538Srpaulo } 755251538Srpaulo tap->wr_dbm_antsignal = rssi; 756289816Savos tap->wr_dbm_antnoise = URTWN_NOISE_FLOOR; 757251538Srpaulo } 758251538Srpaulo 759251538Srpaulo *rssi_p = rssi; 760251538Srpaulo 761251538Srpaulo return (m); 762251538Srpaulo} 763251538Srpaulo 764251538Srpaulostatic struct mbuf * 765292167Savosurtwn_report_intr(struct usb_xfer *xfer, struct urtwn_data *data, int *rssi, 766251538Srpaulo int8_t *nf) 767251538Srpaulo{ 768251538Srpaulo struct urtwn_softc *sc = data->sc; 769287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 770251538Srpaulo struct r92c_rx_stat *stat; 771251538Srpaulo uint8_t *buf; 772292167Savos int len; 773251538Srpaulo 774251538Srpaulo usbd_xfer_status(xfer, &len, NULL, NULL, NULL); 775251538Srpaulo 776251538Srpaulo if (len < sizeof(*stat)) { 777287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 778251538Srpaulo return (NULL); 779251538Srpaulo } 780251538Srpaulo 781251538Srpaulo buf = data->buf; 782292167Savos stat = (struct r92c_rx_stat *)buf; 783292167Savos 784292167Savos if (sc->chip & URTWN_CHIP_88E) { 785292167Savos int report_sel = MS(le32toh(stat->rxdw3), R88E_RXDW3_RPT); 786292167Savos 787292167Savos switch (report_sel) { 788292167Savos case R88E_RXDW3_RPT_RX: 789292167Savos return (urtwn_rxeof(sc, buf, len, rssi, nf)); 790292167Savos case R88E_RXDW3_RPT_TX1: 791292167Savos urtwn_r88e_ratectl_tx_complete(sc, &stat[1]); 792292167Savos break; 793292167Savos default: 794292167Savos DPRINTFN(7, "case %d was not handled\n", report_sel); 795292167Savos break; 796292167Savos } 797292167Savos } else 798292167Savos return (urtwn_rxeof(sc, buf, len, rssi, nf)); 799292167Savos 800292167Savos return (NULL); 801292167Savos} 802292167Savos 803292167Savosstatic struct mbuf * 804292167Savosurtwn_rxeof(struct urtwn_softc *sc, uint8_t *buf, int len, int *rssi, 805292167Savos int8_t *nf) 806292167Savos{ 807292167Savos struct r92c_rx_stat *stat; 808292167Savos struct mbuf *m, *m0 = NULL, *prevm = NULL; 809292167Savos uint32_t rxdw0; 810292167Savos int totlen, pktlen, infosz, npkts; 811292167Savos 812251538Srpaulo /* Get the number of encapsulated frames. */ 813251538Srpaulo stat = (struct r92c_rx_stat *)buf; 814251538Srpaulo npkts = MS(le32toh(stat->rxdw2), R92C_RXDW2_PKTCNT); 815251538Srpaulo DPRINTFN(6, "Rx %d frames in one chunk\n", npkts); 816251538Srpaulo 817251538Srpaulo /* Process all of them. */ 818251538Srpaulo while (npkts-- > 0) { 819251538Srpaulo if (len < sizeof(*stat)) 820251538Srpaulo break; 821251538Srpaulo stat = (struct r92c_rx_stat *)buf; 822251538Srpaulo rxdw0 = le32toh(stat->rxdw0); 823251538Srpaulo 824251538Srpaulo pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); 825251538Srpaulo if (pktlen == 0) 826251538Srpaulo break; 827251538Srpaulo 828251538Srpaulo infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; 829251538Srpaulo 830251538Srpaulo /* Make sure everything fits in xfer. */ 831251538Srpaulo totlen = sizeof(*stat) + infosz + pktlen; 832251538Srpaulo if (totlen > len) 833251538Srpaulo break; 834251538Srpaulo 835251538Srpaulo m = urtwn_rx_frame(sc, buf, pktlen, rssi); 836251538Srpaulo if (m0 == NULL) 837251538Srpaulo m0 = m; 838251538Srpaulo if (prevm == NULL) 839251538Srpaulo prevm = m; 840251538Srpaulo else { 841251538Srpaulo prevm->m_next = m; 842251538Srpaulo prevm = m; 843251538Srpaulo } 844251538Srpaulo 845251538Srpaulo /* Next chunk is 128-byte aligned. */ 846251538Srpaulo totlen = (totlen + 127) & ~127; 847251538Srpaulo buf += totlen; 848251538Srpaulo len -= totlen; 849251538Srpaulo } 850251538Srpaulo 851251538Srpaulo return (m0); 852251538Srpaulo} 853251538Srpaulo 854251538Srpaulostatic void 855292167Savosurtwn_r88e_ratectl_tx_complete(struct urtwn_softc *sc, void *arg) 856292167Savos{ 857292167Savos struct r88e_tx_rpt_ccx *rpt = arg; 858292167Savos struct ieee80211vap *vap; 859292167Savos struct ieee80211_node *ni; 860292167Savos uint8_t macid; 861292167Savos int ntries; 862292167Savos 863292167Savos macid = MS(rpt->rptb1, R88E_RPTB1_MACID); 864292167Savos ntries = MS(rpt->rptb2, R88E_RPTB2_RETRY_CNT); 865292167Savos 866292167Savos URTWN_NT_LOCK(sc); 867292167Savos ni = sc->node_list[macid]; 868292167Savos if (ni != NULL) { 869292167Savos vap = ni->ni_vap; 870292167Savos 871292167Savos if (rpt->rptb1 & R88E_RPTB1_PKT_OK) { 872292167Savos ieee80211_ratectl_tx_complete(vap, ni, 873292167Savos IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL); 874292167Savos } else { 875292167Savos ieee80211_ratectl_tx_complete(vap, ni, 876292167Savos IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL); 877292167Savos } 878292167Savos } else 879292167Savos DPRINTFN(8, "macid %d, ni is NULL\n", macid); 880292167Savos URTWN_NT_UNLOCK(sc); 881292167Savos} 882292167Savos 883292167Savosstatic void 884251538Srpaulourtwn_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) 885251538Srpaulo{ 886251538Srpaulo struct urtwn_softc *sc = usbd_xfer_softc(xfer); 887287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 888290022Savos struct ieee80211_frame_min *wh; 889251538Srpaulo struct ieee80211_node *ni; 890251538Srpaulo struct mbuf *m = NULL, *next; 891251538Srpaulo struct urtwn_data *data; 892251538Srpaulo int8_t nf; 893251538Srpaulo int rssi = 1; 894251538Srpaulo 895251538Srpaulo URTWN_ASSERT_LOCKED(sc); 896251538Srpaulo 897251538Srpaulo switch (USB_GET_STATE(xfer)) { 898251538Srpaulo case USB_ST_TRANSFERRED: 899251538Srpaulo data = STAILQ_FIRST(&sc->sc_rx_active); 900251538Srpaulo if (data == NULL) 901251538Srpaulo goto tr_setup; 902251538Srpaulo STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next); 903292167Savos m = urtwn_report_intr(xfer, data, &rssi, &nf); 904251538Srpaulo STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); 905251538Srpaulo /* FALLTHROUGH */ 906251538Srpaulo case USB_ST_SETUP: 907251538Srpaulotr_setup: 908251538Srpaulo data = STAILQ_FIRST(&sc->sc_rx_inactive); 909251538Srpaulo if (data == NULL) { 910251538Srpaulo KASSERT(m == NULL, ("mbuf isn't NULL")); 911251538Srpaulo return; 912251538Srpaulo } 913251538Srpaulo STAILQ_REMOVE_HEAD(&sc->sc_rx_inactive, next); 914251538Srpaulo STAILQ_INSERT_TAIL(&sc->sc_rx_active, data, next); 915251538Srpaulo usbd_xfer_set_frame_data(xfer, 0, data->buf, 916251538Srpaulo usbd_xfer_max_len(xfer)); 917251538Srpaulo usbd_transfer_submit(xfer); 918251538Srpaulo 919251538Srpaulo /* 920251538Srpaulo * To avoid LOR we should unlock our private mutex here to call 921251538Srpaulo * ieee80211_input() because here is at the end of a USB 922251538Srpaulo * callback and safe to unlock. 923251538Srpaulo */ 924251538Srpaulo URTWN_UNLOCK(sc); 925251538Srpaulo while (m != NULL) { 926251538Srpaulo next = m->m_next; 927251538Srpaulo m->m_next = NULL; 928290022Savos wh = mtod(m, struct ieee80211_frame_min *); 929290022Savos if (m->m_len >= sizeof(*wh)) 930290022Savos ni = ieee80211_find_rxnode(ic, wh); 931290022Savos else 932290022Savos ni = NULL; 933251538Srpaulo nf = URTWN_NOISE_FLOOR; 934251538Srpaulo if (ni != NULL) { 935289799Savos (void)ieee80211_input(ni, m, rssi - nf, nf); 936251538Srpaulo ieee80211_free_node(ni); 937289799Savos } else { 938289799Savos (void)ieee80211_input_all(ic, m, rssi - nf, 939289799Savos nf); 940289799Savos } 941251538Srpaulo m = next; 942251538Srpaulo } 943251538Srpaulo URTWN_LOCK(sc); 944251538Srpaulo break; 945251538Srpaulo default: 946251538Srpaulo /* needs it to the inactive queue due to a error. */ 947251538Srpaulo data = STAILQ_FIRST(&sc->sc_rx_active); 948251538Srpaulo if (data != NULL) { 949251538Srpaulo STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next); 950251538Srpaulo STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); 951251538Srpaulo } 952251538Srpaulo if (error != USB_ERR_CANCELLED) { 953251538Srpaulo usbd_xfer_set_stall(xfer); 954287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 955251538Srpaulo goto tr_setup; 956251538Srpaulo } 957251538Srpaulo break; 958251538Srpaulo } 959251538Srpaulo} 960251538Srpaulo 961251538Srpaulostatic void 962289891Savosurtwn_txeof(struct urtwn_softc *sc, struct urtwn_data *data, int status) 963251538Srpaulo{ 964251538Srpaulo 965251538Srpaulo URTWN_ASSERT_LOCKED(sc); 966289891Savos 967290631Savos if (data->ni != NULL) /* not a beacon frame */ 968290631Savos ieee80211_tx_complete(data->ni, data->m, status); 969289891Savos 970287197Sglebius data->ni = NULL; 971287197Sglebius data->m = NULL; 972289891Savos 973251538Srpaulo sc->sc_txtimer = 0; 974289891Savos 975289891Savos STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next); 976251538Srpaulo} 977251538Srpaulo 978289066Skevlostatic int 979289066Skevlourtwn_alloc_list(struct urtwn_softc *sc, struct urtwn_data data[], 980289066Skevlo int ndata, int maxsz) 981289066Skevlo{ 982289066Skevlo int i, error; 983289066Skevlo 984289066Skevlo for (i = 0; i < ndata; i++) { 985289066Skevlo struct urtwn_data *dp = &data[i]; 986289066Skevlo dp->sc = sc; 987289066Skevlo dp->m = NULL; 988289066Skevlo dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT); 989289066Skevlo if (dp->buf == NULL) { 990289066Skevlo device_printf(sc->sc_dev, 991289066Skevlo "could not allocate buffer\n"); 992289066Skevlo error = ENOMEM; 993289066Skevlo goto fail; 994289066Skevlo } 995289066Skevlo dp->ni = NULL; 996289066Skevlo } 997289066Skevlo 998289066Skevlo return (0); 999289066Skevlofail: 1000289066Skevlo urtwn_free_list(sc, data, ndata); 1001289066Skevlo return (error); 1002289066Skevlo} 1003289066Skevlo 1004289066Skevlostatic int 1005289066Skevlourtwn_alloc_rx_list(struct urtwn_softc *sc) 1006289066Skevlo{ 1007289066Skevlo int error, i; 1008289066Skevlo 1009289066Skevlo error = urtwn_alloc_list(sc, sc->sc_rx, URTWN_RX_LIST_COUNT, 1010289066Skevlo URTWN_RXBUFSZ); 1011289066Skevlo if (error != 0) 1012289066Skevlo return (error); 1013289066Skevlo 1014289066Skevlo STAILQ_INIT(&sc->sc_rx_active); 1015289066Skevlo STAILQ_INIT(&sc->sc_rx_inactive); 1016289066Skevlo 1017289066Skevlo for (i = 0; i < URTWN_RX_LIST_COUNT; i++) 1018289066Skevlo STAILQ_INSERT_HEAD(&sc->sc_rx_inactive, &sc->sc_rx[i], next); 1019289066Skevlo 1020289066Skevlo return (0); 1021289066Skevlo} 1022289066Skevlo 1023289066Skevlostatic int 1024289066Skevlourtwn_alloc_tx_list(struct urtwn_softc *sc) 1025289066Skevlo{ 1026289066Skevlo int error, i; 1027289066Skevlo 1028289066Skevlo error = urtwn_alloc_list(sc, sc->sc_tx, URTWN_TX_LIST_COUNT, 1029289066Skevlo URTWN_TXBUFSZ); 1030289066Skevlo if (error != 0) 1031289066Skevlo return (error); 1032289066Skevlo 1033289066Skevlo STAILQ_INIT(&sc->sc_tx_active); 1034289066Skevlo STAILQ_INIT(&sc->sc_tx_inactive); 1035289066Skevlo STAILQ_INIT(&sc->sc_tx_pending); 1036289066Skevlo 1037289066Skevlo for (i = 0; i < URTWN_TX_LIST_COUNT; i++) 1038289066Skevlo STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, &sc->sc_tx[i], next); 1039289066Skevlo 1040289066Skevlo return (0); 1041289066Skevlo} 1042289066Skevlo 1043251538Srpaulostatic void 1044289066Skevlourtwn_free_list(struct urtwn_softc *sc, struct urtwn_data data[], int ndata) 1045289066Skevlo{ 1046289066Skevlo int i; 1047289066Skevlo 1048289066Skevlo for (i = 0; i < ndata; i++) { 1049289066Skevlo struct urtwn_data *dp = &data[i]; 1050289066Skevlo 1051289066Skevlo if (dp->buf != NULL) { 1052289066Skevlo free(dp->buf, M_USBDEV); 1053289066Skevlo dp->buf = NULL; 1054289066Skevlo } 1055289066Skevlo if (dp->ni != NULL) { 1056289066Skevlo ieee80211_free_node(dp->ni); 1057289066Skevlo dp->ni = NULL; 1058289066Skevlo } 1059289066Skevlo } 1060289066Skevlo} 1061289066Skevlo 1062289066Skevlostatic void 1063289066Skevlourtwn_free_rx_list(struct urtwn_softc *sc) 1064289066Skevlo{ 1065289066Skevlo urtwn_free_list(sc, sc->sc_rx, URTWN_RX_LIST_COUNT); 1066289066Skevlo} 1067289066Skevlo 1068289066Skevlostatic void 1069289066Skevlourtwn_free_tx_list(struct urtwn_softc *sc) 1070289066Skevlo{ 1071289066Skevlo urtwn_free_list(sc, sc->sc_tx, URTWN_TX_LIST_COUNT); 1072289066Skevlo} 1073289066Skevlo 1074289066Skevlostatic void 1075251538Srpaulourtwn_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) 1076251538Srpaulo{ 1077251538Srpaulo struct urtwn_softc *sc = usbd_xfer_softc(xfer); 1078251538Srpaulo struct urtwn_data *data; 1079251538Srpaulo 1080251538Srpaulo URTWN_ASSERT_LOCKED(sc); 1081251538Srpaulo 1082251538Srpaulo switch (USB_GET_STATE(xfer)){ 1083251538Srpaulo case USB_ST_TRANSFERRED: 1084251538Srpaulo data = STAILQ_FIRST(&sc->sc_tx_active); 1085251538Srpaulo if (data == NULL) 1086251538Srpaulo goto tr_setup; 1087251538Srpaulo STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next); 1088289891Savos urtwn_txeof(sc, data, 0); 1089251538Srpaulo /* FALLTHROUGH */ 1090251538Srpaulo case USB_ST_SETUP: 1091251538Srpaulotr_setup: 1092251538Srpaulo data = STAILQ_FIRST(&sc->sc_tx_pending); 1093251538Srpaulo if (data == NULL) { 1094251538Srpaulo DPRINTF("%s: empty pending queue\n", __func__); 1095288353Sadrian goto finish; 1096251538Srpaulo } 1097251538Srpaulo STAILQ_REMOVE_HEAD(&sc->sc_tx_pending, next); 1098251538Srpaulo STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next); 1099251538Srpaulo usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); 1100251538Srpaulo usbd_transfer_submit(xfer); 1101251538Srpaulo break; 1102251538Srpaulo default: 1103251538Srpaulo data = STAILQ_FIRST(&sc->sc_tx_active); 1104251538Srpaulo if (data == NULL) 1105251538Srpaulo goto tr_setup; 1106289891Savos STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next); 1107289891Savos urtwn_txeof(sc, data, 1); 1108251538Srpaulo if (error != USB_ERR_CANCELLED) { 1109251538Srpaulo usbd_xfer_set_stall(xfer); 1110251538Srpaulo goto tr_setup; 1111251538Srpaulo } 1112251538Srpaulo break; 1113251538Srpaulo } 1114288353Sadrianfinish: 1115288353Sadrian /* Kick-start more transmit */ 1116288353Sadrian urtwn_start(sc); 1117251538Srpaulo} 1118251538Srpaulo 1119251538Srpaulostatic struct urtwn_data * 1120251538Srpaulo_urtwn_getbuf(struct urtwn_softc *sc) 1121251538Srpaulo{ 1122251538Srpaulo struct urtwn_data *bf; 1123251538Srpaulo 1124251538Srpaulo bf = STAILQ_FIRST(&sc->sc_tx_inactive); 1125251538Srpaulo if (bf != NULL) 1126251538Srpaulo STAILQ_REMOVE_HEAD(&sc->sc_tx_inactive, next); 1127251538Srpaulo else 1128251538Srpaulo DPRINTF("%s: %s\n", __func__, "out of xmit buffers"); 1129251538Srpaulo return (bf); 1130251538Srpaulo} 1131251538Srpaulo 1132251538Srpaulostatic struct urtwn_data * 1133251538Srpaulourtwn_getbuf(struct urtwn_softc *sc) 1134251538Srpaulo{ 1135251538Srpaulo struct urtwn_data *bf; 1136251538Srpaulo 1137251538Srpaulo URTWN_ASSERT_LOCKED(sc); 1138251538Srpaulo 1139251538Srpaulo bf = _urtwn_getbuf(sc); 1140287197Sglebius if (bf == NULL) 1141251538Srpaulo DPRINTF("%s: stop queue\n", __func__); 1142251538Srpaulo return (bf); 1143251538Srpaulo} 1144251538Srpaulo 1145291698Savosstatic usb_error_t 1146251538Srpaulourtwn_write_region_1(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, 1147251538Srpaulo int len) 1148251538Srpaulo{ 1149251538Srpaulo usb_device_request_t req; 1150251538Srpaulo 1151251538Srpaulo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1152251538Srpaulo req.bRequest = R92C_REQ_REGS; 1153251538Srpaulo USETW(req.wValue, addr); 1154251538Srpaulo USETW(req.wIndex, 0); 1155251538Srpaulo USETW(req.wLength, len); 1156251538Srpaulo return (urtwn_do_request(sc, &req, buf)); 1157251538Srpaulo} 1158251538Srpaulo 1159291698Savosstatic usb_error_t 1160251538Srpaulourtwn_write_1(struct urtwn_softc *sc, uint16_t addr, uint8_t val) 1161251538Srpaulo{ 1162291698Savos return (urtwn_write_region_1(sc, addr, &val, sizeof(val))); 1163251538Srpaulo} 1164251538Srpaulo 1165291698Savosstatic usb_error_t 1166251538Srpaulourtwn_write_2(struct urtwn_softc *sc, uint16_t addr, uint16_t val) 1167251538Srpaulo{ 1168251538Srpaulo val = htole16(val); 1169291698Savos return (urtwn_write_region_1(sc, addr, (uint8_t *)&val, sizeof(val))); 1170251538Srpaulo} 1171251538Srpaulo 1172291698Savosstatic usb_error_t 1173251538Srpaulourtwn_write_4(struct urtwn_softc *sc, uint16_t addr, uint32_t val) 1174251538Srpaulo{ 1175251538Srpaulo val = htole32(val); 1176291698Savos return (urtwn_write_region_1(sc, addr, (uint8_t *)&val, sizeof(val))); 1177251538Srpaulo} 1178251538Srpaulo 1179291698Savosstatic usb_error_t 1180251538Srpaulourtwn_read_region_1(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, 1181251538Srpaulo int len) 1182251538Srpaulo{ 1183251538Srpaulo usb_device_request_t req; 1184251538Srpaulo 1185251538Srpaulo req.bmRequestType = UT_READ_VENDOR_DEVICE; 1186251538Srpaulo req.bRequest = R92C_REQ_REGS; 1187251538Srpaulo USETW(req.wValue, addr); 1188251538Srpaulo USETW(req.wIndex, 0); 1189251538Srpaulo USETW(req.wLength, len); 1190251538Srpaulo return (urtwn_do_request(sc, &req, buf)); 1191251538Srpaulo} 1192251538Srpaulo 1193251538Srpaulostatic uint8_t 1194251538Srpaulourtwn_read_1(struct urtwn_softc *sc, uint16_t addr) 1195251538Srpaulo{ 1196251538Srpaulo uint8_t val; 1197251538Srpaulo 1198251538Srpaulo if (urtwn_read_region_1(sc, addr, &val, 1) != 0) 1199251538Srpaulo return (0xff); 1200251538Srpaulo return (val); 1201251538Srpaulo} 1202251538Srpaulo 1203251538Srpaulostatic uint16_t 1204251538Srpaulourtwn_read_2(struct urtwn_softc *sc, uint16_t addr) 1205251538Srpaulo{ 1206251538Srpaulo uint16_t val; 1207251538Srpaulo 1208251538Srpaulo if (urtwn_read_region_1(sc, addr, (uint8_t *)&val, 2) != 0) 1209251538Srpaulo return (0xffff); 1210251538Srpaulo return (le16toh(val)); 1211251538Srpaulo} 1212251538Srpaulo 1213251538Srpaulostatic uint32_t 1214251538Srpaulourtwn_read_4(struct urtwn_softc *sc, uint16_t addr) 1215251538Srpaulo{ 1216251538Srpaulo uint32_t val; 1217251538Srpaulo 1218251538Srpaulo if (urtwn_read_region_1(sc, addr, (uint8_t *)&val, 4) != 0) 1219251538Srpaulo return (0xffffffff); 1220251538Srpaulo return (le32toh(val)); 1221251538Srpaulo} 1222251538Srpaulo 1223251538Srpaulostatic int 1224251538Srpaulourtwn_fw_cmd(struct urtwn_softc *sc, uint8_t id, const void *buf, int len) 1225251538Srpaulo{ 1226251538Srpaulo struct r92c_fw_cmd cmd; 1227291698Savos usb_error_t error; 1228251538Srpaulo int ntries; 1229251538Srpaulo 1230251538Srpaulo /* Wait for current FW box to be empty. */ 1231251538Srpaulo for (ntries = 0; ntries < 100; ntries++) { 1232251538Srpaulo if (!(urtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur))) 1233251538Srpaulo break; 1234266472Shselasky urtwn_ms_delay(sc); 1235251538Srpaulo } 1236251538Srpaulo if (ntries == 100) { 1237251538Srpaulo device_printf(sc->sc_dev, 1238251538Srpaulo "could not send firmware command\n"); 1239251538Srpaulo return (ETIMEDOUT); 1240251538Srpaulo } 1241251538Srpaulo memset(&cmd, 0, sizeof(cmd)); 1242251538Srpaulo cmd.id = id; 1243251538Srpaulo if (len > 3) 1244251538Srpaulo cmd.id |= R92C_CMD_FLAG_EXT; 1245251538Srpaulo KASSERT(len <= sizeof(cmd.msg), ("urtwn_fw_cmd\n")); 1246251538Srpaulo memcpy(cmd.msg, buf, len); 1247251538Srpaulo 1248251538Srpaulo /* Write the first word last since that will trigger the FW. */ 1249291698Savos error = urtwn_write_region_1(sc, R92C_HMEBOX_EXT(sc->fwcur), 1250251538Srpaulo (uint8_t *)&cmd + 4, 2); 1251291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 1252291698Savos return (EIO); 1253291698Savos error = urtwn_write_region_1(sc, R92C_HMEBOX(sc->fwcur), 1254251538Srpaulo (uint8_t *)&cmd + 0, 4); 1255291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 1256291698Savos return (EIO); 1257251538Srpaulo 1258251538Srpaulo sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX; 1259251538Srpaulo return (0); 1260251538Srpaulo} 1261251538Srpaulo 1262264912Skevlostatic __inline void 1263251538Srpaulourtwn_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, uint32_t val) 1264251538Srpaulo{ 1265264912Skevlo 1266264912Skevlo sc->sc_rf_write(sc, chain, addr, val); 1267264912Skevlo} 1268264912Skevlo 1269264912Skevlostatic void 1270264912Skevlourtwn_r92c_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, 1271264912Skevlo uint32_t val) 1272264912Skevlo{ 1273251538Srpaulo urtwn_bb_write(sc, R92C_LSSI_PARAM(chain), 1274251538Srpaulo SM(R92C_LSSI_PARAM_ADDR, addr) | 1275251538Srpaulo SM(R92C_LSSI_PARAM_DATA, val)); 1276251538Srpaulo} 1277251538Srpaulo 1278264912Skevlostatic void 1279264912Skevlourtwn_r88e_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, 1280264912Skevlouint32_t val) 1281264912Skevlo{ 1282264912Skevlo urtwn_bb_write(sc, R92C_LSSI_PARAM(chain), 1283264912Skevlo SM(R88E_LSSI_PARAM_ADDR, addr) | 1284264912Skevlo SM(R92C_LSSI_PARAM_DATA, val)); 1285264912Skevlo} 1286264912Skevlo 1287251538Srpaulostatic uint32_t 1288251538Srpaulourtwn_rf_read(struct urtwn_softc *sc, int chain, uint8_t addr) 1289251538Srpaulo{ 1290251538Srpaulo uint32_t reg[R92C_MAX_CHAINS], val; 1291251538Srpaulo 1292251538Srpaulo reg[0] = urtwn_bb_read(sc, R92C_HSSI_PARAM2(0)); 1293251538Srpaulo if (chain != 0) 1294251538Srpaulo reg[chain] = urtwn_bb_read(sc, R92C_HSSI_PARAM2(chain)); 1295251538Srpaulo 1296251538Srpaulo urtwn_bb_write(sc, R92C_HSSI_PARAM2(0), 1297251538Srpaulo reg[0] & ~R92C_HSSI_PARAM2_READ_EDGE); 1298266472Shselasky urtwn_ms_delay(sc); 1299251538Srpaulo 1300251538Srpaulo urtwn_bb_write(sc, R92C_HSSI_PARAM2(chain), 1301251538Srpaulo RW(reg[chain], R92C_HSSI_PARAM2_READ_ADDR, addr) | 1302251538Srpaulo R92C_HSSI_PARAM2_READ_EDGE); 1303266472Shselasky urtwn_ms_delay(sc); 1304251538Srpaulo 1305251538Srpaulo urtwn_bb_write(sc, R92C_HSSI_PARAM2(0), 1306251538Srpaulo reg[0] | R92C_HSSI_PARAM2_READ_EDGE); 1307266472Shselasky urtwn_ms_delay(sc); 1308251538Srpaulo 1309251538Srpaulo if (urtwn_bb_read(sc, R92C_HSSI_PARAM1(chain)) & R92C_HSSI_PARAM1_PI) 1310251538Srpaulo val = urtwn_bb_read(sc, R92C_HSPI_READBACK(chain)); 1311251538Srpaulo else 1312251538Srpaulo val = urtwn_bb_read(sc, R92C_LSSI_READBACK(chain)); 1313251538Srpaulo return (MS(val, R92C_LSSI_READBACK_DATA)); 1314251538Srpaulo} 1315251538Srpaulo 1316251538Srpaulostatic int 1317251538Srpaulourtwn_llt_write(struct urtwn_softc *sc, uint32_t addr, uint32_t data) 1318251538Srpaulo{ 1319291698Savos usb_error_t error; 1320251538Srpaulo int ntries; 1321251538Srpaulo 1322291698Savos error = urtwn_write_4(sc, R92C_LLT_INIT, 1323251538Srpaulo SM(R92C_LLT_INIT_OP, R92C_LLT_INIT_OP_WRITE) | 1324251538Srpaulo SM(R92C_LLT_INIT_ADDR, addr) | 1325251538Srpaulo SM(R92C_LLT_INIT_DATA, data)); 1326291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 1327291698Savos return (EIO); 1328251538Srpaulo /* Wait for write operation to complete. */ 1329251538Srpaulo for (ntries = 0; ntries < 20; ntries++) { 1330251538Srpaulo if (MS(urtwn_read_4(sc, R92C_LLT_INIT), R92C_LLT_INIT_OP) == 1331251538Srpaulo R92C_LLT_INIT_OP_NO_ACTIVE) 1332251538Srpaulo return (0); 1333266472Shselasky urtwn_ms_delay(sc); 1334251538Srpaulo } 1335251538Srpaulo return (ETIMEDOUT); 1336251538Srpaulo} 1337251538Srpaulo 1338291264Savosstatic int 1339291264Savosurtwn_efuse_read_next(struct urtwn_softc *sc, uint8_t *val) 1340251538Srpaulo{ 1341251538Srpaulo uint32_t reg; 1342291698Savos usb_error_t error; 1343251538Srpaulo int ntries; 1344251538Srpaulo 1345291264Savos if (sc->last_rom_addr >= URTWN_EFUSE_MAX_LEN) 1346291264Savos return (EFAULT); 1347291264Savos 1348251538Srpaulo reg = urtwn_read_4(sc, R92C_EFUSE_CTRL); 1349291264Savos reg = RW(reg, R92C_EFUSE_CTRL_ADDR, sc->last_rom_addr); 1350251538Srpaulo reg &= ~R92C_EFUSE_CTRL_VALID; 1351291264Savos 1352291698Savos error = urtwn_write_4(sc, R92C_EFUSE_CTRL, reg); 1353291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 1354291698Savos return (EIO); 1355251538Srpaulo /* Wait for read operation to complete. */ 1356251538Srpaulo for (ntries = 0; ntries < 100; ntries++) { 1357251538Srpaulo reg = urtwn_read_4(sc, R92C_EFUSE_CTRL); 1358251538Srpaulo if (reg & R92C_EFUSE_CTRL_VALID) 1359291264Savos break; 1360266472Shselasky urtwn_ms_delay(sc); 1361251538Srpaulo } 1362291264Savos if (ntries == 100) { 1363291264Savos device_printf(sc->sc_dev, 1364291264Savos "could not read efuse byte at address 0x%x\n", 1365291264Savos sc->last_rom_addr); 1366291264Savos return (ETIMEDOUT); 1367291264Savos } 1368291264Savos 1369291264Savos *val = MS(reg, R92C_EFUSE_CTRL_DATA); 1370291264Savos sc->last_rom_addr++; 1371291264Savos 1372291264Savos return (0); 1373251538Srpaulo} 1374251538Srpaulo 1375291264Savosstatic int 1376291264Savosurtwn_efuse_read_data(struct urtwn_softc *sc, uint8_t *rom, uint8_t off, 1377291264Savos uint8_t msk) 1378291264Savos{ 1379291264Savos uint8_t reg; 1380291264Savos int i, error; 1381291264Savos 1382291264Savos for (i = 0; i < 4; i++) { 1383291264Savos if (msk & (1 << i)) 1384291264Savos continue; 1385291264Savos error = urtwn_efuse_read_next(sc, ®); 1386291264Savos if (error != 0) 1387291264Savos return (error); 1388291264Savos DPRINTF("rom[0x%03X] == 0x%02X\n", off * 8 + i * 2, reg); 1389291264Savos rom[off * 8 + i * 2 + 0] = reg; 1390291264Savos 1391291264Savos error = urtwn_efuse_read_next(sc, ®); 1392291264Savos if (error != 0) 1393291264Savos return (error); 1394291264Savos DPRINTF("rom[0x%03X] == 0x%02X\n", off * 8 + i * 2 + 1, reg); 1395291264Savos rom[off * 8 + i * 2 + 1] = reg; 1396291264Savos } 1397291264Savos 1398291264Savos return (0); 1399291264Savos} 1400291264Savos 1401291264Savos#ifdef URTWN_DEBUG 1402251538Srpaulostatic void 1403291264Savosurtwn_dump_rom_contents(struct urtwn_softc *sc, uint8_t *rom, uint16_t size) 1404251538Srpaulo{ 1405251538Srpaulo int i; 1406251538Srpaulo 1407291264Savos /* Dump ROM contents. */ 1408291264Savos device_printf(sc->sc_dev, "%s:", __func__); 1409291264Savos for (i = 0; i < size; i++) { 1410291264Savos if (i % 32 == 0) 1411291264Savos printf("\n%03X: ", i); 1412291264Savos else if (i % 4 == 0) 1413291264Savos printf(" "); 1414291264Savos 1415291264Savos printf("%02X", rom[i]); 1416291264Savos } 1417291264Savos printf("\n"); 1418291264Savos} 1419291264Savos#endif 1420291264Savos 1421291264Savosstatic int 1422291264Savosurtwn_efuse_read(struct urtwn_softc *sc, uint8_t *rom, uint16_t size) 1423291264Savos{ 1424291264Savos#define URTWN_CHK(res) do { \ 1425291264Savos if ((error = res) != 0) \ 1426291264Savos goto end; \ 1427291264Savos} while(0) 1428291264Savos uint8_t msk, off, reg; 1429291264Savos int error; 1430291264Savos 1431291698Savos URTWN_CHK(urtwn_efuse_switch_power(sc)); 1432264912Skevlo 1433291264Savos /* Read full ROM image. */ 1434291264Savos sc->last_rom_addr = 0; 1435291264Savos memset(rom, 0xff, size); 1436291264Savos 1437291264Savos URTWN_CHK(urtwn_efuse_read_next(sc, ®)); 1438291264Savos while (reg != 0xff) { 1439291264Savos /* check for extended header */ 1440291264Savos if ((sc->chip & URTWN_CHIP_88E) && (reg & 0x1f) == 0x0f) { 1441291264Savos off = reg >> 5; 1442291264Savos URTWN_CHK(urtwn_efuse_read_next(sc, ®)); 1443291264Savos 1444291264Savos if ((reg & 0x0f) != 0x0f) 1445291264Savos off = ((reg & 0xf0) >> 1) | off; 1446291264Savos else 1447291264Savos continue; 1448291264Savos } else 1449291264Savos off = reg >> 4; 1450251538Srpaulo msk = reg & 0xf; 1451291264Savos 1452291264Savos URTWN_CHK(urtwn_efuse_read_data(sc, rom, off, msk)); 1453291264Savos URTWN_CHK(urtwn_efuse_read_next(sc, ®)); 1454251538Srpaulo } 1455291264Savos 1456291264Savosend: 1457291264Savos 1458251538Srpaulo#ifdef URTWN_DEBUG 1459291264Savos if (urtwn_debug >= 2) 1460291264Savos urtwn_dump_rom_contents(sc, rom, size); 1461251538Srpaulo#endif 1462291264Savos 1463282623Skevlo urtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_OFF); 1464291264Savos 1465291264Savos if (error != 0) { 1466291264Savos device_printf(sc->sc_dev, "%s: error while reading ROM\n", 1467291264Savos __func__); 1468291264Savos } 1469291264Savos 1470291264Savos return (error); 1471291264Savos#undef URTWN_CHK 1472282623Skevlo} 1473281592Skevlo 1474291698Savosstatic int 1475264912Skevlourtwn_efuse_switch_power(struct urtwn_softc *sc) 1476264912Skevlo{ 1477291698Savos usb_error_t error; 1478264912Skevlo uint32_t reg; 1479251538Srpaulo 1480291698Savos error = urtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_ON); 1481291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 1482291698Savos return (EIO); 1483281918Skevlo 1484264912Skevlo reg = urtwn_read_2(sc, R92C_SYS_ISO_CTRL); 1485264912Skevlo if (!(reg & R92C_SYS_ISO_CTRL_PWC_EV12V)) { 1486291698Savos error = urtwn_write_2(sc, R92C_SYS_ISO_CTRL, 1487264912Skevlo reg | R92C_SYS_ISO_CTRL_PWC_EV12V); 1488291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 1489291698Savos return (EIO); 1490264912Skevlo } 1491264912Skevlo reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN); 1492264912Skevlo if (!(reg & R92C_SYS_FUNC_EN_ELDR)) { 1493291698Savos error = urtwn_write_2(sc, R92C_SYS_FUNC_EN, 1494264912Skevlo reg | R92C_SYS_FUNC_EN_ELDR); 1495291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 1496291698Savos return (EIO); 1497264912Skevlo } 1498264912Skevlo reg = urtwn_read_2(sc, R92C_SYS_CLKR); 1499264912Skevlo if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) != 1500264912Skevlo (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) { 1501291698Savos error = urtwn_write_2(sc, R92C_SYS_CLKR, 1502264912Skevlo reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M); 1503291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 1504291698Savos return (EIO); 1505264912Skevlo } 1506291698Savos 1507291698Savos return (0); 1508264912Skevlo} 1509264912Skevlo 1510251538Srpaulostatic int 1511251538Srpaulourtwn_read_chipid(struct urtwn_softc *sc) 1512251538Srpaulo{ 1513251538Srpaulo uint32_t reg; 1514251538Srpaulo 1515264912Skevlo if (sc->chip & URTWN_CHIP_88E) 1516264912Skevlo return (0); 1517264912Skevlo 1518251538Srpaulo reg = urtwn_read_4(sc, R92C_SYS_CFG); 1519251538Srpaulo if (reg & R92C_SYS_CFG_TRP_VAUX_EN) 1520251538Srpaulo return (EIO); 1521251538Srpaulo 1522251538Srpaulo if (reg & R92C_SYS_CFG_TYPE_92C) { 1523251538Srpaulo sc->chip |= URTWN_CHIP_92C; 1524251538Srpaulo /* Check if it is a castrated 8192C. */ 1525251538Srpaulo if (MS(urtwn_read_4(sc, R92C_HPON_FSM), 1526251538Srpaulo R92C_HPON_FSM_CHIP_BONDING_ID) == 1527251538Srpaulo R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R) 1528251538Srpaulo sc->chip |= URTWN_CHIP_92C_1T2R; 1529251538Srpaulo } 1530251538Srpaulo if (reg & R92C_SYS_CFG_VENDOR_UMC) { 1531251538Srpaulo sc->chip |= URTWN_CHIP_UMC; 1532251538Srpaulo if (MS(reg, R92C_SYS_CFG_CHIP_VER_RTL) == 0) 1533251538Srpaulo sc->chip |= URTWN_CHIP_UMC_A_CUT; 1534251538Srpaulo } 1535251538Srpaulo return (0); 1536251538Srpaulo} 1537251538Srpaulo 1538291264Savosstatic int 1539251538Srpaulourtwn_read_rom(struct urtwn_softc *sc) 1540251538Srpaulo{ 1541291264Savos struct r92c_rom *rom = &sc->rom.r92c_rom; 1542291264Savos int error; 1543251538Srpaulo 1544251538Srpaulo /* Read full ROM image. */ 1545291264Savos error = urtwn_efuse_read(sc, (uint8_t *)rom, sizeof(*rom)); 1546291264Savos if (error != 0) 1547291264Savos return (error); 1548251538Srpaulo 1549251538Srpaulo /* XXX Weird but this is what the vendor driver does. */ 1550291264Savos sc->last_rom_addr = 0x1fa; 1551291264Savos error = urtwn_efuse_read_next(sc, &sc->pa_setting); 1552291264Savos if (error != 0) 1553291264Savos return (error); 1554251538Srpaulo DPRINTF("PA setting=0x%x\n", sc->pa_setting); 1555251538Srpaulo 1556251538Srpaulo sc->board_type = MS(rom->rf_opt1, R92C_ROM_RF1_BOARD_TYPE); 1557251538Srpaulo 1558251538Srpaulo sc->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY); 1559251538Srpaulo DPRINTF("regulatory type=%d\n", sc->regulatory); 1560287197Sglebius IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr); 1561251538Srpaulo 1562264912Skevlo sc->sc_rf_write = urtwn_r92c_rf_write; 1563264912Skevlo sc->sc_power_on = urtwn_r92c_power_on; 1564291264Savos 1565291264Savos return (0); 1566251538Srpaulo} 1567251538Srpaulo 1568291264Savosstatic int 1569264912Skevlourtwn_r88e_read_rom(struct urtwn_softc *sc) 1570264912Skevlo{ 1571291264Savos uint8_t *rom = sc->rom.r88e_rom; 1572291264Savos uint16_t addr; 1573291264Savos int error, i; 1574264912Skevlo 1575291264Savos error = urtwn_efuse_read(sc, rom, sizeof(sc->rom.r88e_rom)); 1576291264Savos if (error != 0) 1577291264Savos return (error); 1578264912Skevlo 1579264912Skevlo addr = 0x10; 1580264912Skevlo for (i = 0; i < 6; i++) 1581291264Savos sc->cck_tx_pwr[i] = rom[addr++]; 1582264912Skevlo for (i = 0; i < 5; i++) 1583291264Savos sc->ht40_tx_pwr[i] = rom[addr++]; 1584291264Savos sc->bw20_tx_pwr_diff = (rom[addr] & 0xf0) >> 4; 1585264912Skevlo if (sc->bw20_tx_pwr_diff & 0x08) 1586264912Skevlo sc->bw20_tx_pwr_diff |= 0xf0; 1587291264Savos sc->ofdm_tx_pwr_diff = (rom[addr] & 0xf); 1588264912Skevlo if (sc->ofdm_tx_pwr_diff & 0x08) 1589264912Skevlo sc->ofdm_tx_pwr_diff |= 0xf0; 1590291264Savos sc->regulatory = MS(rom[0xc1], R92C_ROM_RF1_REGULATORY); 1591291264Savos IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, &rom[0xd7]); 1592264912Skevlo 1593264912Skevlo sc->sc_rf_write = urtwn_r88e_rf_write; 1594264912Skevlo sc->sc_power_on = urtwn_r88e_power_on; 1595291264Savos 1596291264Savos return (0); 1597264912Skevlo} 1598264912Skevlo 1599251538Srpaulo/* 1600251538Srpaulo * Initialize rate adaptation in firmware. 1601251538Srpaulo */ 1602251538Srpaulostatic int 1603251538Srpaulourtwn_ra_init(struct urtwn_softc *sc) 1604251538Srpaulo{ 1605287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 1606251538Srpaulo struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 1607251538Srpaulo struct ieee80211_node *ni; 1608251538Srpaulo struct ieee80211_rateset *rs; 1609251538Srpaulo struct r92c_fw_cmd_macid_cfg cmd; 1610251538Srpaulo uint32_t rates, basicrates; 1611251538Srpaulo uint8_t mode; 1612251538Srpaulo int maxrate, maxbasicrate, error, i, j; 1613251538Srpaulo 1614251538Srpaulo ni = ieee80211_ref_node(vap->iv_bss); 1615251538Srpaulo rs = &ni->ni_rates; 1616251538Srpaulo 1617251538Srpaulo /* Get normal and basic rates mask. */ 1618251538Srpaulo rates = basicrates = 0; 1619251538Srpaulo maxrate = maxbasicrate = 0; 1620251538Srpaulo for (i = 0; i < rs->rs_nrates; i++) { 1621251538Srpaulo /* Convert 802.11 rate to HW rate index. */ 1622289758Savos for (j = 0; j < nitems(ridx2rate); j++) 1623289758Savos if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == 1624289758Savos ridx2rate[j]) 1625251538Srpaulo break; 1626289758Savos if (j == nitems(ridx2rate)) /* Unknown rate, skip. */ 1627251538Srpaulo continue; 1628251538Srpaulo rates |= 1 << j; 1629251538Srpaulo if (j > maxrate) 1630251538Srpaulo maxrate = j; 1631251538Srpaulo if (rs->rs_rates[i] & IEEE80211_RATE_BASIC) { 1632251538Srpaulo basicrates |= 1 << j; 1633251538Srpaulo if (j > maxbasicrate) 1634251538Srpaulo maxbasicrate = j; 1635251538Srpaulo } 1636251538Srpaulo } 1637251538Srpaulo if (ic->ic_curmode == IEEE80211_MODE_11B) 1638251538Srpaulo mode = R92C_RAID_11B; 1639251538Srpaulo else 1640251538Srpaulo mode = R92C_RAID_11BG; 1641251538Srpaulo DPRINTF("mode=0x%x rates=0x%08x, basicrates=0x%08x\n", 1642251538Srpaulo mode, rates, basicrates); 1643251538Srpaulo 1644251538Srpaulo /* Set rates mask for group addressed frames. */ 1645251538Srpaulo cmd.macid = URTWN_MACID_BC | URTWN_MACID_VALID; 1646251538Srpaulo cmd.mask = htole32(mode << 28 | basicrates); 1647251538Srpaulo error = urtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); 1648251538Srpaulo if (error != 0) { 1649252401Srpaulo ieee80211_free_node(ni); 1650251538Srpaulo device_printf(sc->sc_dev, 1651251538Srpaulo "could not add broadcast station\n"); 1652251538Srpaulo return (error); 1653251538Srpaulo } 1654251538Srpaulo /* Set initial MRR rate. */ 1655251538Srpaulo DPRINTF("maxbasicrate=%d\n", maxbasicrate); 1656251538Srpaulo urtwn_write_1(sc, R92C_INIDATA_RATE_SEL(URTWN_MACID_BC), 1657251538Srpaulo maxbasicrate); 1658251538Srpaulo 1659251538Srpaulo /* Set rates mask for unicast frames. */ 1660251538Srpaulo cmd.macid = URTWN_MACID_BSS | URTWN_MACID_VALID; 1661251538Srpaulo cmd.mask = htole32(mode << 28 | rates); 1662251538Srpaulo error = urtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); 1663251538Srpaulo if (error != 0) { 1664252401Srpaulo ieee80211_free_node(ni); 1665251538Srpaulo device_printf(sc->sc_dev, "could not add BSS station\n"); 1666251538Srpaulo return (error); 1667251538Srpaulo } 1668251538Srpaulo /* Set initial MRR rate. */ 1669251538Srpaulo DPRINTF("maxrate=%d\n", maxrate); 1670251538Srpaulo urtwn_write_1(sc, R92C_INIDATA_RATE_SEL(URTWN_MACID_BSS), 1671251538Srpaulo maxrate); 1672251538Srpaulo 1673251538Srpaulo /* Indicate highest supported rate. */ 1674252403Srpaulo ni->ni_txrate = rs->rs_rates[rs->rs_nrates - 1]; 1675252401Srpaulo ieee80211_free_node(ni); 1676252401Srpaulo 1677251538Srpaulo return (0); 1678251538Srpaulo} 1679251538Srpaulo 1680290439Savosstatic void 1681290631Savosurtwn_init_beacon(struct urtwn_softc *sc, struct urtwn_vap *uvp) 1682251538Srpaulo{ 1683290631Savos struct r92c_tx_desc *txd = &uvp->bcn_desc; 1684290631Savos 1685290631Savos txd->txdw0 = htole32( 1686290631Savos SM(R92C_TXDW0_OFFSET, sizeof(*txd)) | R92C_TXDW0_BMCAST | 1687290631Savos R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG); 1688290631Savos txd->txdw1 = htole32( 1689290631Savos SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BEACON) | 1690290631Savos SM(R92C_TXDW1_RAID, R92C_RAID_11B)); 1691290631Savos 1692291858Savos if (sc->chip & URTWN_CHIP_88E) { 1693290631Savos txd->txdw1 |= htole32(SM(R88E_TXDW1_MACID, URTWN_MACID_BC)); 1694291858Savos txd->txdseq |= htole16(R88E_TXDSEQ_HWSEQ_EN); 1695291858Savos } else { 1696290631Savos txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, URTWN_MACID_BC)); 1697291858Savos txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN); 1698291858Savos } 1699290631Savos 1700290631Savos txd->txdw4 = htole32(R92C_TXDW4_DRVRATE); 1701290631Savos txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, URTWN_RIDX_CCK1)); 1702251538Srpaulo} 1703251538Srpaulo 1704290631Savosstatic int 1705290631Savosurtwn_setup_beacon(struct urtwn_softc *sc, struct ieee80211_node *ni) 1706290631Savos{ 1707290631Savos struct ieee80211vap *vap = ni->ni_vap; 1708290631Savos struct urtwn_vap *uvp = URTWN_VAP(vap); 1709290631Savos struct mbuf *m; 1710290631Savos int error; 1711290631Savos 1712290631Savos URTWN_ASSERT_LOCKED(sc); 1713290631Savos 1714290631Savos if (ni->ni_chan == IEEE80211_CHAN_ANYC) 1715290631Savos return (EINVAL); 1716290631Savos 1717290631Savos m = ieee80211_beacon_alloc(ni); 1718290631Savos if (m == NULL) { 1719290631Savos device_printf(sc->sc_dev, 1720290631Savos "%s: could not allocate beacon frame\n", __func__); 1721290631Savos return (ENOMEM); 1722290631Savos } 1723290631Savos 1724290631Savos if (uvp->bcn_mbuf != NULL) 1725290631Savos m_freem(uvp->bcn_mbuf); 1726290631Savos 1727290631Savos uvp->bcn_mbuf = m; 1728290631Savos 1729290631Savos if ((error = urtwn_tx_beacon(sc, uvp)) != 0) 1730290631Savos return (error); 1731290631Savos 1732290631Savos /* XXX bcnq stuck workaround */ 1733290631Savos if ((error = urtwn_tx_beacon(sc, uvp)) != 0) 1734290631Savos return (error); 1735290631Savos 1736290631Savos return (0); 1737290631Savos} 1738290631Savos 1739251538Srpaulostatic void 1740290631Savosurtwn_update_beacon(struct ieee80211vap *vap, int item) 1741290631Savos{ 1742290631Savos struct urtwn_softc *sc = vap->iv_ic->ic_softc; 1743290631Savos struct urtwn_vap *uvp = URTWN_VAP(vap); 1744290631Savos struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; 1745290631Savos struct ieee80211_node *ni = vap->iv_bss; 1746290631Savos int mcast = 0; 1747290631Savos 1748290631Savos URTWN_LOCK(sc); 1749290631Savos if (uvp->bcn_mbuf == NULL) { 1750290631Savos uvp->bcn_mbuf = ieee80211_beacon_alloc(ni); 1751290631Savos if (uvp->bcn_mbuf == NULL) { 1752290631Savos device_printf(sc->sc_dev, 1753290631Savos "%s: could not allocate beacon frame\n", __func__); 1754290631Savos URTWN_UNLOCK(sc); 1755290631Savos return; 1756290631Savos } 1757290631Savos } 1758290631Savos URTWN_UNLOCK(sc); 1759290631Savos 1760290631Savos if (item == IEEE80211_BEACON_TIM) 1761290631Savos mcast = 1; /* XXX */ 1762290631Savos 1763290631Savos setbit(bo->bo_flags, item); 1764290631Savos ieee80211_beacon_update(ni, uvp->bcn_mbuf, mcast); 1765290631Savos 1766290631Savos URTWN_LOCK(sc); 1767290631Savos urtwn_tx_beacon(sc, uvp); 1768290631Savos URTWN_UNLOCK(sc); 1769290631Savos} 1770290631Savos 1771290631Savos/* 1772290631Savos * Push a beacon frame into the chip. Beacon will 1773290631Savos * be repeated by the chip every R92C_BCN_INTERVAL. 1774290631Savos */ 1775290631Savosstatic int 1776290631Savosurtwn_tx_beacon(struct urtwn_softc *sc, struct urtwn_vap *uvp) 1777290631Savos{ 1778290631Savos struct r92c_tx_desc *desc = &uvp->bcn_desc; 1779290631Savos struct urtwn_data *bf; 1780290631Savos 1781290631Savos URTWN_ASSERT_LOCKED(sc); 1782290631Savos 1783290631Savos bf = urtwn_getbuf(sc); 1784290631Savos if (bf == NULL) 1785290631Savos return (ENOMEM); 1786290631Savos 1787290631Savos memcpy(bf->buf, desc, sizeof(*desc)); 1788290631Savos urtwn_tx_start(sc, uvp->bcn_mbuf, IEEE80211_FC0_TYPE_MGT, bf); 1789290631Savos 1790290631Savos sc->sc_txtimer = 5; 1791290631Savos callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); 1792290631Savos 1793290631Savos return (0); 1794290631Savos} 1795290631Savos 1796290631Savosstatic void 1797290651Savosurtwn_tsf_task_adhoc(void *arg, int pending) 1798290651Savos{ 1799290651Savos struct ieee80211vap *vap = arg; 1800290651Savos struct urtwn_softc *sc = vap->iv_ic->ic_softc; 1801290651Savos struct ieee80211_node *ni; 1802290651Savos uint32_t reg; 1803290651Savos 1804290651Savos URTWN_LOCK(sc); 1805290651Savos ni = ieee80211_ref_node(vap->iv_bss); 1806290651Savos reg = urtwn_read_1(sc, R92C_BCN_CTRL); 1807290651Savos 1808290651Savos /* Accept beacons with the same BSSID. */ 1809290651Savos urtwn_set_rx_bssid_all(sc, 0); 1810290651Savos 1811290651Savos /* Enable synchronization. */ 1812290651Savos reg &= ~R92C_BCN_CTRL_DIS_TSF_UDT0; 1813290651Savos urtwn_write_1(sc, R92C_BCN_CTRL, reg); 1814290651Savos 1815290651Savos /* Synchronize. */ 1816290651Savos usb_pause_mtx(&sc->sc_mtx, hz * ni->ni_intval * 5 / 1000); 1817290651Savos 1818290651Savos /* Disable synchronization. */ 1819290651Savos reg |= R92C_BCN_CTRL_DIS_TSF_UDT0; 1820290651Savos urtwn_write_1(sc, R92C_BCN_CTRL, reg); 1821290651Savos 1822290651Savos /* Remove beacon filter. */ 1823290651Savos urtwn_set_rx_bssid_all(sc, 1); 1824290651Savos 1825290651Savos /* Enable beaconing. */ 1826290651Savos urtwn_write_1(sc, R92C_MBID_NUM, 1827290651Savos urtwn_read_1(sc, R92C_MBID_NUM) | R92C_MBID_TXBCN_RPT0); 1828290651Savos reg |= R92C_BCN_CTRL_EN_BCN; 1829290651Savos 1830290651Savos urtwn_write_1(sc, R92C_BCN_CTRL, reg); 1831290651Savos ieee80211_free_node(ni); 1832290651Savos URTWN_UNLOCK(sc); 1833290651Savos} 1834290651Savos 1835290651Savosstatic void 1836290631Savosurtwn_tsf_sync_enable(struct urtwn_softc *sc, struct ieee80211vap *vap) 1837290631Savos{ 1838290651Savos struct ieee80211com *ic = &sc->sc_ic; 1839290651Savos struct urtwn_vap *uvp = URTWN_VAP(vap); 1840290651Savos 1841290631Savos /* Reset TSF. */ 1842290631Savos urtwn_write_1(sc, R92C_DUAL_TSF_RST, R92C_DUAL_TSF_RST0); 1843290631Savos 1844290631Savos switch (vap->iv_opmode) { 1845290631Savos case IEEE80211_M_STA: 1846290631Savos /* Enable TSF synchronization. */ 1847290631Savos urtwn_write_1(sc, R92C_BCN_CTRL, 1848290631Savos urtwn_read_1(sc, R92C_BCN_CTRL) & 1849290631Savos ~R92C_BCN_CTRL_DIS_TSF_UDT0); 1850290631Savos break; 1851290651Savos case IEEE80211_M_IBSS: 1852290651Savos ieee80211_runtask(ic, &uvp->tsf_task_adhoc); 1853290651Savos break; 1854290631Savos case IEEE80211_M_HOSTAP: 1855290631Savos /* Enable beaconing. */ 1856290631Savos urtwn_write_1(sc, R92C_MBID_NUM, 1857290631Savos urtwn_read_1(sc, R92C_MBID_NUM) | R92C_MBID_TXBCN_RPT0); 1858290631Savos urtwn_write_1(sc, R92C_BCN_CTRL, 1859290631Savos urtwn_read_1(sc, R92C_BCN_CTRL) | R92C_BCN_CTRL_EN_BCN); 1860290631Savos break; 1861290631Savos default: 1862290631Savos device_printf(sc->sc_dev, "undefined opmode %d\n", 1863290631Savos vap->iv_opmode); 1864290631Savos return; 1865290631Savos } 1866290631Savos} 1867290631Savos 1868290631Savosstatic void 1869251538Srpaulourtwn_set_led(struct urtwn_softc *sc, int led, int on) 1870251538Srpaulo{ 1871251538Srpaulo uint8_t reg; 1872281069Srpaulo 1873251538Srpaulo if (led == URTWN_LED_LINK) { 1874264912Skevlo if (sc->chip & URTWN_CHIP_88E) { 1875264912Skevlo reg = urtwn_read_1(sc, R92C_LEDCFG2) & 0xf0; 1876264912Skevlo urtwn_write_1(sc, R92C_LEDCFG2, reg | 0x60); 1877264912Skevlo if (!on) { 1878264912Skevlo reg = urtwn_read_1(sc, R92C_LEDCFG2) & 0x90; 1879264912Skevlo urtwn_write_1(sc, R92C_LEDCFG2, 1880264912Skevlo reg | R92C_LEDCFG0_DIS); 1881264912Skevlo urtwn_write_1(sc, R92C_MAC_PINMUX_CFG, 1882264912Skevlo urtwn_read_1(sc, R92C_MAC_PINMUX_CFG) & 1883264912Skevlo 0xfe); 1884264912Skevlo } 1885264912Skevlo } else { 1886264912Skevlo reg = urtwn_read_1(sc, R92C_LEDCFG0) & 0x70; 1887264912Skevlo if (!on) 1888264912Skevlo reg |= R92C_LEDCFG0_DIS; 1889264912Skevlo urtwn_write_1(sc, R92C_LEDCFG0, reg); 1890264912Skevlo } 1891264912Skevlo sc->ledlink = on; /* Save LED state. */ 1892251538Srpaulo } 1893251538Srpaulo} 1894251538Srpaulo 1895289811Savosstatic void 1896289811Savosurtwn_set_mode(struct urtwn_softc *sc, uint8_t mode) 1897289811Savos{ 1898289811Savos uint8_t reg; 1899289811Savos 1900289811Savos reg = urtwn_read_1(sc, R92C_MSR); 1901289811Savos reg = (reg & ~R92C_MSR_MASK) | mode; 1902289811Savos urtwn_write_1(sc, R92C_MSR, reg); 1903289811Savos} 1904289811Savos 1905290651Savosstatic void 1906290651Savosurtwn_ibss_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, 1907290651Savos const struct ieee80211_rx_stats *rxs, 1908290651Savos int rssi, int nf) 1909290651Savos{ 1910290651Savos struct ieee80211vap *vap = ni->ni_vap; 1911290651Savos struct urtwn_softc *sc = vap->iv_ic->ic_softc; 1912290651Savos struct urtwn_vap *uvp = URTWN_VAP(vap); 1913290651Savos uint64_t ni_tstamp, curr_tstamp; 1914290651Savos 1915290651Savos uvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf); 1916290651Savos 1917290651Savos if (vap->iv_state == IEEE80211_S_RUN && 1918290651Savos (subtype == IEEE80211_FC0_SUBTYPE_BEACON || 1919290651Savos subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) { 1920290651Savos ni_tstamp = le64toh(ni->ni_tstamp.tsf); 1921290651Savos#ifdef D3831 1922290651Savos URTWN_LOCK(sc); 1923290651Savos urtwn_get_tsf(sc, &curr_tstamp); 1924290651Savos URTWN_UNLOCK(sc); 1925290651Savos curr_tstamp = le64toh(curr_tstamp); 1926290651Savos 1927290651Savos if (ni_tstamp >= curr_tstamp) 1928290651Savos (void) ieee80211_ibss_merge(ni); 1929290651Savos#else 1930290651Savos (void) sc; 1931290651Savos (void) curr_tstamp; 1932290651Savos#endif 1933290651Savos } 1934290651Savos} 1935290651Savos 1936251538Srpaulostatic int 1937251538Srpaulourtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 1938251538Srpaulo{ 1939251538Srpaulo struct urtwn_vap *uvp = URTWN_VAP(vap); 1940251538Srpaulo struct ieee80211com *ic = vap->iv_ic; 1941286949Sadrian struct urtwn_softc *sc = ic->ic_softc; 1942251538Srpaulo struct ieee80211_node *ni; 1943251538Srpaulo enum ieee80211_state ostate; 1944290631Savos uint32_t reg; 1945290631Savos uint8_t mode; 1946290631Savos int error = 0; 1947251538Srpaulo 1948251538Srpaulo ostate = vap->iv_state; 1949251538Srpaulo DPRINTF("%s -> %s\n", ieee80211_state_name[ostate], 1950251538Srpaulo ieee80211_state_name[nstate]); 1951251538Srpaulo 1952251538Srpaulo IEEE80211_UNLOCK(ic); 1953251538Srpaulo URTWN_LOCK(sc); 1954251538Srpaulo callout_stop(&sc->sc_watchdog_ch); 1955251538Srpaulo 1956251538Srpaulo if (ostate == IEEE80211_S_RUN) { 1957251538Srpaulo /* Turn link LED off. */ 1958251538Srpaulo urtwn_set_led(sc, URTWN_LED_LINK, 0); 1959251538Srpaulo 1960251538Srpaulo /* Set media status to 'No Link'. */ 1961289811Savos urtwn_set_mode(sc, R92C_MSR_NOLINK); 1962251538Srpaulo 1963251538Srpaulo /* Stop Rx of data frames. */ 1964251538Srpaulo urtwn_write_2(sc, R92C_RXFLTMAP2, 0); 1965251538Srpaulo 1966251538Srpaulo /* Disable TSF synchronization. */ 1967251538Srpaulo urtwn_write_1(sc, R92C_BCN_CTRL, 1968290631Savos (urtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_EN_BCN) | 1969251538Srpaulo R92C_BCN_CTRL_DIS_TSF_UDT0); 1970251538Srpaulo 1971290631Savos /* Disable beaconing. */ 1972290631Savos urtwn_write_1(sc, R92C_MBID_NUM, 1973290631Savos urtwn_read_1(sc, R92C_MBID_NUM) & ~R92C_MBID_TXBCN_RPT0); 1974290631Savos 1975290631Savos /* Reset TSF. */ 1976290631Savos urtwn_write_1(sc, R92C_DUAL_TSF_RST, R92C_DUAL_TSF_RST0); 1977290631Savos 1978251538Srpaulo /* Reset EDCA parameters. */ 1979251538Srpaulo urtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3217); 1980251538Srpaulo urtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4317); 1981251538Srpaulo urtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x00105320); 1982251538Srpaulo urtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a444); 1983251538Srpaulo } 1984251538Srpaulo 1985251538Srpaulo switch (nstate) { 1986251538Srpaulo case IEEE80211_S_INIT: 1987251538Srpaulo /* Turn link LED off. */ 1988251538Srpaulo urtwn_set_led(sc, URTWN_LED_LINK, 0); 1989251538Srpaulo break; 1990251538Srpaulo case IEEE80211_S_SCAN: 1991251538Srpaulo /* Pause AC Tx queues. */ 1992251538Srpaulo urtwn_write_1(sc, R92C_TXPAUSE, 1993251538Srpaulo urtwn_read_1(sc, R92C_TXPAUSE) | 0x0f); 1994251538Srpaulo break; 1995251538Srpaulo case IEEE80211_S_AUTH: 1996251538Srpaulo urtwn_set_chan(sc, ic->ic_curchan, NULL); 1997251538Srpaulo break; 1998251538Srpaulo case IEEE80211_S_RUN: 1999251538Srpaulo if (vap->iv_opmode == IEEE80211_M_MONITOR) { 2000251538Srpaulo /* Turn link LED on. */ 2001251538Srpaulo urtwn_set_led(sc, URTWN_LED_LINK, 1); 2002251538Srpaulo break; 2003251538Srpaulo } 2004251538Srpaulo 2005251538Srpaulo ni = ieee80211_ref_node(vap->iv_bss); 2006290631Savos 2007290631Savos if (ic->ic_bsschan == IEEE80211_CHAN_ANYC || 2008290631Savos ni->ni_chan == IEEE80211_CHAN_ANYC) { 2009290631Savos device_printf(sc->sc_dev, 2010290631Savos "%s: could not move to RUN state\n", __func__); 2011290631Savos error = EINVAL; 2012290631Savos goto end_run; 2013290631Savos } 2014290631Savos 2015290631Savos switch (vap->iv_opmode) { 2016290631Savos case IEEE80211_M_STA: 2017290631Savos mode = R92C_MSR_INFRA; 2018290631Savos break; 2019290651Savos case IEEE80211_M_IBSS: 2020290651Savos mode = R92C_MSR_ADHOC; 2021290651Savos break; 2022290631Savos case IEEE80211_M_HOSTAP: 2023290631Savos mode = R92C_MSR_AP; 2024290631Savos break; 2025290631Savos default: 2026290631Savos device_printf(sc->sc_dev, "undefined opmode %d\n", 2027290631Savos vap->iv_opmode); 2028290631Savos error = EINVAL; 2029290631Savos goto end_run; 2030290631Savos } 2031290631Savos 2032251538Srpaulo /* Set media status to 'Associated'. */ 2033290631Savos urtwn_set_mode(sc, mode); 2034251538Srpaulo 2035251538Srpaulo /* Set BSSID. */ 2036251538Srpaulo urtwn_write_4(sc, R92C_BSSID + 0, LE_READ_4(&ni->ni_bssid[0])); 2037251538Srpaulo urtwn_write_4(sc, R92C_BSSID + 4, LE_READ_2(&ni->ni_bssid[4])); 2038251538Srpaulo 2039251538Srpaulo if (ic->ic_curmode == IEEE80211_MODE_11B) 2040251538Srpaulo urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 0); 2041251538Srpaulo else /* 802.11b/g */ 2042251538Srpaulo urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 3); 2043251538Srpaulo 2044251538Srpaulo /* Enable Rx of data frames. */ 2045251538Srpaulo urtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff); 2046251538Srpaulo 2047251538Srpaulo /* Flush all AC queues. */ 2048251538Srpaulo urtwn_write_1(sc, R92C_TXPAUSE, 0); 2049251538Srpaulo 2050251538Srpaulo /* Set beacon interval. */ 2051251538Srpaulo urtwn_write_2(sc, R92C_BCN_INTERVAL, ni->ni_intval); 2052251538Srpaulo 2053251538Srpaulo /* Allow Rx from our BSSID only. */ 2054290564Savos if (ic->ic_promisc == 0) { 2055290631Savos reg = urtwn_read_4(sc, R92C_RCR); 2056290631Savos 2057290631Savos if (vap->iv_opmode != IEEE80211_M_HOSTAP) 2058290631Savos reg |= R92C_RCR_CBSSID_DATA; 2059290651Savos if (vap->iv_opmode != IEEE80211_M_IBSS) 2060290651Savos reg |= R92C_RCR_CBSSID_BCN; 2061290631Savos 2062290631Savos urtwn_write_4(sc, R92C_RCR, reg); 2063290564Savos } 2064251538Srpaulo 2065290651Savos if (vap->iv_opmode == IEEE80211_M_HOSTAP || 2066290651Savos vap->iv_opmode == IEEE80211_M_IBSS) { 2067290631Savos error = urtwn_setup_beacon(sc, ni); 2068290631Savos if (error != 0) { 2069290631Savos device_printf(sc->sc_dev, 2070290631Savos "unable to push beacon into the chip, " 2071290631Savos "error %d\n", error); 2072290631Savos goto end_run; 2073290631Savos } 2074290631Savos } 2075290631Savos 2076251538Srpaulo /* Enable TSF synchronization. */ 2077290631Savos urtwn_tsf_sync_enable(sc, vap); 2078251538Srpaulo 2079251538Srpaulo urtwn_write_1(sc, R92C_SIFS_CCK + 1, 10); 2080251538Srpaulo urtwn_write_1(sc, R92C_SIFS_OFDM + 1, 10); 2081251538Srpaulo urtwn_write_1(sc, R92C_SPEC_SIFS + 1, 10); 2082251538Srpaulo urtwn_write_1(sc, R92C_MAC_SPEC_SIFS + 1, 10); 2083251538Srpaulo urtwn_write_1(sc, R92C_R2T_SIFS + 1, 10); 2084251538Srpaulo urtwn_write_1(sc, R92C_T2T_SIFS + 1, 10); 2085251538Srpaulo 2086251538Srpaulo /* Intialize rate adaptation. */ 2087292167Savos if (!(sc->chip & URTWN_CHIP_88E)) 2088264912Skevlo urtwn_ra_init(sc); 2089251538Srpaulo /* Turn link LED on. */ 2090251538Srpaulo urtwn_set_led(sc, URTWN_LED_LINK, 1); 2091251538Srpaulo 2092251538Srpaulo sc->avg_pwdb = -1; /* Reset average RSSI. */ 2093251538Srpaulo /* Reset temperature calibration state machine. */ 2094251538Srpaulo sc->thcal_state = 0; 2095251538Srpaulo sc->thcal_lctemp = 0; 2096290631Savos 2097290631Savosend_run: 2098251538Srpaulo ieee80211_free_node(ni); 2099251538Srpaulo break; 2100251538Srpaulo default: 2101251538Srpaulo break; 2102251538Srpaulo } 2103290631Savos 2104251538Srpaulo URTWN_UNLOCK(sc); 2105251538Srpaulo IEEE80211_LOCK(ic); 2106290631Savos return (error != 0 ? error : uvp->newstate(vap, nstate, arg)); 2107251538Srpaulo} 2108251538Srpaulo 2109251538Srpaulostatic void 2110251538Srpaulourtwn_watchdog(void *arg) 2111251538Srpaulo{ 2112251538Srpaulo struct urtwn_softc *sc = arg; 2113251538Srpaulo 2114251538Srpaulo if (sc->sc_txtimer > 0) { 2115251538Srpaulo if (--sc->sc_txtimer == 0) { 2116251538Srpaulo device_printf(sc->sc_dev, "device timeout\n"); 2117287197Sglebius counter_u64_add(sc->sc_ic.ic_oerrors, 1); 2118251538Srpaulo return; 2119251538Srpaulo } 2120251538Srpaulo callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); 2121251538Srpaulo } 2122251538Srpaulo} 2123251538Srpaulo 2124251538Srpaulostatic void 2125251538Srpaulourtwn_update_avgrssi(struct urtwn_softc *sc, int rate, int8_t rssi) 2126251538Srpaulo{ 2127251538Srpaulo int pwdb; 2128251538Srpaulo 2129251538Srpaulo /* Convert antenna signal to percentage. */ 2130251538Srpaulo if (rssi <= -100 || rssi >= 20) 2131251538Srpaulo pwdb = 0; 2132251538Srpaulo else if (rssi >= 0) 2133251538Srpaulo pwdb = 100; 2134251538Srpaulo else 2135251538Srpaulo pwdb = 100 + rssi; 2136264912Skevlo if (!(sc->chip & URTWN_CHIP_88E)) { 2137289758Savos if (rate <= URTWN_RIDX_CCK11) { 2138264912Skevlo /* CCK gain is smaller than OFDM/MCS gain. */ 2139264912Skevlo pwdb += 6; 2140264912Skevlo if (pwdb > 100) 2141264912Skevlo pwdb = 100; 2142264912Skevlo if (pwdb <= 14) 2143264912Skevlo pwdb -= 4; 2144264912Skevlo else if (pwdb <= 26) 2145264912Skevlo pwdb -= 8; 2146264912Skevlo else if (pwdb <= 34) 2147264912Skevlo pwdb -= 6; 2148264912Skevlo else if (pwdb <= 42) 2149264912Skevlo pwdb -= 2; 2150264912Skevlo } 2151251538Srpaulo } 2152251538Srpaulo if (sc->avg_pwdb == -1) /* Init. */ 2153251538Srpaulo sc->avg_pwdb = pwdb; 2154251538Srpaulo else if (sc->avg_pwdb < pwdb) 2155251538Srpaulo sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20) + 1; 2156251538Srpaulo else 2157251538Srpaulo sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20); 2158251538Srpaulo DPRINTFN(4, "PWDB=%d EMA=%d\n", pwdb, sc->avg_pwdb); 2159251538Srpaulo} 2160251538Srpaulo 2161251538Srpaulostatic int8_t 2162251538Srpaulourtwn_get_rssi(struct urtwn_softc *sc, int rate, void *physt) 2163251538Srpaulo{ 2164251538Srpaulo static const int8_t cckoff[] = { 16, -12, -26, -46 }; 2165251538Srpaulo struct r92c_rx_phystat *phy; 2166251538Srpaulo struct r92c_rx_cck *cck; 2167251538Srpaulo uint8_t rpt; 2168251538Srpaulo int8_t rssi; 2169251538Srpaulo 2170289758Savos if (rate <= URTWN_RIDX_CCK11) { 2171251538Srpaulo cck = (struct r92c_rx_cck *)physt; 2172251538Srpaulo if (sc->sc_flags & URTWN_FLAG_CCK_HIPWR) { 2173251538Srpaulo rpt = (cck->agc_rpt >> 5) & 0x3; 2174251538Srpaulo rssi = (cck->agc_rpt & 0x1f) << 1; 2175251538Srpaulo } else { 2176251538Srpaulo rpt = (cck->agc_rpt >> 6) & 0x3; 2177251538Srpaulo rssi = cck->agc_rpt & 0x3e; 2178251538Srpaulo } 2179251538Srpaulo rssi = cckoff[rpt] - rssi; 2180251538Srpaulo } else { /* OFDM/HT. */ 2181251538Srpaulo phy = (struct r92c_rx_phystat *)physt; 2182251538Srpaulo rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 110; 2183251538Srpaulo } 2184251538Srpaulo return (rssi); 2185251538Srpaulo} 2186251538Srpaulo 2187264912Skevlostatic int8_t 2188264912Skevlourtwn_r88e_get_rssi(struct urtwn_softc *sc, int rate, void *physt) 2189264912Skevlo{ 2190264912Skevlo struct r92c_rx_phystat *phy; 2191264912Skevlo struct r88e_rx_cck *cck; 2192264912Skevlo uint8_t cck_agc_rpt, lna_idx, vga_idx; 2193264912Skevlo int8_t rssi; 2194264912Skevlo 2195264972Skevlo rssi = 0; 2196289758Savos if (rate <= URTWN_RIDX_CCK11) { 2197264912Skevlo cck = (struct r88e_rx_cck *)physt; 2198264912Skevlo cck_agc_rpt = cck->agc_rpt; 2199264912Skevlo lna_idx = (cck_agc_rpt & 0xe0) >> 5; 2200281069Srpaulo vga_idx = cck_agc_rpt & 0x1f; 2201264912Skevlo switch (lna_idx) { 2202264912Skevlo case 7: 2203264912Skevlo if (vga_idx <= 27) 2204264912Skevlo rssi = -100 + 2* (27 - vga_idx); 2205264912Skevlo else 2206264912Skevlo rssi = -100; 2207264912Skevlo break; 2208264912Skevlo case 6: 2209264912Skevlo rssi = -48 + 2 * (2 - vga_idx); 2210264912Skevlo break; 2211264912Skevlo case 5: 2212264912Skevlo rssi = -42 + 2 * (7 - vga_idx); 2213264912Skevlo break; 2214264912Skevlo case 4: 2215264912Skevlo rssi = -36 + 2 * (7 - vga_idx); 2216264912Skevlo break; 2217264912Skevlo case 3: 2218264912Skevlo rssi = -24 + 2 * (7 - vga_idx); 2219264912Skevlo break; 2220264912Skevlo case 2: 2221264912Skevlo rssi = -12 + 2 * (5 - vga_idx); 2222264912Skevlo break; 2223264912Skevlo case 1: 2224264912Skevlo rssi = 8 - (2 * vga_idx); 2225264912Skevlo break; 2226264912Skevlo case 0: 2227264912Skevlo rssi = 14 - (2 * vga_idx); 2228264912Skevlo break; 2229264912Skevlo } 2230264912Skevlo rssi += 6; 2231264912Skevlo } else { /* OFDM/HT. */ 2232264912Skevlo phy = (struct r92c_rx_phystat *)physt; 2233264912Skevlo rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 110; 2234264912Skevlo } 2235264912Skevlo return (rssi); 2236264912Skevlo} 2237264912Skevlo 2238292167Savosstatic __inline uint8_t 2239292167Savosrate2ridx(uint8_t rate) 2240292167Savos{ 2241292167Savos switch (rate) { 2242292167Savos case 12: return 4; 2243292167Savos case 18: return 5; 2244292167Savos case 24: return 6; 2245292167Savos case 36: return 7; 2246292167Savos case 48: return 8; 2247292167Savos case 72: return 9; 2248292167Savos case 96: return 10; 2249292167Savos case 108: return 11; 2250292167Savos case 2: return 0; 2251292167Savos case 4: return 1; 2252292167Savos case 11: return 2; 2253292167Savos case 22: return 3; 2254292167Savos default: return 0; 2255292167Savos } 2256292167Savos} 2257292167Savos 2258251538Srpaulostatic int 2259290630Savosurtwn_tx_data(struct urtwn_softc *sc, struct ieee80211_node *ni, 2260290630Savos struct mbuf *m, struct urtwn_data *data) 2261251538Srpaulo{ 2262292167Savos const struct ieee80211_txparam *tp; 2263287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2264251538Srpaulo struct ieee80211vap *vap = ni->ni_vap; 2265292167Savos struct ieee80211_key *k = NULL; 2266292167Savos struct ieee80211_channel *chan; 2267292167Savos struct ieee80211_frame *wh; 2268251538Srpaulo struct r92c_tx_desc *txd; 2269292167Savos uint8_t macid, raid, rate, ridx, subtype, type, tid, qsel; 2270292014Savos int hasqos, ismcast; 2271251538Srpaulo 2272251538Srpaulo URTWN_ASSERT_LOCKED(sc); 2273251538Srpaulo 2274251538Srpaulo /* 2275251538Srpaulo * Software crypto. 2276251538Srpaulo */ 2277290630Savos wh = mtod(m, struct ieee80211_frame *); 2278264912Skevlo type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 2279290630Savos subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 2280292014Savos hasqos = IEEE80211_QOS_HAS_SEQ(wh); 2281290630Savos ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 2282264912Skevlo 2283292014Savos /* Select TX ring for this frame. */ 2284292014Savos if (hasqos) { 2285292014Savos tid = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; 2286292014Savos tid &= IEEE80211_QOS_TID; 2287292014Savos } else 2288292014Savos tid = 0; 2289292014Savos 2290292167Savos chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? 2291292167Savos ni->ni_chan : ic->ic_curchan; 2292292167Savos tp = &vap->iv_txparms[ieee80211_chan2mode(chan)]; 2293292167Savos 2294292167Savos /* Choose a TX rate index. */ 2295292167Savos if (type == IEEE80211_FC0_TYPE_MGT) 2296292167Savos rate = tp->mgmtrate; 2297292167Savos else if (ismcast) 2298292167Savos rate = tp->mcastrate; 2299292167Savos else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) 2300292167Savos rate = tp->ucastrate; 2301292167Savos else if (m->m_flags & M_EAPOL) 2302292167Savos rate = tp->mgmtrate; 2303292167Savos else { 2304292167Savos if (URTWN_CHIP_HAS_RATECTL(sc)) { 2305292167Savos /* XXX pass pktlen */ 2306292167Savos (void) ieee80211_ratectl_rate(ni, NULL, 0); 2307292167Savos rate = ni->ni_txrate; 2308292167Savos } else { 2309292167Savos if (ic->ic_curmode != IEEE80211_MODE_11B) 2310292167Savos rate = 108; 2311292167Savos else 2312292167Savos rate = 22; 2313292167Savos } 2314292167Savos } 2315292167Savos 2316292167Savos ridx = rate2ridx(rate); 2317292167Savos if (ic->ic_curmode != IEEE80211_MODE_11B) 2318292167Savos raid = R92C_RAID_11BG; 2319292167Savos else 2320292167Savos raid = R92C_RAID_11B; 2321292167Savos 2322260444Skevlo if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 2323290630Savos k = ieee80211_crypto_encap(ni, m); 2324251538Srpaulo if (k == NULL) { 2325251538Srpaulo device_printf(sc->sc_dev, 2326251538Srpaulo "ieee80211_crypto_encap returns NULL.\n"); 2327251538Srpaulo return (ENOBUFS); 2328251538Srpaulo } 2329251538Srpaulo 2330251538Srpaulo /* in case packet header moved, reset pointer */ 2331290630Savos wh = mtod(m, struct ieee80211_frame *); 2332251538Srpaulo } 2333281069Srpaulo 2334251538Srpaulo /* Fill Tx descriptor. */ 2335251538Srpaulo txd = (struct r92c_tx_desc *)data->buf; 2336251538Srpaulo memset(txd, 0, sizeof(*txd)); 2337251538Srpaulo 2338251538Srpaulo txd->txdw0 |= htole32( 2339251538Srpaulo SM(R92C_TXDW0_OFFSET, sizeof(*txd)) | 2340251538Srpaulo R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG); 2341290630Savos if (ismcast) 2342251538Srpaulo txd->txdw0 |= htole32(R92C_TXDW0_BMCAST); 2343290630Savos 2344290630Savos if (!ismcast) { 2345292167Savos if (sc->chip & URTWN_CHIP_88E) { 2346292167Savos struct urtwn_node *un = URTWN_NODE(ni); 2347292167Savos macid = un->id; 2348292167Savos } else 2349292167Savos macid = URTWN_MACID_BSS; 2350290630Savos 2351290630Savos if (type == IEEE80211_FC0_TYPE_DATA) { 2352292014Savos qsel = tid % URTWN_MAX_TID; 2353290630Savos 2354292167Savos if (sc->chip & URTWN_CHIP_88E) { 2355292167Savos txd->txdw2 |= htole32( 2356292167Savos R88E_TXDW2_AGGBK | 2357292167Savos R88E_TXDW2_CCX_RPT); 2358292167Savos } else 2359290630Savos txd->txdw1 |= htole32(R92C_TXDW1_AGGBK); 2360290630Savos 2361290630Savos if (ic->ic_flags & IEEE80211_F_USEPROT) { 2362290630Savos switch (ic->ic_protmode) { 2363290630Savos case IEEE80211_PROT_CTSONLY: 2364290630Savos txd->txdw4 |= htole32( 2365290630Savos R92C_TXDW4_CTS2SELF | 2366290630Savos R92C_TXDW4_HWRTSEN); 2367290630Savos break; 2368290630Savos case IEEE80211_PROT_RTSCTS: 2369290630Savos txd->txdw4 |= htole32( 2370290630Savos R92C_TXDW4_RTSEN | 2371290630Savos R92C_TXDW4_HWRTSEN); 2372290630Savos break; 2373290630Savos default: 2374290630Savos break; 2375290630Savos } 2376290630Savos } 2377290630Savos txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, 2378290630Savos URTWN_RIDX_OFDM24)); 2379290630Savos txd->txdw5 |= htole32(0x0001ff00); 2380290630Savos } else /* IEEE80211_FC0_TYPE_MGT */ 2381290630Savos qsel = R92C_TXDW1_QSEL_MGNT; 2382251538Srpaulo } else { 2383290630Savos macid = URTWN_MACID_BC; 2384290630Savos qsel = R92C_TXDW1_QSEL_MGNT; 2385290630Savos } 2386251538Srpaulo 2387290630Savos txd->txdw1 |= htole32( 2388290630Savos SM(R92C_TXDW1_QSEL, qsel) | 2389290630Savos SM(R92C_TXDW1_RAID, raid)); 2390290630Savos 2391290630Savos if (sc->chip & URTWN_CHIP_88E) 2392290630Savos txd->txdw1 |= htole32(SM(R88E_TXDW1_MACID, macid)); 2393290630Savos else 2394290630Savos txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, macid)); 2395290630Savos 2396290630Savos txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); 2397291858Savos /* Force this rate if needed. */ 2398292167Savos if (URTWN_CHIP_HAS_RATECTL(sc) || ismcast || 2399292167Savos (m->m_flags & M_EAPOL) || type != IEEE80211_FC0_TYPE_DATA) 2400251538Srpaulo txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); 2401251538Srpaulo 2402292014Savos if (!hasqos) { 2403251538Srpaulo /* Use HW sequence numbering for non-QoS frames. */ 2404291858Savos if (sc->chip & URTWN_CHIP_88E) 2405291858Savos txd->txdseq = htole16(R88E_TXDSEQ_HWSEQ_EN); 2406291858Savos else 2407291858Savos txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN); 2408290630Savos } else { 2409290630Savos /* Set sequence number. */ 2410290630Savos txd->txdseq = htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE); 2411290630Savos } 2412251538Srpaulo 2413251538Srpaulo if (ieee80211_radiotap_active_vap(vap)) { 2414251538Srpaulo struct urtwn_tx_radiotap_header *tap = &sc->sc_txtap; 2415251538Srpaulo 2416251538Srpaulo tap->wt_flags = 0; 2417290630Savos if (k != NULL) 2418290630Savos tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; 2419290630Savos ieee80211_radiotap_tx(vap, m); 2420251538Srpaulo } 2421251538Srpaulo 2422290630Savos data->ni = ni; 2423251538Srpaulo 2424290630Savos urtwn_tx_start(sc, m, type, data); 2425290630Savos 2426290630Savos return (0); 2427290630Savos} 2428290630Savos 2429290630Savosstatic void 2430290630Savosurtwn_tx_start(struct urtwn_softc *sc, struct mbuf *m, uint8_t type, 2431290630Savos struct urtwn_data *data) 2432290630Savos{ 2433290630Savos struct usb_xfer *xfer; 2434290630Savos struct r92c_tx_desc *txd; 2435290630Savos uint16_t ac, sum; 2436290630Savos int i, xferlen; 2437290630Savos 2438290630Savos URTWN_ASSERT_LOCKED(sc); 2439290630Savos 2440290630Savos ac = M_WME_GETAC(m); 2441290630Savos 2442290630Savos switch (type) { 2443290630Savos case IEEE80211_FC0_TYPE_CTL: 2444290630Savos case IEEE80211_FC0_TYPE_MGT: 2445290630Savos xfer = sc->sc_xfer[URTWN_BULK_TX_VO]; 2446290630Savos break; 2447290630Savos default: 2448292014Savos xfer = sc->sc_xfer[wme2queue[ac].qid]; 2449290630Savos break; 2450290630Savos } 2451290630Savos 2452290630Savos txd = (struct r92c_tx_desc *)data->buf; 2453290630Savos txd->txdw0 |= htole32(SM(R92C_TXDW0_PKTLEN, m->m_pkthdr.len)); 2454290630Savos 2455290630Savos /* Compute Tx descriptor checksum. */ 2456290630Savos sum = 0; 2457290630Savos for (i = 0; i < sizeof(*txd) / 2; i++) 2458290630Savos sum ^= ((uint16_t *)txd)[i]; 2459290630Savos txd->txdsum = sum; /* NB: already little endian. */ 2460290630Savos 2461290630Savos xferlen = sizeof(*txd) + m->m_pkthdr.len; 2462290630Savos m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&txd[1]); 2463290630Savos 2464251538Srpaulo data->buflen = xferlen; 2465290630Savos data->m = m; 2466251538Srpaulo 2467251538Srpaulo STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next); 2468251538Srpaulo usbd_transfer_start(xfer); 2469251538Srpaulo} 2470251538Srpaulo 2471287197Sglebiusstatic int 2472287197Sglebiusurtwn_transmit(struct ieee80211com *ic, struct mbuf *m) 2473251538Srpaulo{ 2474287197Sglebius struct urtwn_softc *sc = ic->ic_softc; 2475287197Sglebius int error; 2476261863Srpaulo 2477261863Srpaulo URTWN_LOCK(sc); 2478287197Sglebius if ((sc->sc_flags & URTWN_RUNNING) == 0) { 2479287197Sglebius URTWN_UNLOCK(sc); 2480287197Sglebius return (ENXIO); 2481287197Sglebius } 2482287197Sglebius error = mbufq_enqueue(&sc->sc_snd, m); 2483287197Sglebius if (error) { 2484287197Sglebius URTWN_UNLOCK(sc); 2485287197Sglebius return (error); 2486287197Sglebius } 2487287197Sglebius urtwn_start(sc); 2488261863Srpaulo URTWN_UNLOCK(sc); 2489287197Sglebius 2490287197Sglebius return (0); 2491261863Srpaulo} 2492261863Srpaulo 2493261863Srpaulostatic void 2494287197Sglebiusurtwn_start(struct urtwn_softc *sc) 2495261863Srpaulo{ 2496251538Srpaulo struct ieee80211_node *ni; 2497251538Srpaulo struct mbuf *m; 2498251538Srpaulo struct urtwn_data *bf; 2499251538Srpaulo 2500261863Srpaulo URTWN_ASSERT_LOCKED(sc); 2501287197Sglebius while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { 2502251538Srpaulo bf = urtwn_getbuf(sc); 2503251538Srpaulo if (bf == NULL) { 2504287197Sglebius mbufq_prepend(&sc->sc_snd, m); 2505251538Srpaulo break; 2506251538Srpaulo } 2507251538Srpaulo ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 2508251538Srpaulo m->m_pkthdr.rcvif = NULL; 2509290630Savos if (urtwn_tx_data(sc, ni, m, bf) != 0) { 2510287197Sglebius if_inc_counter(ni->ni_vap->iv_ifp, 2511287197Sglebius IFCOUNTER_OERRORS, 1); 2512251538Srpaulo STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); 2513288353Sadrian m_freem(m); 2514251538Srpaulo ieee80211_free_node(ni); 2515251538Srpaulo break; 2516251538Srpaulo } 2517251538Srpaulo sc->sc_txtimer = 5; 2518251538Srpaulo callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); 2519251538Srpaulo } 2520251538Srpaulo} 2521251538Srpaulo 2522287197Sglebiusstatic void 2523287197Sglebiusurtwn_parent(struct ieee80211com *ic) 2524251538Srpaulo{ 2525286949Sadrian struct urtwn_softc *sc = ic->ic_softc; 2526251538Srpaulo 2527263153Skevlo URTWN_LOCK(sc); 2528287197Sglebius if (sc->sc_flags & URTWN_DETACHED) { 2529287197Sglebius URTWN_UNLOCK(sc); 2530287197Sglebius return; 2531287197Sglebius } 2532291698Savos URTWN_UNLOCK(sc); 2533291698Savos 2534287197Sglebius if (ic->ic_nrunning > 0) { 2535291698Savos if (urtwn_init(sc) != 0) { 2536291698Savos struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2537291698Savos if (vap != NULL) 2538291698Savos ieee80211_stop(vap); 2539291698Savos } else 2540291698Savos ieee80211_start_all(ic); 2541291698Savos } else 2542287197Sglebius urtwn_stop(sc); 2543251538Srpaulo} 2544251538Srpaulo 2545264912Skevlostatic __inline int 2546251538Srpaulourtwn_power_on(struct urtwn_softc *sc) 2547251538Srpaulo{ 2548264912Skevlo 2549264912Skevlo return sc->sc_power_on(sc); 2550264912Skevlo} 2551264912Skevlo 2552264912Skevlostatic int 2553264912Skevlourtwn_r92c_power_on(struct urtwn_softc *sc) 2554264912Skevlo{ 2555251538Srpaulo uint32_t reg; 2556291698Savos usb_error_t error; 2557251538Srpaulo int ntries; 2558251538Srpaulo 2559251538Srpaulo /* Wait for autoload done bit. */ 2560251538Srpaulo for (ntries = 0; ntries < 1000; ntries++) { 2561251538Srpaulo if (urtwn_read_1(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_PFM_ALDN) 2562251538Srpaulo break; 2563266472Shselasky urtwn_ms_delay(sc); 2564251538Srpaulo } 2565251538Srpaulo if (ntries == 1000) { 2566251538Srpaulo device_printf(sc->sc_dev, 2567251538Srpaulo "timeout waiting for chip autoload\n"); 2568251538Srpaulo return (ETIMEDOUT); 2569251538Srpaulo } 2570251538Srpaulo 2571251538Srpaulo /* Unlock ISO/CLK/Power control register. */ 2572291698Savos error = urtwn_write_1(sc, R92C_RSV_CTRL, 0); 2573291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2574291698Savos return (EIO); 2575251538Srpaulo /* Move SPS into PWM mode. */ 2576291698Savos error = urtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b); 2577291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2578291698Savos return (EIO); 2579266472Shselasky urtwn_ms_delay(sc); 2580251538Srpaulo 2581251538Srpaulo reg = urtwn_read_1(sc, R92C_LDOV12D_CTRL); 2582251538Srpaulo if (!(reg & R92C_LDOV12D_CTRL_LDV12_EN)) { 2583291698Savos error = urtwn_write_1(sc, R92C_LDOV12D_CTRL, 2584251538Srpaulo reg | R92C_LDOV12D_CTRL_LDV12_EN); 2585291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2586291698Savos return (EIO); 2587266472Shselasky urtwn_ms_delay(sc); 2588291698Savos error = urtwn_write_1(sc, R92C_SYS_ISO_CTRL, 2589251538Srpaulo urtwn_read_1(sc, R92C_SYS_ISO_CTRL) & 2590251538Srpaulo ~R92C_SYS_ISO_CTRL_MD2PP); 2591291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2592291698Savos return (EIO); 2593251538Srpaulo } 2594251538Srpaulo 2595251538Srpaulo /* Auto enable WLAN. */ 2596291698Savos error = urtwn_write_2(sc, R92C_APS_FSMCO, 2597251538Srpaulo urtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC); 2598291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2599291698Savos return (EIO); 2600251538Srpaulo for (ntries = 0; ntries < 1000; ntries++) { 2601262822Skevlo if (!(urtwn_read_2(sc, R92C_APS_FSMCO) & 2602262822Skevlo R92C_APS_FSMCO_APFM_ONMAC)) 2603251538Srpaulo break; 2604266472Shselasky urtwn_ms_delay(sc); 2605251538Srpaulo } 2606251538Srpaulo if (ntries == 1000) { 2607251538Srpaulo device_printf(sc->sc_dev, 2608251538Srpaulo "timeout waiting for MAC auto ON\n"); 2609251538Srpaulo return (ETIMEDOUT); 2610251538Srpaulo } 2611251538Srpaulo 2612251538Srpaulo /* Enable radio, GPIO and LED functions. */ 2613291698Savos error = urtwn_write_2(sc, R92C_APS_FSMCO, 2614251538Srpaulo R92C_APS_FSMCO_AFSM_HSUS | 2615251538Srpaulo R92C_APS_FSMCO_PDN_EN | 2616251538Srpaulo R92C_APS_FSMCO_PFM_ALDN); 2617291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2618291698Savos return (EIO); 2619251538Srpaulo /* Release RF digital isolation. */ 2620291698Savos error = urtwn_write_2(sc, R92C_SYS_ISO_CTRL, 2621251538Srpaulo urtwn_read_2(sc, R92C_SYS_ISO_CTRL) & ~R92C_SYS_ISO_CTRL_DIOR); 2622291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2623291698Savos return (EIO); 2624251538Srpaulo 2625251538Srpaulo /* Initialize MAC. */ 2626291698Savos error = urtwn_write_1(sc, R92C_APSD_CTRL, 2627251538Srpaulo urtwn_read_1(sc, R92C_APSD_CTRL) & ~R92C_APSD_CTRL_OFF); 2628291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2629291698Savos return (EIO); 2630251538Srpaulo for (ntries = 0; ntries < 200; ntries++) { 2631251538Srpaulo if (!(urtwn_read_1(sc, R92C_APSD_CTRL) & 2632251538Srpaulo R92C_APSD_CTRL_OFF_STATUS)) 2633251538Srpaulo break; 2634266472Shselasky urtwn_ms_delay(sc); 2635251538Srpaulo } 2636251538Srpaulo if (ntries == 200) { 2637251538Srpaulo device_printf(sc->sc_dev, 2638251538Srpaulo "timeout waiting for MAC initialization\n"); 2639251538Srpaulo return (ETIMEDOUT); 2640251538Srpaulo } 2641251538Srpaulo 2642251538Srpaulo /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ 2643251538Srpaulo reg = urtwn_read_2(sc, R92C_CR); 2644251538Srpaulo reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | 2645251538Srpaulo R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | 2646251538Srpaulo R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN | 2647251538Srpaulo R92C_CR_ENSEC; 2648291698Savos error = urtwn_write_2(sc, R92C_CR, reg); 2649291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2650291698Savos return (EIO); 2651251538Srpaulo 2652291698Savos error = urtwn_write_1(sc, 0xfe10, 0x19); 2653291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2654291698Savos return (EIO); 2655251538Srpaulo return (0); 2656251538Srpaulo} 2657251538Srpaulo 2658251538Srpaulostatic int 2659264912Skevlourtwn_r88e_power_on(struct urtwn_softc *sc) 2660264912Skevlo{ 2661264912Skevlo uint32_t reg; 2662291698Savos usb_error_t error; 2663264912Skevlo int ntries; 2664264912Skevlo 2665264912Skevlo /* Wait for power ready bit. */ 2666264912Skevlo for (ntries = 0; ntries < 5000; ntries++) { 2667281918Skevlo if (urtwn_read_4(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_SUS_HOST) 2668264912Skevlo break; 2669266472Shselasky urtwn_ms_delay(sc); 2670264912Skevlo } 2671264912Skevlo if (ntries == 5000) { 2672264912Skevlo device_printf(sc->sc_dev, 2673264912Skevlo "timeout waiting for chip power up\n"); 2674264912Skevlo return (ETIMEDOUT); 2675264912Skevlo } 2676264912Skevlo 2677264912Skevlo /* Reset BB. */ 2678291698Savos error = urtwn_write_1(sc, R92C_SYS_FUNC_EN, 2679264912Skevlo urtwn_read_1(sc, R92C_SYS_FUNC_EN) & ~(R92C_SYS_FUNC_EN_BBRSTB | 2680264912Skevlo R92C_SYS_FUNC_EN_BB_GLB_RST)); 2681291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2682291698Savos return (EIO); 2683264912Skevlo 2684291698Savos error = urtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 2, 2685281918Skevlo urtwn_read_1(sc, R92C_AFE_XTAL_CTRL + 2) | 0x80); 2686291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2687291698Savos return (EIO); 2688264912Skevlo 2689264912Skevlo /* Disable HWPDN. */ 2690291698Savos error = urtwn_write_2(sc, R92C_APS_FSMCO, 2691281918Skevlo urtwn_read_2(sc, R92C_APS_FSMCO) & ~R92C_APS_FSMCO_APDM_HPDN); 2692291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2693291698Savos return (EIO); 2694264912Skevlo 2695264912Skevlo /* Disable WL suspend. */ 2696291698Savos error = urtwn_write_2(sc, R92C_APS_FSMCO, 2697281918Skevlo urtwn_read_2(sc, R92C_APS_FSMCO) & 2698281918Skevlo ~(R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_AFSM_PCIE)); 2699291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2700291698Savos return (EIO); 2701264912Skevlo 2702291698Savos error = urtwn_write_2(sc, R92C_APS_FSMCO, 2703281918Skevlo urtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC); 2704291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2705291698Savos return (EIO); 2706264912Skevlo for (ntries = 0; ntries < 5000; ntries++) { 2707281918Skevlo if (!(urtwn_read_2(sc, R92C_APS_FSMCO) & 2708281918Skevlo R92C_APS_FSMCO_APFM_ONMAC)) 2709264912Skevlo break; 2710266472Shselasky urtwn_ms_delay(sc); 2711264912Skevlo } 2712264912Skevlo if (ntries == 5000) 2713264912Skevlo return (ETIMEDOUT); 2714264912Skevlo 2715264912Skevlo /* Enable LDO normal mode. */ 2716291698Savos error = urtwn_write_1(sc, R92C_LPLDO_CTRL, 2717281918Skevlo urtwn_read_1(sc, R92C_LPLDO_CTRL) & ~0x10); 2718291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2719291698Savos return (EIO); 2720264912Skevlo 2721264912Skevlo /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ 2722291698Savos error = urtwn_write_2(sc, R92C_CR, 0); 2723291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2724291698Savos return (EIO); 2725264912Skevlo reg = urtwn_read_2(sc, R92C_CR); 2726264912Skevlo reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | 2727264912Skevlo R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | 2728264912Skevlo R92C_CR_SCHEDULE_EN | R92C_CR_ENSEC | R92C_CR_CALTMR_EN; 2729291698Savos error = urtwn_write_2(sc, R92C_CR, reg); 2730291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2731291698Savos return (EIO); 2732264912Skevlo 2733264912Skevlo return (0); 2734264912Skevlo} 2735264912Skevlo 2736264912Skevlostatic int 2737251538Srpaulourtwn_llt_init(struct urtwn_softc *sc) 2738251538Srpaulo{ 2739264912Skevlo int i, error, page_count, pktbuf_count; 2740251538Srpaulo 2741264912Skevlo page_count = (sc->chip & URTWN_CHIP_88E) ? 2742264912Skevlo R88E_TX_PAGE_COUNT : R92C_TX_PAGE_COUNT; 2743264912Skevlo pktbuf_count = (sc->chip & URTWN_CHIP_88E) ? 2744264912Skevlo R88E_TXPKTBUF_COUNT : R92C_TXPKTBUF_COUNT; 2745264912Skevlo 2746264912Skevlo /* Reserve pages [0; page_count]. */ 2747264912Skevlo for (i = 0; i < page_count; i++) { 2748251538Srpaulo if ((error = urtwn_llt_write(sc, i, i + 1)) != 0) 2749251538Srpaulo return (error); 2750251538Srpaulo } 2751251538Srpaulo /* NB: 0xff indicates end-of-list. */ 2752251538Srpaulo if ((error = urtwn_llt_write(sc, i, 0xff)) != 0) 2753251538Srpaulo return (error); 2754251538Srpaulo /* 2755264912Skevlo * Use pages [page_count + 1; pktbuf_count - 1] 2756251538Srpaulo * as ring buffer. 2757251538Srpaulo */ 2758264912Skevlo for (++i; i < pktbuf_count - 1; i++) { 2759251538Srpaulo if ((error = urtwn_llt_write(sc, i, i + 1)) != 0) 2760251538Srpaulo return (error); 2761251538Srpaulo } 2762251538Srpaulo /* Make the last page point to the beginning of the ring buffer. */ 2763264912Skevlo error = urtwn_llt_write(sc, i, page_count + 1); 2764251538Srpaulo return (error); 2765251538Srpaulo} 2766251538Srpaulo 2767251538Srpaulostatic void 2768251538Srpaulourtwn_fw_reset(struct urtwn_softc *sc) 2769251538Srpaulo{ 2770251538Srpaulo uint16_t reg; 2771251538Srpaulo int ntries; 2772251538Srpaulo 2773251538Srpaulo /* Tell 8051 to reset itself. */ 2774251538Srpaulo urtwn_write_1(sc, R92C_HMETFR + 3, 0x20); 2775251538Srpaulo 2776251538Srpaulo /* Wait until 8051 resets by itself. */ 2777251538Srpaulo for (ntries = 0; ntries < 100; ntries++) { 2778251538Srpaulo reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN); 2779251538Srpaulo if (!(reg & R92C_SYS_FUNC_EN_CPUEN)) 2780251538Srpaulo return; 2781266472Shselasky urtwn_ms_delay(sc); 2782251538Srpaulo } 2783251538Srpaulo /* Force 8051 reset. */ 2784251538Srpaulo urtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN); 2785251538Srpaulo} 2786251538Srpaulo 2787264912Skevlostatic void 2788264912Skevlourtwn_r88e_fw_reset(struct urtwn_softc *sc) 2789264912Skevlo{ 2790264912Skevlo uint16_t reg; 2791264912Skevlo 2792264912Skevlo reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN); 2793264912Skevlo urtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN); 2794264912Skevlo urtwn_write_2(sc, R92C_SYS_FUNC_EN, reg | R92C_SYS_FUNC_EN_CPUEN); 2795264912Skevlo} 2796264912Skevlo 2797251538Srpaulostatic int 2798251538Srpaulourtwn_fw_loadpage(struct urtwn_softc *sc, int page, const uint8_t *buf, int len) 2799251538Srpaulo{ 2800251538Srpaulo uint32_t reg; 2801291698Savos usb_error_t error = USB_ERR_NORMAL_COMPLETION; 2802291698Savos int off, mlen; 2803251538Srpaulo 2804251538Srpaulo reg = urtwn_read_4(sc, R92C_MCUFWDL); 2805251538Srpaulo reg = RW(reg, R92C_MCUFWDL_PAGE, page); 2806251538Srpaulo urtwn_write_4(sc, R92C_MCUFWDL, reg); 2807251538Srpaulo 2808251538Srpaulo off = R92C_FW_START_ADDR; 2809251538Srpaulo while (len > 0) { 2810251538Srpaulo if (len > 196) 2811251538Srpaulo mlen = 196; 2812251538Srpaulo else if (len > 4) 2813251538Srpaulo mlen = 4; 2814251538Srpaulo else 2815251538Srpaulo mlen = 1; 2816251538Srpaulo /* XXX fix this deconst */ 2817281069Srpaulo error = urtwn_write_region_1(sc, off, 2818251538Srpaulo __DECONST(uint8_t *, buf), mlen); 2819291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2820251538Srpaulo break; 2821251538Srpaulo off += mlen; 2822251538Srpaulo buf += mlen; 2823251538Srpaulo len -= mlen; 2824251538Srpaulo } 2825251538Srpaulo return (error); 2826251538Srpaulo} 2827251538Srpaulo 2828251538Srpaulostatic int 2829251538Srpaulourtwn_load_firmware(struct urtwn_softc *sc) 2830251538Srpaulo{ 2831251538Srpaulo const struct firmware *fw; 2832251538Srpaulo const struct r92c_fw_hdr *hdr; 2833251538Srpaulo const char *imagename; 2834251538Srpaulo const u_char *ptr; 2835251538Srpaulo size_t len; 2836251538Srpaulo uint32_t reg; 2837251538Srpaulo int mlen, ntries, page, error; 2838251538Srpaulo 2839264864Skevlo URTWN_UNLOCK(sc); 2840251538Srpaulo /* Read firmware image from the filesystem. */ 2841264912Skevlo if (sc->chip & URTWN_CHIP_88E) 2842264912Skevlo imagename = "urtwn-rtl8188eufw"; 2843264912Skevlo else if ((sc->chip & (URTWN_CHIP_UMC_A_CUT | URTWN_CHIP_92C)) == 2844264912Skevlo URTWN_CHIP_UMC_A_CUT) 2845251538Srpaulo imagename = "urtwn-rtl8192cfwU"; 2846251538Srpaulo else 2847251538Srpaulo imagename = "urtwn-rtl8192cfwT"; 2848251538Srpaulo 2849251538Srpaulo fw = firmware_get(imagename); 2850264864Skevlo URTWN_LOCK(sc); 2851251538Srpaulo if (fw == NULL) { 2852251538Srpaulo device_printf(sc->sc_dev, 2853251538Srpaulo "failed loadfirmware of file %s\n", imagename); 2854251538Srpaulo return (ENOENT); 2855251538Srpaulo } 2856251538Srpaulo 2857251538Srpaulo len = fw->datasize; 2858251538Srpaulo 2859251538Srpaulo if (len < sizeof(*hdr)) { 2860251538Srpaulo device_printf(sc->sc_dev, "firmware too short\n"); 2861251538Srpaulo error = EINVAL; 2862251538Srpaulo goto fail; 2863251538Srpaulo } 2864251538Srpaulo ptr = fw->data; 2865251538Srpaulo hdr = (const struct r92c_fw_hdr *)ptr; 2866251538Srpaulo /* Check if there is a valid FW header and skip it. */ 2867251538Srpaulo if ((le16toh(hdr->signature) >> 4) == 0x88c || 2868264912Skevlo (le16toh(hdr->signature) >> 4) == 0x88e || 2869251538Srpaulo (le16toh(hdr->signature) >> 4) == 0x92c) { 2870251538Srpaulo DPRINTF("FW V%d.%d %02d-%02d %02d:%02d\n", 2871251538Srpaulo le16toh(hdr->version), le16toh(hdr->subversion), 2872251538Srpaulo hdr->month, hdr->date, hdr->hour, hdr->minute); 2873251538Srpaulo ptr += sizeof(*hdr); 2874251538Srpaulo len -= sizeof(*hdr); 2875251538Srpaulo } 2876251538Srpaulo 2877264912Skevlo if (urtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) { 2878264912Skevlo if (sc->chip & URTWN_CHIP_88E) 2879264912Skevlo urtwn_r88e_fw_reset(sc); 2880264912Skevlo else 2881264912Skevlo urtwn_fw_reset(sc); 2882251538Srpaulo urtwn_write_1(sc, R92C_MCUFWDL, 0); 2883251538Srpaulo } 2884264912Skevlo 2885268487Skevlo if (!(sc->chip & URTWN_CHIP_88E)) { 2886268487Skevlo urtwn_write_2(sc, R92C_SYS_FUNC_EN, 2887268487Skevlo urtwn_read_2(sc, R92C_SYS_FUNC_EN) | 2888268487Skevlo R92C_SYS_FUNC_EN_CPUEN); 2889268487Skevlo } 2890251538Srpaulo urtwn_write_1(sc, R92C_MCUFWDL, 2891251538Srpaulo urtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_EN); 2892251538Srpaulo urtwn_write_1(sc, R92C_MCUFWDL + 2, 2893251538Srpaulo urtwn_read_1(sc, R92C_MCUFWDL + 2) & ~0x08); 2894251538Srpaulo 2895263154Skevlo /* Reset the FWDL checksum. */ 2896263154Skevlo urtwn_write_1(sc, R92C_MCUFWDL, 2897263154Skevlo urtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_CHKSUM_RPT); 2898263154Skevlo 2899251538Srpaulo for (page = 0; len > 0; page++) { 2900251538Srpaulo mlen = min(len, R92C_FW_PAGE_SIZE); 2901251538Srpaulo error = urtwn_fw_loadpage(sc, page, ptr, mlen); 2902251538Srpaulo if (error != 0) { 2903251538Srpaulo device_printf(sc->sc_dev, 2904251538Srpaulo "could not load firmware page\n"); 2905251538Srpaulo goto fail; 2906251538Srpaulo } 2907251538Srpaulo ptr += mlen; 2908251538Srpaulo len -= mlen; 2909251538Srpaulo } 2910251538Srpaulo urtwn_write_1(sc, R92C_MCUFWDL, 2911251538Srpaulo urtwn_read_1(sc, R92C_MCUFWDL) & ~R92C_MCUFWDL_EN); 2912251538Srpaulo urtwn_write_1(sc, R92C_MCUFWDL + 1, 0); 2913251538Srpaulo 2914251538Srpaulo /* Wait for checksum report. */ 2915251538Srpaulo for (ntries = 0; ntries < 1000; ntries++) { 2916251538Srpaulo if (urtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_CHKSUM_RPT) 2917251538Srpaulo break; 2918266472Shselasky urtwn_ms_delay(sc); 2919251538Srpaulo } 2920251538Srpaulo if (ntries == 1000) { 2921251538Srpaulo device_printf(sc->sc_dev, 2922251538Srpaulo "timeout waiting for checksum report\n"); 2923251538Srpaulo error = ETIMEDOUT; 2924251538Srpaulo goto fail; 2925251538Srpaulo } 2926251538Srpaulo 2927251538Srpaulo reg = urtwn_read_4(sc, R92C_MCUFWDL); 2928251538Srpaulo reg = (reg & ~R92C_MCUFWDL_WINTINI_RDY) | R92C_MCUFWDL_RDY; 2929251538Srpaulo urtwn_write_4(sc, R92C_MCUFWDL, reg); 2930264912Skevlo if (sc->chip & URTWN_CHIP_88E) 2931264912Skevlo urtwn_r88e_fw_reset(sc); 2932251538Srpaulo /* Wait for firmware readiness. */ 2933251538Srpaulo for (ntries = 0; ntries < 1000; ntries++) { 2934251538Srpaulo if (urtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_WINTINI_RDY) 2935251538Srpaulo break; 2936266472Shselasky urtwn_ms_delay(sc); 2937251538Srpaulo } 2938251538Srpaulo if (ntries == 1000) { 2939251538Srpaulo device_printf(sc->sc_dev, 2940251538Srpaulo "timeout waiting for firmware readiness\n"); 2941251538Srpaulo error = ETIMEDOUT; 2942251538Srpaulo goto fail; 2943251538Srpaulo } 2944251538Srpaulofail: 2945251538Srpaulo firmware_put(fw, FIRMWARE_UNLOAD); 2946251538Srpaulo return (error); 2947251538Srpaulo} 2948251538Srpaulo 2949291902Skevlostatic int 2950251538Srpaulourtwn_dma_init(struct urtwn_softc *sc) 2951251538Srpaulo{ 2952291902Skevlo struct usb_endpoint *ep, *ep_end; 2953291698Savos usb_error_t usb_err; 2954291902Skevlo uint32_t reg; 2955291902Skevlo int hashq, hasnq, haslq, nqueues, ntx; 2956291902Skevlo int error, pagecount, npubqpages, nqpages, nrempages, tx_boundary; 2957281069Srpaulo 2958291695Savos /* Initialize LLT table. */ 2959291695Savos error = urtwn_llt_init(sc); 2960291695Savos if (error != 0) 2961291695Savos return (error); 2962291695Savos 2963291902Skevlo /* Determine the number of bulk-out pipes. */ 2964291902Skevlo ntx = 0; 2965291902Skevlo ep = sc->sc_udev->endpoints; 2966291902Skevlo ep_end = sc->sc_udev->endpoints + sc->sc_udev->endpoints_max; 2967291902Skevlo for (; ep != ep_end; ep++) { 2968291902Skevlo if ((ep->edesc == NULL) || 2969291902Skevlo (ep->iface_index != sc->sc_iface_index)) 2970291902Skevlo continue; 2971291902Skevlo if (UE_GET_DIR(ep->edesc->bEndpointAddress) == UE_DIR_OUT) 2972291902Skevlo ntx++; 2973291902Skevlo } 2974291902Skevlo if (ntx == 0) { 2975291902Skevlo device_printf(sc->sc_dev, 2976291902Skevlo "%d: invalid number of Tx bulk pipes\n", ntx); 2977291698Savos return (EIO); 2978291902Skevlo } 2979291695Savos 2980251538Srpaulo /* Get Tx queues to USB endpoints mapping. */ 2981291902Skevlo hashq = hasnq = haslq = nqueues = 0; 2982291902Skevlo switch (ntx) { 2983291902Skevlo case 1: hashq = 1; break; 2984291902Skevlo case 2: hashq = hasnq = 1; break; 2985291902Skevlo case 3: case 4: hashq = hasnq = haslq = 1; break; 2986291902Skevlo } 2987251538Srpaulo nqueues = hashq + hasnq + haslq; 2988251538Srpaulo if (nqueues == 0) 2989251538Srpaulo return (EIO); 2990251538Srpaulo 2991291902Skevlo npubqpages = nqpages = nrempages = pagecount = 0; 2992291902Skevlo if (sc->chip & URTWN_CHIP_88E) 2993291902Skevlo tx_boundary = R88E_TX_PAGE_BOUNDARY; 2994291902Skevlo else { 2995291902Skevlo pagecount = R92C_TX_PAGE_COUNT; 2996291902Skevlo npubqpages = R92C_PUBQ_NPAGES; 2997291902Skevlo tx_boundary = R92C_TX_PAGE_BOUNDARY; 2998291902Skevlo } 2999291902Skevlo 3000251538Srpaulo /* Set number of pages for normal priority queue. */ 3001291902Skevlo if (sc->chip & URTWN_CHIP_88E) { 3002291902Skevlo usb_err = urtwn_write_2(sc, R92C_RQPN_NPQ, 0xd); 3003291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 3004291902Skevlo return (EIO); 3005291902Skevlo usb_err = urtwn_write_4(sc, R92C_RQPN, 0x808e000d); 3006291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 3007291902Skevlo return (EIO); 3008291902Skevlo } else { 3009291902Skevlo /* Get the number of pages for each queue. */ 3010291902Skevlo nqpages = (pagecount - npubqpages) / nqueues; 3011291902Skevlo /* 3012291902Skevlo * The remaining pages are assigned to the high priority 3013291902Skevlo * queue. 3014291902Skevlo */ 3015291902Skevlo nrempages = (pagecount - npubqpages) % nqueues; 3016291902Skevlo usb_err = urtwn_write_1(sc, R92C_RQPN_NPQ, hasnq ? nqpages : 0); 3017291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 3018291902Skevlo return (EIO); 3019291902Skevlo usb_err = urtwn_write_4(sc, R92C_RQPN, 3020291902Skevlo /* Set number of pages for public queue. */ 3021291902Skevlo SM(R92C_RQPN_PUBQ, npubqpages) | 3022291902Skevlo /* Set number of pages for high priority queue. */ 3023291902Skevlo SM(R92C_RQPN_HPQ, hashq ? nqpages + nrempages : 0) | 3024291902Skevlo /* Set number of pages for low priority queue. */ 3025291902Skevlo SM(R92C_RQPN_LPQ, haslq ? nqpages : 0) | 3026291902Skevlo /* Load values. */ 3027291902Skevlo R92C_RQPN_LD); 3028291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 3029291902Skevlo return (EIO); 3030291902Skevlo } 3031251538Srpaulo 3032291902Skevlo usb_err = urtwn_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, tx_boundary); 3033291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 3034291698Savos return (EIO); 3035291902Skevlo usb_err = urtwn_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, tx_boundary); 3036291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 3037291698Savos return (EIO); 3038291902Skevlo usb_err = urtwn_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD, tx_boundary); 3039291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 3040291698Savos return (EIO); 3041291902Skevlo usb_err = urtwn_write_1(sc, R92C_TRXFF_BNDY, tx_boundary); 3042291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 3043291698Savos return (EIO); 3044291902Skevlo usb_err = urtwn_write_1(sc, R92C_TDECTRL + 1, tx_boundary); 3045291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 3046291698Savos return (EIO); 3047251538Srpaulo 3048251538Srpaulo /* Set queue to USB pipe mapping. */ 3049251538Srpaulo reg = urtwn_read_2(sc, R92C_TRXDMA_CTRL); 3050251538Srpaulo reg &= ~R92C_TRXDMA_CTRL_QMAP_M; 3051251538Srpaulo if (nqueues == 1) { 3052251538Srpaulo if (hashq) 3053251538Srpaulo reg |= R92C_TRXDMA_CTRL_QMAP_HQ; 3054251538Srpaulo else if (hasnq) 3055251538Srpaulo reg |= R92C_TRXDMA_CTRL_QMAP_NQ; 3056251538Srpaulo else 3057251538Srpaulo reg |= R92C_TRXDMA_CTRL_QMAP_LQ; 3058251538Srpaulo } else if (nqueues == 2) { 3059292056Skevlo /* 3060292056Skevlo * All 2-endpoints configs have high and normal 3061292056Skevlo * priority queues. 3062292056Skevlo */ 3063292056Skevlo reg |= R92C_TRXDMA_CTRL_QMAP_HQ_NQ; 3064251538Srpaulo } else 3065251538Srpaulo reg |= R92C_TRXDMA_CTRL_QMAP_3EP; 3066291902Skevlo usb_err = urtwn_write_2(sc, R92C_TRXDMA_CTRL, reg); 3067291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 3068291698Savos return (EIO); 3069251538Srpaulo 3070251538Srpaulo /* Set Tx/Rx transfer page boundary. */ 3071291902Skevlo usb_err = urtwn_write_2(sc, R92C_TRXFF_BNDY + 2, 3072291902Skevlo (sc->chip & URTWN_CHIP_88E) ? 0x23ff : 0x27ff); 3073291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 3074291698Savos return (EIO); 3075251538Srpaulo 3076291902Skevlo /* Set Tx/Rx transfer page size. */ 3077291902Skevlo usb_err = urtwn_write_1(sc, R92C_PBP, 3078291902Skevlo SM(R92C_PBP_PSRX, R92C_PBP_128) | 3079291902Skevlo SM(R92C_PBP_PSTX, R92C_PBP_128)); 3080291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 3081264912Skevlo return (EIO); 3082264912Skevlo 3083264912Skevlo return (0); 3084264912Skevlo} 3085264912Skevlo 3086291698Savosstatic int 3087251538Srpaulourtwn_mac_init(struct urtwn_softc *sc) 3088251538Srpaulo{ 3089291698Savos usb_error_t error; 3090251538Srpaulo int i; 3091251538Srpaulo 3092251538Srpaulo /* Write MAC initialization values. */ 3093264912Skevlo if (sc->chip & URTWN_CHIP_88E) { 3094264912Skevlo for (i = 0; i < nitems(rtl8188eu_mac); i++) { 3095291698Savos error = urtwn_write_1(sc, rtl8188eu_mac[i].reg, 3096264912Skevlo rtl8188eu_mac[i].val); 3097291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 3098291698Savos return (EIO); 3099264912Skevlo } 3100264912Skevlo urtwn_write_1(sc, R92C_MAX_AGGR_NUM, 0x07); 3101264912Skevlo } else { 3102264912Skevlo for (i = 0; i < nitems(rtl8192cu_mac); i++) 3103291698Savos error = urtwn_write_1(sc, rtl8192cu_mac[i].reg, 3104264912Skevlo rtl8192cu_mac[i].val); 3105291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 3106291698Savos return (EIO); 3107264912Skevlo } 3108291698Savos 3109291698Savos return (0); 3110251538Srpaulo} 3111251538Srpaulo 3112251538Srpaulostatic void 3113251538Srpaulourtwn_bb_init(struct urtwn_softc *sc) 3114251538Srpaulo{ 3115251538Srpaulo const struct urtwn_bb_prog *prog; 3116251538Srpaulo uint32_t reg; 3117264912Skevlo uint8_t crystalcap; 3118251538Srpaulo int i; 3119251538Srpaulo 3120251538Srpaulo /* Enable BB and RF. */ 3121251538Srpaulo urtwn_write_2(sc, R92C_SYS_FUNC_EN, 3122251538Srpaulo urtwn_read_2(sc, R92C_SYS_FUNC_EN) | 3123251538Srpaulo R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST | 3124251538Srpaulo R92C_SYS_FUNC_EN_DIO_RF); 3125251538Srpaulo 3126264912Skevlo if (!(sc->chip & URTWN_CHIP_88E)) 3127264912Skevlo urtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0xdb83); 3128251538Srpaulo 3129251538Srpaulo urtwn_write_1(sc, R92C_RF_CTRL, 3130251538Srpaulo R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB); 3131251538Srpaulo urtwn_write_1(sc, R92C_SYS_FUNC_EN, 3132251538Srpaulo R92C_SYS_FUNC_EN_USBA | R92C_SYS_FUNC_EN_USBD | 3133251538Srpaulo R92C_SYS_FUNC_EN_BB_GLB_RST | R92C_SYS_FUNC_EN_BBRSTB); 3134251538Srpaulo 3135264912Skevlo if (!(sc->chip & URTWN_CHIP_88E)) { 3136264912Skevlo urtwn_write_1(sc, R92C_LDOHCI12_CTRL, 0x0f); 3137264912Skevlo urtwn_write_1(sc, 0x15, 0xe9); 3138264912Skevlo urtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80); 3139264912Skevlo } 3140251538Srpaulo 3141251538Srpaulo /* Select BB programming based on board type. */ 3142264912Skevlo if (sc->chip & URTWN_CHIP_88E) 3143264912Skevlo prog = &rtl8188eu_bb_prog; 3144264912Skevlo else if (!(sc->chip & URTWN_CHIP_92C)) { 3145251538Srpaulo if (sc->board_type == R92C_BOARD_TYPE_MINICARD) 3146251538Srpaulo prog = &rtl8188ce_bb_prog; 3147251538Srpaulo else if (sc->board_type == R92C_BOARD_TYPE_HIGHPA) 3148251538Srpaulo prog = &rtl8188ru_bb_prog; 3149251538Srpaulo else 3150251538Srpaulo prog = &rtl8188cu_bb_prog; 3151251538Srpaulo } else { 3152251538Srpaulo if (sc->board_type == R92C_BOARD_TYPE_MINICARD) 3153251538Srpaulo prog = &rtl8192ce_bb_prog; 3154251538Srpaulo else 3155251538Srpaulo prog = &rtl8192cu_bb_prog; 3156251538Srpaulo } 3157251538Srpaulo /* Write BB initialization values. */ 3158251538Srpaulo for (i = 0; i < prog->count; i++) { 3159251538Srpaulo urtwn_bb_write(sc, prog->regs[i], prog->vals[i]); 3160266472Shselasky urtwn_ms_delay(sc); 3161251538Srpaulo } 3162251538Srpaulo 3163251538Srpaulo if (sc->chip & URTWN_CHIP_92C_1T2R) { 3164251538Srpaulo /* 8192C 1T only configuration. */ 3165251538Srpaulo reg = urtwn_bb_read(sc, R92C_FPGA0_TXINFO); 3166251538Srpaulo reg = (reg & ~0x00000003) | 0x2; 3167251538Srpaulo urtwn_bb_write(sc, R92C_FPGA0_TXINFO, reg); 3168251538Srpaulo 3169251538Srpaulo reg = urtwn_bb_read(sc, R92C_FPGA1_TXINFO); 3170251538Srpaulo reg = (reg & ~0x00300033) | 0x00200022; 3171251538Srpaulo urtwn_bb_write(sc, R92C_FPGA1_TXINFO, reg); 3172251538Srpaulo 3173251538Srpaulo reg = urtwn_bb_read(sc, R92C_CCK0_AFESETTING); 3174251538Srpaulo reg = (reg & ~0xff000000) | 0x45 << 24; 3175251538Srpaulo urtwn_bb_write(sc, R92C_CCK0_AFESETTING, reg); 3176251538Srpaulo 3177251538Srpaulo reg = urtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA); 3178251538Srpaulo reg = (reg & ~0x000000ff) | 0x23; 3179251538Srpaulo urtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, reg); 3180251538Srpaulo 3181251538Srpaulo reg = urtwn_bb_read(sc, R92C_OFDM0_AGCPARAM1); 3182251538Srpaulo reg = (reg & ~0x00000030) | 1 << 4; 3183251538Srpaulo urtwn_bb_write(sc, R92C_OFDM0_AGCPARAM1, reg); 3184251538Srpaulo 3185251538Srpaulo reg = urtwn_bb_read(sc, 0xe74); 3186251538Srpaulo reg = (reg & ~0x0c000000) | 2 << 26; 3187251538Srpaulo urtwn_bb_write(sc, 0xe74, reg); 3188251538Srpaulo reg = urtwn_bb_read(sc, 0xe78); 3189251538Srpaulo reg = (reg & ~0x0c000000) | 2 << 26; 3190251538Srpaulo urtwn_bb_write(sc, 0xe78, reg); 3191251538Srpaulo reg = urtwn_bb_read(sc, 0xe7c); 3192251538Srpaulo reg = (reg & ~0x0c000000) | 2 << 26; 3193251538Srpaulo urtwn_bb_write(sc, 0xe7c, reg); 3194251538Srpaulo reg = urtwn_bb_read(sc, 0xe80); 3195251538Srpaulo reg = (reg & ~0x0c000000) | 2 << 26; 3196251538Srpaulo urtwn_bb_write(sc, 0xe80, reg); 3197251538Srpaulo reg = urtwn_bb_read(sc, 0xe88); 3198251538Srpaulo reg = (reg & ~0x0c000000) | 2 << 26; 3199251538Srpaulo urtwn_bb_write(sc, 0xe88, reg); 3200251538Srpaulo } 3201251538Srpaulo 3202251538Srpaulo /* Write AGC values. */ 3203251538Srpaulo for (i = 0; i < prog->agccount; i++) { 3204251538Srpaulo urtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE, 3205251538Srpaulo prog->agcvals[i]); 3206266472Shselasky urtwn_ms_delay(sc); 3207251538Srpaulo } 3208251538Srpaulo 3209264912Skevlo if (sc->chip & URTWN_CHIP_88E) { 3210264912Skevlo urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x69553422); 3211266472Shselasky urtwn_ms_delay(sc); 3212264912Skevlo urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x69553420); 3213266472Shselasky urtwn_ms_delay(sc); 3214264912Skevlo 3215291264Savos crystalcap = sc->rom.r88e_rom[0xb9]; 3216264912Skevlo if (crystalcap == 0xff) 3217264912Skevlo crystalcap = 0x20; 3218264912Skevlo crystalcap &= 0x3f; 3219264912Skevlo reg = urtwn_bb_read(sc, R92C_AFE_XTAL_CTRL); 3220264912Skevlo urtwn_bb_write(sc, R92C_AFE_XTAL_CTRL, 3221264912Skevlo RW(reg, R92C_AFE_XTAL_CTRL_ADDR, 3222264912Skevlo crystalcap | crystalcap << 6)); 3223264912Skevlo } else { 3224264912Skevlo if (urtwn_bb_read(sc, R92C_HSSI_PARAM2(0)) & 3225264912Skevlo R92C_HSSI_PARAM2_CCK_HIPWR) 3226264912Skevlo sc->sc_flags |= URTWN_FLAG_CCK_HIPWR; 3227264912Skevlo } 3228251538Srpaulo} 3229251538Srpaulo 3230289066Skevlostatic void 3231251538Srpaulourtwn_rf_init(struct urtwn_softc *sc) 3232251538Srpaulo{ 3233251538Srpaulo const struct urtwn_rf_prog *prog; 3234251538Srpaulo uint32_t reg, type; 3235251538Srpaulo int i, j, idx, off; 3236251538Srpaulo 3237251538Srpaulo /* Select RF programming based on board type. */ 3238264912Skevlo if (sc->chip & URTWN_CHIP_88E) 3239264912Skevlo prog = rtl8188eu_rf_prog; 3240264912Skevlo else if (!(sc->chip & URTWN_CHIP_92C)) { 3241251538Srpaulo if (sc->board_type == R92C_BOARD_TYPE_MINICARD) 3242251538Srpaulo prog = rtl8188ce_rf_prog; 3243251538Srpaulo else if (sc->board_type == R92C_BOARD_TYPE_HIGHPA) 3244251538Srpaulo prog = rtl8188ru_rf_prog; 3245251538Srpaulo else 3246251538Srpaulo prog = rtl8188cu_rf_prog; 3247251538Srpaulo } else 3248251538Srpaulo prog = rtl8192ce_rf_prog; 3249251538Srpaulo 3250251538Srpaulo for (i = 0; i < sc->nrxchains; i++) { 3251251538Srpaulo /* Save RF_ENV control type. */ 3252251538Srpaulo idx = i / 2; 3253251538Srpaulo off = (i % 2) * 16; 3254251538Srpaulo reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx)); 3255251538Srpaulo type = (reg >> off) & 0x10; 3256251538Srpaulo 3257251538Srpaulo /* Set RF_ENV enable. */ 3258251538Srpaulo reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i)); 3259251538Srpaulo reg |= 0x100000; 3260251538Srpaulo urtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg); 3261266472Shselasky urtwn_ms_delay(sc); 3262251538Srpaulo /* Set RF_ENV output high. */ 3263251538Srpaulo reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i)); 3264251538Srpaulo reg |= 0x10; 3265251538Srpaulo urtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg); 3266266472Shselasky urtwn_ms_delay(sc); 3267251538Srpaulo /* Set address and data lengths of RF registers. */ 3268251538Srpaulo reg = urtwn_bb_read(sc, R92C_HSSI_PARAM2(i)); 3269251538Srpaulo reg &= ~R92C_HSSI_PARAM2_ADDR_LENGTH; 3270251538Srpaulo urtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg); 3271266472Shselasky urtwn_ms_delay(sc); 3272251538Srpaulo reg = urtwn_bb_read(sc, R92C_HSSI_PARAM2(i)); 3273251538Srpaulo reg &= ~R92C_HSSI_PARAM2_DATA_LENGTH; 3274251538Srpaulo urtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg); 3275266472Shselasky urtwn_ms_delay(sc); 3276251538Srpaulo 3277251538Srpaulo /* Write RF initialization values for this chain. */ 3278251538Srpaulo for (j = 0; j < prog[i].count; j++) { 3279251538Srpaulo if (prog[i].regs[j] >= 0xf9 && 3280251538Srpaulo prog[i].regs[j] <= 0xfe) { 3281251538Srpaulo /* 3282251538Srpaulo * These are fake RF registers offsets that 3283251538Srpaulo * indicate a delay is required. 3284251538Srpaulo */ 3285266472Shselasky usb_pause_mtx(&sc->sc_mtx, hz / 20); /* 50ms */ 3286251538Srpaulo continue; 3287251538Srpaulo } 3288251538Srpaulo urtwn_rf_write(sc, i, prog[i].regs[j], 3289251538Srpaulo prog[i].vals[j]); 3290266472Shselasky urtwn_ms_delay(sc); 3291251538Srpaulo } 3292251538Srpaulo 3293251538Srpaulo /* Restore RF_ENV control type. */ 3294251538Srpaulo reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx)); 3295251538Srpaulo reg &= ~(0x10 << off) | (type << off); 3296251538Srpaulo urtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(idx), reg); 3297251538Srpaulo 3298251538Srpaulo /* Cache RF register CHNLBW. */ 3299251538Srpaulo sc->rf_chnlbw[i] = urtwn_rf_read(sc, i, R92C_RF_CHNLBW); 3300251538Srpaulo } 3301251538Srpaulo 3302251538Srpaulo if ((sc->chip & (URTWN_CHIP_UMC_A_CUT | URTWN_CHIP_92C)) == 3303251538Srpaulo URTWN_CHIP_UMC_A_CUT) { 3304251538Srpaulo urtwn_rf_write(sc, 0, R92C_RF_RX_G1, 0x30255); 3305251538Srpaulo urtwn_rf_write(sc, 0, R92C_RF_RX_G2, 0x50a00); 3306251538Srpaulo } 3307251538Srpaulo} 3308251538Srpaulo 3309251538Srpaulostatic void 3310251538Srpaulourtwn_cam_init(struct urtwn_softc *sc) 3311251538Srpaulo{ 3312251538Srpaulo /* Invalidate all CAM entries. */ 3313251538Srpaulo urtwn_write_4(sc, R92C_CAMCMD, 3314251538Srpaulo R92C_CAMCMD_POLLING | R92C_CAMCMD_CLR); 3315251538Srpaulo} 3316251538Srpaulo 3317251538Srpaulostatic void 3318251538Srpaulourtwn_pa_bias_init(struct urtwn_softc *sc) 3319251538Srpaulo{ 3320251538Srpaulo uint8_t reg; 3321251538Srpaulo int i; 3322251538Srpaulo 3323251538Srpaulo for (i = 0; i < sc->nrxchains; i++) { 3324251538Srpaulo if (sc->pa_setting & (1 << i)) 3325251538Srpaulo continue; 3326251538Srpaulo urtwn_rf_write(sc, i, R92C_RF_IPA, 0x0f406); 3327251538Srpaulo urtwn_rf_write(sc, i, R92C_RF_IPA, 0x4f406); 3328251538Srpaulo urtwn_rf_write(sc, i, R92C_RF_IPA, 0x8f406); 3329251538Srpaulo urtwn_rf_write(sc, i, R92C_RF_IPA, 0xcf406); 3330251538Srpaulo } 3331251538Srpaulo if (!(sc->pa_setting & 0x10)) { 3332251538Srpaulo reg = urtwn_read_1(sc, 0x16); 3333251538Srpaulo reg = (reg & ~0xf0) | 0x90; 3334251538Srpaulo urtwn_write_1(sc, 0x16, reg); 3335251538Srpaulo } 3336251538Srpaulo} 3337251538Srpaulo 3338251538Srpaulostatic void 3339251538Srpaulourtwn_rxfilter_init(struct urtwn_softc *sc) 3340251538Srpaulo{ 3341290564Savos struct ieee80211com *ic = &sc->sc_ic; 3342290564Savos struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 3343290564Savos uint32_t rcr; 3344290564Savos uint16_t filter; 3345290564Savos 3346290564Savos URTWN_ASSERT_LOCKED(sc); 3347290564Savos 3348251538Srpaulo /* Accept all multicast frames. */ 3349251538Srpaulo urtwn_write_4(sc, R92C_MAR + 0, 0xffffffff); 3350251538Srpaulo urtwn_write_4(sc, R92C_MAR + 4, 0xffffffff); 3351290564Savos 3352290564Savos /* Filter for management frames. */ 3353290564Savos filter = 0x7f3f; 3354290631Savos switch (vap->iv_opmode) { 3355290631Savos case IEEE80211_M_STA: 3356290564Savos filter &= ~( 3357290564Savos R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_REQ) | 3358290564Savos R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_REQ) | 3359290564Savos R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_PROBE_REQ)); 3360290631Savos break; 3361290631Savos case IEEE80211_M_HOSTAP: 3362290631Savos filter &= ~( 3363290631Savos R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_RESP) | 3364290631Savos R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_RESP) | 3365290631Savos R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_BEACON)); 3366290631Savos break; 3367290631Savos case IEEE80211_M_MONITOR: 3368290651Savos case IEEE80211_M_IBSS: 3369290631Savos break; 3370290631Savos default: 3371290631Savos device_printf(sc->sc_dev, "%s: undefined opmode %d\n", 3372290631Savos __func__, vap->iv_opmode); 3373290631Savos break; 3374290564Savos } 3375290564Savos urtwn_write_2(sc, R92C_RXFLTMAP0, filter); 3376290564Savos 3377251538Srpaulo /* Reject all control frames. */ 3378251538Srpaulo urtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000); 3379290564Savos 3380290564Savos /* Reject all data frames. */ 3381290564Savos urtwn_write_2(sc, R92C_RXFLTMAP2, 0x0000); 3382290564Savos 3383290564Savos rcr = R92C_RCR_AM | R92C_RCR_AB | R92C_RCR_APM | 3384290564Savos R92C_RCR_HTC_LOC_CTRL | R92C_RCR_APP_PHYSTS | 3385290564Savos R92C_RCR_APP_ICV | R92C_RCR_APP_MIC; 3386290564Savos 3387290564Savos if (vap->iv_opmode == IEEE80211_M_MONITOR) { 3388290564Savos /* Accept all frames. */ 3389290564Savos rcr |= R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | 3390290564Savos R92C_RCR_AAP; 3391290564Savos } 3392290564Savos 3393290564Savos /* Set Rx filter. */ 3394290564Savos urtwn_write_4(sc, R92C_RCR, rcr); 3395290564Savos 3396290564Savos if (ic->ic_promisc != 0) { 3397290564Savos /* Update Rx filter. */ 3398290564Savos urtwn_set_promisc(sc); 3399290564Savos } 3400251538Srpaulo} 3401251538Srpaulo 3402251538Srpaulostatic void 3403251538Srpaulourtwn_edca_init(struct urtwn_softc *sc) 3404251538Srpaulo{ 3405251538Srpaulo urtwn_write_2(sc, R92C_SPEC_SIFS, 0x100a); 3406251538Srpaulo urtwn_write_2(sc, R92C_MAC_SPEC_SIFS, 0x100a); 3407251538Srpaulo urtwn_write_2(sc, R92C_SIFS_CCK, 0x100a); 3408251538Srpaulo urtwn_write_2(sc, R92C_SIFS_OFDM, 0x100a); 3409251538Srpaulo urtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x005ea42b); 3410251538Srpaulo urtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a44f); 3411251538Srpaulo urtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005ea324); 3412251538Srpaulo urtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002fa226); 3413251538Srpaulo} 3414251538Srpaulo 3415289066Skevlostatic void 3416251538Srpaulourtwn_write_txpower(struct urtwn_softc *sc, int chain, 3417251538Srpaulo uint16_t power[URTWN_RIDX_COUNT]) 3418251538Srpaulo{ 3419251538Srpaulo uint32_t reg; 3420251538Srpaulo 3421251538Srpaulo /* Write per-CCK rate Tx power. */ 3422251538Srpaulo if (chain == 0) { 3423251538Srpaulo reg = urtwn_bb_read(sc, R92C_TXAGC_A_CCK1_MCS32); 3424251538Srpaulo reg = RW(reg, R92C_TXAGC_A_CCK1, power[0]); 3425251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_A_CCK1_MCS32, reg); 3426251538Srpaulo reg = urtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); 3427251538Srpaulo reg = RW(reg, R92C_TXAGC_A_CCK2, power[1]); 3428251538Srpaulo reg = RW(reg, R92C_TXAGC_A_CCK55, power[2]); 3429251538Srpaulo reg = RW(reg, R92C_TXAGC_A_CCK11, power[3]); 3430251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); 3431251538Srpaulo } else { 3432251538Srpaulo reg = urtwn_bb_read(sc, R92C_TXAGC_B_CCK1_55_MCS32); 3433251538Srpaulo reg = RW(reg, R92C_TXAGC_B_CCK1, power[0]); 3434251538Srpaulo reg = RW(reg, R92C_TXAGC_B_CCK2, power[1]); 3435251538Srpaulo reg = RW(reg, R92C_TXAGC_B_CCK55, power[2]); 3436251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_B_CCK1_55_MCS32, reg); 3437251538Srpaulo reg = urtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); 3438251538Srpaulo reg = RW(reg, R92C_TXAGC_B_CCK11, power[3]); 3439251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); 3440251538Srpaulo } 3441251538Srpaulo /* Write per-OFDM rate Tx power. */ 3442251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_RATE18_06(chain), 3443251538Srpaulo SM(R92C_TXAGC_RATE06, power[ 4]) | 3444251538Srpaulo SM(R92C_TXAGC_RATE09, power[ 5]) | 3445251538Srpaulo SM(R92C_TXAGC_RATE12, power[ 6]) | 3446251538Srpaulo SM(R92C_TXAGC_RATE18, power[ 7])); 3447251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_RATE54_24(chain), 3448251538Srpaulo SM(R92C_TXAGC_RATE24, power[ 8]) | 3449251538Srpaulo SM(R92C_TXAGC_RATE36, power[ 9]) | 3450251538Srpaulo SM(R92C_TXAGC_RATE48, power[10]) | 3451251538Srpaulo SM(R92C_TXAGC_RATE54, power[11])); 3452251538Srpaulo /* Write per-MCS Tx power. */ 3453251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_MCS03_MCS00(chain), 3454251538Srpaulo SM(R92C_TXAGC_MCS00, power[12]) | 3455251538Srpaulo SM(R92C_TXAGC_MCS01, power[13]) | 3456251538Srpaulo SM(R92C_TXAGC_MCS02, power[14]) | 3457251538Srpaulo SM(R92C_TXAGC_MCS03, power[15])); 3458251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_MCS07_MCS04(chain), 3459251538Srpaulo SM(R92C_TXAGC_MCS04, power[16]) | 3460251538Srpaulo SM(R92C_TXAGC_MCS05, power[17]) | 3461251538Srpaulo SM(R92C_TXAGC_MCS06, power[18]) | 3462251538Srpaulo SM(R92C_TXAGC_MCS07, power[19])); 3463251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_MCS11_MCS08(chain), 3464251538Srpaulo SM(R92C_TXAGC_MCS08, power[20]) | 3465261506Skevlo SM(R92C_TXAGC_MCS09, power[21]) | 3466251538Srpaulo SM(R92C_TXAGC_MCS10, power[22]) | 3467251538Srpaulo SM(R92C_TXAGC_MCS11, power[23])); 3468251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_MCS15_MCS12(chain), 3469251538Srpaulo SM(R92C_TXAGC_MCS12, power[24]) | 3470251538Srpaulo SM(R92C_TXAGC_MCS13, power[25]) | 3471251538Srpaulo SM(R92C_TXAGC_MCS14, power[26]) | 3472251538Srpaulo SM(R92C_TXAGC_MCS15, power[27])); 3473251538Srpaulo} 3474251538Srpaulo 3475289066Skevlostatic void 3476251538Srpaulourtwn_get_txpower(struct urtwn_softc *sc, int chain, 3477251538Srpaulo struct ieee80211_channel *c, struct ieee80211_channel *extc, 3478251538Srpaulo uint16_t power[URTWN_RIDX_COUNT]) 3479251538Srpaulo{ 3480287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3481291264Savos struct r92c_rom *rom = &sc->rom.r92c_rom; 3482251538Srpaulo uint16_t cckpow, ofdmpow, htpow, diff, max; 3483251538Srpaulo const struct urtwn_txpwr *base; 3484251538Srpaulo int ridx, chan, group; 3485251538Srpaulo 3486251538Srpaulo /* Determine channel group. */ 3487251538Srpaulo chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ 3488251538Srpaulo if (chan <= 3) 3489251538Srpaulo group = 0; 3490251538Srpaulo else if (chan <= 9) 3491251538Srpaulo group = 1; 3492251538Srpaulo else 3493251538Srpaulo group = 2; 3494251538Srpaulo 3495251538Srpaulo /* Get original Tx power based on board type and RF chain. */ 3496251538Srpaulo if (!(sc->chip & URTWN_CHIP_92C)) { 3497251538Srpaulo if (sc->board_type == R92C_BOARD_TYPE_HIGHPA) 3498251538Srpaulo base = &rtl8188ru_txagc[chain]; 3499251538Srpaulo else 3500251538Srpaulo base = &rtl8192cu_txagc[chain]; 3501251538Srpaulo } else 3502251538Srpaulo base = &rtl8192cu_txagc[chain]; 3503251538Srpaulo 3504251538Srpaulo memset(power, 0, URTWN_RIDX_COUNT * sizeof(power[0])); 3505251538Srpaulo if (sc->regulatory == 0) { 3506289758Savos for (ridx = URTWN_RIDX_CCK1; ridx <= URTWN_RIDX_CCK11; ridx++) 3507251538Srpaulo power[ridx] = base->pwr[0][ridx]; 3508251538Srpaulo } 3509289758Savos for (ridx = URTWN_RIDX_OFDM6; ridx < URTWN_RIDX_COUNT; ridx++) { 3510251538Srpaulo if (sc->regulatory == 3) { 3511251538Srpaulo power[ridx] = base->pwr[0][ridx]; 3512251538Srpaulo /* Apply vendor limits. */ 3513251538Srpaulo if (extc != NULL) 3514251538Srpaulo max = rom->ht40_max_pwr[group]; 3515251538Srpaulo else 3516251538Srpaulo max = rom->ht20_max_pwr[group]; 3517251538Srpaulo max = (max >> (chain * 4)) & 0xf; 3518251538Srpaulo if (power[ridx] > max) 3519251538Srpaulo power[ridx] = max; 3520251538Srpaulo } else if (sc->regulatory == 1) { 3521251538Srpaulo if (extc == NULL) 3522251538Srpaulo power[ridx] = base->pwr[group][ridx]; 3523251538Srpaulo } else if (sc->regulatory != 2) 3524251538Srpaulo power[ridx] = base->pwr[0][ridx]; 3525251538Srpaulo } 3526251538Srpaulo 3527251538Srpaulo /* Compute per-CCK rate Tx power. */ 3528251538Srpaulo cckpow = rom->cck_tx_pwr[chain][group]; 3529289758Savos for (ridx = URTWN_RIDX_CCK1; ridx <= URTWN_RIDX_CCK11; ridx++) { 3530251538Srpaulo power[ridx] += cckpow; 3531251538Srpaulo if (power[ridx] > R92C_MAX_TX_PWR) 3532251538Srpaulo power[ridx] = R92C_MAX_TX_PWR; 3533251538Srpaulo } 3534251538Srpaulo 3535251538Srpaulo htpow = rom->ht40_1s_tx_pwr[chain][group]; 3536251538Srpaulo if (sc->ntxchains > 1) { 3537251538Srpaulo /* Apply reduction for 2 spatial streams. */ 3538251538Srpaulo diff = rom->ht40_2s_tx_pwr_diff[group]; 3539251538Srpaulo diff = (diff >> (chain * 4)) & 0xf; 3540251538Srpaulo htpow = (htpow > diff) ? htpow - diff : 0; 3541251538Srpaulo } 3542251538Srpaulo 3543251538Srpaulo /* Compute per-OFDM rate Tx power. */ 3544251538Srpaulo diff = rom->ofdm_tx_pwr_diff[group]; 3545251538Srpaulo diff = (diff >> (chain * 4)) & 0xf; 3546251538Srpaulo ofdmpow = htpow + diff; /* HT->OFDM correction. */ 3547289758Savos for (ridx = URTWN_RIDX_OFDM6; ridx <= URTWN_RIDX_OFDM54; ridx++) { 3548251538Srpaulo power[ridx] += ofdmpow; 3549251538Srpaulo if (power[ridx] > R92C_MAX_TX_PWR) 3550251538Srpaulo power[ridx] = R92C_MAX_TX_PWR; 3551251538Srpaulo } 3552251538Srpaulo 3553251538Srpaulo /* Compute per-MCS Tx power. */ 3554251538Srpaulo if (extc == NULL) { 3555251538Srpaulo diff = rom->ht20_tx_pwr_diff[group]; 3556251538Srpaulo diff = (diff >> (chain * 4)) & 0xf; 3557251538Srpaulo htpow += diff; /* HT40->HT20 correction. */ 3558251538Srpaulo } 3559251538Srpaulo for (ridx = 12; ridx <= 27; ridx++) { 3560251538Srpaulo power[ridx] += htpow; 3561251538Srpaulo if (power[ridx] > R92C_MAX_TX_PWR) 3562251538Srpaulo power[ridx] = R92C_MAX_TX_PWR; 3563251538Srpaulo } 3564251538Srpaulo#ifdef URTWN_DEBUG 3565251538Srpaulo if (urtwn_debug >= 4) { 3566251538Srpaulo /* Dump per-rate Tx power values. */ 3567251538Srpaulo printf("Tx power for chain %d:\n", chain); 3568289758Savos for (ridx = URTWN_RIDX_CCK1; ridx < URTWN_RIDX_COUNT; ridx++) 3569251538Srpaulo printf("Rate %d = %u\n", ridx, power[ridx]); 3570251538Srpaulo } 3571251538Srpaulo#endif 3572251538Srpaulo} 3573251538Srpaulo 3574289066Skevlostatic void 3575264912Skevlourtwn_r88e_get_txpower(struct urtwn_softc *sc, int chain, 3576264912Skevlo struct ieee80211_channel *c, struct ieee80211_channel *extc, 3577264912Skevlo uint16_t power[URTWN_RIDX_COUNT]) 3578264912Skevlo{ 3579287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3580264912Skevlo uint16_t cckpow, ofdmpow, bw20pow, htpow; 3581264912Skevlo const struct urtwn_r88e_txpwr *base; 3582264912Skevlo int ridx, chan, group; 3583264912Skevlo 3584264912Skevlo /* Determine channel group. */ 3585264912Skevlo chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ 3586264912Skevlo if (chan <= 2) 3587264912Skevlo group = 0; 3588264912Skevlo else if (chan <= 5) 3589264912Skevlo group = 1; 3590264912Skevlo else if (chan <= 8) 3591264912Skevlo group = 2; 3592264912Skevlo else if (chan <= 11) 3593264912Skevlo group = 3; 3594264912Skevlo else if (chan <= 13) 3595264912Skevlo group = 4; 3596264912Skevlo else 3597264912Skevlo group = 5; 3598264912Skevlo 3599264912Skevlo /* Get original Tx power based on board type and RF chain. */ 3600264912Skevlo base = &rtl8188eu_txagc[chain]; 3601264912Skevlo 3602264912Skevlo memset(power, 0, URTWN_RIDX_COUNT * sizeof(power[0])); 3603264912Skevlo if (sc->regulatory == 0) { 3604289758Savos for (ridx = URTWN_RIDX_CCK1; ridx <= URTWN_RIDX_CCK11; ridx++) 3605264912Skevlo power[ridx] = base->pwr[0][ridx]; 3606264912Skevlo } 3607289758Savos for (ridx = URTWN_RIDX_OFDM6; ridx < URTWN_RIDX_COUNT; ridx++) { 3608264912Skevlo if (sc->regulatory == 3) 3609264912Skevlo power[ridx] = base->pwr[0][ridx]; 3610264912Skevlo else if (sc->regulatory == 1) { 3611264912Skevlo if (extc == NULL) 3612264912Skevlo power[ridx] = base->pwr[group][ridx]; 3613264912Skevlo } else if (sc->regulatory != 2) 3614264912Skevlo power[ridx] = base->pwr[0][ridx]; 3615264912Skevlo } 3616264912Skevlo 3617264912Skevlo /* Compute per-CCK rate Tx power. */ 3618264912Skevlo cckpow = sc->cck_tx_pwr[group]; 3619289758Savos for (ridx = URTWN_RIDX_CCK1; ridx <= URTWN_RIDX_CCK11; ridx++) { 3620264912Skevlo power[ridx] += cckpow; 3621264912Skevlo if (power[ridx] > R92C_MAX_TX_PWR) 3622264912Skevlo power[ridx] = R92C_MAX_TX_PWR; 3623264912Skevlo } 3624264912Skevlo 3625264912Skevlo htpow = sc->ht40_tx_pwr[group]; 3626264912Skevlo 3627264912Skevlo /* Compute per-OFDM rate Tx power. */ 3628264912Skevlo ofdmpow = htpow + sc->ofdm_tx_pwr_diff; 3629289758Savos for (ridx = URTWN_RIDX_OFDM6; ridx <= URTWN_RIDX_OFDM54; ridx++) { 3630264912Skevlo power[ridx] += ofdmpow; 3631264912Skevlo if (power[ridx] > R92C_MAX_TX_PWR) 3632264912Skevlo power[ridx] = R92C_MAX_TX_PWR; 3633264912Skevlo } 3634264912Skevlo 3635264912Skevlo bw20pow = htpow + sc->bw20_tx_pwr_diff; 3636264912Skevlo for (ridx = 12; ridx <= 27; ridx++) { 3637264912Skevlo power[ridx] += bw20pow; 3638264912Skevlo if (power[ridx] > R92C_MAX_TX_PWR) 3639264912Skevlo power[ridx] = R92C_MAX_TX_PWR; 3640264912Skevlo } 3641264912Skevlo} 3642264912Skevlo 3643289066Skevlostatic void 3644251538Srpaulourtwn_set_txpower(struct urtwn_softc *sc, struct ieee80211_channel *c, 3645251538Srpaulo struct ieee80211_channel *extc) 3646251538Srpaulo{ 3647251538Srpaulo uint16_t power[URTWN_RIDX_COUNT]; 3648251538Srpaulo int i; 3649251538Srpaulo 3650251538Srpaulo for (i = 0; i < sc->ntxchains; i++) { 3651251538Srpaulo /* Compute per-rate Tx power values. */ 3652264912Skevlo if (sc->chip & URTWN_CHIP_88E) 3653264912Skevlo urtwn_r88e_get_txpower(sc, i, c, extc, power); 3654264912Skevlo else 3655264912Skevlo urtwn_get_txpower(sc, i, c, extc, power); 3656251538Srpaulo /* Write per-rate Tx power values to hardware. */ 3657251538Srpaulo urtwn_write_txpower(sc, i, power); 3658251538Srpaulo } 3659251538Srpaulo} 3660251538Srpaulo 3661251538Srpaulostatic void 3662290048Savosurtwn_set_rx_bssid_all(struct urtwn_softc *sc, int enable) 3663290048Savos{ 3664290048Savos uint32_t reg; 3665290048Savos 3666290048Savos reg = urtwn_read_4(sc, R92C_RCR); 3667290048Savos if (enable) 3668290048Savos reg &= ~R92C_RCR_CBSSID_BCN; 3669290048Savos else 3670290048Savos reg |= R92C_RCR_CBSSID_BCN; 3671290048Savos urtwn_write_4(sc, R92C_RCR, reg); 3672290048Savos} 3673290048Savos 3674290048Savosstatic void 3675290048Savosurtwn_set_gain(struct urtwn_softc *sc, uint8_t gain) 3676290048Savos{ 3677290048Savos uint32_t reg; 3678290048Savos 3679290048Savos reg = urtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0)); 3680290048Savos reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, gain); 3681290048Savos urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg); 3682290048Savos 3683290048Savos if (!(sc->chip & URTWN_CHIP_88E)) { 3684290048Savos reg = urtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(1)); 3685290048Savos reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, gain); 3686290048Savos urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(1), reg); 3687290048Savos } 3688290048Savos} 3689290048Savos 3690290048Savosstatic void 3691251538Srpaulourtwn_scan_start(struct ieee80211com *ic) 3692251538Srpaulo{ 3693290048Savos struct urtwn_softc *sc = ic->ic_softc; 3694290048Savos 3695290048Savos URTWN_LOCK(sc); 3696290048Savos /* Receive beacons / probe responses from any BSSID. */ 3697290651Savos if (ic->ic_opmode != IEEE80211_M_IBSS) 3698290651Savos urtwn_set_rx_bssid_all(sc, 1); 3699290651Savos 3700290048Savos /* Set gain for scanning. */ 3701290048Savos urtwn_set_gain(sc, 0x20); 3702290048Savos URTWN_UNLOCK(sc); 3703251538Srpaulo} 3704251538Srpaulo 3705251538Srpaulostatic void 3706251538Srpaulourtwn_scan_end(struct ieee80211com *ic) 3707251538Srpaulo{ 3708290048Savos struct urtwn_softc *sc = ic->ic_softc; 3709290048Savos 3710290048Savos URTWN_LOCK(sc); 3711290048Savos /* Restore limitations. */ 3712290651Savos if (ic->ic_promisc == 0 && ic->ic_opmode != IEEE80211_M_IBSS) 3713290564Savos urtwn_set_rx_bssid_all(sc, 0); 3714290651Savos 3715290048Savos /* Set gain under link. */ 3716290048Savos urtwn_set_gain(sc, 0x32); 3717290048Savos URTWN_UNLOCK(sc); 3718251538Srpaulo} 3719251538Srpaulo 3720251538Srpaulostatic void 3721251538Srpaulourtwn_set_channel(struct ieee80211com *ic) 3722251538Srpaulo{ 3723286949Sadrian struct urtwn_softc *sc = ic->ic_softc; 3724292173Savos struct ieee80211_channel *c = ic->ic_curchan; 3725281070Srpaulo struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 3726251538Srpaulo 3727251538Srpaulo URTWN_LOCK(sc); 3728281070Srpaulo if (vap->iv_state == IEEE80211_S_SCAN) { 3729281070Srpaulo /* Make link LED blink during scan. */ 3730281070Srpaulo urtwn_set_led(sc, URTWN_LED_LINK, !sc->ledlink); 3731281070Srpaulo } 3732292173Savos urtwn_set_chan(sc, c, NULL); 3733292173Savos sc->sc_rxtap.wr_chan_freq = htole16(c->ic_freq); 3734292173Savos sc->sc_rxtap.wr_chan_flags = htole16(c->ic_flags); 3735292173Savos sc->sc_txtap.wt_chan_freq = htole16(c->ic_freq); 3736292173Savos sc->sc_txtap.wt_chan_flags = htole16(c->ic_flags); 3737251538Srpaulo URTWN_UNLOCK(sc); 3738251538Srpaulo} 3739251538Srpaulo 3740292014Savosstatic int 3741292014Savosurtwn_wme_update(struct ieee80211com *ic) 3742292014Savos{ 3743292014Savos const struct wmeParams *wmep = 3744292014Savos ic->ic_wme.wme_chanParams.cap_wmeParams; 3745292014Savos struct urtwn_softc *sc = ic->ic_softc; 3746292014Savos uint8_t aifs, acm, slottime; 3747292014Savos int ac; 3748292014Savos 3749292014Savos acm = 0; 3750292165Savos slottime = IEEE80211_GET_SLOTTIME(ic); 3751292014Savos 3752292014Savos URTWN_LOCK(sc); 3753292014Savos for (ac = WME_AC_BE; ac < WME_NUM_AC; ac++) { 3754292014Savos /* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */ 3755292014Savos aifs = wmep[ac].wmep_aifsn * slottime + IEEE80211_DUR_SIFS; 3756292014Savos urtwn_write_4(sc, wme2queue[ac].reg, 3757292014Savos SM(R92C_EDCA_PARAM_TXOP, wmep[ac].wmep_txopLimit) | 3758292014Savos SM(R92C_EDCA_PARAM_ECWMIN, wmep[ac].wmep_logcwmin) | 3759292014Savos SM(R92C_EDCA_PARAM_ECWMAX, wmep[ac].wmep_logcwmax) | 3760292014Savos SM(R92C_EDCA_PARAM_AIFS, aifs)); 3761292014Savos if (ac != WME_AC_BE) 3762292014Savos acm |= wmep[ac].wmep_acm << ac; 3763292014Savos } 3764292014Savos 3765292014Savos if (acm != 0) 3766292014Savos acm |= R92C_ACMHWCTRL_EN; 3767292014Savos urtwn_write_1(sc, R92C_ACMHWCTRL, 3768292014Savos (urtwn_read_1(sc, R92C_ACMHWCTRL) & ~R92C_ACMHWCTRL_ACM_MASK) | 3769292014Savos acm); 3770292014Savos 3771292014Savos URTWN_UNLOCK(sc); 3772292014Savos 3773292014Savos return 0; 3774292014Savos} 3775292014Savos 3776251538Srpaulostatic void 3777290564Savosurtwn_set_promisc(struct urtwn_softc *sc) 3778290564Savos{ 3779290564Savos struct ieee80211com *ic = &sc->sc_ic; 3780290564Savos struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 3781290564Savos uint32_t rcr, mask1, mask2; 3782290564Savos 3783290564Savos URTWN_ASSERT_LOCKED(sc); 3784290564Savos 3785290564Savos if (vap->iv_opmode == IEEE80211_M_MONITOR) 3786290564Savos return; 3787290564Savos 3788290564Savos mask1 = R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | R92C_RCR_AAP; 3789290564Savos mask2 = R92C_RCR_APM; 3790290564Savos 3791290564Savos if (vap->iv_state == IEEE80211_S_RUN) { 3792290564Savos switch (vap->iv_opmode) { 3793290564Savos case IEEE80211_M_STA: 3794290631Savos mask2 |= R92C_RCR_CBSSID_DATA; 3795290631Savos /* FALLTHROUGH */ 3796290631Savos case IEEE80211_M_HOSTAP: 3797290631Savos mask2 |= R92C_RCR_CBSSID_BCN; 3798290564Savos break; 3799290651Savos case IEEE80211_M_IBSS: 3800290651Savos mask2 |= R92C_RCR_CBSSID_DATA; 3801290651Savos break; 3802290564Savos default: 3803290564Savos device_printf(sc->sc_dev, "%s: undefined opmode %d\n", 3804290564Savos __func__, vap->iv_opmode); 3805290564Savos return; 3806290564Savos } 3807290564Savos } 3808290564Savos 3809290564Savos rcr = urtwn_read_4(sc, R92C_RCR); 3810290564Savos if (ic->ic_promisc == 0) 3811290564Savos rcr = (rcr & ~mask1) | mask2; 3812290564Savos else 3813290564Savos rcr = (rcr & ~mask2) | mask1; 3814290564Savos urtwn_write_4(sc, R92C_RCR, rcr); 3815290564Savos} 3816290564Savos 3817290564Savosstatic void 3818290564Savosurtwn_update_promisc(struct ieee80211com *ic) 3819290564Savos{ 3820290564Savos struct urtwn_softc *sc = ic->ic_softc; 3821290564Savos 3822290564Savos URTWN_LOCK(sc); 3823290564Savos if (sc->sc_flags & URTWN_RUNNING) 3824290564Savos urtwn_set_promisc(sc); 3825290564Savos URTWN_UNLOCK(sc); 3826290564Savos} 3827290564Savos 3828290564Savosstatic void 3829283540Sglebiusurtwn_update_mcast(struct ieee80211com *ic) 3830251538Srpaulo{ 3831251538Srpaulo /* XXX do nothing? */ 3832251538Srpaulo} 3833251538Srpaulo 3834292167Savosstatic struct ieee80211_node * 3835292167Savosurtwn_r88e_node_alloc(struct ieee80211vap *vap, 3836292167Savos const uint8_t mac[IEEE80211_ADDR_LEN]) 3837292167Savos{ 3838292167Savos struct urtwn_node *un; 3839292167Savos 3840292167Savos un = malloc(sizeof (struct urtwn_node), M_80211_NODE, 3841292167Savos M_NOWAIT | M_ZERO); 3842292167Savos 3843292167Savos if (un == NULL) 3844292167Savos return NULL; 3845292167Savos 3846292167Savos un->id = URTWN_MACID_UNDEFINED; 3847292167Savos 3848292167Savos return &un->ni; 3849292167Savos} 3850292167Savos 3851251538Srpaulostatic void 3852292167Savosurtwn_r88e_newassoc(struct ieee80211_node *ni, int isnew) 3853292167Savos{ 3854292167Savos struct urtwn_softc *sc = ni->ni_ic->ic_softc; 3855292167Savos struct urtwn_node *un = URTWN_NODE(ni); 3856292167Savos uint8_t id; 3857292167Savos 3858292167Savos if (!isnew) 3859292167Savos return; 3860292167Savos 3861292167Savos URTWN_NT_LOCK(sc); 3862292167Savos for (id = 0; id <= URTWN_MACID_MAX(sc); id++) { 3863292167Savos if (id != URTWN_MACID_BC && sc->node_list[id] == NULL) { 3864292167Savos un->id = id; 3865292167Savos sc->node_list[id] = ni; 3866292167Savos break; 3867292167Savos } 3868292167Savos } 3869292167Savos URTWN_NT_UNLOCK(sc); 3870292167Savos 3871292167Savos if (id > URTWN_MACID_MAX(sc)) { 3872292167Savos device_printf(sc->sc_dev, "%s: node table is full\n", 3873292167Savos __func__); 3874292167Savos } 3875292167Savos} 3876292167Savos 3877292167Savosstatic void 3878292167Savosurtwn_r88e_node_free(struct ieee80211_node *ni) 3879292167Savos{ 3880292167Savos struct urtwn_softc *sc = ni->ni_ic->ic_softc; 3881292167Savos struct urtwn_node *un = URTWN_NODE(ni); 3882292167Savos 3883292167Savos URTWN_NT_LOCK(sc); 3884292167Savos if (un->id != URTWN_MACID_UNDEFINED) 3885292167Savos sc->node_list[un->id] = NULL; 3886292167Savos URTWN_NT_UNLOCK(sc); 3887292167Savos 3888292167Savos sc->sc_node_free(ni); 3889292167Savos} 3890292167Savos 3891292167Savosstatic void 3892251538Srpaulourtwn_set_chan(struct urtwn_softc *sc, struct ieee80211_channel *c, 3893251538Srpaulo struct ieee80211_channel *extc) 3894251538Srpaulo{ 3895287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3896251538Srpaulo uint32_t reg; 3897251538Srpaulo u_int chan; 3898251538Srpaulo int i; 3899251538Srpaulo 3900251538Srpaulo chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ 3901251538Srpaulo if (chan == 0 || chan == IEEE80211_CHAN_ANY) { 3902251538Srpaulo device_printf(sc->sc_dev, 3903251538Srpaulo "%s: invalid channel %x\n", __func__, chan); 3904251538Srpaulo return; 3905251538Srpaulo } 3906251538Srpaulo 3907251538Srpaulo /* Set Tx power for this new channel. */ 3908251538Srpaulo urtwn_set_txpower(sc, c, extc); 3909251538Srpaulo 3910251538Srpaulo for (i = 0; i < sc->nrxchains; i++) { 3911251538Srpaulo urtwn_rf_write(sc, i, R92C_RF_CHNLBW, 3912251538Srpaulo RW(sc->rf_chnlbw[i], R92C_RF_CHNLBW_CHNL, chan)); 3913251538Srpaulo } 3914251538Srpaulo#ifndef IEEE80211_NO_HT 3915251538Srpaulo if (extc != NULL) { 3916251538Srpaulo /* Is secondary channel below or above primary? */ 3917251538Srpaulo int prichlo = c->ic_freq < extc->ic_freq; 3918251538Srpaulo 3919251538Srpaulo urtwn_write_1(sc, R92C_BWOPMODE, 3920251538Srpaulo urtwn_read_1(sc, R92C_BWOPMODE) & ~R92C_BWOPMODE_20MHZ); 3921251538Srpaulo 3922251538Srpaulo reg = urtwn_read_1(sc, R92C_RRSR + 2); 3923251538Srpaulo reg = (reg & ~0x6f) | (prichlo ? 1 : 2) << 5; 3924251538Srpaulo urtwn_write_1(sc, R92C_RRSR + 2, reg); 3925251538Srpaulo 3926251538Srpaulo urtwn_bb_write(sc, R92C_FPGA0_RFMOD, 3927251538Srpaulo urtwn_bb_read(sc, R92C_FPGA0_RFMOD) | R92C_RFMOD_40MHZ); 3928251538Srpaulo urtwn_bb_write(sc, R92C_FPGA1_RFMOD, 3929251538Srpaulo urtwn_bb_read(sc, R92C_FPGA1_RFMOD) | R92C_RFMOD_40MHZ); 3930251538Srpaulo 3931251538Srpaulo /* Set CCK side band. */ 3932251538Srpaulo reg = urtwn_bb_read(sc, R92C_CCK0_SYSTEM); 3933251538Srpaulo reg = (reg & ~0x00000010) | (prichlo ? 0 : 1) << 4; 3934251538Srpaulo urtwn_bb_write(sc, R92C_CCK0_SYSTEM, reg); 3935251538Srpaulo 3936251538Srpaulo reg = urtwn_bb_read(sc, R92C_OFDM1_LSTF); 3937251538Srpaulo reg = (reg & ~0x00000c00) | (prichlo ? 1 : 2) << 10; 3938251538Srpaulo urtwn_bb_write(sc, R92C_OFDM1_LSTF, reg); 3939251538Srpaulo 3940251538Srpaulo urtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2, 3941251538Srpaulo urtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) & 3942251538Srpaulo ~R92C_FPGA0_ANAPARAM2_CBW20); 3943251538Srpaulo 3944251538Srpaulo reg = urtwn_bb_read(sc, 0x818); 3945251538Srpaulo reg = (reg & ~0x0c000000) | (prichlo ? 2 : 1) << 26; 3946251538Srpaulo urtwn_bb_write(sc, 0x818, reg); 3947251538Srpaulo 3948251538Srpaulo /* Select 40MHz bandwidth. */ 3949251538Srpaulo urtwn_rf_write(sc, 0, R92C_RF_CHNLBW, 3950251538Srpaulo (sc->rf_chnlbw[0] & ~0xfff) | chan); 3951251538Srpaulo } else 3952251538Srpaulo#endif 3953251538Srpaulo { 3954251538Srpaulo urtwn_write_1(sc, R92C_BWOPMODE, 3955251538Srpaulo urtwn_read_1(sc, R92C_BWOPMODE) | R92C_BWOPMODE_20MHZ); 3956251538Srpaulo 3957251538Srpaulo urtwn_bb_write(sc, R92C_FPGA0_RFMOD, 3958251538Srpaulo urtwn_bb_read(sc, R92C_FPGA0_RFMOD) & ~R92C_RFMOD_40MHZ); 3959251538Srpaulo urtwn_bb_write(sc, R92C_FPGA1_RFMOD, 3960251538Srpaulo urtwn_bb_read(sc, R92C_FPGA1_RFMOD) & ~R92C_RFMOD_40MHZ); 3961251538Srpaulo 3962264912Skevlo if (!(sc->chip & URTWN_CHIP_88E)) { 3963264912Skevlo urtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2, 3964264912Skevlo urtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) | 3965264912Skevlo R92C_FPGA0_ANAPARAM2_CBW20); 3966264912Skevlo } 3967281069Srpaulo 3968251538Srpaulo /* Select 20MHz bandwidth. */ 3969251538Srpaulo urtwn_rf_write(sc, 0, R92C_RF_CHNLBW, 3970281069Srpaulo (sc->rf_chnlbw[0] & ~0xfff) | chan | 3971264912Skevlo ((sc->chip & URTWN_CHIP_88E) ? R88E_RF_CHNLBW_BW20 : 3972264912Skevlo R92C_RF_CHNLBW_BW20)); 3973251538Srpaulo } 3974251538Srpaulo} 3975251538Srpaulo 3976251538Srpaulostatic void 3977251538Srpaulourtwn_iq_calib(struct urtwn_softc *sc) 3978251538Srpaulo{ 3979251538Srpaulo /* TODO */ 3980251538Srpaulo} 3981251538Srpaulo 3982251538Srpaulostatic void 3983251538Srpaulourtwn_lc_calib(struct urtwn_softc *sc) 3984251538Srpaulo{ 3985251538Srpaulo uint32_t rf_ac[2]; 3986251538Srpaulo uint8_t txmode; 3987251538Srpaulo int i; 3988251538Srpaulo 3989251538Srpaulo txmode = urtwn_read_1(sc, R92C_OFDM1_LSTF + 3); 3990251538Srpaulo if ((txmode & 0x70) != 0) { 3991251538Srpaulo /* Disable all continuous Tx. */ 3992251538Srpaulo urtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode & ~0x70); 3993251538Srpaulo 3994251538Srpaulo /* Set RF mode to standby mode. */ 3995251538Srpaulo for (i = 0; i < sc->nrxchains; i++) { 3996251538Srpaulo rf_ac[i] = urtwn_rf_read(sc, i, R92C_RF_AC); 3997251538Srpaulo urtwn_rf_write(sc, i, R92C_RF_AC, 3998251538Srpaulo RW(rf_ac[i], R92C_RF_AC_MODE, 3999251538Srpaulo R92C_RF_AC_MODE_STANDBY)); 4000251538Srpaulo } 4001251538Srpaulo } else { 4002251538Srpaulo /* Block all Tx queues. */ 4003251538Srpaulo urtwn_write_1(sc, R92C_TXPAUSE, 0xff); 4004251538Srpaulo } 4005251538Srpaulo /* Start calibration. */ 4006251538Srpaulo urtwn_rf_write(sc, 0, R92C_RF_CHNLBW, 4007251538Srpaulo urtwn_rf_read(sc, 0, R92C_RF_CHNLBW) | R92C_RF_CHNLBW_LCSTART); 4008251538Srpaulo 4009251538Srpaulo /* Give calibration the time to complete. */ 4010266472Shselasky usb_pause_mtx(&sc->sc_mtx, hz / 10); /* 100ms */ 4011251538Srpaulo 4012251538Srpaulo /* Restore configuration. */ 4013251538Srpaulo if ((txmode & 0x70) != 0) { 4014251538Srpaulo /* Restore Tx mode. */ 4015251538Srpaulo urtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode); 4016251538Srpaulo /* Restore RF mode. */ 4017251538Srpaulo for (i = 0; i < sc->nrxchains; i++) 4018251538Srpaulo urtwn_rf_write(sc, i, R92C_RF_AC, rf_ac[i]); 4019251538Srpaulo } else { 4020251538Srpaulo /* Unblock all Tx queues. */ 4021251538Srpaulo urtwn_write_1(sc, R92C_TXPAUSE, 0x00); 4022251538Srpaulo } 4023251538Srpaulo} 4024251538Srpaulo 4025291698Savosstatic int 4026287197Sglebiusurtwn_init(struct urtwn_softc *sc) 4027251538Srpaulo{ 4028287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 4029287197Sglebius struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 4030287197Sglebius uint8_t macaddr[IEEE80211_ADDR_LEN]; 4031251538Srpaulo uint32_t reg; 4032291698Savos usb_error_t usb_err = USB_ERR_NORMAL_COMPLETION; 4033251538Srpaulo int error; 4034251538Srpaulo 4035291698Savos URTWN_LOCK(sc); 4036291698Savos if (sc->sc_flags & URTWN_RUNNING) { 4037291698Savos URTWN_UNLOCK(sc); 4038291698Savos return (0); 4039291698Savos } 4040264864Skevlo 4041251538Srpaulo /* Init firmware commands ring. */ 4042251538Srpaulo sc->fwcur = 0; 4043251538Srpaulo 4044251538Srpaulo /* Allocate Tx/Rx buffers. */ 4045251538Srpaulo error = urtwn_alloc_rx_list(sc); 4046251538Srpaulo if (error != 0) 4047251538Srpaulo goto fail; 4048281069Srpaulo 4049251538Srpaulo error = urtwn_alloc_tx_list(sc); 4050251538Srpaulo if (error != 0) 4051251538Srpaulo goto fail; 4052251538Srpaulo 4053251538Srpaulo /* Power on adapter. */ 4054251538Srpaulo error = urtwn_power_on(sc); 4055251538Srpaulo if (error != 0) 4056251538Srpaulo goto fail; 4057251538Srpaulo 4058251538Srpaulo /* Initialize DMA. */ 4059251538Srpaulo error = urtwn_dma_init(sc); 4060251538Srpaulo if (error != 0) 4061251538Srpaulo goto fail; 4062251538Srpaulo 4063251538Srpaulo /* Set info size in Rx descriptors (in 64-bit words). */ 4064251538Srpaulo urtwn_write_1(sc, R92C_RX_DRVINFO_SZ, 4); 4065251538Srpaulo 4066251538Srpaulo /* Init interrupts. */ 4067264912Skevlo if (sc->chip & URTWN_CHIP_88E) { 4068291698Savos usb_err = urtwn_write_4(sc, R88E_HISR, 0xffffffff); 4069291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 4070291698Savos goto fail; 4071291698Savos usb_err = urtwn_write_4(sc, R88E_HIMR, R88E_HIMR_CPWM | R88E_HIMR_CPWM2 | 4072264912Skevlo R88E_HIMR_TBDER | R88E_HIMR_PSTIMEOUT); 4073291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 4074291698Savos goto fail; 4075291698Savos usb_err = urtwn_write_4(sc, R88E_HIMRE, R88E_HIMRE_RXFOVW | 4076264912Skevlo R88E_HIMRE_TXFOVW | R88E_HIMRE_RXERR | R88E_HIMRE_TXERR); 4077291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 4078291698Savos goto fail; 4079291698Savos usb_err = urtwn_write_1(sc, R92C_USB_SPECIAL_OPTION, 4080264912Skevlo urtwn_read_1(sc, R92C_USB_SPECIAL_OPTION) | 4081264912Skevlo R92C_USB_SPECIAL_OPTION_INT_BULK_SEL); 4082291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 4083291698Savos goto fail; 4084264912Skevlo } else { 4085291698Savos usb_err = urtwn_write_4(sc, R92C_HISR, 0xffffffff); 4086291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 4087291698Savos goto fail; 4088291698Savos usb_err = urtwn_write_4(sc, R92C_HIMR, 0xffffffff); 4089291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 4090291698Savos goto fail; 4091264912Skevlo } 4092251538Srpaulo 4093251538Srpaulo /* Set MAC address. */ 4094287197Sglebius IEEE80211_ADDR_COPY(macaddr, vap ? vap->iv_myaddr : ic->ic_macaddr); 4095291698Savos usb_err = urtwn_write_region_1(sc, R92C_MACID, macaddr, IEEE80211_ADDR_LEN); 4096291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 4097291698Savos goto fail; 4098251538Srpaulo 4099251538Srpaulo /* Set initial network type. */ 4100289811Savos urtwn_set_mode(sc, R92C_MSR_INFRA); 4101251538Srpaulo 4102290564Savos /* Initialize Rx filter. */ 4103251538Srpaulo urtwn_rxfilter_init(sc); 4104251538Srpaulo 4105282623Skevlo /* Set response rate. */ 4106251538Srpaulo reg = urtwn_read_4(sc, R92C_RRSR); 4107251538Srpaulo reg = RW(reg, R92C_RRSR_RATE_BITMAP, R92C_RRSR_RATE_CCK_ONLY_1M); 4108251538Srpaulo urtwn_write_4(sc, R92C_RRSR, reg); 4109251538Srpaulo 4110251538Srpaulo /* Set short/long retry limits. */ 4111251538Srpaulo urtwn_write_2(sc, R92C_RL, 4112251538Srpaulo SM(R92C_RL_SRL, 0x30) | SM(R92C_RL_LRL, 0x30)); 4113251538Srpaulo 4114251538Srpaulo /* Initialize EDCA parameters. */ 4115251538Srpaulo urtwn_edca_init(sc); 4116251538Srpaulo 4117251538Srpaulo /* Setup rate fallback. */ 4118264912Skevlo if (!(sc->chip & URTWN_CHIP_88E)) { 4119264912Skevlo urtwn_write_4(sc, R92C_DARFRC + 0, 0x00000000); 4120264912Skevlo urtwn_write_4(sc, R92C_DARFRC + 4, 0x10080404); 4121264912Skevlo urtwn_write_4(sc, R92C_RARFRC + 0, 0x04030201); 4122264912Skevlo urtwn_write_4(sc, R92C_RARFRC + 4, 0x08070605); 4123264912Skevlo } 4124251538Srpaulo 4125251538Srpaulo urtwn_write_1(sc, R92C_FWHW_TXQ_CTRL, 4126251538Srpaulo urtwn_read_1(sc, R92C_FWHW_TXQ_CTRL) | 4127251538Srpaulo R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW); 4128251538Srpaulo /* Set ACK timeout. */ 4129251538Srpaulo urtwn_write_1(sc, R92C_ACKTO, 0x40); 4130251538Srpaulo 4131251538Srpaulo /* Setup USB aggregation. */ 4132251538Srpaulo reg = urtwn_read_4(sc, R92C_TDECTRL); 4133251538Srpaulo reg = RW(reg, R92C_TDECTRL_BLK_DESC_NUM, 6); 4134251538Srpaulo urtwn_write_4(sc, R92C_TDECTRL, reg); 4135251538Srpaulo urtwn_write_1(sc, R92C_TRXDMA_CTRL, 4136251538Srpaulo urtwn_read_1(sc, R92C_TRXDMA_CTRL) | 4137251538Srpaulo R92C_TRXDMA_CTRL_RXDMA_AGG_EN); 4138251538Srpaulo urtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH, 48); 4139264912Skevlo if (sc->chip & URTWN_CHIP_88E) 4140264912Skevlo urtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH + 1, 4); 4141282266Skevlo else { 4142264912Skevlo urtwn_write_1(sc, R92C_USB_DMA_AGG_TO, 4); 4143282266Skevlo urtwn_write_1(sc, R92C_USB_SPECIAL_OPTION, 4144282266Skevlo urtwn_read_1(sc, R92C_USB_SPECIAL_OPTION) | 4145282266Skevlo R92C_USB_SPECIAL_OPTION_AGG_EN); 4146282266Skevlo urtwn_write_1(sc, R92C_USB_AGG_TH, 8); 4147282266Skevlo urtwn_write_1(sc, R92C_USB_AGG_TO, 6); 4148282266Skevlo } 4149251538Srpaulo 4150251538Srpaulo /* Initialize beacon parameters. */ 4151264912Skevlo urtwn_write_2(sc, R92C_BCN_CTRL, 0x1010); 4152251538Srpaulo urtwn_write_2(sc, R92C_TBTT_PROHIBIT, 0x6404); 4153251538Srpaulo urtwn_write_1(sc, R92C_DRVERLYINT, 0x05); 4154251538Srpaulo urtwn_write_1(sc, R92C_BCNDMATIM, 0x02); 4155251538Srpaulo urtwn_write_2(sc, R92C_BCNTCFG, 0x660f); 4156251538Srpaulo 4157264912Skevlo if (!(sc->chip & URTWN_CHIP_88E)) { 4158264912Skevlo /* Setup AMPDU aggregation. */ 4159264912Skevlo urtwn_write_4(sc, R92C_AGGLEN_LMT, 0x99997631); /* MCS7~0 */ 4160264912Skevlo urtwn_write_1(sc, R92C_AGGR_BREAK_TIME, 0x16); 4161264912Skevlo urtwn_write_2(sc, R92C_MAX_AGGR_NUM, 0x0708); 4162251538Srpaulo 4163264912Skevlo urtwn_write_1(sc, R92C_BCN_MAX_ERR, 0xff); 4164264912Skevlo } 4165251538Srpaulo 4166251538Srpaulo /* Load 8051 microcode. */ 4167251538Srpaulo error = urtwn_load_firmware(sc); 4168251538Srpaulo if (error != 0) 4169251538Srpaulo goto fail; 4170251538Srpaulo 4171251538Srpaulo /* Initialize MAC/BB/RF blocks. */ 4172291698Savos error = urtwn_mac_init(sc); 4173291698Savos if (error != 0) { 4174291698Savos device_printf(sc->sc_dev, 4175291698Savos "%s: error while initializing MAC block\n", __func__); 4176291698Savos goto fail; 4177291698Savos } 4178251538Srpaulo urtwn_bb_init(sc); 4179251538Srpaulo urtwn_rf_init(sc); 4180251538Srpaulo 4181290564Savos /* Reinitialize Rx filter (D3845 is not committed yet). */ 4182290564Savos urtwn_rxfilter_init(sc); 4183290564Savos 4184264912Skevlo if (sc->chip & URTWN_CHIP_88E) { 4185264912Skevlo urtwn_write_2(sc, R92C_CR, 4186264912Skevlo urtwn_read_2(sc, R92C_CR) | R92C_CR_MACTXEN | 4187264912Skevlo R92C_CR_MACRXEN); 4188264912Skevlo } 4189264912Skevlo 4190251538Srpaulo /* Turn CCK and OFDM blocks on. */ 4191251538Srpaulo reg = urtwn_bb_read(sc, R92C_FPGA0_RFMOD); 4192251538Srpaulo reg |= R92C_RFMOD_CCK_EN; 4193291698Savos usb_err = urtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg); 4194291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 4195291698Savos goto fail; 4196251538Srpaulo reg = urtwn_bb_read(sc, R92C_FPGA0_RFMOD); 4197251538Srpaulo reg |= R92C_RFMOD_OFDM_EN; 4198291698Savos usb_err = urtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg); 4199291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 4200291698Savos goto fail; 4201251538Srpaulo 4202251538Srpaulo /* Clear per-station keys table. */ 4203251538Srpaulo urtwn_cam_init(sc); 4204251538Srpaulo 4205251538Srpaulo /* Enable hardware sequence numbering. */ 4206251538Srpaulo urtwn_write_1(sc, R92C_HWSEQ_CTRL, 0xff); 4207251538Srpaulo 4208292167Savos /* Enable per-packet TX report. */ 4209292167Savos if (sc->chip & URTWN_CHIP_88E) { 4210292167Savos urtwn_write_1(sc, R88E_TX_RPT_CTRL, 4211292167Savos urtwn_read_1(sc, R88E_TX_RPT_CTRL) | R88E_TX_RPT1_ENA); 4212292167Savos } 4213292167Savos 4214251538Srpaulo /* Perform LO and IQ calibrations. */ 4215251538Srpaulo urtwn_iq_calib(sc); 4216251538Srpaulo /* Perform LC calibration. */ 4217251538Srpaulo urtwn_lc_calib(sc); 4218251538Srpaulo 4219251538Srpaulo /* Fix USB interference issue. */ 4220264912Skevlo if (!(sc->chip & URTWN_CHIP_88E)) { 4221264912Skevlo urtwn_write_1(sc, 0xfe40, 0xe0); 4222264912Skevlo urtwn_write_1(sc, 0xfe41, 0x8d); 4223264912Skevlo urtwn_write_1(sc, 0xfe42, 0x80); 4224251538Srpaulo 4225264912Skevlo urtwn_pa_bias_init(sc); 4226264912Skevlo } 4227251538Srpaulo 4228251538Srpaulo /* Initialize GPIO setting. */ 4229251538Srpaulo urtwn_write_1(sc, R92C_GPIO_MUXCFG, 4230251538Srpaulo urtwn_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_ENBT); 4231251538Srpaulo 4232251538Srpaulo /* Fix for lower temperature. */ 4233264912Skevlo if (!(sc->chip & URTWN_CHIP_88E)) 4234264912Skevlo urtwn_write_1(sc, 0x15, 0xe9); 4235251538Srpaulo 4236251538Srpaulo usbd_transfer_start(sc->sc_xfer[URTWN_BULK_RX]); 4237251538Srpaulo 4238287197Sglebius sc->sc_flags |= URTWN_RUNNING; 4239251538Srpaulo 4240251538Srpaulo callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); 4241251538Srpaulofail: 4242291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 4243291698Savos error = EIO; 4244291698Savos 4245291698Savos URTWN_UNLOCK(sc); 4246291698Savos 4247291698Savos return (error); 4248251538Srpaulo} 4249251538Srpaulo 4250251538Srpaulostatic void 4251287197Sglebiusurtwn_stop(struct urtwn_softc *sc) 4252251538Srpaulo{ 4253251538Srpaulo 4254291698Savos URTWN_LOCK(sc); 4255291698Savos if (!(sc->sc_flags & URTWN_RUNNING)) { 4256291698Savos URTWN_UNLOCK(sc); 4257291698Savos return; 4258291698Savos } 4259291698Savos 4260287197Sglebius sc->sc_flags &= ~URTWN_RUNNING; 4261251538Srpaulo callout_stop(&sc->sc_watchdog_ch); 4262251538Srpaulo urtwn_abort_xfers(sc); 4263288353Sadrian 4264288353Sadrian urtwn_drain_mbufq(sc); 4265291698Savos URTWN_UNLOCK(sc); 4266251538Srpaulo} 4267251538Srpaulo 4268251538Srpaulostatic void 4269251538Srpaulourtwn_abort_xfers(struct urtwn_softc *sc) 4270251538Srpaulo{ 4271251538Srpaulo int i; 4272251538Srpaulo 4273251538Srpaulo URTWN_ASSERT_LOCKED(sc); 4274251538Srpaulo 4275251538Srpaulo /* abort any pending transfers */ 4276251538Srpaulo for (i = 0; i < URTWN_N_TRANSFER; i++) 4277251538Srpaulo usbd_transfer_stop(sc->sc_xfer[i]); 4278251538Srpaulo} 4279251538Srpaulo 4280251538Srpaulostatic int 4281251538Srpaulourtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 4282251538Srpaulo const struct ieee80211_bpf_params *params) 4283251538Srpaulo{ 4284251538Srpaulo struct ieee80211com *ic = ni->ni_ic; 4285286949Sadrian struct urtwn_softc *sc = ic->ic_softc; 4286251538Srpaulo struct urtwn_data *bf; 4287290630Savos int error; 4288251538Srpaulo 4289251538Srpaulo /* prevent management frames from being sent if we're not ready */ 4290290630Savos URTWN_LOCK(sc); 4291287197Sglebius if (!(sc->sc_flags & URTWN_RUNNING)) { 4292290630Savos error = ENETDOWN; 4293290630Savos goto end; 4294251538Srpaulo } 4295290630Savos 4296251538Srpaulo bf = urtwn_getbuf(sc); 4297251538Srpaulo if (bf == NULL) { 4298290630Savos error = ENOBUFS; 4299290630Savos goto end; 4300251538Srpaulo } 4301251538Srpaulo 4302290630Savos if ((error = urtwn_tx_data(sc, ni, m, bf)) != 0) { 4303251538Srpaulo STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); 4304290630Savos goto end; 4305251538Srpaulo } 4306290630Savos 4307288353Sadrian sc->sc_txtimer = 5; 4308290630Savos callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); 4309290630Savos 4310290630Savosend: 4311290630Savos if (error != 0) 4312290630Savos m_freem(m); 4313290630Savos 4314251538Srpaulo URTWN_UNLOCK(sc); 4315251538Srpaulo 4316290630Savos return (error); 4317251538Srpaulo} 4318251538Srpaulo 4319266472Shselaskystatic void 4320266472Shselaskyurtwn_ms_delay(struct urtwn_softc *sc) 4321266472Shselasky{ 4322266472Shselasky usb_pause_mtx(&sc->sc_mtx, hz / 1000); 4323266472Shselasky} 4324266472Shselasky 4325251538Srpaulostatic device_method_t urtwn_methods[] = { 4326251538Srpaulo /* Device interface */ 4327251538Srpaulo DEVMETHOD(device_probe, urtwn_match), 4328251538Srpaulo DEVMETHOD(device_attach, urtwn_attach), 4329251538Srpaulo DEVMETHOD(device_detach, urtwn_detach), 4330251538Srpaulo 4331264912Skevlo DEVMETHOD_END 4332251538Srpaulo}; 4333251538Srpaulo 4334251538Srpaulostatic driver_t urtwn_driver = { 4335251538Srpaulo "urtwn", 4336251538Srpaulo urtwn_methods, 4337251538Srpaulo sizeof(struct urtwn_softc) 4338251538Srpaulo}; 4339251538Srpaulo 4340251538Srpaulostatic devclass_t urtwn_devclass; 4341251538Srpaulo 4342251538SrpauloDRIVER_MODULE(urtwn, uhub, urtwn_driver, urtwn_devclass, NULL, NULL); 4343251538SrpauloMODULE_DEPEND(urtwn, usb, 1, 1, 1); 4344251538SrpauloMODULE_DEPEND(urtwn, wlan, 1, 1, 1); 4345251538SrpauloMODULE_DEPEND(urtwn, firmware, 1, 1, 1); 4346251538SrpauloMODULE_VERSION(urtwn, 1); 4347292080SimpUSB_PNP_HOST_INFO(urtwn_devs); 4348