1156321Sdamien/* $FreeBSD: releng/11.0/sys/dev/ral/rt2560.c 300752 2016-05-26 16:05:19Z avos $ */ 2156321Sdamien 3156321Sdamien/*- 4156321Sdamien * Copyright (c) 2005, 2006 5156321Sdamien * Damien Bergamini <damien.bergamini@free.fr> 6156321Sdamien * 7156321Sdamien * Permission to use, copy, modify, and distribute this software for any 8156321Sdamien * purpose with or without fee is hereby granted, provided that the above 9156321Sdamien * copyright notice and this permission notice appear in all copies. 10156321Sdamien * 11156321Sdamien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12156321Sdamien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13156321Sdamien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14156321Sdamien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15156321Sdamien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16156321Sdamien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17156321Sdamien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18156321Sdamien */ 19156321Sdamien 20156321Sdamien#include <sys/cdefs.h> 21156321Sdamien__FBSDID("$FreeBSD: releng/11.0/sys/dev/ral/rt2560.c 300752 2016-05-26 16:05:19Z avos $"); 22156321Sdamien 23156321Sdamien/*- 24156321Sdamien * Ralink Technology RT2560 chipset driver 25156321Sdamien * http://www.ralinktech.com/ 26156321Sdamien */ 27156321Sdamien 28156321Sdamien#include <sys/param.h> 29156321Sdamien#include <sys/sysctl.h> 30156321Sdamien#include <sys/sockio.h> 31156321Sdamien#include <sys/mbuf.h> 32156321Sdamien#include <sys/kernel.h> 33156321Sdamien#include <sys/socket.h> 34156321Sdamien#include <sys/systm.h> 35156321Sdamien#include <sys/malloc.h> 36164982Skevlo#include <sys/lock.h> 37164982Skevlo#include <sys/mutex.h> 38156321Sdamien#include <sys/module.h> 39156321Sdamien#include <sys/bus.h> 40156321Sdamien#include <sys/endian.h> 41156321Sdamien 42156321Sdamien#include <machine/bus.h> 43156321Sdamien#include <machine/resource.h> 44156321Sdamien#include <sys/rman.h> 45156321Sdamien 46156321Sdamien#include <net/bpf.h> 47156321Sdamien#include <net/if.h> 48257176Sglebius#include <net/if_var.h> 49156321Sdamien#include <net/if_arp.h> 50156321Sdamien#include <net/ethernet.h> 51156321Sdamien#include <net/if_dl.h> 52156321Sdamien#include <net/if_media.h> 53156321Sdamien#include <net/if_types.h> 54156321Sdamien 55156321Sdamien#include <net80211/ieee80211_var.h> 56156321Sdamien#include <net80211/ieee80211_radiotap.h> 57170530Ssam#include <net80211/ieee80211_regdomain.h> 58206358Srpaulo#include <net80211/ieee80211_ratectl.h> 59156321Sdamien 60156321Sdamien#include <netinet/in.h> 61156321Sdamien#include <netinet/in_systm.h> 62156321Sdamien#include <netinet/in_var.h> 63156321Sdamien#include <netinet/ip.h> 64156321Sdamien#include <netinet/if_ether.h> 65156321Sdamien 66156327Ssilby#include <dev/ral/rt2560reg.h> 67156327Ssilby#include <dev/ral/rt2560var.h> 68156321Sdamien 69170530Ssam#define RT2560_RSSI(sc, rssi) \ 70170530Ssam ((rssi) > (RT2560_NOISE_FLOOR + (sc)->rssi_corr) ? \ 71170530Ssam ((rssi) - RT2560_NOISE_FLOOR - (sc)->rssi_corr) : 0) 72170530Ssam 73178354Ssam#define RAL_DEBUG 74156321Sdamien#ifdef RAL_DEBUG 75178354Ssam#define DPRINTF(sc, fmt, ...) do { \ 76178354Ssam if (sc->sc_debug > 0) \ 77178354Ssam printf(fmt, __VA_ARGS__); \ 78178354Ssam} while (0) 79178354Ssam#define DPRINTFN(sc, n, fmt, ...) do { \ 80178354Ssam if (sc->sc_debug >= (n)) \ 81178354Ssam printf(fmt, __VA_ARGS__); \ 82178354Ssam} while (0) 83156321Sdamien#else 84178354Ssam#define DPRINTF(sc, fmt, ...) 85178354Ssam#define DPRINTFN(sc, n, fmt, ...) 86156321Sdamien#endif 87156321Sdamien 88178354Ssamstatic struct ieee80211vap *rt2560_vap_create(struct ieee80211com *, 89228621Sbschmidt const char [IFNAMSIZ], int, enum ieee80211_opmode, 90228621Sbschmidt int, const uint8_t [IEEE80211_ADDR_LEN], 91228621Sbschmidt const uint8_t [IEEE80211_ADDR_LEN]); 92178354Ssamstatic void rt2560_vap_delete(struct ieee80211vap *); 93156321Sdamienstatic void rt2560_dma_map_addr(void *, bus_dma_segment_t *, int, 94156321Sdamien int); 95156321Sdamienstatic int rt2560_alloc_tx_ring(struct rt2560_softc *, 96156321Sdamien struct rt2560_tx_ring *, int); 97156321Sdamienstatic void rt2560_reset_tx_ring(struct rt2560_softc *, 98156321Sdamien struct rt2560_tx_ring *); 99156321Sdamienstatic void rt2560_free_tx_ring(struct rt2560_softc *, 100156321Sdamien struct rt2560_tx_ring *); 101156321Sdamienstatic int rt2560_alloc_rx_ring(struct rt2560_softc *, 102156321Sdamien struct rt2560_rx_ring *, int); 103156321Sdamienstatic void rt2560_reset_rx_ring(struct rt2560_softc *, 104156321Sdamien struct rt2560_rx_ring *); 105156321Sdamienstatic void rt2560_free_rx_ring(struct rt2560_softc *, 106156321Sdamien struct rt2560_rx_ring *); 107178354Ssamstatic int rt2560_newstate(struct ieee80211vap *, 108156321Sdamien enum ieee80211_state, int); 109156321Sdamienstatic uint16_t rt2560_eeprom_read(struct rt2560_softc *, uint8_t); 110156321Sdamienstatic void rt2560_encryption_intr(struct rt2560_softc *); 111156321Sdamienstatic void rt2560_tx_intr(struct rt2560_softc *); 112156321Sdamienstatic void rt2560_prio_intr(struct rt2560_softc *); 113156321Sdamienstatic void rt2560_decryption_intr(struct rt2560_softc *); 114156321Sdamienstatic void rt2560_rx_intr(struct rt2560_softc *); 115178354Ssamstatic void rt2560_beacon_update(struct ieee80211vap *, int item); 116156321Sdamienstatic void rt2560_beacon_expire(struct rt2560_softc *); 117156321Sdamienstatic void rt2560_wakeup_expire(struct rt2560_softc *); 118170530Ssamstatic void rt2560_scan_start(struct ieee80211com *); 119170530Ssamstatic void rt2560_scan_end(struct ieee80211com *); 120300752Savosstatic void rt2560_getradiocaps(struct ieee80211com *, int, int *, 121300752Savos struct ieee80211_channel[]); 122170530Ssamstatic void rt2560_set_channel(struct ieee80211com *); 123156321Sdamienstatic void rt2560_setup_tx_desc(struct rt2560_softc *, 124156321Sdamien struct rt2560_tx_desc *, uint32_t, int, int, int, 125156321Sdamien bus_addr_t); 126156321Sdamienstatic int rt2560_tx_bcn(struct rt2560_softc *, struct mbuf *, 127156321Sdamien struct ieee80211_node *); 128156321Sdamienstatic int rt2560_tx_mgt(struct rt2560_softc *, struct mbuf *, 129156321Sdamien struct ieee80211_node *); 130156321Sdamienstatic int rt2560_tx_data(struct rt2560_softc *, struct mbuf *, 131156321Sdamien struct ieee80211_node *); 132287197Sglebiusstatic int rt2560_transmit(struct ieee80211com *, struct mbuf *); 133287197Sglebiusstatic void rt2560_start(struct rt2560_softc *); 134165352Sbmsstatic void rt2560_watchdog(void *); 135287197Sglebiusstatic void rt2560_parent(struct ieee80211com *); 136156321Sdamienstatic void rt2560_bbp_write(struct rt2560_softc *, uint8_t, 137156321Sdamien uint8_t); 138156321Sdamienstatic uint8_t rt2560_bbp_read(struct rt2560_softc *, uint8_t); 139156321Sdamienstatic void rt2560_rf_write(struct rt2560_softc *, uint8_t, 140156321Sdamien uint32_t); 141156321Sdamienstatic void rt2560_set_chan(struct rt2560_softc *, 142156321Sdamien struct ieee80211_channel *); 143156321Sdamien#if 0 144156321Sdamienstatic void rt2560_disable_rf_tune(struct rt2560_softc *); 145156321Sdamien#endif 146156321Sdamienstatic void rt2560_enable_tsf_sync(struct rt2560_softc *); 147192468Ssamstatic void rt2560_enable_tsf(struct rt2560_softc *); 148156321Sdamienstatic void rt2560_update_plcp(struct rt2560_softc *); 149283540Sglebiusstatic void rt2560_update_slot(struct ieee80211com *); 150220502Sbschmidtstatic void rt2560_set_basicrates(struct rt2560_softc *, 151220502Sbschmidt const struct ieee80211_rateset *); 152156321Sdamienstatic void rt2560_update_led(struct rt2560_softc *, int, int); 153170530Ssamstatic void rt2560_set_bssid(struct rt2560_softc *, const uint8_t *); 154287197Sglebiusstatic void rt2560_set_macaddr(struct rt2560_softc *, 155287197Sglebius const uint8_t *); 156156321Sdamienstatic void rt2560_get_macaddr(struct rt2560_softc *, uint8_t *); 157283540Sglebiusstatic void rt2560_update_promisc(struct ieee80211com *); 158156321Sdamienstatic const char *rt2560_get_rf(int); 159175938Ssephestatic void rt2560_read_config(struct rt2560_softc *); 160156321Sdamienstatic int rt2560_bbp_init(struct rt2560_softc *); 161156321Sdamienstatic void rt2560_set_txantenna(struct rt2560_softc *, int); 162156321Sdamienstatic void rt2560_set_rxantenna(struct rt2560_softc *, int); 163178354Ssamstatic void rt2560_init_locked(struct rt2560_softc *); 164156321Sdamienstatic void rt2560_init(void *); 165178354Ssamstatic void rt2560_stop_locked(struct rt2560_softc *); 166160691Ssamstatic int rt2560_raw_xmit(struct ieee80211_node *, struct mbuf *, 167160691Ssam const struct ieee80211_bpf_params *); 168156321Sdamien 169156321Sdamienstatic const struct { 170156321Sdamien uint32_t reg; 171156321Sdamien uint32_t val; 172156321Sdamien} rt2560_def_mac[] = { 173156321Sdamien RT2560_DEF_MAC 174156321Sdamien}; 175156321Sdamien 176156321Sdamienstatic const struct { 177156321Sdamien uint8_t reg; 178156321Sdamien uint8_t val; 179156321Sdamien} rt2560_def_bbp[] = { 180156321Sdamien RT2560_DEF_BBP 181156321Sdamien}; 182156321Sdamien 183156321Sdamienstatic const uint32_t rt2560_rf2522_r2[] = RT2560_RF2522_R2; 184156321Sdamienstatic const uint32_t rt2560_rf2523_r2[] = RT2560_RF2523_R2; 185156321Sdamienstatic const uint32_t rt2560_rf2524_r2[] = RT2560_RF2524_R2; 186156321Sdamienstatic const uint32_t rt2560_rf2525_r2[] = RT2560_RF2525_R2; 187156321Sdamienstatic const uint32_t rt2560_rf2525_hi_r2[] = RT2560_RF2525_HI_R2; 188156321Sdamienstatic const uint32_t rt2560_rf2525e_r2[] = RT2560_RF2525E_R2; 189156321Sdamienstatic const uint32_t rt2560_rf2526_r2[] = RT2560_RF2526_R2; 190156321Sdamienstatic const uint32_t rt2560_rf2526_hi_r2[] = RT2560_RF2526_HI_R2; 191156321Sdamien 192300752Savosstatic const uint8_t rt2560_chan_2ghz[] = 193300752Savos { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; 194300752Savos 195300752Savosstatic const uint8_t rt2560_chan_5ghz[] = 196300752Savos { 36, 40, 44, 48, 52, 56, 60, 64, 197300752Savos 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 198300752Savos 149, 153, 157, 161 }; 199300752Savos 200156321Sdamienstatic const struct { 201156321Sdamien uint8_t chan; 202156321Sdamien uint32_t r1, r2, r4; 203156321Sdamien} rt2560_rf5222[] = { 204156321Sdamien RT2560_RF5222 205156321Sdamien}; 206156321Sdamien 207156321Sdamienint 208156321Sdamienrt2560_attach(device_t dev, int id) 209156321Sdamien{ 210156321Sdamien struct rt2560_softc *sc = device_get_softc(dev); 211287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 212286437Sadrian int error; 213156321Sdamien 214156321Sdamien sc->sc_dev = dev; 215156321Sdamien 216156321Sdamien mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 217156321Sdamien MTX_DEF | MTX_RECURSE); 218156321Sdamien 219165352Sbms callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0); 220287197Sglebius mbufq_init(&sc->sc_snd, ifqmaxlen); 221156321Sdamien 222156321Sdamien /* retrieve RT2560 rev. no */ 223156321Sdamien sc->asic_rev = RAL_READ(sc, RT2560_CSR0); 224156321Sdamien 225156321Sdamien /* retrieve RF rev. no and various other things from EEPROM */ 226175938Ssephe rt2560_read_config(sc); 227156321Sdamien 228156321Sdamien device_printf(dev, "MAC/BBP RT2560 (rev 0x%02x), RF %s\n", 229156321Sdamien sc->asic_rev, rt2560_get_rf(sc->rf_rev)); 230156321Sdamien 231156321Sdamien /* 232156321Sdamien * Allocate Tx and Rx rings. 233156321Sdamien */ 234156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->txq, RT2560_TX_RING_COUNT); 235156321Sdamien if (error != 0) { 236156321Sdamien device_printf(sc->sc_dev, "could not allocate Tx ring\n"); 237156321Sdamien goto fail1; 238156321Sdamien } 239156321Sdamien 240156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->atimq, RT2560_ATIM_RING_COUNT); 241156321Sdamien if (error != 0) { 242156321Sdamien device_printf(sc->sc_dev, "could not allocate ATIM ring\n"); 243156321Sdamien goto fail2; 244156321Sdamien } 245156321Sdamien 246156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->prioq, RT2560_PRIO_RING_COUNT); 247156321Sdamien if (error != 0) { 248156321Sdamien device_printf(sc->sc_dev, "could not allocate Prio ring\n"); 249156321Sdamien goto fail3; 250156321Sdamien } 251156321Sdamien 252156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->bcnq, RT2560_BEACON_RING_COUNT); 253156321Sdamien if (error != 0) { 254156321Sdamien device_printf(sc->sc_dev, "could not allocate Beacon ring\n"); 255156321Sdamien goto fail4; 256156321Sdamien } 257156321Sdamien 258156321Sdamien error = rt2560_alloc_rx_ring(sc, &sc->rxq, RT2560_RX_RING_COUNT); 259156321Sdamien if (error != 0) { 260156321Sdamien device_printf(sc->sc_dev, "could not allocate Rx ring\n"); 261156321Sdamien goto fail5; 262156321Sdamien } 263156321Sdamien 264178354Ssam /* retrieve MAC address */ 265287197Sglebius rt2560_get_macaddr(sc, ic->ic_macaddr); 266178354Ssam 267283537Sglebius ic->ic_softc = sc; 268283527Sglebius ic->ic_name = device_get_nameunit(dev); 269178354Ssam ic->ic_opmode = IEEE80211_M_STA; 270156321Sdamien ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 271156321Sdamien 272156321Sdamien /* set device capabilities */ 273156321Sdamien ic->ic_caps = 274178957Ssam IEEE80211_C_STA /* station mode */ 275178957Ssam | IEEE80211_C_IBSS /* ibss, nee adhoc, mode */ 276178354Ssam | IEEE80211_C_HOSTAP /* hostap mode */ 277178354Ssam | IEEE80211_C_MONITOR /* monitor mode */ 278178354Ssam | IEEE80211_C_AHDEMO /* adhoc demo mode */ 279178354Ssam | IEEE80211_C_WDS /* 4-address traffic works */ 280195618Srpaulo | IEEE80211_C_MBSS /* mesh point link mode */ 281178354Ssam | IEEE80211_C_SHPREAMBLE /* short preamble supported */ 282178354Ssam | IEEE80211_C_SHSLOT /* short slot time supported */ 283178354Ssam | IEEE80211_C_WPA /* capable of WPA1+WPA2 */ 284178354Ssam | IEEE80211_C_BGSCAN /* capable of bg scanning */ 285178354Ssam#ifdef notyet 286178354Ssam | IEEE80211_C_TXFRAG /* handle tx frags */ 287178354Ssam#endif 288178354Ssam ; 289156321Sdamien 290300752Savos rt2560_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans, 291300752Savos ic->ic_channels); 292156321Sdamien 293287197Sglebius ieee80211_ifattach(ic); 294178354Ssam ic->ic_raw_xmit = rt2560_raw_xmit; 295178354Ssam ic->ic_updateslot = rt2560_update_slot; 296178354Ssam ic->ic_update_promisc = rt2560_update_promisc; 297170530Ssam ic->ic_scan_start = rt2560_scan_start; 298170530Ssam ic->ic_scan_end = rt2560_scan_end; 299300752Savos ic->ic_getradiocaps = rt2560_getradiocaps; 300170530Ssam ic->ic_set_channel = rt2560_set_channel; 301156321Sdamien 302178354Ssam ic->ic_vap_create = rt2560_vap_create; 303178354Ssam ic->ic_vap_delete = rt2560_vap_delete; 304287197Sglebius ic->ic_parent = rt2560_parent; 305287197Sglebius ic->ic_transmit = rt2560_transmit; 306156321Sdamien 307192468Ssam ieee80211_radiotap_attach(ic, 308192468Ssam &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), 309192468Ssam RT2560_TX_RADIOTAP_PRESENT, 310192468Ssam &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 311192468Ssam RT2560_RX_RADIOTAP_PRESENT); 312156321Sdamien 313156321Sdamien /* 314156321Sdamien * Add a few sysctl knobs. 315156321Sdamien */ 316178354Ssam#ifdef RAL_DEBUG 317156321Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 318156321Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 319178354Ssam "debug", CTLFLAG_RW, &sc->sc_debug, 0, "debug msgs"); 320178354Ssam#endif 321178354Ssam SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 322178354Ssam SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 323156321Sdamien "txantenna", CTLFLAG_RW, &sc->tx_ant, 0, "tx antenna (0=auto)"); 324156321Sdamien 325156321Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 326156321Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 327156321Sdamien "rxantenna", CTLFLAG_RW, &sc->rx_ant, 0, "rx antenna (0=auto)"); 328156321Sdamien 329156321Sdamien if (bootverbose) 330156321Sdamien ieee80211_announce(ic); 331156321Sdamien 332156321Sdamien return 0; 333156321Sdamien 334156321Sdamienfail5: rt2560_free_tx_ring(sc, &sc->bcnq); 335156321Sdamienfail4: rt2560_free_tx_ring(sc, &sc->prioq); 336156321Sdamienfail3: rt2560_free_tx_ring(sc, &sc->atimq); 337156321Sdamienfail2: rt2560_free_tx_ring(sc, &sc->txq); 338156321Sdamienfail1: mtx_destroy(&sc->sc_mtx); 339156321Sdamien 340156321Sdamien return ENXIO; 341156321Sdamien} 342156321Sdamien 343156321Sdamienint 344156321Sdamienrt2560_detach(void *xsc) 345156321Sdamien{ 346156321Sdamien struct rt2560_softc *sc = xsc; 347287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 348170530Ssam 349156321Sdamien rt2560_stop(sc); 350156321Sdamien 351156321Sdamien ieee80211_ifdetach(ic); 352287197Sglebius mbufq_drain(&sc->sc_snd); 353156321Sdamien 354156321Sdamien rt2560_free_tx_ring(sc, &sc->txq); 355156321Sdamien rt2560_free_tx_ring(sc, &sc->atimq); 356156321Sdamien rt2560_free_tx_ring(sc, &sc->prioq); 357156321Sdamien rt2560_free_tx_ring(sc, &sc->bcnq); 358156321Sdamien rt2560_free_rx_ring(sc, &sc->rxq); 359156321Sdamien 360156321Sdamien mtx_destroy(&sc->sc_mtx); 361156321Sdamien 362156321Sdamien return 0; 363156321Sdamien} 364156321Sdamien 365178354Ssamstatic struct ieee80211vap * 366228621Sbschmidtrt2560_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, 367228621Sbschmidt enum ieee80211_opmode opmode, int flags, 368228621Sbschmidt const uint8_t bssid[IEEE80211_ADDR_LEN], 369228621Sbschmidt const uint8_t mac[IEEE80211_ADDR_LEN]) 370178354Ssam{ 371287197Sglebius struct rt2560_softc *sc = ic->ic_softc; 372178354Ssam struct rt2560_vap *rvp; 373178354Ssam struct ieee80211vap *vap; 374178354Ssam 375178354Ssam switch (opmode) { 376178354Ssam case IEEE80211_M_STA: 377178354Ssam case IEEE80211_M_IBSS: 378178354Ssam case IEEE80211_M_AHDEMO: 379178354Ssam case IEEE80211_M_MONITOR: 380178354Ssam case IEEE80211_M_HOSTAP: 381195618Srpaulo case IEEE80211_M_MBSS: 382195618Srpaulo /* XXXRP: TBD */ 383178354Ssam if (!TAILQ_EMPTY(&ic->ic_vaps)) { 384287197Sglebius device_printf(sc->sc_dev, "only 1 vap supported\n"); 385178354Ssam return NULL; 386178354Ssam } 387178354Ssam if (opmode == IEEE80211_M_STA) 388178354Ssam flags |= IEEE80211_CLONE_NOBEACONS; 389178354Ssam break; 390178354Ssam case IEEE80211_M_WDS: 391178354Ssam if (TAILQ_EMPTY(&ic->ic_vaps) || 392178354Ssam ic->ic_opmode != IEEE80211_M_HOSTAP) { 393287197Sglebius device_printf(sc->sc_dev, 394287197Sglebius "wds only supported in ap mode\n"); 395178354Ssam return NULL; 396178354Ssam } 397178354Ssam /* 398178354Ssam * Silently remove any request for a unique 399178354Ssam * bssid; WDS vap's always share the local 400178354Ssam * mac address. 401178354Ssam */ 402178354Ssam flags &= ~IEEE80211_CLONE_BSSID; 403178354Ssam break; 404178354Ssam default: 405287197Sglebius device_printf(sc->sc_dev, "unknown opmode %d\n", opmode); 406178354Ssam return NULL; 407178354Ssam } 408287197Sglebius rvp = malloc(sizeof(struct rt2560_vap), M_80211_VAP, M_WAITOK | M_ZERO); 409178354Ssam vap = &rvp->ral_vap; 410287197Sglebius ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); 411178354Ssam 412178354Ssam /* override state transition machine */ 413178354Ssam rvp->ral_newstate = vap->iv_newstate; 414178354Ssam vap->iv_newstate = rt2560_newstate; 415178354Ssam vap->iv_update_beacon = rt2560_beacon_update; 416178354Ssam 417206358Srpaulo ieee80211_ratectl_init(vap); 418178354Ssam /* complete setup */ 419287197Sglebius ieee80211_vap_attach(vap, ieee80211_media_change, 420287197Sglebius ieee80211_media_status, mac); 421178354Ssam if (TAILQ_FIRST(&ic->ic_vaps) == vap) 422178354Ssam ic->ic_opmode = opmode; 423178354Ssam return vap; 424178354Ssam} 425178354Ssam 426178354Ssamstatic void 427178354Ssamrt2560_vap_delete(struct ieee80211vap *vap) 428178354Ssam{ 429178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 430178354Ssam 431206358Srpaulo ieee80211_ratectl_deinit(vap); 432178354Ssam ieee80211_vap_detach(vap); 433178354Ssam free(rvp, M_80211_VAP); 434178354Ssam} 435178354Ssam 436156321Sdamienvoid 437156321Sdamienrt2560_resume(void *xsc) 438156321Sdamien{ 439156321Sdamien struct rt2560_softc *sc = xsc; 440156321Sdamien 441287197Sglebius if (sc->sc_ic.ic_nrunning > 0) 442178354Ssam rt2560_init(sc); 443156321Sdamien} 444156321Sdamien 445156321Sdamienstatic void 446156321Sdamienrt2560_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 447156321Sdamien{ 448156321Sdamien if (error != 0) 449156321Sdamien return; 450156321Sdamien 451156321Sdamien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 452156321Sdamien 453156321Sdamien *(bus_addr_t *)arg = segs[0].ds_addr; 454156321Sdamien} 455156321Sdamien 456156321Sdamienstatic int 457156321Sdamienrt2560_alloc_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring, 458156321Sdamien int count) 459156321Sdamien{ 460156321Sdamien int i, error; 461156321Sdamien 462156321Sdamien ring->count = count; 463156321Sdamien ring->queued = 0; 464156321Sdamien ring->cur = ring->next = 0; 465156321Sdamien ring->cur_encrypt = ring->next_encrypt = 0; 466156321Sdamien 467171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 4, 0, 468171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 469171535Skevlo count * RT2560_TX_DESC_SIZE, 1, count * RT2560_TX_DESC_SIZE, 470171535Skevlo 0, NULL, NULL, &ring->desc_dmat); 471156321Sdamien if (error != 0) { 472156321Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 473156321Sdamien goto fail; 474156321Sdamien } 475156321Sdamien 476156321Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 477156321Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 478156321Sdamien if (error != 0) { 479156321Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 480156321Sdamien goto fail; 481156321Sdamien } 482156321Sdamien 483156321Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 484156321Sdamien count * RT2560_TX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr, 485156321Sdamien 0); 486156321Sdamien if (error != 0) { 487156321Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 488156321Sdamien goto fail; 489156321Sdamien } 490156321Sdamien 491156321Sdamien ring->data = malloc(count * sizeof (struct rt2560_tx_data), M_DEVBUF, 492156321Sdamien M_NOWAIT | M_ZERO); 493156321Sdamien if (ring->data == NULL) { 494156321Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 495156321Sdamien error = ENOMEM; 496156321Sdamien goto fail; 497156321Sdamien } 498156321Sdamien 499171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 500171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 501171535Skevlo MCLBYTES, RT2560_MAX_SCATTER, MCLBYTES, 0, NULL, NULL, 502171535Skevlo &ring->data_dmat); 503156321Sdamien if (error != 0) { 504156321Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 505156321Sdamien goto fail; 506156321Sdamien } 507156321Sdamien 508156321Sdamien for (i = 0; i < count; i++) { 509156321Sdamien error = bus_dmamap_create(ring->data_dmat, 0, 510156321Sdamien &ring->data[i].map); 511156321Sdamien if (error != 0) { 512156321Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 513156321Sdamien goto fail; 514156321Sdamien } 515156321Sdamien } 516156321Sdamien 517156321Sdamien return 0; 518156321Sdamien 519156321Sdamienfail: rt2560_free_tx_ring(sc, ring); 520156321Sdamien return error; 521156321Sdamien} 522156321Sdamien 523156321Sdamienstatic void 524156321Sdamienrt2560_reset_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) 525156321Sdamien{ 526156321Sdamien struct rt2560_tx_desc *desc; 527156321Sdamien struct rt2560_tx_data *data; 528156321Sdamien int i; 529156321Sdamien 530156321Sdamien for (i = 0; i < ring->count; i++) { 531156321Sdamien desc = &ring->desc[i]; 532156321Sdamien data = &ring->data[i]; 533156321Sdamien 534156321Sdamien if (data->m != NULL) { 535156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 536156321Sdamien BUS_DMASYNC_POSTWRITE); 537156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 538156321Sdamien m_freem(data->m); 539156321Sdamien data->m = NULL; 540156321Sdamien } 541156321Sdamien 542156321Sdamien if (data->ni != NULL) { 543156321Sdamien ieee80211_free_node(data->ni); 544156321Sdamien data->ni = NULL; 545156321Sdamien } 546156321Sdamien 547156321Sdamien desc->flags = 0; 548156321Sdamien } 549156321Sdamien 550156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 551156321Sdamien 552156321Sdamien ring->queued = 0; 553156321Sdamien ring->cur = ring->next = 0; 554156321Sdamien ring->cur_encrypt = ring->next_encrypt = 0; 555156321Sdamien} 556156321Sdamien 557156321Sdamienstatic void 558156321Sdamienrt2560_free_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) 559156321Sdamien{ 560156321Sdamien struct rt2560_tx_data *data; 561156321Sdamien int i; 562156321Sdamien 563156321Sdamien if (ring->desc != NULL) { 564156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 565156321Sdamien BUS_DMASYNC_POSTWRITE); 566156321Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 567156321Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 568156321Sdamien } 569156321Sdamien 570156321Sdamien if (ring->desc_dmat != NULL) 571156321Sdamien bus_dma_tag_destroy(ring->desc_dmat); 572156321Sdamien 573156321Sdamien if (ring->data != NULL) { 574156321Sdamien for (i = 0; i < ring->count; i++) { 575156321Sdamien data = &ring->data[i]; 576156321Sdamien 577156321Sdamien if (data->m != NULL) { 578156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 579156321Sdamien BUS_DMASYNC_POSTWRITE); 580156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 581156321Sdamien m_freem(data->m); 582156321Sdamien } 583156321Sdamien 584156321Sdamien if (data->ni != NULL) 585156321Sdamien ieee80211_free_node(data->ni); 586156321Sdamien 587156321Sdamien if (data->map != NULL) 588156321Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 589156321Sdamien } 590156321Sdamien 591156321Sdamien free(ring->data, M_DEVBUF); 592156321Sdamien } 593156321Sdamien 594156321Sdamien if (ring->data_dmat != NULL) 595156321Sdamien bus_dma_tag_destroy(ring->data_dmat); 596156321Sdamien} 597156321Sdamien 598156321Sdamienstatic int 599156321Sdamienrt2560_alloc_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring, 600156321Sdamien int count) 601156321Sdamien{ 602156321Sdamien struct rt2560_rx_desc *desc; 603156321Sdamien struct rt2560_rx_data *data; 604156321Sdamien bus_addr_t physaddr; 605156321Sdamien int i, error; 606156321Sdamien 607156321Sdamien ring->count = count; 608156321Sdamien ring->cur = ring->next = 0; 609156321Sdamien ring->cur_decrypt = 0; 610156321Sdamien 611171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 4, 0, 612171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 613171535Skevlo count * RT2560_RX_DESC_SIZE, 1, count * RT2560_RX_DESC_SIZE, 614171535Skevlo 0, NULL, NULL, &ring->desc_dmat); 615156321Sdamien if (error != 0) { 616156321Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 617156321Sdamien goto fail; 618156321Sdamien } 619156321Sdamien 620156321Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 621156321Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 622156321Sdamien if (error != 0) { 623156321Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 624156321Sdamien goto fail; 625156321Sdamien } 626156321Sdamien 627156321Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 628156321Sdamien count * RT2560_RX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr, 629156321Sdamien 0); 630156321Sdamien if (error != 0) { 631156321Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 632156321Sdamien goto fail; 633156321Sdamien } 634156321Sdamien 635156321Sdamien ring->data = malloc(count * sizeof (struct rt2560_rx_data), M_DEVBUF, 636156321Sdamien M_NOWAIT | M_ZERO); 637156321Sdamien if (ring->data == NULL) { 638156321Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 639156321Sdamien error = ENOMEM; 640156321Sdamien goto fail; 641156321Sdamien } 642156321Sdamien 643156321Sdamien /* 644156321Sdamien * Pre-allocate Rx buffers and populate Rx ring. 645156321Sdamien */ 646171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 647171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 648171535Skevlo 1, MCLBYTES, 0, NULL, NULL, &ring->data_dmat); 649156321Sdamien if (error != 0) { 650156321Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 651156321Sdamien goto fail; 652156321Sdamien } 653156321Sdamien 654156321Sdamien for (i = 0; i < count; i++) { 655156321Sdamien desc = &sc->rxq.desc[i]; 656156321Sdamien data = &sc->rxq.data[i]; 657156321Sdamien 658156321Sdamien error = bus_dmamap_create(ring->data_dmat, 0, &data->map); 659156321Sdamien if (error != 0) { 660156321Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 661156321Sdamien goto fail; 662156321Sdamien } 663156321Sdamien 664243857Sglebius data->m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 665156321Sdamien if (data->m == NULL) { 666156321Sdamien device_printf(sc->sc_dev, 667156321Sdamien "could not allocate rx mbuf\n"); 668156321Sdamien error = ENOMEM; 669156321Sdamien goto fail; 670156321Sdamien } 671156321Sdamien 672156321Sdamien error = bus_dmamap_load(ring->data_dmat, data->map, 673156321Sdamien mtod(data->m, void *), MCLBYTES, rt2560_dma_map_addr, 674156321Sdamien &physaddr, 0); 675156321Sdamien if (error != 0) { 676156321Sdamien device_printf(sc->sc_dev, 677156321Sdamien "could not load rx buf DMA map"); 678156321Sdamien goto fail; 679156321Sdamien } 680156321Sdamien 681156321Sdamien desc->flags = htole32(RT2560_RX_BUSY); 682156321Sdamien desc->physaddr = htole32(physaddr); 683156321Sdamien } 684156321Sdamien 685156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 686156321Sdamien 687156321Sdamien return 0; 688156321Sdamien 689156321Sdamienfail: rt2560_free_rx_ring(sc, ring); 690156321Sdamien return error; 691156321Sdamien} 692156321Sdamien 693156321Sdamienstatic void 694156321Sdamienrt2560_reset_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) 695156321Sdamien{ 696156321Sdamien int i; 697156321Sdamien 698156321Sdamien for (i = 0; i < ring->count; i++) { 699156321Sdamien ring->desc[i].flags = htole32(RT2560_RX_BUSY); 700156321Sdamien ring->data[i].drop = 0; 701156321Sdamien } 702156321Sdamien 703156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 704156321Sdamien 705156321Sdamien ring->cur = ring->next = 0; 706156321Sdamien ring->cur_decrypt = 0; 707156321Sdamien} 708156321Sdamien 709156321Sdamienstatic void 710156321Sdamienrt2560_free_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) 711156321Sdamien{ 712156321Sdamien struct rt2560_rx_data *data; 713156321Sdamien int i; 714156321Sdamien 715156321Sdamien if (ring->desc != NULL) { 716156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 717156321Sdamien BUS_DMASYNC_POSTWRITE); 718156321Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 719156321Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 720156321Sdamien } 721156321Sdamien 722156321Sdamien if (ring->desc_dmat != NULL) 723156321Sdamien bus_dma_tag_destroy(ring->desc_dmat); 724156321Sdamien 725156321Sdamien if (ring->data != NULL) { 726156321Sdamien for (i = 0; i < ring->count; i++) { 727156321Sdamien data = &ring->data[i]; 728156321Sdamien 729156321Sdamien if (data->m != NULL) { 730156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 731156321Sdamien BUS_DMASYNC_POSTREAD); 732156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 733156321Sdamien m_freem(data->m); 734156321Sdamien } 735156321Sdamien 736156321Sdamien if (data->map != NULL) 737156321Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 738156321Sdamien } 739156321Sdamien 740156321Sdamien free(ring->data, M_DEVBUF); 741156321Sdamien } 742156321Sdamien 743156321Sdamien if (ring->data_dmat != NULL) 744156321Sdamien bus_dma_tag_destroy(ring->data_dmat); 745156321Sdamien} 746156321Sdamien 747156321Sdamienstatic int 748178354Ssamrt2560_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 749156321Sdamien{ 750178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 751287197Sglebius struct rt2560_softc *sc = vap->iv_ic->ic_softc; 752178354Ssam int error; 753156321Sdamien 754178354Ssam if (nstate == IEEE80211_S_INIT && vap->iv_state == IEEE80211_S_RUN) { 755178354Ssam /* abort TSF synchronization */ 756178354Ssam RAL_WRITE(sc, RT2560_CSR14, 0); 757156321Sdamien 758178354Ssam /* turn association led off */ 759178354Ssam rt2560_update_led(sc, 0, 0); 760178354Ssam } 761156321Sdamien 762178354Ssam error = rvp->ral_newstate(vap, nstate, arg); 763156321Sdamien 764178354Ssam if (error == 0 && nstate == IEEE80211_S_RUN) { 765178354Ssam struct ieee80211_node *ni = vap->iv_bss; 766178354Ssam struct mbuf *m; 767156321Sdamien 768178354Ssam if (vap->iv_opmode != IEEE80211_M_MONITOR) { 769156321Sdamien rt2560_update_plcp(sc); 770220502Sbschmidt rt2560_set_basicrates(sc, &ni->ni_rates); 771156321Sdamien rt2560_set_bssid(sc, ni->ni_bssid); 772156321Sdamien } 773156321Sdamien 774178354Ssam if (vap->iv_opmode == IEEE80211_M_HOSTAP || 775195618Srpaulo vap->iv_opmode == IEEE80211_M_IBSS || 776195618Srpaulo vap->iv_opmode == IEEE80211_M_MBSS) { 777288636Sadrian m = ieee80211_beacon_alloc(ni); 778156321Sdamien if (m == NULL) { 779287197Sglebius device_printf(sc->sc_dev, 780287197Sglebius "could not allocate beacon\n"); 781178354Ssam return ENOBUFS; 782156321Sdamien } 783156321Sdamien ieee80211_ref_node(ni); 784156321Sdamien error = rt2560_tx_bcn(sc, m, ni); 785156321Sdamien if (error != 0) 786178354Ssam return error; 787156321Sdamien } 788156321Sdamien 789298955Spfg /* turn association led on */ 790156321Sdamien rt2560_update_led(sc, 1, 0); 791156321Sdamien 792184345Ssam if (vap->iv_opmode != IEEE80211_M_MONITOR) 793156321Sdamien rt2560_enable_tsf_sync(sc); 794192468Ssam else 795192468Ssam rt2560_enable_tsf(sc); 796156321Sdamien } 797178354Ssam return error; 798156321Sdamien} 799156321Sdamien 800156321Sdamien/* 801156321Sdamien * Read 16 bits at address 'addr' from the serial EEPROM (either 93C46 or 802156321Sdamien * 93C66). 803156321Sdamien */ 804156321Sdamienstatic uint16_t 805156321Sdamienrt2560_eeprom_read(struct rt2560_softc *sc, uint8_t addr) 806156321Sdamien{ 807156321Sdamien uint32_t tmp; 808156321Sdamien uint16_t val; 809156321Sdamien int n; 810156321Sdamien 811156321Sdamien /* clock C once before the first command */ 812156321Sdamien RT2560_EEPROM_CTL(sc, 0); 813156321Sdamien 814156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 815156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 816156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 817156321Sdamien 818156321Sdamien /* write start bit (1) */ 819156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D); 820156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C); 821156321Sdamien 822156321Sdamien /* write READ opcode (10) */ 823156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D); 824156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C); 825156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 826156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 827156321Sdamien 828156321Sdamien /* write address (A5-A0 or A7-A0) */ 829156321Sdamien n = (RAL_READ(sc, RT2560_CSR21) & RT2560_93C46) ? 5 : 7; 830156321Sdamien for (; n >= 0; n--) { 831156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | 832156321Sdamien (((addr >> n) & 1) << RT2560_SHIFT_D)); 833156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | 834156321Sdamien (((addr >> n) & 1) << RT2560_SHIFT_D) | RT2560_C); 835156321Sdamien } 836156321Sdamien 837156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 838156321Sdamien 839156321Sdamien /* read data Q15-Q0 */ 840156321Sdamien val = 0; 841156321Sdamien for (n = 15; n >= 0; n--) { 842156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 843156321Sdamien tmp = RAL_READ(sc, RT2560_CSR21); 844156321Sdamien val |= ((tmp & RT2560_Q) >> RT2560_SHIFT_Q) << n; 845156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 846156321Sdamien } 847156321Sdamien 848156321Sdamien RT2560_EEPROM_CTL(sc, 0); 849156321Sdamien 850156321Sdamien /* clear Chip Select and clock C */ 851156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 852156321Sdamien RT2560_EEPROM_CTL(sc, 0); 853156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_C); 854156321Sdamien 855156321Sdamien return val; 856156321Sdamien} 857156321Sdamien 858156321Sdamien/* 859156321Sdamien * Some frames were processed by the hardware cipher engine and are ready for 860156321Sdamien * transmission. 861156321Sdamien */ 862156321Sdamienstatic void 863156321Sdamienrt2560_encryption_intr(struct rt2560_softc *sc) 864156321Sdamien{ 865156321Sdamien struct rt2560_tx_desc *desc; 866156321Sdamien int hw; 867156321Sdamien 868156321Sdamien /* retrieve last descriptor index processed by cipher engine */ 869156321Sdamien hw = RAL_READ(sc, RT2560_SECCSR1) - sc->txq.physaddr; 870156321Sdamien hw /= RT2560_TX_DESC_SIZE; 871156321Sdamien 872156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 873156321Sdamien BUS_DMASYNC_POSTREAD); 874156321Sdamien 875175938Ssephe while (sc->txq.next_encrypt != hw) { 876175938Ssephe if (sc->txq.next_encrypt == sc->txq.cur_encrypt) { 877175938Ssephe printf("hw encrypt %d, cur_encrypt %d\n", hw, 878175938Ssephe sc->txq.cur_encrypt); 879175938Ssephe break; 880175938Ssephe } 881175938Ssephe 882156321Sdamien desc = &sc->txq.desc[sc->txq.next_encrypt]; 883156321Sdamien 884156321Sdamien if ((le32toh(desc->flags) & RT2560_TX_BUSY) || 885156321Sdamien (le32toh(desc->flags) & RT2560_TX_CIPHER_BUSY)) 886156321Sdamien break; 887156321Sdamien 888156321Sdamien /* for TKIP, swap eiv field to fix a bug in ASIC */ 889156321Sdamien if ((le32toh(desc->flags) & RT2560_TX_CIPHER_MASK) == 890156321Sdamien RT2560_TX_CIPHER_TKIP) 891156321Sdamien desc->eiv = bswap32(desc->eiv); 892156321Sdamien 893156321Sdamien /* mark the frame ready for transmission */ 894175938Ssephe desc->flags |= htole32(RT2560_TX_VALID); 895175938Ssephe desc->flags |= htole32(RT2560_TX_BUSY); 896156321Sdamien 897178354Ssam DPRINTFN(sc, 15, "encryption done idx=%u\n", 898178354Ssam sc->txq.next_encrypt); 899156321Sdamien 900156321Sdamien sc->txq.next_encrypt = 901156321Sdamien (sc->txq.next_encrypt + 1) % RT2560_TX_RING_COUNT; 902156321Sdamien } 903156321Sdamien 904156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 905156321Sdamien BUS_DMASYNC_PREWRITE); 906156321Sdamien 907156321Sdamien /* kick Tx */ 908156321Sdamien RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_TX); 909156321Sdamien} 910156321Sdamien 911156321Sdamienstatic void 912156321Sdamienrt2560_tx_intr(struct rt2560_softc *sc) 913156321Sdamien{ 914156321Sdamien struct rt2560_tx_desc *desc; 915156321Sdamien struct rt2560_tx_data *data; 916178354Ssam struct mbuf *m; 917206358Srpaulo struct ieee80211vap *vap; 918206358Srpaulo struct ieee80211_node *ni; 919287197Sglebius uint32_t flags; 920287197Sglebius int retrycnt, status; 921156321Sdamien 922156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 923156321Sdamien BUS_DMASYNC_POSTREAD); 924156321Sdamien 925156321Sdamien for (;;) { 926156321Sdamien desc = &sc->txq.desc[sc->txq.next]; 927156321Sdamien data = &sc->txq.data[sc->txq.next]; 928156321Sdamien 929178354Ssam flags = le32toh(desc->flags); 930178354Ssam if ((flags & RT2560_TX_BUSY) || 931178354Ssam (flags & RT2560_TX_CIPHER_BUSY) || 932178354Ssam !(flags & RT2560_TX_VALID)) 933156321Sdamien break; 934156321Sdamien 935178354Ssam m = data->m; 936206358Srpaulo ni = data->ni; 937206358Srpaulo vap = ni->ni_vap; 938156321Sdamien 939178354Ssam switch (flags & RT2560_TX_RESULT_MASK) { 940156321Sdamien case RT2560_TX_SUCCESS: 941206358Srpaulo retrycnt = 0; 942206358Srpaulo 943178354Ssam DPRINTFN(sc, 10, "%s\n", "data frame sent successfully"); 944178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 945206358Srpaulo ieee80211_ratectl_tx_complete(vap, ni, 946206358Srpaulo IEEE80211_RATECTL_TX_SUCCESS, 947206358Srpaulo &retrycnt, NULL); 948287197Sglebius status = 0; 949156321Sdamien break; 950156321Sdamien 951156321Sdamien case RT2560_TX_SUCCESS_RETRY: 952178354Ssam retrycnt = RT2560_TX_RETRYCNT(flags); 953178354Ssam 954178354Ssam DPRINTFN(sc, 9, "data frame sent after %u retries\n", 955178354Ssam retrycnt); 956178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 957206358Srpaulo ieee80211_ratectl_tx_complete(vap, ni, 958206358Srpaulo IEEE80211_RATECTL_TX_SUCCESS, 959206358Srpaulo &retrycnt, NULL); 960287197Sglebius status = 0; 961156321Sdamien break; 962156321Sdamien 963156321Sdamien case RT2560_TX_FAIL_RETRY: 964178354Ssam retrycnt = RT2560_TX_RETRYCNT(flags); 965178354Ssam 966178354Ssam DPRINTFN(sc, 9, "data frame failed after %d retries\n", 967178354Ssam retrycnt); 968178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 969206358Srpaulo ieee80211_ratectl_tx_complete(vap, ni, 970206358Srpaulo IEEE80211_RATECTL_TX_FAILURE, 971206358Srpaulo &retrycnt, NULL); 972287197Sglebius status = 1; 973156321Sdamien break; 974156321Sdamien 975156321Sdamien case RT2560_TX_FAIL_INVALID: 976156321Sdamien case RT2560_TX_FAIL_OTHER: 977156321Sdamien default: 978156321Sdamien device_printf(sc->sc_dev, "sending data frame failed " 979178354Ssam "0x%08x\n", flags); 980287197Sglebius status = 1; 981156321Sdamien } 982156321Sdamien 983156321Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, 984156321Sdamien BUS_DMASYNC_POSTWRITE); 985156321Sdamien bus_dmamap_unload(sc->txq.data_dmat, data->map); 986287197Sglebius 987287197Sglebius ieee80211_tx_complete(ni, m, status); 988287197Sglebius data->ni = NULL; 989286437Sadrian data->m = NULL; 990156321Sdamien 991156321Sdamien /* descriptor is no longer valid */ 992156321Sdamien desc->flags &= ~htole32(RT2560_TX_VALID); 993156321Sdamien 994178354Ssam DPRINTFN(sc, 15, "tx done idx=%u\n", sc->txq.next); 995156321Sdamien 996156321Sdamien sc->txq.queued--; 997156321Sdamien sc->txq.next = (sc->txq.next + 1) % RT2560_TX_RING_COUNT; 998156321Sdamien } 999156321Sdamien 1000156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 1001156321Sdamien BUS_DMASYNC_PREWRITE); 1002156321Sdamien 1003175938Ssephe if (sc->prioq.queued == 0 && sc->txq.queued == 0) 1004175938Ssephe sc->sc_tx_timer = 0; 1005175938Ssephe 1006287197Sglebius if (sc->txq.queued < RT2560_TX_RING_COUNT - 1) 1007287197Sglebius rt2560_start(sc); 1008156321Sdamien} 1009156321Sdamien 1010156321Sdamienstatic void 1011156321Sdamienrt2560_prio_intr(struct rt2560_softc *sc) 1012156321Sdamien{ 1013156321Sdamien struct rt2560_tx_desc *desc; 1014156321Sdamien struct rt2560_tx_data *data; 1015170530Ssam struct ieee80211_node *ni; 1016170530Ssam struct mbuf *m; 1017170530Ssam int flags; 1018156321Sdamien 1019156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1020156321Sdamien BUS_DMASYNC_POSTREAD); 1021156321Sdamien 1022156321Sdamien for (;;) { 1023156321Sdamien desc = &sc->prioq.desc[sc->prioq.next]; 1024156321Sdamien data = &sc->prioq.data[sc->prioq.next]; 1025156321Sdamien 1026170530Ssam flags = le32toh(desc->flags); 1027170530Ssam if ((flags & RT2560_TX_BUSY) || (flags & RT2560_TX_VALID) == 0) 1028156321Sdamien break; 1029156321Sdamien 1030170530Ssam switch (flags & RT2560_TX_RESULT_MASK) { 1031156321Sdamien case RT2560_TX_SUCCESS: 1032178354Ssam DPRINTFN(sc, 10, "%s\n", "mgt frame sent successfully"); 1033156321Sdamien break; 1034156321Sdamien 1035156321Sdamien case RT2560_TX_SUCCESS_RETRY: 1036178354Ssam DPRINTFN(sc, 9, "mgt frame sent after %u retries\n", 1037178354Ssam (flags >> 5) & 0x7); 1038156321Sdamien break; 1039156321Sdamien 1040156321Sdamien case RT2560_TX_FAIL_RETRY: 1041178354Ssam DPRINTFN(sc, 9, "%s\n", 1042178354Ssam "sending mgt frame failed (too much retries)"); 1043156321Sdamien break; 1044156321Sdamien 1045156321Sdamien case RT2560_TX_FAIL_INVALID: 1046156321Sdamien case RT2560_TX_FAIL_OTHER: 1047156321Sdamien default: 1048156321Sdamien device_printf(sc->sc_dev, "sending mgt frame failed " 1049170530Ssam "0x%08x\n", flags); 1050170530Ssam break; 1051156321Sdamien } 1052156321Sdamien 1053156321Sdamien bus_dmamap_sync(sc->prioq.data_dmat, data->map, 1054156321Sdamien BUS_DMASYNC_POSTWRITE); 1055156321Sdamien bus_dmamap_unload(sc->prioq.data_dmat, data->map); 1056170530Ssam 1057170530Ssam m = data->m; 1058156321Sdamien data->m = NULL; 1059170530Ssam ni = data->ni; 1060156321Sdamien data->ni = NULL; 1061156321Sdamien 1062156321Sdamien /* descriptor is no longer valid */ 1063156321Sdamien desc->flags &= ~htole32(RT2560_TX_VALID); 1064156321Sdamien 1065178354Ssam DPRINTFN(sc, 15, "prio done idx=%u\n", sc->prioq.next); 1066156321Sdamien 1067156321Sdamien sc->prioq.queued--; 1068156321Sdamien sc->prioq.next = (sc->prioq.next + 1) % RT2560_PRIO_RING_COUNT; 1069170530Ssam 1070170530Ssam if (m->m_flags & M_TXCB) 1071170530Ssam ieee80211_process_callback(ni, m, 1072170530Ssam (flags & RT2560_TX_RESULT_MASK) &~ 1073170530Ssam (RT2560_TX_SUCCESS | RT2560_TX_SUCCESS_RETRY)); 1074170530Ssam m_freem(m); 1075170530Ssam ieee80211_free_node(ni); 1076156321Sdamien } 1077156321Sdamien 1078156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1079156321Sdamien BUS_DMASYNC_PREWRITE); 1080156321Sdamien 1081175938Ssephe if (sc->prioq.queued == 0 && sc->txq.queued == 0) 1082175938Ssephe sc->sc_tx_timer = 0; 1083175938Ssephe 1084287197Sglebius if (sc->prioq.queued < RT2560_PRIO_RING_COUNT) 1085287197Sglebius rt2560_start(sc); 1086156321Sdamien} 1087156321Sdamien 1088156321Sdamien/* 1089156321Sdamien * Some frames were processed by the hardware cipher engine and are ready for 1090178354Ssam * handoff to the IEEE802.11 layer. 1091156321Sdamien */ 1092156321Sdamienstatic void 1093156321Sdamienrt2560_decryption_intr(struct rt2560_softc *sc) 1094156321Sdamien{ 1095287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 1096156321Sdamien struct rt2560_rx_desc *desc; 1097156321Sdamien struct rt2560_rx_data *data; 1098156321Sdamien bus_addr_t physaddr; 1099156321Sdamien struct ieee80211_frame *wh; 1100156321Sdamien struct ieee80211_node *ni; 1101156321Sdamien struct mbuf *mnew, *m; 1102156321Sdamien int hw, error; 1103192468Ssam int8_t rssi, nf; 1104156321Sdamien 1105298955Spfg /* retrieve last descriptor index processed by cipher engine */ 1106156321Sdamien hw = RAL_READ(sc, RT2560_SECCSR0) - sc->rxq.physaddr; 1107156321Sdamien hw /= RT2560_RX_DESC_SIZE; 1108156321Sdamien 1109156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1110156321Sdamien BUS_DMASYNC_POSTREAD); 1111156321Sdamien 1112156321Sdamien for (; sc->rxq.cur_decrypt != hw;) { 1113156321Sdamien desc = &sc->rxq.desc[sc->rxq.cur_decrypt]; 1114156321Sdamien data = &sc->rxq.data[sc->rxq.cur_decrypt]; 1115156321Sdamien 1116156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_BUSY) || 1117156321Sdamien (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY)) 1118156321Sdamien break; 1119156321Sdamien 1120156321Sdamien if (data->drop) { 1121287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 1122156321Sdamien goto skip; 1123156321Sdamien } 1124156321Sdamien 1125156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_CIPHER_MASK) != 0 && 1126156321Sdamien (le32toh(desc->flags) & RT2560_RX_ICV_ERROR)) { 1127287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 1128156321Sdamien goto skip; 1129156321Sdamien } 1130156321Sdamien 1131156321Sdamien /* 1132156321Sdamien * Try to allocate a new mbuf for this ring element and load it 1133156321Sdamien * before processing the current mbuf. If the ring element 1134156321Sdamien * cannot be loaded, drop the received packet and reuse the old 1135156321Sdamien * mbuf. In the unlikely case that the old mbuf can't be 1136156321Sdamien * reloaded either, explicitly panic. 1137156321Sdamien */ 1138243857Sglebius mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1139156321Sdamien if (mnew == NULL) { 1140287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 1141156321Sdamien goto skip; 1142156321Sdamien } 1143156321Sdamien 1144156321Sdamien bus_dmamap_sync(sc->rxq.data_dmat, data->map, 1145156321Sdamien BUS_DMASYNC_POSTREAD); 1146156321Sdamien bus_dmamap_unload(sc->rxq.data_dmat, data->map); 1147156321Sdamien 1148156321Sdamien error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 1149156321Sdamien mtod(mnew, void *), MCLBYTES, rt2560_dma_map_addr, 1150156321Sdamien &physaddr, 0); 1151156321Sdamien if (error != 0) { 1152156321Sdamien m_freem(mnew); 1153156321Sdamien 1154156321Sdamien /* try to reload the old mbuf */ 1155156321Sdamien error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 1156156321Sdamien mtod(data->m, void *), MCLBYTES, 1157156321Sdamien rt2560_dma_map_addr, &physaddr, 0); 1158156321Sdamien if (error != 0) { 1159156321Sdamien /* very unlikely that it will fail... */ 1160156321Sdamien panic("%s: could not load old rx mbuf", 1161156321Sdamien device_get_name(sc->sc_dev)); 1162156321Sdamien } 1163287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 1164156321Sdamien goto skip; 1165156321Sdamien } 1166156321Sdamien 1167156321Sdamien /* 1168156321Sdamien * New mbuf successfully loaded, update Rx ring and continue 1169156321Sdamien * processing. 1170156321Sdamien */ 1171156321Sdamien m = data->m; 1172156321Sdamien data->m = mnew; 1173156321Sdamien desc->physaddr = htole32(physaddr); 1174156321Sdamien 1175156321Sdamien /* finalize mbuf */ 1176156321Sdamien m->m_pkthdr.len = m->m_len = 1177156321Sdamien (le32toh(desc->flags) >> 16) & 0xfff; 1178156321Sdamien 1179192468Ssam rssi = RT2560_RSSI(sc, desc->rssi); 1180192468Ssam nf = RT2560_NOISE_FLOOR; 1181192468Ssam if (ieee80211_radiotap_active(ic)) { 1182156321Sdamien struct rt2560_rx_radiotap_header *tap = &sc->sc_rxtap; 1183156321Sdamien uint32_t tsf_lo, tsf_hi; 1184156321Sdamien 1185156321Sdamien /* get timestamp (low and high 32 bits) */ 1186156321Sdamien tsf_hi = RAL_READ(sc, RT2560_CSR17); 1187156321Sdamien tsf_lo = RAL_READ(sc, RT2560_CSR16); 1188156321Sdamien 1189156321Sdamien tap->wr_tsf = 1190156321Sdamien htole64(((uint64_t)tsf_hi << 32) | tsf_lo); 1191156321Sdamien tap->wr_flags = 0; 1192178354Ssam tap->wr_rate = ieee80211_plcp2rate(desc->rate, 1193178958Ssam (desc->flags & htole32(RT2560_RX_OFDM)) ? 1194178958Ssam IEEE80211_T_OFDM : IEEE80211_T_CCK); 1195156321Sdamien tap->wr_antenna = sc->rx_ant; 1196192468Ssam tap->wr_antsignal = nf + rssi; 1197192468Ssam tap->wr_antnoise = nf; 1198156321Sdamien } 1199156321Sdamien 1200175938Ssephe sc->sc_flags |= RT2560_F_INPUT_RUNNING; 1201170530Ssam RAL_UNLOCK(sc); 1202156321Sdamien wh = mtod(m, struct ieee80211_frame *); 1203156321Sdamien ni = ieee80211_find_rxnode(ic, 1204156321Sdamien (struct ieee80211_frame_min *)wh); 1205178354Ssam if (ni != NULL) { 1206192468Ssam (void) ieee80211_input(ni, m, rssi, nf); 1207178354Ssam ieee80211_free_node(ni); 1208178354Ssam } else 1209192468Ssam (void) ieee80211_input_all(ic, m, rssi, nf); 1210156321Sdamien 1211170530Ssam RAL_LOCK(sc); 1212175938Ssephe sc->sc_flags &= ~RT2560_F_INPUT_RUNNING; 1213156321Sdamienskip: desc->flags = htole32(RT2560_RX_BUSY); 1214156321Sdamien 1215178354Ssam DPRINTFN(sc, 15, "decryption done idx=%u\n", sc->rxq.cur_decrypt); 1216156321Sdamien 1217156321Sdamien sc->rxq.cur_decrypt = 1218156321Sdamien (sc->rxq.cur_decrypt + 1) % RT2560_RX_RING_COUNT; 1219156321Sdamien } 1220156321Sdamien 1221156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1222156321Sdamien BUS_DMASYNC_PREWRITE); 1223156321Sdamien} 1224156321Sdamien 1225156321Sdamien/* 1226156321Sdamien * Some frames were received. Pass them to the hardware cipher engine before 1227156321Sdamien * sending them to the 802.11 layer. 1228156321Sdamien */ 1229156321Sdamienstatic void 1230156321Sdamienrt2560_rx_intr(struct rt2560_softc *sc) 1231156321Sdamien{ 1232156321Sdamien struct rt2560_rx_desc *desc; 1233156321Sdamien struct rt2560_rx_data *data; 1234156321Sdamien 1235156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1236156321Sdamien BUS_DMASYNC_POSTREAD); 1237156321Sdamien 1238156321Sdamien for (;;) { 1239156321Sdamien desc = &sc->rxq.desc[sc->rxq.cur]; 1240156321Sdamien data = &sc->rxq.data[sc->rxq.cur]; 1241156321Sdamien 1242156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_BUSY) || 1243156321Sdamien (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY)) 1244156321Sdamien break; 1245156321Sdamien 1246156321Sdamien data->drop = 0; 1247156321Sdamien 1248156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_PHY_ERROR) || 1249156321Sdamien (le32toh(desc->flags) & RT2560_RX_CRC_ERROR)) { 1250156321Sdamien /* 1251156321Sdamien * This should not happen since we did not request 1252156321Sdamien * to receive those frames when we filled RXCSR0. 1253156321Sdamien */ 1254178354Ssam DPRINTFN(sc, 5, "PHY or CRC error flags 0x%08x\n", 1255178354Ssam le32toh(desc->flags)); 1256156321Sdamien data->drop = 1; 1257156321Sdamien } 1258156321Sdamien 1259156321Sdamien if (((le32toh(desc->flags) >> 16) & 0xfff) > MCLBYTES) { 1260178354Ssam DPRINTFN(sc, 5, "%s\n", "bad length"); 1261156321Sdamien data->drop = 1; 1262156321Sdamien } 1263156321Sdamien 1264156321Sdamien /* mark the frame for decryption */ 1265156321Sdamien desc->flags |= htole32(RT2560_RX_CIPHER_BUSY); 1266156321Sdamien 1267178354Ssam DPRINTFN(sc, 15, "rx done idx=%u\n", sc->rxq.cur); 1268156321Sdamien 1269156321Sdamien sc->rxq.cur = (sc->rxq.cur + 1) % RT2560_RX_RING_COUNT; 1270156321Sdamien } 1271156321Sdamien 1272156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1273156321Sdamien BUS_DMASYNC_PREWRITE); 1274156321Sdamien 1275156321Sdamien /* kick decrypt */ 1276156321Sdamien RAL_WRITE(sc, RT2560_SECCSR0, RT2560_KICK_DECRYPT); 1277156321Sdamien} 1278156321Sdamien 1279172211Ssamstatic void 1280178354Ssamrt2560_beacon_update(struct ieee80211vap *vap, int item) 1281172211Ssam{ 1282288095Sadrian struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; 1283172211Ssam 1284172211Ssam setbit(bo->bo_flags, item); 1285172211Ssam} 1286172211Ssam 1287156321Sdamien/* 1288156321Sdamien * This function is called periodically in IBSS mode when a new beacon must be 1289156321Sdamien * sent out. 1290156321Sdamien */ 1291156321Sdamienstatic void 1292156321Sdamienrt2560_beacon_expire(struct rt2560_softc *sc) 1293156321Sdamien{ 1294287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 1295156321Sdamien struct rt2560_tx_data *data; 1296156321Sdamien 1297156321Sdamien if (ic->ic_opmode != IEEE80211_M_IBSS && 1298195618Srpaulo ic->ic_opmode != IEEE80211_M_HOSTAP && 1299195618Srpaulo ic->ic_opmode != IEEE80211_M_MBSS) 1300170530Ssam return; 1301156321Sdamien 1302156321Sdamien data = &sc->bcnq.data[sc->bcnq.next]; 1303170530Ssam /* 1304170530Ssam * Don't send beacon if bsschan isn't set 1305170530Ssam */ 1306170530Ssam if (data->ni == NULL) 1307170530Ssam return; 1308156321Sdamien 1309156321Sdamien bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_POSTWRITE); 1310156321Sdamien bus_dmamap_unload(sc->bcnq.data_dmat, data->map); 1311156321Sdamien 1312178354Ssam /* XXX 1 =>'s mcast frames which means all PS sta's will wakeup! */ 1313288636Sadrian ieee80211_beacon_update(data->ni, data->m, 1); 1314156321Sdamien 1315156321Sdamien rt2560_tx_bcn(sc, data->m, data->ni); 1316156321Sdamien 1317178354Ssam DPRINTFN(sc, 15, "%s", "beacon expired\n"); 1318156321Sdamien 1319156321Sdamien sc->bcnq.next = (sc->bcnq.next + 1) % RT2560_BEACON_RING_COUNT; 1320156321Sdamien} 1321156321Sdamien 1322156321Sdamien/* ARGSUSED */ 1323156321Sdamienstatic void 1324156321Sdamienrt2560_wakeup_expire(struct rt2560_softc *sc) 1325156321Sdamien{ 1326178354Ssam DPRINTFN(sc, 2, "%s", "wakeup expired\n"); 1327156321Sdamien} 1328156321Sdamien 1329156321Sdamienvoid 1330156321Sdamienrt2560_intr(void *arg) 1331156321Sdamien{ 1332156321Sdamien struct rt2560_softc *sc = arg; 1333156321Sdamien uint32_t r; 1334156321Sdamien 1335156321Sdamien RAL_LOCK(sc); 1336156321Sdamien 1337156321Sdamien /* disable interrupts */ 1338156321Sdamien RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 1339156321Sdamien 1340156975Sdamien /* don't re-enable interrupts if we're shutting down */ 1341287197Sglebius if (!(sc->sc_flags & RT2560_F_RUNNING)) { 1342156975Sdamien RAL_UNLOCK(sc); 1343156975Sdamien return; 1344156975Sdamien } 1345156975Sdamien 1346156321Sdamien r = RAL_READ(sc, RT2560_CSR7); 1347156321Sdamien RAL_WRITE(sc, RT2560_CSR7, r); 1348156321Sdamien 1349156321Sdamien if (r & RT2560_BEACON_EXPIRE) 1350156321Sdamien rt2560_beacon_expire(sc); 1351156321Sdamien 1352156321Sdamien if (r & RT2560_WAKEUP_EXPIRE) 1353156321Sdamien rt2560_wakeup_expire(sc); 1354156321Sdamien 1355156321Sdamien if (r & RT2560_ENCRYPTION_DONE) 1356156321Sdamien rt2560_encryption_intr(sc); 1357156321Sdamien 1358156321Sdamien if (r & RT2560_TX_DONE) 1359156321Sdamien rt2560_tx_intr(sc); 1360156321Sdamien 1361156321Sdamien if (r & RT2560_PRIO_DONE) 1362156321Sdamien rt2560_prio_intr(sc); 1363156321Sdamien 1364156321Sdamien if (r & RT2560_DECRYPTION_DONE) 1365156321Sdamien rt2560_decryption_intr(sc); 1366156321Sdamien 1367175938Ssephe if (r & RT2560_RX_DONE) { 1368156321Sdamien rt2560_rx_intr(sc); 1369175938Ssephe rt2560_encryption_intr(sc); 1370175938Ssephe } 1371156321Sdamien 1372156321Sdamien /* re-enable interrupts */ 1373156321Sdamien RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); 1374156321Sdamien 1375156321Sdamien RAL_UNLOCK(sc); 1376156321Sdamien} 1377156321Sdamien 1378156321Sdamien#define RAL_SIFS 10 /* us */ 1379156321Sdamien 1380156321Sdamien#define RT2560_TXRX_TURNAROUND 10 /* us */ 1381156321Sdamien 1382178958Ssamstatic uint8_t 1383178958Ssamrt2560_plcp_signal(int rate) 1384178958Ssam{ 1385178958Ssam switch (rate) { 1386178958Ssam /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ 1387178958Ssam case 12: return 0xb; 1388178958Ssam case 18: return 0xf; 1389178958Ssam case 24: return 0xa; 1390178958Ssam case 36: return 0xe; 1391178958Ssam case 48: return 0x9; 1392178958Ssam case 72: return 0xd; 1393178958Ssam case 96: return 0x8; 1394178958Ssam case 108: return 0xc; 1395178958Ssam 1396178958Ssam /* CCK rates (NB: not IEEE std, device-specific) */ 1397178958Ssam case 2: return 0x0; 1398178958Ssam case 4: return 0x1; 1399178958Ssam case 11: return 0x2; 1400178958Ssam case 22: return 0x3; 1401178958Ssam } 1402178958Ssam return 0xff; /* XXX unsupported/unknown rate */ 1403178958Ssam} 1404178958Ssam 1405156321Sdamienstatic void 1406156321Sdamienrt2560_setup_tx_desc(struct rt2560_softc *sc, struct rt2560_tx_desc *desc, 1407156321Sdamien uint32_t flags, int len, int rate, int encrypt, bus_addr_t physaddr) 1408156321Sdamien{ 1409287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 1410156321Sdamien uint16_t plcp_length; 1411156321Sdamien int remainder; 1412156321Sdamien 1413156321Sdamien desc->flags = htole32(flags); 1414156321Sdamien desc->flags |= htole32(len << 16); 1415156321Sdamien 1416156321Sdamien desc->physaddr = htole32(physaddr); 1417156321Sdamien desc->wme = htole16( 1418156321Sdamien RT2560_AIFSN(2) | 1419156321Sdamien RT2560_LOGCWMIN(3) | 1420156321Sdamien RT2560_LOGCWMAX(8)); 1421156321Sdamien 1422156321Sdamien /* setup PLCP fields */ 1423178958Ssam desc->plcp_signal = rt2560_plcp_signal(rate); 1424156321Sdamien desc->plcp_service = 4; 1425156321Sdamien 1426156321Sdamien len += IEEE80211_CRC_LEN; 1427190532Ssam if (ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) { 1428156321Sdamien desc->flags |= htole32(RT2560_TX_OFDM); 1429156321Sdamien 1430156321Sdamien plcp_length = len & 0xfff; 1431156321Sdamien desc->plcp_length_hi = plcp_length >> 6; 1432156321Sdamien desc->plcp_length_lo = plcp_length & 0x3f; 1433156321Sdamien } else { 1434298646Spfg plcp_length = howmany(16 * len, rate); 1435156321Sdamien if (rate == 22) { 1436156321Sdamien remainder = (16 * len) % 22; 1437156321Sdamien if (remainder != 0 && remainder < 7) 1438156321Sdamien desc->plcp_service |= RT2560_PLCP_LENGEXT; 1439156321Sdamien } 1440156321Sdamien desc->plcp_length_hi = plcp_length >> 8; 1441156321Sdamien desc->plcp_length_lo = plcp_length & 0xff; 1442156321Sdamien 1443156321Sdamien if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 1444156321Sdamien desc->plcp_signal |= 0x08; 1445156321Sdamien } 1446175938Ssephe 1447175938Ssephe if (!encrypt) 1448175938Ssephe desc->flags |= htole32(RT2560_TX_VALID); 1449175938Ssephe desc->flags |= encrypt ? htole32(RT2560_TX_CIPHER_BUSY) 1450175938Ssephe : htole32(RT2560_TX_BUSY); 1451156321Sdamien} 1452156321Sdamien 1453156321Sdamienstatic int 1454156321Sdamienrt2560_tx_bcn(struct rt2560_softc *sc, struct mbuf *m0, 1455156321Sdamien struct ieee80211_node *ni) 1456156321Sdamien{ 1457178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1458156321Sdamien struct rt2560_tx_desc *desc; 1459156321Sdamien struct rt2560_tx_data *data; 1460156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1461156321Sdamien int nsegs, rate, error; 1462156321Sdamien 1463156321Sdamien desc = &sc->bcnq.desc[sc->bcnq.cur]; 1464156321Sdamien data = &sc->bcnq.data[sc->bcnq.cur]; 1465156321Sdamien 1466178354Ssam /* XXX maybe a separate beacon rate? */ 1467178354Ssam rate = vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)].mgmtrate; 1468156321Sdamien 1469156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->bcnq.data_dmat, data->map, m0, 1470156321Sdamien segs, &nsegs, BUS_DMA_NOWAIT); 1471156321Sdamien if (error != 0) { 1472156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1473156321Sdamien error); 1474156321Sdamien m_freem(m0); 1475156321Sdamien return error; 1476156321Sdamien } 1477156321Sdamien 1478192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 1479156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1480156321Sdamien 1481156321Sdamien tap->wt_flags = 0; 1482156321Sdamien tap->wt_rate = rate; 1483156321Sdamien tap->wt_antenna = sc->tx_ant; 1484156321Sdamien 1485192468Ssam ieee80211_radiotap_tx(vap, m0); 1486156321Sdamien } 1487156321Sdamien 1488156321Sdamien data->m = m0; 1489156321Sdamien data->ni = ni; 1490156321Sdamien 1491156321Sdamien rt2560_setup_tx_desc(sc, desc, RT2560_TX_IFS_NEWBACKOFF | 1492156321Sdamien RT2560_TX_TIMESTAMP, m0->m_pkthdr.len, rate, 0, segs->ds_addr); 1493156321Sdamien 1494178354Ssam DPRINTFN(sc, 10, "sending beacon frame len=%u idx=%u rate=%u\n", 1495178354Ssam m0->m_pkthdr.len, sc->bcnq.cur, rate); 1496156321Sdamien 1497156321Sdamien bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1498156321Sdamien bus_dmamap_sync(sc->bcnq.desc_dmat, sc->bcnq.desc_map, 1499156321Sdamien BUS_DMASYNC_PREWRITE); 1500156321Sdamien 1501156321Sdamien sc->bcnq.cur = (sc->bcnq.cur + 1) % RT2560_BEACON_RING_COUNT; 1502156321Sdamien 1503156321Sdamien return 0; 1504156321Sdamien} 1505156321Sdamien 1506156321Sdamienstatic int 1507156321Sdamienrt2560_tx_mgt(struct rt2560_softc *sc, struct mbuf *m0, 1508156321Sdamien struct ieee80211_node *ni) 1509156321Sdamien{ 1510178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1511178354Ssam struct ieee80211com *ic = ni->ni_ic; 1512156321Sdamien struct rt2560_tx_desc *desc; 1513156321Sdamien struct rt2560_tx_data *data; 1514156321Sdamien struct ieee80211_frame *wh; 1515173386Skevlo struct ieee80211_key *k; 1516156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1517156321Sdamien uint16_t dur; 1518156321Sdamien uint32_t flags = 0; 1519156321Sdamien int nsegs, rate, error; 1520156321Sdamien 1521156321Sdamien desc = &sc->prioq.desc[sc->prioq.cur]; 1522156321Sdamien data = &sc->prioq.data[sc->prioq.cur]; 1523156321Sdamien 1524178354Ssam rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate; 1525156321Sdamien 1526173386Skevlo wh = mtod(m0, struct ieee80211_frame *); 1527173386Skevlo 1528260444Skevlo if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 1529178354Ssam k = ieee80211_crypto_encap(ni, m0); 1530173386Skevlo if (k == NULL) { 1531173386Skevlo m_freem(m0); 1532173386Skevlo return ENOBUFS; 1533173386Skevlo } 1534173386Skevlo } 1535173386Skevlo 1536156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, 1537156321Sdamien segs, &nsegs, 0); 1538156321Sdamien if (error != 0) { 1539156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1540156321Sdamien error); 1541156321Sdamien m_freem(m0); 1542156321Sdamien return error; 1543156321Sdamien } 1544156321Sdamien 1545192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 1546156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1547156321Sdamien 1548156321Sdamien tap->wt_flags = 0; 1549156321Sdamien tap->wt_rate = rate; 1550156321Sdamien tap->wt_antenna = sc->tx_ant; 1551156321Sdamien 1552192468Ssam ieee80211_radiotap_tx(vap, m0); 1553156321Sdamien } 1554156321Sdamien 1555156321Sdamien data->m = m0; 1556156321Sdamien data->ni = ni; 1557178354Ssam /* management frames are not taken into account for amrr */ 1558178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1559156321Sdamien 1560156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1561156321Sdamien 1562156321Sdamien if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1563156321Sdamien flags |= RT2560_TX_ACK; 1564156321Sdamien 1565190532Ssam dur = ieee80211_ack_duration(ic->ic_rt, 1566178354Ssam rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); 1567156321Sdamien *(uint16_t *)wh->i_dur = htole16(dur); 1568156321Sdamien 1569156321Sdamien /* tell hardware to add timestamp for probe responses */ 1570156321Sdamien if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 1571156321Sdamien IEEE80211_FC0_TYPE_MGT && 1572156321Sdamien (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 1573156321Sdamien IEEE80211_FC0_SUBTYPE_PROBE_RESP) 1574156321Sdamien flags |= RT2560_TX_TIMESTAMP; 1575156321Sdamien } 1576156321Sdamien 1577156321Sdamien rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 0, 1578156321Sdamien segs->ds_addr); 1579156321Sdamien 1580156321Sdamien bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1581156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1582156321Sdamien BUS_DMASYNC_PREWRITE); 1583156321Sdamien 1584178354Ssam DPRINTFN(sc, 10, "sending mgt frame len=%u idx=%u rate=%u\n", 1585178354Ssam m0->m_pkthdr.len, sc->prioq.cur, rate); 1586156321Sdamien 1587156321Sdamien /* kick prio */ 1588156321Sdamien sc->prioq.queued++; 1589156321Sdamien sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; 1590156321Sdamien RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); 1591156321Sdamien 1592156321Sdamien return 0; 1593156321Sdamien} 1594156321Sdamien 1595160691Ssamstatic int 1596178354Ssamrt2560_sendprot(struct rt2560_softc *sc, 1597178354Ssam const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) 1598178354Ssam{ 1599178354Ssam struct ieee80211com *ic = ni->ni_ic; 1600178354Ssam const struct ieee80211_frame *wh; 1601178354Ssam struct rt2560_tx_desc *desc; 1602178354Ssam struct rt2560_tx_data *data; 1603178354Ssam struct mbuf *mprot; 1604178354Ssam int protrate, ackrate, pktlen, flags, isshort, error; 1605178354Ssam uint16_t dur; 1606178354Ssam bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1607178354Ssam int nsegs; 1608178354Ssam 1609178354Ssam KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, 1610178354Ssam ("protection %d", prot)); 1611178354Ssam 1612178354Ssam wh = mtod(m, const struct ieee80211_frame *); 1613178354Ssam pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; 1614178354Ssam 1615190532Ssam protrate = ieee80211_ctl_rate(ic->ic_rt, rate); 1616190532Ssam ackrate = ieee80211_ack_rate(ic->ic_rt, rate); 1617178354Ssam 1618178354Ssam isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; 1619190532Ssam dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort) 1620190532Ssam + ieee80211_ack_duration(ic->ic_rt, rate, isshort); 1621178354Ssam flags = RT2560_TX_MORE_FRAG; 1622178354Ssam if (prot == IEEE80211_PROT_RTSCTS) { 1623178354Ssam /* NB: CTS is the same size as an ACK */ 1624190532Ssam dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); 1625178354Ssam flags |= RT2560_TX_ACK; 1626178354Ssam mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); 1627178354Ssam } else { 1628178354Ssam mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); 1629178354Ssam } 1630178354Ssam if (mprot == NULL) { 1631178354Ssam /* XXX stat + msg */ 1632178354Ssam return ENOBUFS; 1633178354Ssam } 1634178354Ssam 1635178354Ssam desc = &sc->txq.desc[sc->txq.cur_encrypt]; 1636178354Ssam data = &sc->txq.data[sc->txq.cur_encrypt]; 1637178354Ssam 1638178354Ssam error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, 1639178354Ssam mprot, segs, &nsegs, 0); 1640178354Ssam if (error != 0) { 1641178354Ssam device_printf(sc->sc_dev, 1642178354Ssam "could not map mbuf (error %d)\n", error); 1643178354Ssam m_freem(mprot); 1644178354Ssam return error; 1645178354Ssam } 1646178354Ssam 1647178354Ssam data->m = mprot; 1648178354Ssam data->ni = ieee80211_ref_node(ni); 1649178354Ssam /* ctl frames are not taken into account for amrr */ 1650178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1651178354Ssam 1652178354Ssam rt2560_setup_tx_desc(sc, desc, flags, mprot->m_pkthdr.len, protrate, 1, 1653178354Ssam segs->ds_addr); 1654178354Ssam 1655178354Ssam bus_dmamap_sync(sc->txq.data_dmat, data->map, 1656178354Ssam BUS_DMASYNC_PREWRITE); 1657178354Ssam 1658178354Ssam sc->txq.queued++; 1659178354Ssam sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; 1660178354Ssam 1661178354Ssam return 0; 1662178354Ssam} 1663178354Ssam 1664178354Ssamstatic int 1665160691Ssamrt2560_tx_raw(struct rt2560_softc *sc, struct mbuf *m0, 1666160691Ssam struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) 1667160691Ssam{ 1668192468Ssam struct ieee80211vap *vap = ni->ni_vap; 1669193073Ssam struct ieee80211com *ic = ni->ni_ic; 1670160691Ssam struct rt2560_tx_desc *desc; 1671160691Ssam struct rt2560_tx_data *data; 1672160691Ssam bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1673160691Ssam uint32_t flags; 1674160691Ssam int nsegs, rate, error; 1675160691Ssam 1676160691Ssam desc = &sc->prioq.desc[sc->prioq.cur]; 1677160691Ssam data = &sc->prioq.data[sc->prioq.cur]; 1678160691Ssam 1679193073Ssam rate = params->ibp_rate0; 1680193073Ssam if (!ieee80211_isratevalid(ic->ic_rt, rate)) { 1681178354Ssam /* XXX fall back to mcast/mgmt rate? */ 1682168860Ssephe m_freem(m0); 1683160691Ssam return EINVAL; 1684168860Ssephe } 1685160691Ssam 1686178354Ssam flags = 0; 1687178354Ssam if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) 1688178354Ssam flags |= RT2560_TX_ACK; 1689178354Ssam if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { 1690178354Ssam error = rt2560_sendprot(sc, m0, ni, 1691178354Ssam params->ibp_flags & IEEE80211_BPF_RTS ? 1692178354Ssam IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, 1693178354Ssam rate); 1694178354Ssam if (error) { 1695178354Ssam m_freem(m0); 1696178354Ssam return error; 1697178354Ssam } 1698178354Ssam flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; 1699178354Ssam } 1700178354Ssam 1701160691Ssam error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, 1702160691Ssam segs, &nsegs, 0); 1703160691Ssam if (error != 0) { 1704160691Ssam device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1705160691Ssam error); 1706160691Ssam m_freem(m0); 1707160691Ssam return error; 1708160691Ssam } 1709160691Ssam 1710192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 1711160691Ssam struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1712160691Ssam 1713160691Ssam tap->wt_flags = 0; 1714160691Ssam tap->wt_rate = rate; 1715160691Ssam tap->wt_antenna = sc->tx_ant; 1716160691Ssam 1717192468Ssam ieee80211_radiotap_tx(ni->ni_vap, m0); 1718160691Ssam } 1719160691Ssam 1720160691Ssam data->m = m0; 1721160691Ssam data->ni = ni; 1722160691Ssam 1723160691Ssam /* XXX need to setup descriptor ourself */ 1724160691Ssam rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, 1725160691Ssam rate, (params->ibp_flags & IEEE80211_BPF_CRYPTO) != 0, 1726160691Ssam segs->ds_addr); 1727160691Ssam 1728160691Ssam bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1729160691Ssam bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1730160691Ssam BUS_DMASYNC_PREWRITE); 1731160691Ssam 1732178354Ssam DPRINTFN(sc, 10, "sending raw frame len=%u idx=%u rate=%u\n", 1733178354Ssam m0->m_pkthdr.len, sc->prioq.cur, rate); 1734160691Ssam 1735160691Ssam /* kick prio */ 1736160691Ssam sc->prioq.queued++; 1737160691Ssam sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; 1738160691Ssam RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); 1739160691Ssam 1740160691Ssam return 0; 1741160691Ssam} 1742160691Ssam 1743156321Sdamienstatic int 1744156321Sdamienrt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0, 1745156321Sdamien struct ieee80211_node *ni) 1746156321Sdamien{ 1747178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1748178354Ssam struct ieee80211com *ic = ni->ni_ic; 1749156321Sdamien struct rt2560_tx_desc *desc; 1750156321Sdamien struct rt2560_tx_data *data; 1751156321Sdamien struct ieee80211_frame *wh; 1752178354Ssam const struct ieee80211_txparam *tp; 1753156321Sdamien struct ieee80211_key *k; 1754156321Sdamien struct mbuf *mnew; 1755156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1756156321Sdamien uint16_t dur; 1757178354Ssam uint32_t flags; 1758156321Sdamien int nsegs, rate, error; 1759156321Sdamien 1760156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1761156321Sdamien 1762178354Ssam tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; 1763178354Ssam if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1764178354Ssam rate = tp->mcastrate; 1765178354Ssam } else if (m0->m_flags & M_EAPOL) { 1766178354Ssam rate = tp->mgmtrate; 1767178354Ssam } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 1768178354Ssam rate = tp->ucastrate; 1769156321Sdamien } else { 1770206358Srpaulo (void) ieee80211_ratectl_rate(ni, NULL, 0); 1771178354Ssam rate = ni->ni_txrate; 1772156321Sdamien } 1773156321Sdamien 1774260444Skevlo if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 1775178354Ssam k = ieee80211_crypto_encap(ni, m0); 1776156321Sdamien if (k == NULL) { 1777156321Sdamien m_freem(m0); 1778156321Sdamien return ENOBUFS; 1779156321Sdamien } 1780156321Sdamien 1781156321Sdamien /* packet header may have moved, reset our local pointer */ 1782156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1783156321Sdamien } 1784156321Sdamien 1785178354Ssam flags = 0; 1786178354Ssam if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1787178354Ssam int prot = IEEE80211_PROT_NONE; 1788178354Ssam if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) 1789178354Ssam prot = IEEE80211_PROT_RTSCTS; 1790178354Ssam else if ((ic->ic_flags & IEEE80211_F_USEPROT) && 1791190532Ssam ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) 1792178354Ssam prot = ic->ic_protmode; 1793178354Ssam if (prot != IEEE80211_PROT_NONE) { 1794178354Ssam error = rt2560_sendprot(sc, m0, ni, prot, rate); 1795178354Ssam if (error) { 1796178354Ssam m_freem(m0); 1797178354Ssam return error; 1798178354Ssam } 1799178354Ssam flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; 1800156321Sdamien } 1801156321Sdamien } 1802156321Sdamien 1803156321Sdamien data = &sc->txq.data[sc->txq.cur_encrypt]; 1804156321Sdamien desc = &sc->txq.desc[sc->txq.cur_encrypt]; 1805156321Sdamien 1806156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, m0, 1807156321Sdamien segs, &nsegs, 0); 1808156321Sdamien if (error != 0 && error != EFBIG) { 1809156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1810156321Sdamien error); 1811156321Sdamien m_freem(m0); 1812156321Sdamien return error; 1813156321Sdamien } 1814156321Sdamien if (error != 0) { 1815243857Sglebius mnew = m_defrag(m0, M_NOWAIT); 1816156321Sdamien if (mnew == NULL) { 1817156321Sdamien device_printf(sc->sc_dev, 1818156321Sdamien "could not defragment mbuf\n"); 1819156321Sdamien m_freem(m0); 1820156321Sdamien return ENOBUFS; 1821156321Sdamien } 1822156321Sdamien m0 = mnew; 1823156321Sdamien 1824156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, 1825156321Sdamien m0, segs, &nsegs, 0); 1826156321Sdamien if (error != 0) { 1827156321Sdamien device_printf(sc->sc_dev, 1828156321Sdamien "could not map mbuf (error %d)\n", error); 1829156321Sdamien m_freem(m0); 1830156321Sdamien return error; 1831156321Sdamien } 1832156321Sdamien 1833156321Sdamien /* packet header may have moved, reset our local pointer */ 1834156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1835156321Sdamien } 1836156321Sdamien 1837192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 1838156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1839156321Sdamien 1840156321Sdamien tap->wt_flags = 0; 1841156321Sdamien tap->wt_rate = rate; 1842156321Sdamien tap->wt_antenna = sc->tx_ant; 1843156321Sdamien 1844192468Ssam ieee80211_radiotap_tx(vap, m0); 1845156321Sdamien } 1846156321Sdamien 1847156321Sdamien data->m = m0; 1848156321Sdamien data->ni = ni; 1849156321Sdamien 1850156321Sdamien /* remember link conditions for rate adaptation algorithm */ 1851178354Ssam if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) { 1852178354Ssam data->rix = ni->ni_txrate; 1853178354Ssam /* XXX probably need last rssi value and not avg */ 1854178354Ssam data->rssi = ic->ic_node_getrssi(ni); 1855156321Sdamien } else 1856178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1857156321Sdamien 1858156321Sdamien if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1859156321Sdamien flags |= RT2560_TX_ACK; 1860156321Sdamien 1861190532Ssam dur = ieee80211_ack_duration(ic->ic_rt, 1862178354Ssam rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); 1863156321Sdamien *(uint16_t *)wh->i_dur = htole16(dur); 1864156321Sdamien } 1865156321Sdamien 1866156321Sdamien rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 1, 1867156321Sdamien segs->ds_addr); 1868156321Sdamien 1869156321Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1870156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 1871156321Sdamien BUS_DMASYNC_PREWRITE); 1872156321Sdamien 1873178354Ssam DPRINTFN(sc, 10, "sending data frame len=%u idx=%u rate=%u\n", 1874178354Ssam m0->m_pkthdr.len, sc->txq.cur_encrypt, rate); 1875156321Sdamien 1876156321Sdamien /* kick encrypt */ 1877156321Sdamien sc->txq.queued++; 1878156321Sdamien sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; 1879156321Sdamien RAL_WRITE(sc, RT2560_SECCSR1, RT2560_KICK_ENCRYPT); 1880156321Sdamien 1881156321Sdamien return 0; 1882156321Sdamien} 1883156321Sdamien 1884287197Sglebiusstatic int 1885287197Sglebiusrt2560_transmit(struct ieee80211com *ic, struct mbuf *m) 1886287197Sglebius{ 1887287197Sglebius struct rt2560_softc *sc = ic->ic_softc; 1888287197Sglebius int error; 1889287197Sglebius 1890287197Sglebius RAL_LOCK(sc); 1891287197Sglebius if ((sc->sc_flags & RT2560_F_RUNNING) == 0) { 1892287197Sglebius RAL_UNLOCK(sc); 1893287197Sglebius return (ENXIO); 1894287197Sglebius } 1895287197Sglebius error = mbufq_enqueue(&sc->sc_snd, m); 1896287197Sglebius if (error) { 1897287197Sglebius RAL_UNLOCK(sc); 1898287197Sglebius return (error); 1899287197Sglebius } 1900287197Sglebius rt2560_start(sc); 1901287197Sglebius RAL_UNLOCK(sc); 1902287197Sglebius 1903287197Sglebius return (0); 1904287197Sglebius} 1905287197Sglebius 1906156321Sdamienstatic void 1907287197Sglebiusrt2560_start(struct rt2560_softc *sc) 1908156321Sdamien{ 1909287197Sglebius struct ieee80211_node *ni; 1910286437Sadrian struct mbuf *m; 1911156321Sdamien 1912178354Ssam RAL_LOCK_ASSERT(sc); 1913156321Sdamien 1914287197Sglebius while (sc->txq.queued < RT2560_TX_RING_COUNT - 1 && 1915287197Sglebius (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { 1916178354Ssam ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; 1917178354Ssam if (rt2560_tx_data(sc, m, ni) != 0) { 1918287197Sglebius if_inc_counter(ni->ni_vap->iv_ifp, 1919287197Sglebius IFCOUNTER_OERRORS, 1); 1920178354Ssam ieee80211_free_node(ni); 1921178354Ssam break; 1922156321Sdamien } 1923156321Sdamien sc->sc_tx_timer = 5; 1924156321Sdamien } 1925178354Ssam} 1926156321Sdamien 1927178354Ssamstatic void 1928165352Sbmsrt2560_watchdog(void *arg) 1929156321Sdamien{ 1930167470Ssam struct rt2560_softc *sc = arg; 1931156321Sdamien 1932178354Ssam RAL_LOCK_ASSERT(sc); 1933178354Ssam 1934287197Sglebius KASSERT(sc->sc_flags & RT2560_F_RUNNING, ("not running")); 1935178354Ssam 1936178354Ssam if (sc->sc_invalid) /* card ejected */ 1937175938Ssephe return; 1938175938Ssephe 1939175938Ssephe rt2560_encryption_intr(sc); 1940175938Ssephe rt2560_tx_intr(sc); 1941175938Ssephe 1942178354Ssam if (sc->sc_tx_timer > 0 && --sc->sc_tx_timer == 0) { 1943287197Sglebius device_printf(sc->sc_dev, "device timeout\n"); 1944178354Ssam rt2560_init_locked(sc); 1945287197Sglebius counter_u64_add(sc->sc_ic.ic_oerrors, 1); 1946178354Ssam /* NB: callout is reset in rt2560_init() */ 1947178354Ssam return; 1948156321Sdamien } 1949175938Ssephe callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); 1950156321Sdamien} 1951156321Sdamien 1952287197Sglebiusstatic void 1953287197Sglebiusrt2560_parent(struct ieee80211com *ic) 1954156321Sdamien{ 1955287197Sglebius struct rt2560_softc *sc = ic->ic_softc; 1956287197Sglebius int startall = 0; 1957156321Sdamien 1958287197Sglebius RAL_LOCK(sc); 1959287197Sglebius if (ic->ic_nrunning > 0) { 1960287197Sglebius if ((sc->sc_flags & RT2560_F_RUNNING) == 0) { 1961287197Sglebius rt2560_init_locked(sc); 1962287197Sglebius startall = 1; 1963287197Sglebius } else 1964287197Sglebius rt2560_update_promisc(ic); 1965287197Sglebius } else if (sc->sc_flags & RT2560_F_RUNNING) 1966287197Sglebius rt2560_stop_locked(sc); 1967287197Sglebius RAL_UNLOCK(sc); 1968287197Sglebius if (startall) 1969287197Sglebius ieee80211_start_all(ic); 1970156321Sdamien} 1971156321Sdamien 1972156321Sdamienstatic void 1973156321Sdamienrt2560_bbp_write(struct rt2560_softc *sc, uint8_t reg, uint8_t val) 1974156321Sdamien{ 1975156321Sdamien uint32_t tmp; 1976156321Sdamien int ntries; 1977156321Sdamien 1978156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 1979156321Sdamien if (!(RAL_READ(sc, RT2560_BBPCSR) & RT2560_BBP_BUSY)) 1980156321Sdamien break; 1981156321Sdamien DELAY(1); 1982156321Sdamien } 1983156321Sdamien if (ntries == 100) { 1984156321Sdamien device_printf(sc->sc_dev, "could not write to BBP\n"); 1985156321Sdamien return; 1986156321Sdamien } 1987156321Sdamien 1988156321Sdamien tmp = RT2560_BBP_WRITE | RT2560_BBP_BUSY | reg << 8 | val; 1989156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR, tmp); 1990156321Sdamien 1991178354Ssam DPRINTFN(sc, 15, "BBP R%u <- 0x%02x\n", reg, val); 1992156321Sdamien} 1993156321Sdamien 1994156321Sdamienstatic uint8_t 1995156321Sdamienrt2560_bbp_read(struct rt2560_softc *sc, uint8_t reg) 1996156321Sdamien{ 1997156321Sdamien uint32_t val; 1998156321Sdamien int ntries; 1999156321Sdamien 2000175938Ssephe for (ntries = 0; ntries < 100; ntries++) { 2001175938Ssephe if (!(RAL_READ(sc, RT2560_BBPCSR) & RT2560_BBP_BUSY)) 2002175938Ssephe break; 2003175938Ssephe DELAY(1); 2004175938Ssephe } 2005175938Ssephe if (ntries == 100) { 2006175938Ssephe device_printf(sc->sc_dev, "could not read from BBP\n"); 2007175938Ssephe return 0; 2008175938Ssephe } 2009175938Ssephe 2010156321Sdamien val = RT2560_BBP_BUSY | reg << 8; 2011156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR, val); 2012156321Sdamien 2013156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2014156321Sdamien val = RAL_READ(sc, RT2560_BBPCSR); 2015156321Sdamien if (!(val & RT2560_BBP_BUSY)) 2016156321Sdamien return val & 0xff; 2017156321Sdamien DELAY(1); 2018156321Sdamien } 2019156321Sdamien 2020156321Sdamien device_printf(sc->sc_dev, "could not read from BBP\n"); 2021156321Sdamien return 0; 2022156321Sdamien} 2023156321Sdamien 2024156321Sdamienstatic void 2025156321Sdamienrt2560_rf_write(struct rt2560_softc *sc, uint8_t reg, uint32_t val) 2026156321Sdamien{ 2027156321Sdamien uint32_t tmp; 2028156321Sdamien int ntries; 2029156321Sdamien 2030156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2031156321Sdamien if (!(RAL_READ(sc, RT2560_RFCSR) & RT2560_RF_BUSY)) 2032156321Sdamien break; 2033156321Sdamien DELAY(1); 2034156321Sdamien } 2035156321Sdamien if (ntries == 100) { 2036156321Sdamien device_printf(sc->sc_dev, "could not write to RF\n"); 2037156321Sdamien return; 2038156321Sdamien } 2039156321Sdamien 2040156321Sdamien tmp = RT2560_RF_BUSY | RT2560_RF_20BIT | (val & 0xfffff) << 2 | 2041156321Sdamien (reg & 0x3); 2042156321Sdamien RAL_WRITE(sc, RT2560_RFCSR, tmp); 2043156321Sdamien 2044156321Sdamien /* remember last written value in sc */ 2045156321Sdamien sc->rf_regs[reg] = val; 2046156321Sdamien 2047178354Ssam DPRINTFN(sc, 15, "RF R[%u] <- 0x%05x\n", reg & 0x3, val & 0xfffff); 2048156321Sdamien} 2049156321Sdamien 2050156321Sdamienstatic void 2051156321Sdamienrt2560_set_chan(struct rt2560_softc *sc, struct ieee80211_channel *c) 2052156321Sdamien{ 2053287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2054156321Sdamien uint8_t power, tmp; 2055156321Sdamien u_int i, chan; 2056156321Sdamien 2057156321Sdamien chan = ieee80211_chan2ieee(ic, c); 2058178354Ssam KASSERT(chan != 0 && chan != IEEE80211_CHAN_ANY, ("chan 0x%x", chan)); 2059156321Sdamien 2060156321Sdamien if (IEEE80211_IS_CHAN_2GHZ(c)) 2061156321Sdamien power = min(sc->txpow[chan - 1], 31); 2062156321Sdamien else 2063156321Sdamien power = 31; 2064156321Sdamien 2065156321Sdamien /* adjust txpower using ifconfig settings */ 2066156321Sdamien power -= (100 - ic->ic_txpowlimit) / 8; 2067156321Sdamien 2068178354Ssam DPRINTFN(sc, 2, "setting channel to %u, txpower to %u\n", chan, power); 2069156321Sdamien 2070156321Sdamien switch (sc->rf_rev) { 2071156321Sdamien case RT2560_RF_2522: 2072156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x00814); 2073156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2522_r2[chan - 1]); 2074156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2075156321Sdamien break; 2076156321Sdamien 2077156321Sdamien case RT2560_RF_2523: 2078156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08804); 2079156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2523_r2[chan - 1]); 2080156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x38044); 2081156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2082156321Sdamien break; 2083156321Sdamien 2084156321Sdamien case RT2560_RF_2524: 2085156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x0c808); 2086156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2524_r2[chan - 1]); 2087156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2088156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2089156321Sdamien break; 2090156321Sdamien 2091156321Sdamien case RT2560_RF_2525: 2092156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2093156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_hi_r2[chan - 1]); 2094156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2095156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2096156321Sdamien 2097156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2098156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_r2[chan - 1]); 2099156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2100156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2101156321Sdamien break; 2102156321Sdamien 2103156321Sdamien case RT2560_RF_2525E: 2104156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2105156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525e_r2[chan - 1]); 2106156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2107156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00286 : 0x00282); 2108156321Sdamien break; 2109156321Sdamien 2110156321Sdamien case RT2560_RF_2526: 2111156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_hi_r2[chan - 1]); 2112156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); 2113156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08804); 2114156321Sdamien 2115156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_r2[chan - 1]); 2116156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2117156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); 2118156321Sdamien break; 2119156321Sdamien 2120156321Sdamien /* dual-band RF */ 2121156321Sdamien case RT2560_RF_5222: 2122156321Sdamien for (i = 0; rt2560_rf5222[i].chan != chan; i++); 2123156321Sdamien 2124156321Sdamien rt2560_rf_write(sc, RAL_RF1, rt2560_rf5222[i].r1); 2125156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf5222[i].r2); 2126156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2127156321Sdamien rt2560_rf_write(sc, RAL_RF4, rt2560_rf5222[i].r4); 2128156321Sdamien break; 2129170530Ssam default: 2130170530Ssam printf("unknown ral rev=%d\n", sc->rf_rev); 2131156321Sdamien } 2132156321Sdamien 2133178354Ssam /* XXX */ 2134178354Ssam if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { 2135156321Sdamien /* set Japan filter bit for channel 14 */ 2136156321Sdamien tmp = rt2560_bbp_read(sc, 70); 2137156321Sdamien 2138156321Sdamien tmp &= ~RT2560_JAPAN_FILTER; 2139156321Sdamien if (chan == 14) 2140156321Sdamien tmp |= RT2560_JAPAN_FILTER; 2141156321Sdamien 2142156321Sdamien rt2560_bbp_write(sc, 70, tmp); 2143156321Sdamien 2144156321Sdamien /* clear CRC errors */ 2145156321Sdamien RAL_READ(sc, RT2560_CNT0); 2146156321Sdamien } 2147156321Sdamien} 2148156321Sdamien 2149170530Ssamstatic void 2150300752Savosrt2560_getradiocaps(struct ieee80211com *ic, 2151300752Savos int maxchans, int *nchans, struct ieee80211_channel chans[]) 2152300752Savos{ 2153300752Savos struct rt2560_softc *sc = ic->ic_softc; 2154300752Savos uint8_t bands[IEEE80211_MODE_BYTES]; 2155300752Savos 2156300752Savos memset(bands, 0, sizeof(bands)); 2157300752Savos setbit(bands, IEEE80211_MODE_11B); 2158300752Savos setbit(bands, IEEE80211_MODE_11G); 2159300752Savos ieee80211_add_channel_list_2ghz(chans, maxchans, nchans, 2160300752Savos rt2560_chan_2ghz, nitems(rt2560_chan_2ghz), bands, 0); 2161300752Savos 2162300752Savos if (sc->rf_rev == RT2560_RF_5222) { 2163300752Savos setbit(bands, IEEE80211_MODE_11A); 2164300752Savos ieee80211_add_channel_list_5ghz(chans, maxchans, nchans, 2165300752Savos rt2560_chan_5ghz, nitems(rt2560_chan_5ghz), bands, 0); 2166300752Savos } 2167300752Savos} 2168300752Savos 2169300752Savosstatic void 2170170530Ssamrt2560_set_channel(struct ieee80211com *ic) 2171170530Ssam{ 2172287197Sglebius struct rt2560_softc *sc = ic->ic_softc; 2173170530Ssam 2174170530Ssam RAL_LOCK(sc); 2175170530Ssam rt2560_set_chan(sc, ic->ic_curchan); 2176170530Ssam RAL_UNLOCK(sc); 2177170530Ssam 2178170530Ssam} 2179170530Ssam 2180156321Sdamien#if 0 2181156321Sdamien/* 2182156321Sdamien * Disable RF auto-tuning. 2183156321Sdamien */ 2184156321Sdamienstatic void 2185156321Sdamienrt2560_disable_rf_tune(struct rt2560_softc *sc) 2186156321Sdamien{ 2187156321Sdamien uint32_t tmp; 2188156321Sdamien 2189156321Sdamien if (sc->rf_rev != RT2560_RF_2523) { 2190156321Sdamien tmp = sc->rf_regs[RAL_RF1] & ~RAL_RF1_AUTOTUNE; 2191156321Sdamien rt2560_rf_write(sc, RAL_RF1, tmp); 2192156321Sdamien } 2193156321Sdamien 2194156321Sdamien tmp = sc->rf_regs[RAL_RF3] & ~RAL_RF3_AUTOTUNE; 2195156321Sdamien rt2560_rf_write(sc, RAL_RF3, tmp); 2196156321Sdamien 2197178354Ssam DPRINTFN(sc, 2, "%s", "disabling RF autotune\n"); 2198156321Sdamien} 2199156321Sdamien#endif 2200156321Sdamien 2201156321Sdamien/* 2202156321Sdamien * Refer to IEEE Std 802.11-1999 pp. 123 for more information on TSF 2203156321Sdamien * synchronization. 2204156321Sdamien */ 2205156321Sdamienstatic void 2206156321Sdamienrt2560_enable_tsf_sync(struct rt2560_softc *sc) 2207156321Sdamien{ 2208287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2209178354Ssam struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2210156321Sdamien uint16_t logcwmin, preload; 2211156321Sdamien uint32_t tmp; 2212156321Sdamien 2213156321Sdamien /* first, disable TSF synchronization */ 2214156321Sdamien RAL_WRITE(sc, RT2560_CSR14, 0); 2215156321Sdamien 2216178354Ssam tmp = 16 * vap->iv_bss->ni_intval; 2217156321Sdamien RAL_WRITE(sc, RT2560_CSR12, tmp); 2218156321Sdamien 2219156321Sdamien RAL_WRITE(sc, RT2560_CSR13, 0); 2220156321Sdamien 2221156321Sdamien logcwmin = 5; 2222178354Ssam preload = (vap->iv_opmode == IEEE80211_M_STA) ? 384 : 1024; 2223156321Sdamien tmp = logcwmin << 16 | preload; 2224156321Sdamien RAL_WRITE(sc, RT2560_BCNOCSR, tmp); 2225156321Sdamien 2226156321Sdamien /* finally, enable TSF synchronization */ 2227156321Sdamien tmp = RT2560_ENABLE_TSF | RT2560_ENABLE_TBCN; 2228156321Sdamien if (ic->ic_opmode == IEEE80211_M_STA) 2229156321Sdamien tmp |= RT2560_ENABLE_TSF_SYNC(1); 2230156321Sdamien else 2231156321Sdamien tmp |= RT2560_ENABLE_TSF_SYNC(2) | 2232156321Sdamien RT2560_ENABLE_BEACON_GENERATOR; 2233156321Sdamien RAL_WRITE(sc, RT2560_CSR14, tmp); 2234156321Sdamien 2235178354Ssam DPRINTF(sc, "%s", "enabling TSF synchronization\n"); 2236156321Sdamien} 2237156321Sdamien 2238156321Sdamienstatic void 2239192468Ssamrt2560_enable_tsf(struct rt2560_softc *sc) 2240192468Ssam{ 2241192468Ssam RAL_WRITE(sc, RT2560_CSR14, 0); 2242192468Ssam RAL_WRITE(sc, RT2560_CSR14, 2243192468Ssam RT2560_ENABLE_TSF_SYNC(2) | RT2560_ENABLE_TSF); 2244192468Ssam} 2245192468Ssam 2246192468Ssamstatic void 2247156321Sdamienrt2560_update_plcp(struct rt2560_softc *sc) 2248156321Sdamien{ 2249287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2250156321Sdamien 2251156321Sdamien /* no short preamble for 1Mbps */ 2252156321Sdamien RAL_WRITE(sc, RT2560_PLCP1MCSR, 0x00700400); 2253156321Sdamien 2254156321Sdamien if (!(ic->ic_flags & IEEE80211_F_SHPREAMBLE)) { 2255156321Sdamien /* values taken from the reference driver */ 2256156321Sdamien RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380401); 2257156321Sdamien RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x00150402); 2258156321Sdamien RAL_WRITE(sc, RT2560_PLCP11MCSR, 0x000b8403); 2259156321Sdamien } else { 2260156321Sdamien /* same values as above or'ed 0x8 */ 2261156321Sdamien RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380409); 2262156321Sdamien RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x0015040a); 2263156321Sdamien RAL_WRITE(sc, RT2560_PLCP11MCSR, 0x000b840b); 2264156321Sdamien } 2265156321Sdamien 2266178354Ssam DPRINTF(sc, "updating PLCP for %s preamble\n", 2267178354Ssam (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? "short" : "long"); 2268156321Sdamien} 2269156321Sdamien 2270156321Sdamien/* 2271156321Sdamien * This function can be called by ieee80211_set_shortslottime(). Refer to 2272156321Sdamien * IEEE Std 802.11-1999 pp. 85 to know how these values are computed. 2273156321Sdamien */ 2274156321Sdamienstatic void 2275283540Sglebiusrt2560_update_slot(struct ieee80211com *ic) 2276156321Sdamien{ 2277283540Sglebius struct rt2560_softc *sc = ic->ic_softc; 2278156321Sdamien uint8_t slottime; 2279156321Sdamien uint16_t tx_sifs, tx_pifs, tx_difs, eifs; 2280156321Sdamien uint32_t tmp; 2281156321Sdamien 2282175938Ssephe#ifndef FORCE_SLOTTIME 2283292165Savos slottime = IEEE80211_GET_SLOTTIME(ic); 2284175938Ssephe#else 2285175938Ssephe /* 2286175938Ssephe * Setting slot time according to "short slot time" capability 2287175938Ssephe * in beacon/probe_resp seems to cause problem to acknowledge 2288175938Ssephe * certain AP's data frames transimitted at CCK/DS rates: the 2289175938Ssephe * problematic AP keeps retransmitting data frames, probably 2290175938Ssephe * because MAC level acks are not received by hardware. 2291175938Ssephe * So we cheat a little bit here by claiming we are capable of 2292175938Ssephe * "short slot time" but setting hardware slot time to the normal 2293175938Ssephe * slot time. ral(4) does not seem to have trouble to receive 2294175938Ssephe * frames transmitted using short slot time even if hardware 2295175938Ssephe * slot time is set to normal slot time. If we didn't use this 2296175938Ssephe * trick, we would have to claim that short slot time is not 2297175938Ssephe * supported; this would give relative poor RX performance 2298175938Ssephe * (-1Mb~-2Mb lower) and the _whole_ BSS would stop using short 2299175938Ssephe * slot time. 2300175938Ssephe */ 2301292165Savos slottime = IEEE80211_DUR_SLOT; 2302175938Ssephe#endif 2303156321Sdamien 2304156321Sdamien /* update the MAC slot boundaries */ 2305156321Sdamien tx_sifs = RAL_SIFS - RT2560_TXRX_TURNAROUND; 2306156321Sdamien tx_pifs = tx_sifs + slottime; 2307292165Savos tx_difs = IEEE80211_DUR_DIFS(tx_sifs, slottime); 2308156321Sdamien eifs = (ic->ic_curmode == IEEE80211_MODE_11B) ? 364 : 60; 2309156321Sdamien 2310156321Sdamien tmp = RAL_READ(sc, RT2560_CSR11); 2311156321Sdamien tmp = (tmp & ~0x1f00) | slottime << 8; 2312156321Sdamien RAL_WRITE(sc, RT2560_CSR11, tmp); 2313156321Sdamien 2314156321Sdamien tmp = tx_pifs << 16 | tx_sifs; 2315156321Sdamien RAL_WRITE(sc, RT2560_CSR18, tmp); 2316156321Sdamien 2317156321Sdamien tmp = eifs << 16 | tx_difs; 2318156321Sdamien RAL_WRITE(sc, RT2560_CSR19, tmp); 2319156321Sdamien 2320178354Ssam DPRINTF(sc, "setting slottime to %uus\n", slottime); 2321156321Sdamien} 2322156321Sdamien 2323156321Sdamienstatic void 2324220502Sbschmidtrt2560_set_basicrates(struct rt2560_softc *sc, 2325220502Sbschmidt const struct ieee80211_rateset *rs) 2326156321Sdamien{ 2327287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2328220502Sbschmidt uint32_t mask = 0; 2329220502Sbschmidt uint8_t rate; 2330220502Sbschmidt int i; 2331156321Sdamien 2332220502Sbschmidt for (i = 0; i < rs->rs_nrates; i++) { 2333220502Sbschmidt rate = rs->rs_rates[i]; 2334220502Sbschmidt 2335220502Sbschmidt if (!(rate & IEEE80211_RATE_BASIC)) 2336220502Sbschmidt continue; 2337220502Sbschmidt 2338288087Sadrian mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt, 2339288087Sadrian IEEE80211_RV(rate)); 2340156321Sdamien } 2341220502Sbschmidt 2342220502Sbschmidt RAL_WRITE(sc, RT2560_ARSP_PLCP_1, mask); 2343220502Sbschmidt 2344220502Sbschmidt DPRINTF(sc, "Setting basic rate mask to 0x%x\n", mask); 2345156321Sdamien} 2346156321Sdamien 2347156321Sdamienstatic void 2348156321Sdamienrt2560_update_led(struct rt2560_softc *sc, int led1, int led2) 2349156321Sdamien{ 2350156321Sdamien uint32_t tmp; 2351156321Sdamien 2352156321Sdamien /* set ON period to 70ms and OFF period to 30ms */ 2353156321Sdamien tmp = led1 << 16 | led2 << 17 | 70 << 8 | 30; 2354156321Sdamien RAL_WRITE(sc, RT2560_LEDCSR, tmp); 2355156321Sdamien} 2356156321Sdamien 2357156321Sdamienstatic void 2358170530Ssamrt2560_set_bssid(struct rt2560_softc *sc, const uint8_t *bssid) 2359156321Sdamien{ 2360156321Sdamien uint32_t tmp; 2361156321Sdamien 2362156321Sdamien tmp = bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24; 2363156321Sdamien RAL_WRITE(sc, RT2560_CSR5, tmp); 2364156321Sdamien 2365156321Sdamien tmp = bssid[4] | bssid[5] << 8; 2366156321Sdamien RAL_WRITE(sc, RT2560_CSR6, tmp); 2367156321Sdamien 2368178354Ssam DPRINTF(sc, "setting BSSID to %6D\n", bssid, ":"); 2369156321Sdamien} 2370156321Sdamien 2371156321Sdamienstatic void 2372287197Sglebiusrt2560_set_macaddr(struct rt2560_softc *sc, const uint8_t *addr) 2373156321Sdamien{ 2374156321Sdamien uint32_t tmp; 2375156321Sdamien 2376156321Sdamien tmp = addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24; 2377156321Sdamien RAL_WRITE(sc, RT2560_CSR3, tmp); 2378156321Sdamien 2379156321Sdamien tmp = addr[4] | addr[5] << 8; 2380156321Sdamien RAL_WRITE(sc, RT2560_CSR4, tmp); 2381156321Sdamien 2382178354Ssam DPRINTF(sc, "setting MAC address to %6D\n", addr, ":"); 2383156321Sdamien} 2384156321Sdamien 2385156321Sdamienstatic void 2386156321Sdamienrt2560_get_macaddr(struct rt2560_softc *sc, uint8_t *addr) 2387156321Sdamien{ 2388156321Sdamien uint32_t tmp; 2389156321Sdamien 2390156321Sdamien tmp = RAL_READ(sc, RT2560_CSR3); 2391156321Sdamien addr[0] = tmp & 0xff; 2392156321Sdamien addr[1] = (tmp >> 8) & 0xff; 2393156321Sdamien addr[2] = (tmp >> 16) & 0xff; 2394156321Sdamien addr[3] = (tmp >> 24); 2395156321Sdamien 2396156321Sdamien tmp = RAL_READ(sc, RT2560_CSR4); 2397156321Sdamien addr[4] = tmp & 0xff; 2398156321Sdamien addr[5] = (tmp >> 8) & 0xff; 2399156321Sdamien} 2400156321Sdamien 2401156321Sdamienstatic void 2402283540Sglebiusrt2560_update_promisc(struct ieee80211com *ic) 2403156321Sdamien{ 2404283540Sglebius struct rt2560_softc *sc = ic->ic_softc; 2405156321Sdamien uint32_t tmp; 2406156321Sdamien 2407156321Sdamien tmp = RAL_READ(sc, RT2560_RXCSR0); 2408156321Sdamien 2409156321Sdamien tmp &= ~RT2560_DROP_NOT_TO_ME; 2410287197Sglebius if (ic->ic_promisc == 0) 2411156321Sdamien tmp |= RT2560_DROP_NOT_TO_ME; 2412156321Sdamien 2413156321Sdamien RAL_WRITE(sc, RT2560_RXCSR0, tmp); 2414156321Sdamien 2415283540Sglebius DPRINTF(sc, "%s promiscuous mode\n", 2416287197Sglebius (ic->ic_promisc > 0) ? "entering" : "leaving"); 2417156321Sdamien} 2418156321Sdamien 2419156321Sdamienstatic const char * 2420156321Sdamienrt2560_get_rf(int rev) 2421156321Sdamien{ 2422156321Sdamien switch (rev) { 2423156321Sdamien case RT2560_RF_2522: return "RT2522"; 2424156321Sdamien case RT2560_RF_2523: return "RT2523"; 2425156321Sdamien case RT2560_RF_2524: return "RT2524"; 2426156321Sdamien case RT2560_RF_2525: return "RT2525"; 2427156321Sdamien case RT2560_RF_2525E: return "RT2525e"; 2428156321Sdamien case RT2560_RF_2526: return "RT2526"; 2429156321Sdamien case RT2560_RF_5222: return "RT5222"; 2430156321Sdamien default: return "unknown"; 2431156321Sdamien } 2432156321Sdamien} 2433156321Sdamien 2434156321Sdamienstatic void 2435175938Ssephert2560_read_config(struct rt2560_softc *sc) 2436156321Sdamien{ 2437156321Sdamien uint16_t val; 2438156321Sdamien int i; 2439156321Sdamien 2440156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_CONFIG0); 2441156321Sdamien sc->rf_rev = (val >> 11) & 0x7; 2442156321Sdamien sc->hw_radio = (val >> 10) & 0x1; 2443156321Sdamien sc->led_mode = (val >> 6) & 0x7; 2444156321Sdamien sc->rx_ant = (val >> 4) & 0x3; 2445156321Sdamien sc->tx_ant = (val >> 2) & 0x3; 2446156321Sdamien sc->nb_ant = val & 0x3; 2447156321Sdamien 2448156321Sdamien /* read default values for BBP registers */ 2449156321Sdamien for (i = 0; i < 16; i++) { 2450156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_BBP_BASE + i); 2451175938Ssephe if (val == 0 || val == 0xffff) 2452175938Ssephe continue; 2453175938Ssephe 2454156321Sdamien sc->bbp_prom[i].reg = val >> 8; 2455156321Sdamien sc->bbp_prom[i].val = val & 0xff; 2456156321Sdamien } 2457156321Sdamien 2458156321Sdamien /* read Tx power for all b/g channels */ 2459156321Sdamien for (i = 0; i < 14 / 2; i++) { 2460156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_TXPOWER + i); 2461175938Ssephe sc->txpow[i * 2] = val & 0xff; 2462175938Ssephe sc->txpow[i * 2 + 1] = val >> 8; 2463156321Sdamien } 2464175938Ssephe for (i = 0; i < 14; ++i) { 2465175938Ssephe if (sc->txpow[i] > 31) 2466175938Ssephe sc->txpow[i] = 24; 2467175938Ssephe } 2468170530Ssam 2469170530Ssam val = rt2560_eeprom_read(sc, RT2560_EEPROM_CALIBRATE); 2470170530Ssam if ((val & 0xff) == 0xff) 2471170530Ssam sc->rssi_corr = RT2560_DEFAULT_RSSI_CORR; 2472170530Ssam else 2473170530Ssam sc->rssi_corr = val & 0xff; 2474178354Ssam DPRINTF(sc, "rssi correction %d, calibrate 0x%02x\n", 2475178354Ssam sc->rssi_corr, val); 2476156321Sdamien} 2477156321Sdamien 2478170530Ssam 2479170530Ssamstatic void 2480170530Ssamrt2560_scan_start(struct ieee80211com *ic) 2481170530Ssam{ 2482287197Sglebius struct rt2560_softc *sc = ic->ic_softc; 2483170530Ssam 2484170530Ssam /* abort TSF synchronization */ 2485170530Ssam RAL_WRITE(sc, RT2560_CSR14, 0); 2486287197Sglebius rt2560_set_bssid(sc, ieee80211broadcastaddr); 2487170530Ssam} 2488170530Ssam 2489170530Ssamstatic void 2490170530Ssamrt2560_scan_end(struct ieee80211com *ic) 2491170530Ssam{ 2492287197Sglebius struct rt2560_softc *sc = ic->ic_softc; 2493178354Ssam struct ieee80211vap *vap = ic->ic_scan->ss_vap; 2494170530Ssam 2495170530Ssam rt2560_enable_tsf_sync(sc); 2496170530Ssam /* XXX keep local copy */ 2497178354Ssam rt2560_set_bssid(sc, vap->iv_bss->ni_bssid); 2498170530Ssam} 2499170530Ssam 2500156321Sdamienstatic int 2501156321Sdamienrt2560_bbp_init(struct rt2560_softc *sc) 2502156321Sdamien{ 2503156321Sdamien int i, ntries; 2504156321Sdamien 2505156321Sdamien /* wait for BBP to be ready */ 2506156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2507156321Sdamien if (rt2560_bbp_read(sc, RT2560_BBP_VERSION) != 0) 2508156321Sdamien break; 2509156321Sdamien DELAY(1); 2510156321Sdamien } 2511156321Sdamien if (ntries == 100) { 2512156321Sdamien device_printf(sc->sc_dev, "timeout waiting for BBP\n"); 2513156321Sdamien return EIO; 2514156321Sdamien } 2515156321Sdamien 2516156321Sdamien /* initialize BBP registers to default values */ 2517288087Sadrian for (i = 0; i < nitems(rt2560_def_bbp); i++) { 2518156321Sdamien rt2560_bbp_write(sc, rt2560_def_bbp[i].reg, 2519156321Sdamien rt2560_def_bbp[i].val); 2520156321Sdamien } 2521175938Ssephe 2522156321Sdamien /* initialize BBP registers to values stored in EEPROM */ 2523156321Sdamien for (i = 0; i < 16; i++) { 2524175938Ssephe if (sc->bbp_prom[i].reg == 0 && sc->bbp_prom[i].val == 0) 2525175938Ssephe break; 2526156321Sdamien rt2560_bbp_write(sc, sc->bbp_prom[i].reg, sc->bbp_prom[i].val); 2527156321Sdamien } 2528175938Ssephe rt2560_bbp_write(sc, 17, 0x48); /* XXX restore bbp17 */ 2529156321Sdamien 2530156321Sdamien return 0; 2531156321Sdamien} 2532156321Sdamien 2533156321Sdamienstatic void 2534156321Sdamienrt2560_set_txantenna(struct rt2560_softc *sc, int antenna) 2535156321Sdamien{ 2536156321Sdamien uint32_t tmp; 2537156321Sdamien uint8_t tx; 2538156321Sdamien 2539156321Sdamien tx = rt2560_bbp_read(sc, RT2560_BBP_TX) & ~RT2560_BBP_ANTMASK; 2540156321Sdamien if (antenna == 1) 2541156321Sdamien tx |= RT2560_BBP_ANTA; 2542156321Sdamien else if (antenna == 2) 2543156321Sdamien tx |= RT2560_BBP_ANTB; 2544156321Sdamien else 2545156321Sdamien tx |= RT2560_BBP_DIVERSITY; 2546156321Sdamien 2547156321Sdamien /* need to force I/Q flip for RF 2525e, 2526 and 5222 */ 2548156321Sdamien if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526 || 2549156321Sdamien sc->rf_rev == RT2560_RF_5222) 2550156321Sdamien tx |= RT2560_BBP_FLIPIQ; 2551156321Sdamien 2552156321Sdamien rt2560_bbp_write(sc, RT2560_BBP_TX, tx); 2553156321Sdamien 2554156321Sdamien /* update values for CCK and OFDM in BBPCSR1 */ 2555156321Sdamien tmp = RAL_READ(sc, RT2560_BBPCSR1) & ~0x00070007; 2556156321Sdamien tmp |= (tx & 0x7) << 16 | (tx & 0x7); 2557156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR1, tmp); 2558156321Sdamien} 2559156321Sdamien 2560156321Sdamienstatic void 2561156321Sdamienrt2560_set_rxantenna(struct rt2560_softc *sc, int antenna) 2562156321Sdamien{ 2563156321Sdamien uint8_t rx; 2564156321Sdamien 2565156321Sdamien rx = rt2560_bbp_read(sc, RT2560_BBP_RX) & ~RT2560_BBP_ANTMASK; 2566156321Sdamien if (antenna == 1) 2567156321Sdamien rx |= RT2560_BBP_ANTA; 2568156321Sdamien else if (antenna == 2) 2569156321Sdamien rx |= RT2560_BBP_ANTB; 2570156321Sdamien else 2571156321Sdamien rx |= RT2560_BBP_DIVERSITY; 2572156321Sdamien 2573156321Sdamien /* need to force no I/Q flip for RF 2525e and 2526 */ 2574156321Sdamien if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526) 2575156321Sdamien rx &= ~RT2560_BBP_FLIPIQ; 2576156321Sdamien 2577156321Sdamien rt2560_bbp_write(sc, RT2560_BBP_RX, rx); 2578156321Sdamien} 2579156321Sdamien 2580156321Sdamienstatic void 2581178354Ssamrt2560_init_locked(struct rt2560_softc *sc) 2582156321Sdamien{ 2583287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2584287197Sglebius struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2585156321Sdamien uint32_t tmp; 2586156321Sdamien int i; 2587156321Sdamien 2588178354Ssam RAL_LOCK_ASSERT(sc); 2589156975Sdamien 2590178354Ssam rt2560_stop_locked(sc); 2591170530Ssam 2592156321Sdamien /* setup tx rings */ 2593156321Sdamien tmp = RT2560_PRIO_RING_COUNT << 24 | 2594156321Sdamien RT2560_ATIM_RING_COUNT << 16 | 2595156321Sdamien RT2560_TX_RING_COUNT << 8 | 2596156321Sdamien RT2560_TX_DESC_SIZE; 2597156321Sdamien 2598156321Sdamien /* rings must be initialized in this exact order */ 2599156321Sdamien RAL_WRITE(sc, RT2560_TXCSR2, tmp); 2600156321Sdamien RAL_WRITE(sc, RT2560_TXCSR3, sc->txq.physaddr); 2601156321Sdamien RAL_WRITE(sc, RT2560_TXCSR5, sc->prioq.physaddr); 2602156321Sdamien RAL_WRITE(sc, RT2560_TXCSR4, sc->atimq.physaddr); 2603156321Sdamien RAL_WRITE(sc, RT2560_TXCSR6, sc->bcnq.physaddr); 2604156321Sdamien 2605156321Sdamien /* setup rx ring */ 2606156321Sdamien tmp = RT2560_RX_RING_COUNT << 8 | RT2560_RX_DESC_SIZE; 2607156321Sdamien 2608156321Sdamien RAL_WRITE(sc, RT2560_RXCSR1, tmp); 2609156321Sdamien RAL_WRITE(sc, RT2560_RXCSR2, sc->rxq.physaddr); 2610156321Sdamien 2611156321Sdamien /* initialize MAC registers to default values */ 2612288087Sadrian for (i = 0; i < nitems(rt2560_def_mac); i++) 2613156321Sdamien RAL_WRITE(sc, rt2560_def_mac[i].reg, rt2560_def_mac[i].val); 2614156321Sdamien 2615287197Sglebius rt2560_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); 2616156321Sdamien 2617156321Sdamien /* set basic rate set (will be updated later) */ 2618156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x153); 2619156321Sdamien 2620283540Sglebius rt2560_update_slot(ic); 2621156321Sdamien rt2560_update_plcp(sc); 2622156321Sdamien rt2560_update_led(sc, 0, 0); 2623156321Sdamien 2624156321Sdamien RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 2625156321Sdamien RAL_WRITE(sc, RT2560_CSR1, RT2560_HOST_READY); 2626156321Sdamien 2627156321Sdamien if (rt2560_bbp_init(sc) != 0) { 2628213268Sjhb rt2560_stop_locked(sc); 2629156321Sdamien return; 2630156321Sdamien } 2631156321Sdamien 2632175938Ssephe rt2560_set_txantenna(sc, sc->tx_ant); 2633175938Ssephe rt2560_set_rxantenna(sc, sc->rx_ant); 2634175938Ssephe 2635156321Sdamien /* set default BSS channel */ 2636156321Sdamien rt2560_set_chan(sc, ic->ic_curchan); 2637156321Sdamien 2638156321Sdamien /* kick Rx */ 2639156321Sdamien tmp = RT2560_DROP_PHY_ERROR | RT2560_DROP_CRC_ERROR; 2640156321Sdamien if (ic->ic_opmode != IEEE80211_M_MONITOR) { 2641156321Sdamien tmp |= RT2560_DROP_CTL | RT2560_DROP_VERSION_ERROR; 2642195618Srpaulo if (ic->ic_opmode != IEEE80211_M_HOSTAP && 2643195618Srpaulo ic->ic_opmode != IEEE80211_M_MBSS) 2644156321Sdamien tmp |= RT2560_DROP_TODS; 2645287197Sglebius if (ic->ic_promisc == 0) 2646156321Sdamien tmp |= RT2560_DROP_NOT_TO_ME; 2647156321Sdamien } 2648156321Sdamien RAL_WRITE(sc, RT2560_RXCSR0, tmp); 2649156321Sdamien 2650156321Sdamien /* clear old FCS and Rx FIFO errors */ 2651156321Sdamien RAL_READ(sc, RT2560_CNT0); 2652156321Sdamien RAL_READ(sc, RT2560_CNT4); 2653156321Sdamien 2654156321Sdamien /* clear any pending interrupts */ 2655156321Sdamien RAL_WRITE(sc, RT2560_CSR7, 0xffffffff); 2656156321Sdamien 2657156321Sdamien /* enable interrupts */ 2658156321Sdamien RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); 2659156321Sdamien 2660287197Sglebius sc->sc_flags |= RT2560_F_RUNNING; 2661156321Sdamien 2662175938Ssephe callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); 2663178354Ssam} 2664175938Ssephe 2665178354Ssamstatic void 2666178354Ssamrt2560_init(void *priv) 2667178354Ssam{ 2668178354Ssam struct rt2560_softc *sc = priv; 2669287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2670156975Sdamien 2671178354Ssam RAL_LOCK(sc); 2672178354Ssam rt2560_init_locked(sc); 2673156975Sdamien RAL_UNLOCK(sc); 2674178354Ssam 2675287197Sglebius if (sc->sc_flags & RT2560_F_RUNNING) 2676178931Sthompsa ieee80211_start_all(ic); /* start all vap's */ 2677156321Sdamien} 2678156321Sdamien 2679178354Ssamstatic void 2680178354Ssamrt2560_stop_locked(struct rt2560_softc *sc) 2681156321Sdamien{ 2682170530Ssam volatile int *flags = &sc->sc_flags; 2683156321Sdamien 2684178354Ssam RAL_LOCK_ASSERT(sc); 2685156321Sdamien 2686178354Ssam while (*flags & RT2560_F_INPUT_RUNNING) 2687178354Ssam msleep(sc, &sc->sc_mtx, 0, "ralrunning", hz/10); 2688175938Ssephe 2689175938Ssephe callout_stop(&sc->watchdog_ch); 2690178354Ssam sc->sc_tx_timer = 0; 2691175938Ssephe 2692287197Sglebius if (sc->sc_flags & RT2560_F_RUNNING) { 2693287197Sglebius sc->sc_flags &= ~RT2560_F_RUNNING; 2694156975Sdamien 2695170530Ssam /* abort Tx */ 2696170530Ssam RAL_WRITE(sc, RT2560_TXCSR0, RT2560_ABORT_TX); 2697170530Ssam 2698170530Ssam /* disable Rx */ 2699170530Ssam RAL_WRITE(sc, RT2560_RXCSR0, RT2560_DISABLE_RX); 2700156321Sdamien 2701170530Ssam /* reset ASIC (imply reset BBP) */ 2702170530Ssam RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 2703170530Ssam RAL_WRITE(sc, RT2560_CSR1, 0); 2704156321Sdamien 2705170530Ssam /* disable interrupts */ 2706170530Ssam RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 2707170530Ssam 2708170530Ssam /* reset Tx and Rx rings */ 2709170530Ssam rt2560_reset_tx_ring(sc, &sc->txq); 2710170530Ssam rt2560_reset_tx_ring(sc, &sc->atimq); 2711170530Ssam rt2560_reset_tx_ring(sc, &sc->prioq); 2712170530Ssam rt2560_reset_tx_ring(sc, &sc->bcnq); 2713170530Ssam rt2560_reset_rx_ring(sc, &sc->rxq); 2714170530Ssam } 2715178354Ssam} 2716175938Ssephe 2717178354Ssamvoid 2718178354Ssamrt2560_stop(void *arg) 2719178354Ssam{ 2720178354Ssam struct rt2560_softc *sc = arg; 2721178354Ssam 2722178354Ssam RAL_LOCK(sc); 2723178354Ssam rt2560_stop_locked(sc); 2724170530Ssam RAL_UNLOCK(sc); 2725156321Sdamien} 2726160691Ssam 2727160691Ssamstatic int 2728160691Ssamrt2560_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 2729160691Ssam const struct ieee80211_bpf_params *params) 2730160691Ssam{ 2731160691Ssam struct ieee80211com *ic = ni->ni_ic; 2732287197Sglebius struct rt2560_softc *sc = ic->ic_softc; 2733160691Ssam 2734160691Ssam RAL_LOCK(sc); 2735160691Ssam 2736160691Ssam /* prevent management frames from being sent if we're not ready */ 2737287197Sglebius if (!(sc->sc_flags & RT2560_F_RUNNING)) { 2738160691Ssam RAL_UNLOCK(sc); 2739168860Ssephe m_freem(m); 2740160691Ssam return ENETDOWN; 2741160691Ssam } 2742160691Ssam if (sc->prioq.queued >= RT2560_PRIO_RING_COUNT) { 2743160691Ssam RAL_UNLOCK(sc); 2744168860Ssephe m_freem(m); 2745160691Ssam return ENOBUFS; /* XXX */ 2746160691Ssam } 2747160691Ssam 2748160691Ssam if (params == NULL) { 2749160691Ssam /* 2750160691Ssam * Legacy path; interpret frame contents to decide 2751160691Ssam * precisely how to send the frame. 2752160691Ssam */ 2753160691Ssam if (rt2560_tx_mgt(sc, m, ni) != 0) 2754160691Ssam goto bad; 2755160691Ssam } else { 2756160691Ssam /* 2757160691Ssam * Caller supplied explicit parameters to use in 2758160691Ssam * sending the frame. 2759160691Ssam */ 2760160691Ssam if (rt2560_tx_raw(sc, m, ni, params)) 2761160691Ssam goto bad; 2762160691Ssam } 2763160691Ssam sc->sc_tx_timer = 5; 2764160691Ssam 2765160691Ssam RAL_UNLOCK(sc); 2766160691Ssam 2767160691Ssam return 0; 2768160691Ssambad: 2769160691Ssam RAL_UNLOCK(sc); 2770160691Ssam return EIO; /* XXX */ 2771160691Ssam} 2772