1156321Sdamien/* $FreeBSD: stable/11/sys/dev/ral/rt2560.c 343976 2019-02-10 21:00:02Z 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: stable/11/sys/dev/ral/rt2560.c 343976 2019-02-10 21:00:02Z 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_5ghz[] = 193300752Savos { 36, 40, 44, 48, 52, 56, 60, 64, 194300752Savos 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 195300752Savos 149, 153, 157, 161 }; 196300752Savos 197156321Sdamienstatic const struct { 198156321Sdamien uint8_t chan; 199156321Sdamien uint32_t r1, r2, r4; 200156321Sdamien} rt2560_rf5222[] = { 201156321Sdamien RT2560_RF5222 202156321Sdamien}; 203156321Sdamien 204156321Sdamienint 205156321Sdamienrt2560_attach(device_t dev, int id) 206156321Sdamien{ 207156321Sdamien struct rt2560_softc *sc = device_get_softc(dev); 208287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 209286437Sadrian int error; 210156321Sdamien 211156321Sdamien sc->sc_dev = dev; 212156321Sdamien 213156321Sdamien mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 214156321Sdamien MTX_DEF | MTX_RECURSE); 215156321Sdamien 216165352Sbms callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0); 217287197Sglebius mbufq_init(&sc->sc_snd, ifqmaxlen); 218156321Sdamien 219156321Sdamien /* retrieve RT2560 rev. no */ 220156321Sdamien sc->asic_rev = RAL_READ(sc, RT2560_CSR0); 221156321Sdamien 222156321Sdamien /* retrieve RF rev. no and various other things from EEPROM */ 223175938Ssephe rt2560_read_config(sc); 224156321Sdamien 225156321Sdamien device_printf(dev, "MAC/BBP RT2560 (rev 0x%02x), RF %s\n", 226156321Sdamien sc->asic_rev, rt2560_get_rf(sc->rf_rev)); 227156321Sdamien 228156321Sdamien /* 229156321Sdamien * Allocate Tx and Rx rings. 230156321Sdamien */ 231156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->txq, RT2560_TX_RING_COUNT); 232156321Sdamien if (error != 0) { 233156321Sdamien device_printf(sc->sc_dev, "could not allocate Tx ring\n"); 234156321Sdamien goto fail1; 235156321Sdamien } 236156321Sdamien 237156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->atimq, RT2560_ATIM_RING_COUNT); 238156321Sdamien if (error != 0) { 239156321Sdamien device_printf(sc->sc_dev, "could not allocate ATIM ring\n"); 240156321Sdamien goto fail2; 241156321Sdamien } 242156321Sdamien 243156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->prioq, RT2560_PRIO_RING_COUNT); 244156321Sdamien if (error != 0) { 245156321Sdamien device_printf(sc->sc_dev, "could not allocate Prio ring\n"); 246156321Sdamien goto fail3; 247156321Sdamien } 248156321Sdamien 249156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->bcnq, RT2560_BEACON_RING_COUNT); 250156321Sdamien if (error != 0) { 251156321Sdamien device_printf(sc->sc_dev, "could not allocate Beacon ring\n"); 252156321Sdamien goto fail4; 253156321Sdamien } 254156321Sdamien 255156321Sdamien error = rt2560_alloc_rx_ring(sc, &sc->rxq, RT2560_RX_RING_COUNT); 256156321Sdamien if (error != 0) { 257156321Sdamien device_printf(sc->sc_dev, "could not allocate Rx ring\n"); 258156321Sdamien goto fail5; 259156321Sdamien } 260156321Sdamien 261178354Ssam /* retrieve MAC address */ 262287197Sglebius rt2560_get_macaddr(sc, ic->ic_macaddr); 263178354Ssam 264283537Sglebius ic->ic_softc = sc; 265283527Sglebius ic->ic_name = device_get_nameunit(dev); 266178354Ssam ic->ic_opmode = IEEE80211_M_STA; 267156321Sdamien ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 268156321Sdamien 269156321Sdamien /* set device capabilities */ 270156321Sdamien ic->ic_caps = 271178957Ssam IEEE80211_C_STA /* station mode */ 272178957Ssam | IEEE80211_C_IBSS /* ibss, nee adhoc, mode */ 273178354Ssam | IEEE80211_C_HOSTAP /* hostap mode */ 274178354Ssam | IEEE80211_C_MONITOR /* monitor mode */ 275178354Ssam | IEEE80211_C_AHDEMO /* adhoc demo mode */ 276178354Ssam | IEEE80211_C_WDS /* 4-address traffic works */ 277195618Srpaulo | IEEE80211_C_MBSS /* mesh point link mode */ 278178354Ssam | IEEE80211_C_SHPREAMBLE /* short preamble supported */ 279178354Ssam | IEEE80211_C_SHSLOT /* short slot time supported */ 280178354Ssam | IEEE80211_C_WPA /* capable of WPA1+WPA2 */ 281178354Ssam | IEEE80211_C_BGSCAN /* capable of bg scanning */ 282178354Ssam#ifdef notyet 283178354Ssam | IEEE80211_C_TXFRAG /* handle tx frags */ 284178354Ssam#endif 285178354Ssam ; 286156321Sdamien 287300752Savos rt2560_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans, 288300752Savos ic->ic_channels); 289156321Sdamien 290287197Sglebius ieee80211_ifattach(ic); 291178354Ssam ic->ic_raw_xmit = rt2560_raw_xmit; 292178354Ssam ic->ic_updateslot = rt2560_update_slot; 293178354Ssam ic->ic_update_promisc = rt2560_update_promisc; 294170530Ssam ic->ic_scan_start = rt2560_scan_start; 295170530Ssam ic->ic_scan_end = rt2560_scan_end; 296300752Savos ic->ic_getradiocaps = rt2560_getradiocaps; 297170530Ssam ic->ic_set_channel = rt2560_set_channel; 298156321Sdamien 299178354Ssam ic->ic_vap_create = rt2560_vap_create; 300178354Ssam ic->ic_vap_delete = rt2560_vap_delete; 301287197Sglebius ic->ic_parent = rt2560_parent; 302287197Sglebius ic->ic_transmit = rt2560_transmit; 303156321Sdamien 304192468Ssam ieee80211_radiotap_attach(ic, 305192468Ssam &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), 306192468Ssam RT2560_TX_RADIOTAP_PRESENT, 307192468Ssam &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 308192468Ssam RT2560_RX_RADIOTAP_PRESENT); 309156321Sdamien 310156321Sdamien /* 311156321Sdamien * Add a few sysctl knobs. 312156321Sdamien */ 313178354Ssam#ifdef RAL_DEBUG 314156321Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 315156321Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 316178354Ssam "debug", CTLFLAG_RW, &sc->sc_debug, 0, "debug msgs"); 317178354Ssam#endif 318178354Ssam SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 319178354Ssam SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 320156321Sdamien "txantenna", CTLFLAG_RW, &sc->tx_ant, 0, "tx antenna (0=auto)"); 321156321Sdamien 322156321Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 323156321Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 324156321Sdamien "rxantenna", CTLFLAG_RW, &sc->rx_ant, 0, "rx antenna (0=auto)"); 325156321Sdamien 326156321Sdamien if (bootverbose) 327156321Sdamien ieee80211_announce(ic); 328156321Sdamien 329156321Sdamien return 0; 330156321Sdamien 331156321Sdamienfail5: rt2560_free_tx_ring(sc, &sc->bcnq); 332156321Sdamienfail4: rt2560_free_tx_ring(sc, &sc->prioq); 333156321Sdamienfail3: rt2560_free_tx_ring(sc, &sc->atimq); 334156321Sdamienfail2: rt2560_free_tx_ring(sc, &sc->txq); 335156321Sdamienfail1: mtx_destroy(&sc->sc_mtx); 336156321Sdamien 337156321Sdamien return ENXIO; 338156321Sdamien} 339156321Sdamien 340156321Sdamienint 341156321Sdamienrt2560_detach(void *xsc) 342156321Sdamien{ 343156321Sdamien struct rt2560_softc *sc = xsc; 344287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 345170530Ssam 346156321Sdamien rt2560_stop(sc); 347156321Sdamien 348156321Sdamien ieee80211_ifdetach(ic); 349287197Sglebius mbufq_drain(&sc->sc_snd); 350156321Sdamien 351156321Sdamien rt2560_free_tx_ring(sc, &sc->txq); 352156321Sdamien rt2560_free_tx_ring(sc, &sc->atimq); 353156321Sdamien rt2560_free_tx_ring(sc, &sc->prioq); 354156321Sdamien rt2560_free_tx_ring(sc, &sc->bcnq); 355156321Sdamien rt2560_free_rx_ring(sc, &sc->rxq); 356156321Sdamien 357156321Sdamien mtx_destroy(&sc->sc_mtx); 358156321Sdamien 359156321Sdamien return 0; 360156321Sdamien} 361156321Sdamien 362178354Ssamstatic struct ieee80211vap * 363228621Sbschmidtrt2560_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, 364228621Sbschmidt enum ieee80211_opmode opmode, int flags, 365228621Sbschmidt const uint8_t bssid[IEEE80211_ADDR_LEN], 366228621Sbschmidt const uint8_t mac[IEEE80211_ADDR_LEN]) 367178354Ssam{ 368287197Sglebius struct rt2560_softc *sc = ic->ic_softc; 369178354Ssam struct rt2560_vap *rvp; 370178354Ssam struct ieee80211vap *vap; 371178354Ssam 372178354Ssam switch (opmode) { 373178354Ssam case IEEE80211_M_STA: 374178354Ssam case IEEE80211_M_IBSS: 375178354Ssam case IEEE80211_M_AHDEMO: 376178354Ssam case IEEE80211_M_MONITOR: 377178354Ssam case IEEE80211_M_HOSTAP: 378195618Srpaulo case IEEE80211_M_MBSS: 379195618Srpaulo /* XXXRP: TBD */ 380178354Ssam if (!TAILQ_EMPTY(&ic->ic_vaps)) { 381287197Sglebius device_printf(sc->sc_dev, "only 1 vap supported\n"); 382178354Ssam return NULL; 383178354Ssam } 384178354Ssam if (opmode == IEEE80211_M_STA) 385178354Ssam flags |= IEEE80211_CLONE_NOBEACONS; 386178354Ssam break; 387178354Ssam case IEEE80211_M_WDS: 388178354Ssam if (TAILQ_EMPTY(&ic->ic_vaps) || 389178354Ssam ic->ic_opmode != IEEE80211_M_HOSTAP) { 390287197Sglebius device_printf(sc->sc_dev, 391287197Sglebius "wds only supported in ap mode\n"); 392178354Ssam return NULL; 393178354Ssam } 394178354Ssam /* 395178354Ssam * Silently remove any request for a unique 396178354Ssam * bssid; WDS vap's always share the local 397178354Ssam * mac address. 398178354Ssam */ 399178354Ssam flags &= ~IEEE80211_CLONE_BSSID; 400178354Ssam break; 401178354Ssam default: 402287197Sglebius device_printf(sc->sc_dev, "unknown opmode %d\n", opmode); 403178354Ssam return NULL; 404178354Ssam } 405287197Sglebius rvp = malloc(sizeof(struct rt2560_vap), M_80211_VAP, M_WAITOK | M_ZERO); 406178354Ssam vap = &rvp->ral_vap; 407287197Sglebius ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); 408178354Ssam 409178354Ssam /* override state transition machine */ 410178354Ssam rvp->ral_newstate = vap->iv_newstate; 411178354Ssam vap->iv_newstate = rt2560_newstate; 412178354Ssam vap->iv_update_beacon = rt2560_beacon_update; 413178354Ssam 414206358Srpaulo ieee80211_ratectl_init(vap); 415178354Ssam /* complete setup */ 416287197Sglebius ieee80211_vap_attach(vap, ieee80211_media_change, 417287197Sglebius ieee80211_media_status, mac); 418178354Ssam if (TAILQ_FIRST(&ic->ic_vaps) == vap) 419178354Ssam ic->ic_opmode = opmode; 420178354Ssam return vap; 421178354Ssam} 422178354Ssam 423178354Ssamstatic void 424178354Ssamrt2560_vap_delete(struct ieee80211vap *vap) 425178354Ssam{ 426178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 427178354Ssam 428206358Srpaulo ieee80211_ratectl_deinit(vap); 429178354Ssam ieee80211_vap_detach(vap); 430178354Ssam free(rvp, M_80211_VAP); 431178354Ssam} 432178354Ssam 433156321Sdamienvoid 434156321Sdamienrt2560_resume(void *xsc) 435156321Sdamien{ 436156321Sdamien struct rt2560_softc *sc = xsc; 437156321Sdamien 438287197Sglebius if (sc->sc_ic.ic_nrunning > 0) 439178354Ssam rt2560_init(sc); 440156321Sdamien} 441156321Sdamien 442156321Sdamienstatic void 443156321Sdamienrt2560_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 444156321Sdamien{ 445156321Sdamien if (error != 0) 446156321Sdamien return; 447156321Sdamien 448156321Sdamien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 449156321Sdamien 450156321Sdamien *(bus_addr_t *)arg = segs[0].ds_addr; 451156321Sdamien} 452156321Sdamien 453156321Sdamienstatic int 454156321Sdamienrt2560_alloc_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring, 455156321Sdamien int count) 456156321Sdamien{ 457156321Sdamien int i, error; 458156321Sdamien 459156321Sdamien ring->count = count; 460156321Sdamien ring->queued = 0; 461156321Sdamien ring->cur = ring->next = 0; 462156321Sdamien ring->cur_encrypt = ring->next_encrypt = 0; 463156321Sdamien 464171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 4, 0, 465171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 466171535Skevlo count * RT2560_TX_DESC_SIZE, 1, count * RT2560_TX_DESC_SIZE, 467171535Skevlo 0, NULL, NULL, &ring->desc_dmat); 468156321Sdamien if (error != 0) { 469156321Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 470156321Sdamien goto fail; 471156321Sdamien } 472156321Sdamien 473156321Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 474156321Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 475156321Sdamien if (error != 0) { 476156321Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 477156321Sdamien goto fail; 478156321Sdamien } 479156321Sdamien 480156321Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 481156321Sdamien count * RT2560_TX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr, 482156321Sdamien 0); 483156321Sdamien if (error != 0) { 484156321Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 485156321Sdamien goto fail; 486156321Sdamien } 487156321Sdamien 488156321Sdamien ring->data = malloc(count * sizeof (struct rt2560_tx_data), M_DEVBUF, 489156321Sdamien M_NOWAIT | M_ZERO); 490156321Sdamien if (ring->data == NULL) { 491156321Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 492156321Sdamien error = ENOMEM; 493156321Sdamien goto fail; 494156321Sdamien } 495156321Sdamien 496171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 497171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 498171535Skevlo MCLBYTES, RT2560_MAX_SCATTER, MCLBYTES, 0, NULL, NULL, 499171535Skevlo &ring->data_dmat); 500156321Sdamien if (error != 0) { 501156321Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 502156321Sdamien goto fail; 503156321Sdamien } 504156321Sdamien 505156321Sdamien for (i = 0; i < count; i++) { 506156321Sdamien error = bus_dmamap_create(ring->data_dmat, 0, 507156321Sdamien &ring->data[i].map); 508156321Sdamien if (error != 0) { 509156321Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 510156321Sdamien goto fail; 511156321Sdamien } 512156321Sdamien } 513156321Sdamien 514156321Sdamien return 0; 515156321Sdamien 516156321Sdamienfail: rt2560_free_tx_ring(sc, ring); 517156321Sdamien return error; 518156321Sdamien} 519156321Sdamien 520156321Sdamienstatic void 521156321Sdamienrt2560_reset_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) 522156321Sdamien{ 523156321Sdamien struct rt2560_tx_desc *desc; 524156321Sdamien struct rt2560_tx_data *data; 525156321Sdamien int i; 526156321Sdamien 527156321Sdamien for (i = 0; i < ring->count; i++) { 528156321Sdamien desc = &ring->desc[i]; 529156321Sdamien data = &ring->data[i]; 530156321Sdamien 531156321Sdamien if (data->m != NULL) { 532156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 533156321Sdamien BUS_DMASYNC_POSTWRITE); 534156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 535156321Sdamien m_freem(data->m); 536156321Sdamien data->m = NULL; 537156321Sdamien } 538156321Sdamien 539156321Sdamien if (data->ni != NULL) { 540156321Sdamien ieee80211_free_node(data->ni); 541156321Sdamien data->ni = NULL; 542156321Sdamien } 543156321Sdamien 544156321Sdamien desc->flags = 0; 545156321Sdamien } 546156321Sdamien 547156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 548156321Sdamien 549156321Sdamien ring->queued = 0; 550156321Sdamien ring->cur = ring->next = 0; 551156321Sdamien ring->cur_encrypt = ring->next_encrypt = 0; 552156321Sdamien} 553156321Sdamien 554156321Sdamienstatic void 555156321Sdamienrt2560_free_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) 556156321Sdamien{ 557156321Sdamien struct rt2560_tx_data *data; 558156321Sdamien int i; 559156321Sdamien 560156321Sdamien if (ring->desc != NULL) { 561156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 562156321Sdamien BUS_DMASYNC_POSTWRITE); 563156321Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 564156321Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 565156321Sdamien } 566156321Sdamien 567156321Sdamien if (ring->desc_dmat != NULL) 568156321Sdamien bus_dma_tag_destroy(ring->desc_dmat); 569156321Sdamien 570156321Sdamien if (ring->data != NULL) { 571156321Sdamien for (i = 0; i < ring->count; i++) { 572156321Sdamien data = &ring->data[i]; 573156321Sdamien 574156321Sdamien if (data->m != NULL) { 575156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 576156321Sdamien BUS_DMASYNC_POSTWRITE); 577156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 578156321Sdamien m_freem(data->m); 579156321Sdamien } 580156321Sdamien 581156321Sdamien if (data->ni != NULL) 582156321Sdamien ieee80211_free_node(data->ni); 583156321Sdamien 584156321Sdamien if (data->map != NULL) 585156321Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 586156321Sdamien } 587156321Sdamien 588156321Sdamien free(ring->data, M_DEVBUF); 589156321Sdamien } 590156321Sdamien 591156321Sdamien if (ring->data_dmat != NULL) 592156321Sdamien bus_dma_tag_destroy(ring->data_dmat); 593156321Sdamien} 594156321Sdamien 595156321Sdamienstatic int 596156321Sdamienrt2560_alloc_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring, 597156321Sdamien int count) 598156321Sdamien{ 599156321Sdamien struct rt2560_rx_desc *desc; 600156321Sdamien struct rt2560_rx_data *data; 601156321Sdamien bus_addr_t physaddr; 602156321Sdamien int i, error; 603156321Sdamien 604156321Sdamien ring->count = count; 605156321Sdamien ring->cur = ring->next = 0; 606156321Sdamien ring->cur_decrypt = 0; 607156321Sdamien 608171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 4, 0, 609171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 610171535Skevlo count * RT2560_RX_DESC_SIZE, 1, count * RT2560_RX_DESC_SIZE, 611171535Skevlo 0, NULL, NULL, &ring->desc_dmat); 612156321Sdamien if (error != 0) { 613156321Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 614156321Sdamien goto fail; 615156321Sdamien } 616156321Sdamien 617156321Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 618156321Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 619156321Sdamien if (error != 0) { 620156321Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 621156321Sdamien goto fail; 622156321Sdamien } 623156321Sdamien 624156321Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 625156321Sdamien count * RT2560_RX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr, 626156321Sdamien 0); 627156321Sdamien if (error != 0) { 628156321Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 629156321Sdamien goto fail; 630156321Sdamien } 631156321Sdamien 632156321Sdamien ring->data = malloc(count * sizeof (struct rt2560_rx_data), M_DEVBUF, 633156321Sdamien M_NOWAIT | M_ZERO); 634156321Sdamien if (ring->data == NULL) { 635156321Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 636156321Sdamien error = ENOMEM; 637156321Sdamien goto fail; 638156321Sdamien } 639156321Sdamien 640156321Sdamien /* 641156321Sdamien * Pre-allocate Rx buffers and populate Rx ring. 642156321Sdamien */ 643171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 644171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 645171535Skevlo 1, MCLBYTES, 0, NULL, NULL, &ring->data_dmat); 646156321Sdamien if (error != 0) { 647156321Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 648156321Sdamien goto fail; 649156321Sdamien } 650156321Sdamien 651156321Sdamien for (i = 0; i < count; i++) { 652156321Sdamien desc = &sc->rxq.desc[i]; 653156321Sdamien data = &sc->rxq.data[i]; 654156321Sdamien 655156321Sdamien error = bus_dmamap_create(ring->data_dmat, 0, &data->map); 656156321Sdamien if (error != 0) { 657156321Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 658156321Sdamien goto fail; 659156321Sdamien } 660156321Sdamien 661243857Sglebius data->m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 662156321Sdamien if (data->m == NULL) { 663156321Sdamien device_printf(sc->sc_dev, 664156321Sdamien "could not allocate rx mbuf\n"); 665156321Sdamien error = ENOMEM; 666156321Sdamien goto fail; 667156321Sdamien } 668156321Sdamien 669156321Sdamien error = bus_dmamap_load(ring->data_dmat, data->map, 670156321Sdamien mtod(data->m, void *), MCLBYTES, rt2560_dma_map_addr, 671156321Sdamien &physaddr, 0); 672156321Sdamien if (error != 0) { 673156321Sdamien device_printf(sc->sc_dev, 674156321Sdamien "could not load rx buf DMA map"); 675156321Sdamien goto fail; 676156321Sdamien } 677156321Sdamien 678156321Sdamien desc->flags = htole32(RT2560_RX_BUSY); 679156321Sdamien desc->physaddr = htole32(physaddr); 680156321Sdamien } 681156321Sdamien 682156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 683156321Sdamien 684156321Sdamien return 0; 685156321Sdamien 686156321Sdamienfail: rt2560_free_rx_ring(sc, ring); 687156321Sdamien return error; 688156321Sdamien} 689156321Sdamien 690156321Sdamienstatic void 691156321Sdamienrt2560_reset_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) 692156321Sdamien{ 693156321Sdamien int i; 694156321Sdamien 695156321Sdamien for (i = 0; i < ring->count; i++) { 696156321Sdamien ring->desc[i].flags = htole32(RT2560_RX_BUSY); 697156321Sdamien ring->data[i].drop = 0; 698156321Sdamien } 699156321Sdamien 700156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 701156321Sdamien 702156321Sdamien ring->cur = ring->next = 0; 703156321Sdamien ring->cur_decrypt = 0; 704156321Sdamien} 705156321Sdamien 706156321Sdamienstatic void 707156321Sdamienrt2560_free_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) 708156321Sdamien{ 709156321Sdamien struct rt2560_rx_data *data; 710156321Sdamien int i; 711156321Sdamien 712156321Sdamien if (ring->desc != NULL) { 713156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 714156321Sdamien BUS_DMASYNC_POSTWRITE); 715156321Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 716156321Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 717156321Sdamien } 718156321Sdamien 719156321Sdamien if (ring->desc_dmat != NULL) 720156321Sdamien bus_dma_tag_destroy(ring->desc_dmat); 721156321Sdamien 722156321Sdamien if (ring->data != NULL) { 723156321Sdamien for (i = 0; i < ring->count; i++) { 724156321Sdamien data = &ring->data[i]; 725156321Sdamien 726156321Sdamien if (data->m != NULL) { 727156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 728156321Sdamien BUS_DMASYNC_POSTREAD); 729156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 730156321Sdamien m_freem(data->m); 731156321Sdamien } 732156321Sdamien 733156321Sdamien if (data->map != NULL) 734156321Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 735156321Sdamien } 736156321Sdamien 737156321Sdamien free(ring->data, M_DEVBUF); 738156321Sdamien } 739156321Sdamien 740156321Sdamien if (ring->data_dmat != NULL) 741156321Sdamien bus_dma_tag_destroy(ring->data_dmat); 742156321Sdamien} 743156321Sdamien 744156321Sdamienstatic int 745178354Ssamrt2560_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 746156321Sdamien{ 747178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 748287197Sglebius struct rt2560_softc *sc = vap->iv_ic->ic_softc; 749178354Ssam int error; 750156321Sdamien 751178354Ssam if (nstate == IEEE80211_S_INIT && vap->iv_state == IEEE80211_S_RUN) { 752178354Ssam /* abort TSF synchronization */ 753178354Ssam RAL_WRITE(sc, RT2560_CSR14, 0); 754156321Sdamien 755178354Ssam /* turn association led off */ 756178354Ssam rt2560_update_led(sc, 0, 0); 757178354Ssam } 758156321Sdamien 759178354Ssam error = rvp->ral_newstate(vap, nstate, arg); 760156321Sdamien 761178354Ssam if (error == 0 && nstate == IEEE80211_S_RUN) { 762178354Ssam struct ieee80211_node *ni = vap->iv_bss; 763178354Ssam struct mbuf *m; 764156321Sdamien 765178354Ssam if (vap->iv_opmode != IEEE80211_M_MONITOR) { 766156321Sdamien rt2560_update_plcp(sc); 767220502Sbschmidt rt2560_set_basicrates(sc, &ni->ni_rates); 768156321Sdamien rt2560_set_bssid(sc, ni->ni_bssid); 769156321Sdamien } 770156321Sdamien 771178354Ssam if (vap->iv_opmode == IEEE80211_M_HOSTAP || 772195618Srpaulo vap->iv_opmode == IEEE80211_M_IBSS || 773195618Srpaulo vap->iv_opmode == IEEE80211_M_MBSS) { 774288636Sadrian m = ieee80211_beacon_alloc(ni); 775156321Sdamien if (m == NULL) { 776287197Sglebius device_printf(sc->sc_dev, 777287197Sglebius "could not allocate beacon\n"); 778178354Ssam return ENOBUFS; 779156321Sdamien } 780156321Sdamien ieee80211_ref_node(ni); 781156321Sdamien error = rt2560_tx_bcn(sc, m, ni); 782156321Sdamien if (error != 0) 783178354Ssam return error; 784156321Sdamien } 785156321Sdamien 786298955Spfg /* turn association led on */ 787156321Sdamien rt2560_update_led(sc, 1, 0); 788156321Sdamien 789184345Ssam if (vap->iv_opmode != IEEE80211_M_MONITOR) 790156321Sdamien rt2560_enable_tsf_sync(sc); 791192468Ssam else 792192468Ssam rt2560_enable_tsf(sc); 793156321Sdamien } 794178354Ssam return error; 795156321Sdamien} 796156321Sdamien 797156321Sdamien/* 798156321Sdamien * Read 16 bits at address 'addr' from the serial EEPROM (either 93C46 or 799156321Sdamien * 93C66). 800156321Sdamien */ 801156321Sdamienstatic uint16_t 802156321Sdamienrt2560_eeprom_read(struct rt2560_softc *sc, uint8_t addr) 803156321Sdamien{ 804156321Sdamien uint32_t tmp; 805156321Sdamien uint16_t val; 806156321Sdamien int n; 807156321Sdamien 808156321Sdamien /* clock C once before the first command */ 809156321Sdamien RT2560_EEPROM_CTL(sc, 0); 810156321Sdamien 811156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 812156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 813156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 814156321Sdamien 815156321Sdamien /* write start bit (1) */ 816156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D); 817156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C); 818156321Sdamien 819156321Sdamien /* write READ opcode (10) */ 820156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D); 821156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C); 822156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 823156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 824156321Sdamien 825156321Sdamien /* write address (A5-A0 or A7-A0) */ 826156321Sdamien n = (RAL_READ(sc, RT2560_CSR21) & RT2560_93C46) ? 5 : 7; 827156321Sdamien for (; n >= 0; n--) { 828156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | 829156321Sdamien (((addr >> n) & 1) << RT2560_SHIFT_D)); 830156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | 831156321Sdamien (((addr >> n) & 1) << RT2560_SHIFT_D) | RT2560_C); 832156321Sdamien } 833156321Sdamien 834156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 835156321Sdamien 836156321Sdamien /* read data Q15-Q0 */ 837156321Sdamien val = 0; 838156321Sdamien for (n = 15; n >= 0; n--) { 839156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 840156321Sdamien tmp = RAL_READ(sc, RT2560_CSR21); 841156321Sdamien val |= ((tmp & RT2560_Q) >> RT2560_SHIFT_Q) << n; 842156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 843156321Sdamien } 844156321Sdamien 845156321Sdamien RT2560_EEPROM_CTL(sc, 0); 846156321Sdamien 847156321Sdamien /* clear Chip Select and clock C */ 848156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 849156321Sdamien RT2560_EEPROM_CTL(sc, 0); 850156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_C); 851156321Sdamien 852156321Sdamien return val; 853156321Sdamien} 854156321Sdamien 855156321Sdamien/* 856156321Sdamien * Some frames were processed by the hardware cipher engine and are ready for 857156321Sdamien * transmission. 858156321Sdamien */ 859156321Sdamienstatic void 860156321Sdamienrt2560_encryption_intr(struct rt2560_softc *sc) 861156321Sdamien{ 862156321Sdamien struct rt2560_tx_desc *desc; 863156321Sdamien int hw; 864156321Sdamien 865156321Sdamien /* retrieve last descriptor index processed by cipher engine */ 866156321Sdamien hw = RAL_READ(sc, RT2560_SECCSR1) - sc->txq.physaddr; 867156321Sdamien hw /= RT2560_TX_DESC_SIZE; 868156321Sdamien 869156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 870156321Sdamien BUS_DMASYNC_POSTREAD); 871156321Sdamien 872175938Ssephe while (sc->txq.next_encrypt != hw) { 873175938Ssephe if (sc->txq.next_encrypt == sc->txq.cur_encrypt) { 874175938Ssephe printf("hw encrypt %d, cur_encrypt %d\n", hw, 875175938Ssephe sc->txq.cur_encrypt); 876175938Ssephe break; 877175938Ssephe } 878175938Ssephe 879156321Sdamien desc = &sc->txq.desc[sc->txq.next_encrypt]; 880156321Sdamien 881156321Sdamien if ((le32toh(desc->flags) & RT2560_TX_BUSY) || 882156321Sdamien (le32toh(desc->flags) & RT2560_TX_CIPHER_BUSY)) 883156321Sdamien break; 884156321Sdamien 885156321Sdamien /* for TKIP, swap eiv field to fix a bug in ASIC */ 886156321Sdamien if ((le32toh(desc->flags) & RT2560_TX_CIPHER_MASK) == 887156321Sdamien RT2560_TX_CIPHER_TKIP) 888156321Sdamien desc->eiv = bswap32(desc->eiv); 889156321Sdamien 890156321Sdamien /* mark the frame ready for transmission */ 891175938Ssephe desc->flags |= htole32(RT2560_TX_VALID); 892175938Ssephe desc->flags |= htole32(RT2560_TX_BUSY); 893156321Sdamien 894178354Ssam DPRINTFN(sc, 15, "encryption done idx=%u\n", 895178354Ssam sc->txq.next_encrypt); 896156321Sdamien 897156321Sdamien sc->txq.next_encrypt = 898156321Sdamien (sc->txq.next_encrypt + 1) % RT2560_TX_RING_COUNT; 899156321Sdamien } 900156321Sdamien 901156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 902156321Sdamien BUS_DMASYNC_PREWRITE); 903156321Sdamien 904156321Sdamien /* kick Tx */ 905156321Sdamien RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_TX); 906156321Sdamien} 907156321Sdamien 908156321Sdamienstatic void 909156321Sdamienrt2560_tx_intr(struct rt2560_softc *sc) 910156321Sdamien{ 911156321Sdamien struct rt2560_tx_desc *desc; 912156321Sdamien struct rt2560_tx_data *data; 913178354Ssam struct mbuf *m; 914206358Srpaulo struct ieee80211vap *vap; 915206358Srpaulo struct ieee80211_node *ni; 916287197Sglebius uint32_t flags; 917287197Sglebius int retrycnt, status; 918156321Sdamien 919156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 920156321Sdamien BUS_DMASYNC_POSTREAD); 921156321Sdamien 922156321Sdamien for (;;) { 923156321Sdamien desc = &sc->txq.desc[sc->txq.next]; 924156321Sdamien data = &sc->txq.data[sc->txq.next]; 925156321Sdamien 926178354Ssam flags = le32toh(desc->flags); 927178354Ssam if ((flags & RT2560_TX_BUSY) || 928178354Ssam (flags & RT2560_TX_CIPHER_BUSY) || 929178354Ssam !(flags & RT2560_TX_VALID)) 930156321Sdamien break; 931156321Sdamien 932178354Ssam m = data->m; 933206358Srpaulo ni = data->ni; 934206358Srpaulo vap = ni->ni_vap; 935156321Sdamien 936178354Ssam switch (flags & RT2560_TX_RESULT_MASK) { 937156321Sdamien case RT2560_TX_SUCCESS: 938206358Srpaulo retrycnt = 0; 939206358Srpaulo 940178354Ssam DPRINTFN(sc, 10, "%s\n", "data frame sent successfully"); 941178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 942206358Srpaulo ieee80211_ratectl_tx_complete(vap, ni, 943206358Srpaulo IEEE80211_RATECTL_TX_SUCCESS, 944206358Srpaulo &retrycnt, NULL); 945287197Sglebius status = 0; 946156321Sdamien break; 947156321Sdamien 948156321Sdamien case RT2560_TX_SUCCESS_RETRY: 949178354Ssam retrycnt = RT2560_TX_RETRYCNT(flags); 950178354Ssam 951178354Ssam DPRINTFN(sc, 9, "data frame sent after %u retries\n", 952178354Ssam retrycnt); 953178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 954206358Srpaulo ieee80211_ratectl_tx_complete(vap, ni, 955206358Srpaulo IEEE80211_RATECTL_TX_SUCCESS, 956206358Srpaulo &retrycnt, NULL); 957287197Sglebius status = 0; 958156321Sdamien break; 959156321Sdamien 960156321Sdamien case RT2560_TX_FAIL_RETRY: 961178354Ssam retrycnt = RT2560_TX_RETRYCNT(flags); 962178354Ssam 963178354Ssam DPRINTFN(sc, 9, "data frame failed after %d retries\n", 964178354Ssam retrycnt); 965178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 966206358Srpaulo ieee80211_ratectl_tx_complete(vap, ni, 967206358Srpaulo IEEE80211_RATECTL_TX_FAILURE, 968206358Srpaulo &retrycnt, NULL); 969287197Sglebius status = 1; 970156321Sdamien break; 971156321Sdamien 972156321Sdamien case RT2560_TX_FAIL_INVALID: 973156321Sdamien case RT2560_TX_FAIL_OTHER: 974156321Sdamien default: 975156321Sdamien device_printf(sc->sc_dev, "sending data frame failed " 976178354Ssam "0x%08x\n", flags); 977287197Sglebius status = 1; 978156321Sdamien } 979156321Sdamien 980156321Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, 981156321Sdamien BUS_DMASYNC_POSTWRITE); 982156321Sdamien bus_dmamap_unload(sc->txq.data_dmat, data->map); 983287197Sglebius 984287197Sglebius ieee80211_tx_complete(ni, m, status); 985287197Sglebius data->ni = NULL; 986286437Sadrian data->m = NULL; 987156321Sdamien 988156321Sdamien /* descriptor is no longer valid */ 989156321Sdamien desc->flags &= ~htole32(RT2560_TX_VALID); 990156321Sdamien 991178354Ssam DPRINTFN(sc, 15, "tx done idx=%u\n", sc->txq.next); 992156321Sdamien 993156321Sdamien sc->txq.queued--; 994156321Sdamien sc->txq.next = (sc->txq.next + 1) % RT2560_TX_RING_COUNT; 995156321Sdamien } 996156321Sdamien 997156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 998156321Sdamien BUS_DMASYNC_PREWRITE); 999156321Sdamien 1000175938Ssephe if (sc->prioq.queued == 0 && sc->txq.queued == 0) 1001175938Ssephe sc->sc_tx_timer = 0; 1002175938Ssephe 1003287197Sglebius if (sc->txq.queued < RT2560_TX_RING_COUNT - 1) 1004287197Sglebius rt2560_start(sc); 1005156321Sdamien} 1006156321Sdamien 1007156321Sdamienstatic void 1008156321Sdamienrt2560_prio_intr(struct rt2560_softc *sc) 1009156321Sdamien{ 1010156321Sdamien struct rt2560_tx_desc *desc; 1011156321Sdamien struct rt2560_tx_data *data; 1012170530Ssam struct ieee80211_node *ni; 1013170530Ssam struct mbuf *m; 1014170530Ssam int flags; 1015156321Sdamien 1016156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1017156321Sdamien BUS_DMASYNC_POSTREAD); 1018156321Sdamien 1019156321Sdamien for (;;) { 1020156321Sdamien desc = &sc->prioq.desc[sc->prioq.next]; 1021156321Sdamien data = &sc->prioq.data[sc->prioq.next]; 1022156321Sdamien 1023170530Ssam flags = le32toh(desc->flags); 1024170530Ssam if ((flags & RT2560_TX_BUSY) || (flags & RT2560_TX_VALID) == 0) 1025156321Sdamien break; 1026156321Sdamien 1027170530Ssam switch (flags & RT2560_TX_RESULT_MASK) { 1028156321Sdamien case RT2560_TX_SUCCESS: 1029178354Ssam DPRINTFN(sc, 10, "%s\n", "mgt frame sent successfully"); 1030156321Sdamien break; 1031156321Sdamien 1032156321Sdamien case RT2560_TX_SUCCESS_RETRY: 1033178354Ssam DPRINTFN(sc, 9, "mgt frame sent after %u retries\n", 1034178354Ssam (flags >> 5) & 0x7); 1035156321Sdamien break; 1036156321Sdamien 1037156321Sdamien case RT2560_TX_FAIL_RETRY: 1038178354Ssam DPRINTFN(sc, 9, "%s\n", 1039178354Ssam "sending mgt frame failed (too much retries)"); 1040156321Sdamien break; 1041156321Sdamien 1042156321Sdamien case RT2560_TX_FAIL_INVALID: 1043156321Sdamien case RT2560_TX_FAIL_OTHER: 1044156321Sdamien default: 1045156321Sdamien device_printf(sc->sc_dev, "sending mgt frame failed " 1046170530Ssam "0x%08x\n", flags); 1047170530Ssam break; 1048156321Sdamien } 1049156321Sdamien 1050156321Sdamien bus_dmamap_sync(sc->prioq.data_dmat, data->map, 1051156321Sdamien BUS_DMASYNC_POSTWRITE); 1052156321Sdamien bus_dmamap_unload(sc->prioq.data_dmat, data->map); 1053170530Ssam 1054170530Ssam m = data->m; 1055156321Sdamien data->m = NULL; 1056170530Ssam ni = data->ni; 1057156321Sdamien data->ni = NULL; 1058156321Sdamien 1059156321Sdamien /* descriptor is no longer valid */ 1060156321Sdamien desc->flags &= ~htole32(RT2560_TX_VALID); 1061156321Sdamien 1062178354Ssam DPRINTFN(sc, 15, "prio done idx=%u\n", sc->prioq.next); 1063156321Sdamien 1064156321Sdamien sc->prioq.queued--; 1065156321Sdamien sc->prioq.next = (sc->prioq.next + 1) % RT2560_PRIO_RING_COUNT; 1066170530Ssam 1067170530Ssam if (m->m_flags & M_TXCB) 1068170530Ssam ieee80211_process_callback(ni, m, 1069170530Ssam (flags & RT2560_TX_RESULT_MASK) &~ 1070170530Ssam (RT2560_TX_SUCCESS | RT2560_TX_SUCCESS_RETRY)); 1071170530Ssam m_freem(m); 1072170530Ssam ieee80211_free_node(ni); 1073156321Sdamien } 1074156321Sdamien 1075156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1076156321Sdamien BUS_DMASYNC_PREWRITE); 1077156321Sdamien 1078175938Ssephe if (sc->prioq.queued == 0 && sc->txq.queued == 0) 1079175938Ssephe sc->sc_tx_timer = 0; 1080175938Ssephe 1081287197Sglebius if (sc->prioq.queued < RT2560_PRIO_RING_COUNT) 1082287197Sglebius rt2560_start(sc); 1083156321Sdamien} 1084156321Sdamien 1085156321Sdamien/* 1086156321Sdamien * Some frames were processed by the hardware cipher engine and are ready for 1087178354Ssam * handoff to the IEEE802.11 layer. 1088156321Sdamien */ 1089156321Sdamienstatic void 1090156321Sdamienrt2560_decryption_intr(struct rt2560_softc *sc) 1091156321Sdamien{ 1092287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 1093156321Sdamien struct rt2560_rx_desc *desc; 1094156321Sdamien struct rt2560_rx_data *data; 1095156321Sdamien bus_addr_t physaddr; 1096156321Sdamien struct ieee80211_frame *wh; 1097156321Sdamien struct ieee80211_node *ni; 1098156321Sdamien struct mbuf *mnew, *m; 1099156321Sdamien int hw, error; 1100192468Ssam int8_t rssi, nf; 1101156321Sdamien 1102298955Spfg /* retrieve last descriptor index processed by cipher engine */ 1103156321Sdamien hw = RAL_READ(sc, RT2560_SECCSR0) - sc->rxq.physaddr; 1104156321Sdamien hw /= RT2560_RX_DESC_SIZE; 1105156321Sdamien 1106156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1107156321Sdamien BUS_DMASYNC_POSTREAD); 1108156321Sdamien 1109156321Sdamien for (; sc->rxq.cur_decrypt != hw;) { 1110156321Sdamien desc = &sc->rxq.desc[sc->rxq.cur_decrypt]; 1111156321Sdamien data = &sc->rxq.data[sc->rxq.cur_decrypt]; 1112156321Sdamien 1113156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_BUSY) || 1114156321Sdamien (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY)) 1115156321Sdamien break; 1116156321Sdamien 1117156321Sdamien if (data->drop) { 1118287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 1119156321Sdamien goto skip; 1120156321Sdamien } 1121156321Sdamien 1122156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_CIPHER_MASK) != 0 && 1123156321Sdamien (le32toh(desc->flags) & RT2560_RX_ICV_ERROR)) { 1124287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 1125156321Sdamien goto skip; 1126156321Sdamien } 1127156321Sdamien 1128156321Sdamien /* 1129156321Sdamien * Try to allocate a new mbuf for this ring element and load it 1130156321Sdamien * before processing the current mbuf. If the ring element 1131156321Sdamien * cannot be loaded, drop the received packet and reuse the old 1132156321Sdamien * mbuf. In the unlikely case that the old mbuf can't be 1133156321Sdamien * reloaded either, explicitly panic. 1134156321Sdamien */ 1135243857Sglebius mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1136156321Sdamien if (mnew == NULL) { 1137287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 1138156321Sdamien goto skip; 1139156321Sdamien } 1140156321Sdamien 1141156321Sdamien bus_dmamap_sync(sc->rxq.data_dmat, data->map, 1142156321Sdamien BUS_DMASYNC_POSTREAD); 1143156321Sdamien bus_dmamap_unload(sc->rxq.data_dmat, data->map); 1144156321Sdamien 1145156321Sdamien error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 1146156321Sdamien mtod(mnew, void *), MCLBYTES, rt2560_dma_map_addr, 1147156321Sdamien &physaddr, 0); 1148156321Sdamien if (error != 0) { 1149156321Sdamien m_freem(mnew); 1150156321Sdamien 1151156321Sdamien /* try to reload the old mbuf */ 1152156321Sdamien error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 1153156321Sdamien mtod(data->m, void *), MCLBYTES, 1154156321Sdamien rt2560_dma_map_addr, &physaddr, 0); 1155156321Sdamien if (error != 0) { 1156156321Sdamien /* very unlikely that it will fail... */ 1157156321Sdamien panic("%s: could not load old rx mbuf", 1158156321Sdamien device_get_name(sc->sc_dev)); 1159156321Sdamien } 1160287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 1161156321Sdamien goto skip; 1162156321Sdamien } 1163156321Sdamien 1164156321Sdamien /* 1165156321Sdamien * New mbuf successfully loaded, update Rx ring and continue 1166156321Sdamien * processing. 1167156321Sdamien */ 1168156321Sdamien m = data->m; 1169156321Sdamien data->m = mnew; 1170156321Sdamien desc->physaddr = htole32(physaddr); 1171156321Sdamien 1172156321Sdamien /* finalize mbuf */ 1173156321Sdamien m->m_pkthdr.len = m->m_len = 1174156321Sdamien (le32toh(desc->flags) >> 16) & 0xfff; 1175156321Sdamien 1176192468Ssam rssi = RT2560_RSSI(sc, desc->rssi); 1177192468Ssam nf = RT2560_NOISE_FLOOR; 1178192468Ssam if (ieee80211_radiotap_active(ic)) { 1179156321Sdamien struct rt2560_rx_radiotap_header *tap = &sc->sc_rxtap; 1180156321Sdamien uint32_t tsf_lo, tsf_hi; 1181156321Sdamien 1182156321Sdamien /* get timestamp (low and high 32 bits) */ 1183156321Sdamien tsf_hi = RAL_READ(sc, RT2560_CSR17); 1184156321Sdamien tsf_lo = RAL_READ(sc, RT2560_CSR16); 1185156321Sdamien 1186156321Sdamien tap->wr_tsf = 1187156321Sdamien htole64(((uint64_t)tsf_hi << 32) | tsf_lo); 1188156321Sdamien tap->wr_flags = 0; 1189178354Ssam tap->wr_rate = ieee80211_plcp2rate(desc->rate, 1190178958Ssam (desc->flags & htole32(RT2560_RX_OFDM)) ? 1191178958Ssam IEEE80211_T_OFDM : IEEE80211_T_CCK); 1192156321Sdamien tap->wr_antenna = sc->rx_ant; 1193192468Ssam tap->wr_antsignal = nf + rssi; 1194192468Ssam tap->wr_antnoise = nf; 1195156321Sdamien } 1196156321Sdamien 1197175938Ssephe sc->sc_flags |= RT2560_F_INPUT_RUNNING; 1198170530Ssam RAL_UNLOCK(sc); 1199156321Sdamien wh = mtod(m, struct ieee80211_frame *); 1200156321Sdamien ni = ieee80211_find_rxnode(ic, 1201156321Sdamien (struct ieee80211_frame_min *)wh); 1202178354Ssam if (ni != NULL) { 1203192468Ssam (void) ieee80211_input(ni, m, rssi, nf); 1204178354Ssam ieee80211_free_node(ni); 1205178354Ssam } else 1206192468Ssam (void) ieee80211_input_all(ic, m, rssi, nf); 1207156321Sdamien 1208170530Ssam RAL_LOCK(sc); 1209175938Ssephe sc->sc_flags &= ~RT2560_F_INPUT_RUNNING; 1210156321Sdamienskip: desc->flags = htole32(RT2560_RX_BUSY); 1211156321Sdamien 1212178354Ssam DPRINTFN(sc, 15, "decryption done idx=%u\n", sc->rxq.cur_decrypt); 1213156321Sdamien 1214156321Sdamien sc->rxq.cur_decrypt = 1215156321Sdamien (sc->rxq.cur_decrypt + 1) % RT2560_RX_RING_COUNT; 1216156321Sdamien } 1217156321Sdamien 1218156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1219156321Sdamien BUS_DMASYNC_PREWRITE); 1220156321Sdamien} 1221156321Sdamien 1222156321Sdamien/* 1223156321Sdamien * Some frames were received. Pass them to the hardware cipher engine before 1224156321Sdamien * sending them to the 802.11 layer. 1225156321Sdamien */ 1226156321Sdamienstatic void 1227156321Sdamienrt2560_rx_intr(struct rt2560_softc *sc) 1228156321Sdamien{ 1229156321Sdamien struct rt2560_rx_desc *desc; 1230156321Sdamien struct rt2560_rx_data *data; 1231156321Sdamien 1232156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1233156321Sdamien BUS_DMASYNC_POSTREAD); 1234156321Sdamien 1235156321Sdamien for (;;) { 1236156321Sdamien desc = &sc->rxq.desc[sc->rxq.cur]; 1237156321Sdamien data = &sc->rxq.data[sc->rxq.cur]; 1238156321Sdamien 1239156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_BUSY) || 1240156321Sdamien (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY)) 1241156321Sdamien break; 1242156321Sdamien 1243156321Sdamien data->drop = 0; 1244156321Sdamien 1245156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_PHY_ERROR) || 1246156321Sdamien (le32toh(desc->flags) & RT2560_RX_CRC_ERROR)) { 1247156321Sdamien /* 1248156321Sdamien * This should not happen since we did not request 1249156321Sdamien * to receive those frames when we filled RXCSR0. 1250156321Sdamien */ 1251178354Ssam DPRINTFN(sc, 5, "PHY or CRC error flags 0x%08x\n", 1252178354Ssam le32toh(desc->flags)); 1253156321Sdamien data->drop = 1; 1254156321Sdamien } 1255156321Sdamien 1256156321Sdamien if (((le32toh(desc->flags) >> 16) & 0xfff) > MCLBYTES) { 1257178354Ssam DPRINTFN(sc, 5, "%s\n", "bad length"); 1258156321Sdamien data->drop = 1; 1259156321Sdamien } 1260156321Sdamien 1261156321Sdamien /* mark the frame for decryption */ 1262156321Sdamien desc->flags |= htole32(RT2560_RX_CIPHER_BUSY); 1263156321Sdamien 1264178354Ssam DPRINTFN(sc, 15, "rx done idx=%u\n", sc->rxq.cur); 1265156321Sdamien 1266156321Sdamien sc->rxq.cur = (sc->rxq.cur + 1) % RT2560_RX_RING_COUNT; 1267156321Sdamien } 1268156321Sdamien 1269156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1270156321Sdamien BUS_DMASYNC_PREWRITE); 1271156321Sdamien 1272156321Sdamien /* kick decrypt */ 1273156321Sdamien RAL_WRITE(sc, RT2560_SECCSR0, RT2560_KICK_DECRYPT); 1274156321Sdamien} 1275156321Sdamien 1276172211Ssamstatic void 1277178354Ssamrt2560_beacon_update(struct ieee80211vap *vap, int item) 1278172211Ssam{ 1279288095Sadrian struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; 1280172211Ssam 1281172211Ssam setbit(bo->bo_flags, item); 1282172211Ssam} 1283172211Ssam 1284156321Sdamien/* 1285156321Sdamien * This function is called periodically in IBSS mode when a new beacon must be 1286156321Sdamien * sent out. 1287156321Sdamien */ 1288156321Sdamienstatic void 1289156321Sdamienrt2560_beacon_expire(struct rt2560_softc *sc) 1290156321Sdamien{ 1291287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 1292156321Sdamien struct rt2560_tx_data *data; 1293156321Sdamien 1294156321Sdamien if (ic->ic_opmode != IEEE80211_M_IBSS && 1295195618Srpaulo ic->ic_opmode != IEEE80211_M_HOSTAP && 1296195618Srpaulo ic->ic_opmode != IEEE80211_M_MBSS) 1297170530Ssam return; 1298156321Sdamien 1299156321Sdamien data = &sc->bcnq.data[sc->bcnq.next]; 1300170530Ssam /* 1301170530Ssam * Don't send beacon if bsschan isn't set 1302170530Ssam */ 1303170530Ssam if (data->ni == NULL) 1304170530Ssam return; 1305156321Sdamien 1306156321Sdamien bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_POSTWRITE); 1307156321Sdamien bus_dmamap_unload(sc->bcnq.data_dmat, data->map); 1308156321Sdamien 1309178354Ssam /* XXX 1 =>'s mcast frames which means all PS sta's will wakeup! */ 1310288636Sadrian ieee80211_beacon_update(data->ni, data->m, 1); 1311156321Sdamien 1312156321Sdamien rt2560_tx_bcn(sc, data->m, data->ni); 1313156321Sdamien 1314178354Ssam DPRINTFN(sc, 15, "%s", "beacon expired\n"); 1315156321Sdamien 1316156321Sdamien sc->bcnq.next = (sc->bcnq.next + 1) % RT2560_BEACON_RING_COUNT; 1317156321Sdamien} 1318156321Sdamien 1319156321Sdamien/* ARGSUSED */ 1320156321Sdamienstatic void 1321156321Sdamienrt2560_wakeup_expire(struct rt2560_softc *sc) 1322156321Sdamien{ 1323178354Ssam DPRINTFN(sc, 2, "%s", "wakeup expired\n"); 1324156321Sdamien} 1325156321Sdamien 1326156321Sdamienvoid 1327156321Sdamienrt2560_intr(void *arg) 1328156321Sdamien{ 1329156321Sdamien struct rt2560_softc *sc = arg; 1330156321Sdamien uint32_t r; 1331156321Sdamien 1332156321Sdamien RAL_LOCK(sc); 1333156321Sdamien 1334156321Sdamien /* disable interrupts */ 1335156321Sdamien RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 1336156321Sdamien 1337156975Sdamien /* don't re-enable interrupts if we're shutting down */ 1338287197Sglebius if (!(sc->sc_flags & RT2560_F_RUNNING)) { 1339156975Sdamien RAL_UNLOCK(sc); 1340156975Sdamien return; 1341156975Sdamien } 1342156975Sdamien 1343156321Sdamien r = RAL_READ(sc, RT2560_CSR7); 1344156321Sdamien RAL_WRITE(sc, RT2560_CSR7, r); 1345156321Sdamien 1346156321Sdamien if (r & RT2560_BEACON_EXPIRE) 1347156321Sdamien rt2560_beacon_expire(sc); 1348156321Sdamien 1349156321Sdamien if (r & RT2560_WAKEUP_EXPIRE) 1350156321Sdamien rt2560_wakeup_expire(sc); 1351156321Sdamien 1352156321Sdamien if (r & RT2560_ENCRYPTION_DONE) 1353156321Sdamien rt2560_encryption_intr(sc); 1354156321Sdamien 1355156321Sdamien if (r & RT2560_TX_DONE) 1356156321Sdamien rt2560_tx_intr(sc); 1357156321Sdamien 1358156321Sdamien if (r & RT2560_PRIO_DONE) 1359156321Sdamien rt2560_prio_intr(sc); 1360156321Sdamien 1361156321Sdamien if (r & RT2560_DECRYPTION_DONE) 1362156321Sdamien rt2560_decryption_intr(sc); 1363156321Sdamien 1364175938Ssephe if (r & RT2560_RX_DONE) { 1365156321Sdamien rt2560_rx_intr(sc); 1366175938Ssephe rt2560_encryption_intr(sc); 1367175938Ssephe } 1368156321Sdamien 1369156321Sdamien /* re-enable interrupts */ 1370156321Sdamien RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); 1371156321Sdamien 1372156321Sdamien RAL_UNLOCK(sc); 1373156321Sdamien} 1374156321Sdamien 1375156321Sdamien#define RAL_SIFS 10 /* us */ 1376156321Sdamien 1377156321Sdamien#define RT2560_TXRX_TURNAROUND 10 /* us */ 1378156321Sdamien 1379178958Ssamstatic uint8_t 1380178958Ssamrt2560_plcp_signal(int rate) 1381178958Ssam{ 1382178958Ssam switch (rate) { 1383178958Ssam /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ 1384178958Ssam case 12: return 0xb; 1385178958Ssam case 18: return 0xf; 1386178958Ssam case 24: return 0xa; 1387178958Ssam case 36: return 0xe; 1388178958Ssam case 48: return 0x9; 1389178958Ssam case 72: return 0xd; 1390178958Ssam case 96: return 0x8; 1391178958Ssam case 108: return 0xc; 1392178958Ssam 1393178958Ssam /* CCK rates (NB: not IEEE std, device-specific) */ 1394178958Ssam case 2: return 0x0; 1395178958Ssam case 4: return 0x1; 1396178958Ssam case 11: return 0x2; 1397178958Ssam case 22: return 0x3; 1398178958Ssam } 1399178958Ssam return 0xff; /* XXX unsupported/unknown rate */ 1400178958Ssam} 1401178958Ssam 1402156321Sdamienstatic void 1403156321Sdamienrt2560_setup_tx_desc(struct rt2560_softc *sc, struct rt2560_tx_desc *desc, 1404156321Sdamien uint32_t flags, int len, int rate, int encrypt, bus_addr_t physaddr) 1405156321Sdamien{ 1406287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 1407156321Sdamien uint16_t plcp_length; 1408156321Sdamien int remainder; 1409156321Sdamien 1410156321Sdamien desc->flags = htole32(flags); 1411156321Sdamien desc->flags |= htole32(len << 16); 1412156321Sdamien 1413156321Sdamien desc->physaddr = htole32(physaddr); 1414156321Sdamien desc->wme = htole16( 1415156321Sdamien RT2560_AIFSN(2) | 1416156321Sdamien RT2560_LOGCWMIN(3) | 1417156321Sdamien RT2560_LOGCWMAX(8)); 1418156321Sdamien 1419156321Sdamien /* setup PLCP fields */ 1420178958Ssam desc->plcp_signal = rt2560_plcp_signal(rate); 1421156321Sdamien desc->plcp_service = 4; 1422156321Sdamien 1423156321Sdamien len += IEEE80211_CRC_LEN; 1424190532Ssam if (ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) { 1425156321Sdamien desc->flags |= htole32(RT2560_TX_OFDM); 1426156321Sdamien 1427156321Sdamien plcp_length = len & 0xfff; 1428156321Sdamien desc->plcp_length_hi = plcp_length >> 6; 1429156321Sdamien desc->plcp_length_lo = plcp_length & 0x3f; 1430156321Sdamien } else { 1431298646Spfg plcp_length = howmany(16 * len, rate); 1432156321Sdamien if (rate == 22) { 1433156321Sdamien remainder = (16 * len) % 22; 1434156321Sdamien if (remainder != 0 && remainder < 7) 1435156321Sdamien desc->plcp_service |= RT2560_PLCP_LENGEXT; 1436156321Sdamien } 1437156321Sdamien desc->plcp_length_hi = plcp_length >> 8; 1438156321Sdamien desc->plcp_length_lo = plcp_length & 0xff; 1439156321Sdamien 1440156321Sdamien if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 1441156321Sdamien desc->plcp_signal |= 0x08; 1442156321Sdamien } 1443175938Ssephe 1444175938Ssephe if (!encrypt) 1445175938Ssephe desc->flags |= htole32(RT2560_TX_VALID); 1446175938Ssephe desc->flags |= encrypt ? htole32(RT2560_TX_CIPHER_BUSY) 1447175938Ssephe : htole32(RT2560_TX_BUSY); 1448156321Sdamien} 1449156321Sdamien 1450156321Sdamienstatic int 1451156321Sdamienrt2560_tx_bcn(struct rt2560_softc *sc, struct mbuf *m0, 1452156321Sdamien struct ieee80211_node *ni) 1453156321Sdamien{ 1454178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1455156321Sdamien struct rt2560_tx_desc *desc; 1456156321Sdamien struct rt2560_tx_data *data; 1457156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1458156321Sdamien int nsegs, rate, error; 1459156321Sdamien 1460156321Sdamien desc = &sc->bcnq.desc[sc->bcnq.cur]; 1461156321Sdamien data = &sc->bcnq.data[sc->bcnq.cur]; 1462156321Sdamien 1463178354Ssam /* XXX maybe a separate beacon rate? */ 1464178354Ssam rate = vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)].mgmtrate; 1465156321Sdamien 1466156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->bcnq.data_dmat, data->map, m0, 1467156321Sdamien segs, &nsegs, BUS_DMA_NOWAIT); 1468156321Sdamien if (error != 0) { 1469156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1470156321Sdamien error); 1471156321Sdamien m_freem(m0); 1472156321Sdamien return error; 1473156321Sdamien } 1474156321Sdamien 1475192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 1476156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1477156321Sdamien 1478156321Sdamien tap->wt_flags = 0; 1479156321Sdamien tap->wt_rate = rate; 1480156321Sdamien tap->wt_antenna = sc->tx_ant; 1481156321Sdamien 1482192468Ssam ieee80211_radiotap_tx(vap, m0); 1483156321Sdamien } 1484156321Sdamien 1485156321Sdamien data->m = m0; 1486156321Sdamien data->ni = ni; 1487156321Sdamien 1488156321Sdamien rt2560_setup_tx_desc(sc, desc, RT2560_TX_IFS_NEWBACKOFF | 1489156321Sdamien RT2560_TX_TIMESTAMP, m0->m_pkthdr.len, rate, 0, segs->ds_addr); 1490156321Sdamien 1491178354Ssam DPRINTFN(sc, 10, "sending beacon frame len=%u idx=%u rate=%u\n", 1492178354Ssam m0->m_pkthdr.len, sc->bcnq.cur, rate); 1493156321Sdamien 1494156321Sdamien bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1495156321Sdamien bus_dmamap_sync(sc->bcnq.desc_dmat, sc->bcnq.desc_map, 1496156321Sdamien BUS_DMASYNC_PREWRITE); 1497156321Sdamien 1498156321Sdamien sc->bcnq.cur = (sc->bcnq.cur + 1) % RT2560_BEACON_RING_COUNT; 1499156321Sdamien 1500156321Sdamien return 0; 1501156321Sdamien} 1502156321Sdamien 1503156321Sdamienstatic int 1504156321Sdamienrt2560_tx_mgt(struct rt2560_softc *sc, struct mbuf *m0, 1505156321Sdamien struct ieee80211_node *ni) 1506156321Sdamien{ 1507178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1508178354Ssam struct ieee80211com *ic = ni->ni_ic; 1509156321Sdamien struct rt2560_tx_desc *desc; 1510156321Sdamien struct rt2560_tx_data *data; 1511156321Sdamien struct ieee80211_frame *wh; 1512173386Skevlo struct ieee80211_key *k; 1513156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1514156321Sdamien uint16_t dur; 1515156321Sdamien uint32_t flags = 0; 1516156321Sdamien int nsegs, rate, error; 1517156321Sdamien 1518156321Sdamien desc = &sc->prioq.desc[sc->prioq.cur]; 1519156321Sdamien data = &sc->prioq.data[sc->prioq.cur]; 1520156321Sdamien 1521178354Ssam rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate; 1522156321Sdamien 1523173386Skevlo wh = mtod(m0, struct ieee80211_frame *); 1524173386Skevlo 1525260444Skevlo if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 1526178354Ssam k = ieee80211_crypto_encap(ni, m0); 1527173386Skevlo if (k == NULL) { 1528173386Skevlo m_freem(m0); 1529173386Skevlo return ENOBUFS; 1530173386Skevlo } 1531173386Skevlo } 1532173386Skevlo 1533156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, 1534156321Sdamien segs, &nsegs, 0); 1535156321Sdamien if (error != 0) { 1536156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1537156321Sdamien error); 1538156321Sdamien m_freem(m0); 1539156321Sdamien return error; 1540156321Sdamien } 1541156321Sdamien 1542192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 1543156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1544156321Sdamien 1545156321Sdamien tap->wt_flags = 0; 1546156321Sdamien tap->wt_rate = rate; 1547156321Sdamien tap->wt_antenna = sc->tx_ant; 1548156321Sdamien 1549192468Ssam ieee80211_radiotap_tx(vap, m0); 1550156321Sdamien } 1551156321Sdamien 1552156321Sdamien data->m = m0; 1553156321Sdamien data->ni = ni; 1554178354Ssam /* management frames are not taken into account for amrr */ 1555178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1556156321Sdamien 1557156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1558156321Sdamien 1559156321Sdamien if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1560156321Sdamien flags |= RT2560_TX_ACK; 1561156321Sdamien 1562190532Ssam dur = ieee80211_ack_duration(ic->ic_rt, 1563178354Ssam rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); 1564156321Sdamien *(uint16_t *)wh->i_dur = htole16(dur); 1565156321Sdamien 1566156321Sdamien /* tell hardware to add timestamp for probe responses */ 1567156321Sdamien if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 1568156321Sdamien IEEE80211_FC0_TYPE_MGT && 1569156321Sdamien (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 1570156321Sdamien IEEE80211_FC0_SUBTYPE_PROBE_RESP) 1571156321Sdamien flags |= RT2560_TX_TIMESTAMP; 1572156321Sdamien } 1573156321Sdamien 1574156321Sdamien rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 0, 1575156321Sdamien segs->ds_addr); 1576156321Sdamien 1577156321Sdamien bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1578156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1579156321Sdamien BUS_DMASYNC_PREWRITE); 1580156321Sdamien 1581178354Ssam DPRINTFN(sc, 10, "sending mgt frame len=%u idx=%u rate=%u\n", 1582178354Ssam m0->m_pkthdr.len, sc->prioq.cur, rate); 1583156321Sdamien 1584156321Sdamien /* kick prio */ 1585156321Sdamien sc->prioq.queued++; 1586156321Sdamien sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; 1587156321Sdamien RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); 1588156321Sdamien 1589156321Sdamien return 0; 1590156321Sdamien} 1591156321Sdamien 1592160691Ssamstatic int 1593178354Ssamrt2560_sendprot(struct rt2560_softc *sc, 1594178354Ssam const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) 1595178354Ssam{ 1596178354Ssam struct ieee80211com *ic = ni->ni_ic; 1597178354Ssam const struct ieee80211_frame *wh; 1598178354Ssam struct rt2560_tx_desc *desc; 1599178354Ssam struct rt2560_tx_data *data; 1600178354Ssam struct mbuf *mprot; 1601178354Ssam int protrate, ackrate, pktlen, flags, isshort, error; 1602178354Ssam uint16_t dur; 1603178354Ssam bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1604178354Ssam int nsegs; 1605178354Ssam 1606178354Ssam KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, 1607178354Ssam ("protection %d", prot)); 1608178354Ssam 1609178354Ssam wh = mtod(m, const struct ieee80211_frame *); 1610178354Ssam pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; 1611178354Ssam 1612190532Ssam protrate = ieee80211_ctl_rate(ic->ic_rt, rate); 1613190532Ssam ackrate = ieee80211_ack_rate(ic->ic_rt, rate); 1614178354Ssam 1615178354Ssam isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; 1616190532Ssam dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort) 1617190532Ssam + ieee80211_ack_duration(ic->ic_rt, rate, isshort); 1618178354Ssam flags = RT2560_TX_MORE_FRAG; 1619178354Ssam if (prot == IEEE80211_PROT_RTSCTS) { 1620178354Ssam /* NB: CTS is the same size as an ACK */ 1621190532Ssam dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); 1622178354Ssam flags |= RT2560_TX_ACK; 1623178354Ssam mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); 1624178354Ssam } else { 1625178354Ssam mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); 1626178354Ssam } 1627178354Ssam if (mprot == NULL) { 1628178354Ssam /* XXX stat + msg */ 1629178354Ssam return ENOBUFS; 1630178354Ssam } 1631178354Ssam 1632178354Ssam desc = &sc->txq.desc[sc->txq.cur_encrypt]; 1633178354Ssam data = &sc->txq.data[sc->txq.cur_encrypt]; 1634178354Ssam 1635178354Ssam error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, 1636178354Ssam mprot, segs, &nsegs, 0); 1637178354Ssam if (error != 0) { 1638178354Ssam device_printf(sc->sc_dev, 1639178354Ssam "could not map mbuf (error %d)\n", error); 1640178354Ssam m_freem(mprot); 1641178354Ssam return error; 1642178354Ssam } 1643178354Ssam 1644178354Ssam data->m = mprot; 1645178354Ssam data->ni = ieee80211_ref_node(ni); 1646178354Ssam /* ctl frames are not taken into account for amrr */ 1647178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1648178354Ssam 1649178354Ssam rt2560_setup_tx_desc(sc, desc, flags, mprot->m_pkthdr.len, protrate, 1, 1650178354Ssam segs->ds_addr); 1651178354Ssam 1652178354Ssam bus_dmamap_sync(sc->txq.data_dmat, data->map, 1653178354Ssam BUS_DMASYNC_PREWRITE); 1654178354Ssam 1655178354Ssam sc->txq.queued++; 1656178354Ssam sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; 1657178354Ssam 1658178354Ssam return 0; 1659178354Ssam} 1660178354Ssam 1661178354Ssamstatic int 1662160691Ssamrt2560_tx_raw(struct rt2560_softc *sc, struct mbuf *m0, 1663160691Ssam struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) 1664160691Ssam{ 1665192468Ssam struct ieee80211vap *vap = ni->ni_vap; 1666193073Ssam struct ieee80211com *ic = ni->ni_ic; 1667160691Ssam struct rt2560_tx_desc *desc; 1668160691Ssam struct rt2560_tx_data *data; 1669160691Ssam bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1670160691Ssam uint32_t flags; 1671160691Ssam int nsegs, rate, error; 1672160691Ssam 1673160691Ssam desc = &sc->prioq.desc[sc->prioq.cur]; 1674160691Ssam data = &sc->prioq.data[sc->prioq.cur]; 1675160691Ssam 1676193073Ssam rate = params->ibp_rate0; 1677193073Ssam if (!ieee80211_isratevalid(ic->ic_rt, rate)) { 1678178354Ssam /* XXX fall back to mcast/mgmt rate? */ 1679168860Ssephe m_freem(m0); 1680160691Ssam return EINVAL; 1681168860Ssephe } 1682160691Ssam 1683178354Ssam flags = 0; 1684178354Ssam if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) 1685178354Ssam flags |= RT2560_TX_ACK; 1686178354Ssam if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { 1687178354Ssam error = rt2560_sendprot(sc, m0, ni, 1688178354Ssam params->ibp_flags & IEEE80211_BPF_RTS ? 1689178354Ssam IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, 1690178354Ssam rate); 1691178354Ssam if (error) { 1692178354Ssam m_freem(m0); 1693178354Ssam return error; 1694178354Ssam } 1695178354Ssam flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; 1696178354Ssam } 1697178354Ssam 1698160691Ssam error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, 1699160691Ssam segs, &nsegs, 0); 1700160691Ssam if (error != 0) { 1701160691Ssam device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1702160691Ssam error); 1703160691Ssam m_freem(m0); 1704160691Ssam return error; 1705160691Ssam } 1706160691Ssam 1707192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 1708160691Ssam struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1709160691Ssam 1710160691Ssam tap->wt_flags = 0; 1711160691Ssam tap->wt_rate = rate; 1712160691Ssam tap->wt_antenna = sc->tx_ant; 1713160691Ssam 1714192468Ssam ieee80211_radiotap_tx(ni->ni_vap, m0); 1715160691Ssam } 1716160691Ssam 1717160691Ssam data->m = m0; 1718160691Ssam data->ni = ni; 1719160691Ssam 1720160691Ssam /* XXX need to setup descriptor ourself */ 1721160691Ssam rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, 1722160691Ssam rate, (params->ibp_flags & IEEE80211_BPF_CRYPTO) != 0, 1723160691Ssam segs->ds_addr); 1724160691Ssam 1725160691Ssam bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1726160691Ssam bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1727160691Ssam BUS_DMASYNC_PREWRITE); 1728160691Ssam 1729178354Ssam DPRINTFN(sc, 10, "sending raw frame len=%u idx=%u rate=%u\n", 1730178354Ssam m0->m_pkthdr.len, sc->prioq.cur, rate); 1731160691Ssam 1732160691Ssam /* kick prio */ 1733160691Ssam sc->prioq.queued++; 1734160691Ssam sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; 1735160691Ssam RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); 1736160691Ssam 1737160691Ssam return 0; 1738160691Ssam} 1739160691Ssam 1740156321Sdamienstatic int 1741156321Sdamienrt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0, 1742156321Sdamien struct ieee80211_node *ni) 1743156321Sdamien{ 1744178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1745178354Ssam struct ieee80211com *ic = ni->ni_ic; 1746156321Sdamien struct rt2560_tx_desc *desc; 1747156321Sdamien struct rt2560_tx_data *data; 1748156321Sdamien struct ieee80211_frame *wh; 1749178354Ssam const struct ieee80211_txparam *tp; 1750156321Sdamien struct ieee80211_key *k; 1751156321Sdamien struct mbuf *mnew; 1752156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1753156321Sdamien uint16_t dur; 1754178354Ssam uint32_t flags; 1755156321Sdamien int nsegs, rate, error; 1756156321Sdamien 1757156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1758156321Sdamien 1759178354Ssam tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; 1760178354Ssam if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1761178354Ssam rate = tp->mcastrate; 1762178354Ssam } else if (m0->m_flags & M_EAPOL) { 1763178354Ssam rate = tp->mgmtrate; 1764178354Ssam } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 1765178354Ssam rate = tp->ucastrate; 1766156321Sdamien } else { 1767206358Srpaulo (void) ieee80211_ratectl_rate(ni, NULL, 0); 1768178354Ssam rate = ni->ni_txrate; 1769156321Sdamien } 1770156321Sdamien 1771260444Skevlo if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 1772178354Ssam k = ieee80211_crypto_encap(ni, m0); 1773156321Sdamien if (k == NULL) { 1774156321Sdamien m_freem(m0); 1775156321Sdamien return ENOBUFS; 1776156321Sdamien } 1777156321Sdamien 1778156321Sdamien /* packet header may have moved, reset our local pointer */ 1779156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1780156321Sdamien } 1781156321Sdamien 1782178354Ssam flags = 0; 1783178354Ssam if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1784178354Ssam int prot = IEEE80211_PROT_NONE; 1785178354Ssam if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) 1786178354Ssam prot = IEEE80211_PROT_RTSCTS; 1787178354Ssam else if ((ic->ic_flags & IEEE80211_F_USEPROT) && 1788190532Ssam ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) 1789178354Ssam prot = ic->ic_protmode; 1790178354Ssam if (prot != IEEE80211_PROT_NONE) { 1791178354Ssam error = rt2560_sendprot(sc, m0, ni, prot, rate); 1792178354Ssam if (error) { 1793178354Ssam m_freem(m0); 1794178354Ssam return error; 1795178354Ssam } 1796178354Ssam flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; 1797156321Sdamien } 1798156321Sdamien } 1799156321Sdamien 1800156321Sdamien data = &sc->txq.data[sc->txq.cur_encrypt]; 1801156321Sdamien desc = &sc->txq.desc[sc->txq.cur_encrypt]; 1802156321Sdamien 1803156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, m0, 1804156321Sdamien segs, &nsegs, 0); 1805156321Sdamien if (error != 0 && error != EFBIG) { 1806156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1807156321Sdamien error); 1808156321Sdamien m_freem(m0); 1809156321Sdamien return error; 1810156321Sdamien } 1811156321Sdamien if (error != 0) { 1812243857Sglebius mnew = m_defrag(m0, M_NOWAIT); 1813156321Sdamien if (mnew == NULL) { 1814156321Sdamien device_printf(sc->sc_dev, 1815156321Sdamien "could not defragment mbuf\n"); 1816156321Sdamien m_freem(m0); 1817156321Sdamien return ENOBUFS; 1818156321Sdamien } 1819156321Sdamien m0 = mnew; 1820156321Sdamien 1821156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, 1822156321Sdamien m0, segs, &nsegs, 0); 1823156321Sdamien if (error != 0) { 1824156321Sdamien device_printf(sc->sc_dev, 1825156321Sdamien "could not map mbuf (error %d)\n", error); 1826156321Sdamien m_freem(m0); 1827156321Sdamien return error; 1828156321Sdamien } 1829156321Sdamien 1830156321Sdamien /* packet header may have moved, reset our local pointer */ 1831156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1832156321Sdamien } 1833156321Sdamien 1834192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 1835156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1836156321Sdamien 1837156321Sdamien tap->wt_flags = 0; 1838156321Sdamien tap->wt_rate = rate; 1839156321Sdamien tap->wt_antenna = sc->tx_ant; 1840156321Sdamien 1841192468Ssam ieee80211_radiotap_tx(vap, m0); 1842156321Sdamien } 1843156321Sdamien 1844156321Sdamien data->m = m0; 1845156321Sdamien data->ni = ni; 1846156321Sdamien 1847156321Sdamien /* remember link conditions for rate adaptation algorithm */ 1848178354Ssam if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) { 1849178354Ssam data->rix = ni->ni_txrate; 1850178354Ssam /* XXX probably need last rssi value and not avg */ 1851178354Ssam data->rssi = ic->ic_node_getrssi(ni); 1852156321Sdamien } else 1853178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1854156321Sdamien 1855156321Sdamien if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1856156321Sdamien flags |= RT2560_TX_ACK; 1857156321Sdamien 1858190532Ssam dur = ieee80211_ack_duration(ic->ic_rt, 1859178354Ssam rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); 1860156321Sdamien *(uint16_t *)wh->i_dur = htole16(dur); 1861156321Sdamien } 1862156321Sdamien 1863156321Sdamien rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 1, 1864156321Sdamien segs->ds_addr); 1865156321Sdamien 1866156321Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1867156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 1868156321Sdamien BUS_DMASYNC_PREWRITE); 1869156321Sdamien 1870178354Ssam DPRINTFN(sc, 10, "sending data frame len=%u idx=%u rate=%u\n", 1871178354Ssam m0->m_pkthdr.len, sc->txq.cur_encrypt, rate); 1872156321Sdamien 1873156321Sdamien /* kick encrypt */ 1874156321Sdamien sc->txq.queued++; 1875156321Sdamien sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; 1876156321Sdamien RAL_WRITE(sc, RT2560_SECCSR1, RT2560_KICK_ENCRYPT); 1877156321Sdamien 1878156321Sdamien return 0; 1879156321Sdamien} 1880156321Sdamien 1881287197Sglebiusstatic int 1882287197Sglebiusrt2560_transmit(struct ieee80211com *ic, struct mbuf *m) 1883287197Sglebius{ 1884287197Sglebius struct rt2560_softc *sc = ic->ic_softc; 1885287197Sglebius int error; 1886287197Sglebius 1887287197Sglebius RAL_LOCK(sc); 1888287197Sglebius if ((sc->sc_flags & RT2560_F_RUNNING) == 0) { 1889287197Sglebius RAL_UNLOCK(sc); 1890287197Sglebius return (ENXIO); 1891287197Sglebius } 1892287197Sglebius error = mbufq_enqueue(&sc->sc_snd, m); 1893287197Sglebius if (error) { 1894287197Sglebius RAL_UNLOCK(sc); 1895287197Sglebius return (error); 1896287197Sglebius } 1897287197Sglebius rt2560_start(sc); 1898287197Sglebius RAL_UNLOCK(sc); 1899287197Sglebius 1900287197Sglebius return (0); 1901287197Sglebius} 1902287197Sglebius 1903156321Sdamienstatic void 1904287197Sglebiusrt2560_start(struct rt2560_softc *sc) 1905156321Sdamien{ 1906287197Sglebius struct ieee80211_node *ni; 1907286437Sadrian struct mbuf *m; 1908156321Sdamien 1909178354Ssam RAL_LOCK_ASSERT(sc); 1910156321Sdamien 1911287197Sglebius while (sc->txq.queued < RT2560_TX_RING_COUNT - 1 && 1912287197Sglebius (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { 1913178354Ssam ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; 1914178354Ssam if (rt2560_tx_data(sc, m, ni) != 0) { 1915287197Sglebius if_inc_counter(ni->ni_vap->iv_ifp, 1916287197Sglebius IFCOUNTER_OERRORS, 1); 1917178354Ssam ieee80211_free_node(ni); 1918178354Ssam break; 1919156321Sdamien } 1920156321Sdamien sc->sc_tx_timer = 5; 1921156321Sdamien } 1922178354Ssam} 1923156321Sdamien 1924178354Ssamstatic void 1925165352Sbmsrt2560_watchdog(void *arg) 1926156321Sdamien{ 1927167470Ssam struct rt2560_softc *sc = arg; 1928156321Sdamien 1929178354Ssam RAL_LOCK_ASSERT(sc); 1930178354Ssam 1931287197Sglebius KASSERT(sc->sc_flags & RT2560_F_RUNNING, ("not running")); 1932178354Ssam 1933178354Ssam if (sc->sc_invalid) /* card ejected */ 1934175938Ssephe return; 1935175938Ssephe 1936175938Ssephe rt2560_encryption_intr(sc); 1937175938Ssephe rt2560_tx_intr(sc); 1938175938Ssephe 1939178354Ssam if (sc->sc_tx_timer > 0 && --sc->sc_tx_timer == 0) { 1940287197Sglebius device_printf(sc->sc_dev, "device timeout\n"); 1941178354Ssam rt2560_init_locked(sc); 1942287197Sglebius counter_u64_add(sc->sc_ic.ic_oerrors, 1); 1943178354Ssam /* NB: callout is reset in rt2560_init() */ 1944178354Ssam return; 1945156321Sdamien } 1946175938Ssephe callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); 1947156321Sdamien} 1948156321Sdamien 1949287197Sglebiusstatic void 1950287197Sglebiusrt2560_parent(struct ieee80211com *ic) 1951156321Sdamien{ 1952287197Sglebius struct rt2560_softc *sc = ic->ic_softc; 1953287197Sglebius int startall = 0; 1954156321Sdamien 1955287197Sglebius RAL_LOCK(sc); 1956287197Sglebius if (ic->ic_nrunning > 0) { 1957287197Sglebius if ((sc->sc_flags & RT2560_F_RUNNING) == 0) { 1958287197Sglebius rt2560_init_locked(sc); 1959287197Sglebius startall = 1; 1960287197Sglebius } else 1961287197Sglebius rt2560_update_promisc(ic); 1962287197Sglebius } else if (sc->sc_flags & RT2560_F_RUNNING) 1963287197Sglebius rt2560_stop_locked(sc); 1964287197Sglebius RAL_UNLOCK(sc); 1965287197Sglebius if (startall) 1966287197Sglebius ieee80211_start_all(ic); 1967156321Sdamien} 1968156321Sdamien 1969156321Sdamienstatic void 1970156321Sdamienrt2560_bbp_write(struct rt2560_softc *sc, uint8_t reg, uint8_t val) 1971156321Sdamien{ 1972156321Sdamien uint32_t tmp; 1973156321Sdamien int ntries; 1974156321Sdamien 1975156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 1976156321Sdamien if (!(RAL_READ(sc, RT2560_BBPCSR) & RT2560_BBP_BUSY)) 1977156321Sdamien break; 1978156321Sdamien DELAY(1); 1979156321Sdamien } 1980156321Sdamien if (ntries == 100) { 1981156321Sdamien device_printf(sc->sc_dev, "could not write to BBP\n"); 1982156321Sdamien return; 1983156321Sdamien } 1984156321Sdamien 1985156321Sdamien tmp = RT2560_BBP_WRITE | RT2560_BBP_BUSY | reg << 8 | val; 1986156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR, tmp); 1987156321Sdamien 1988178354Ssam DPRINTFN(sc, 15, "BBP R%u <- 0x%02x\n", reg, val); 1989156321Sdamien} 1990156321Sdamien 1991156321Sdamienstatic uint8_t 1992156321Sdamienrt2560_bbp_read(struct rt2560_softc *sc, uint8_t reg) 1993156321Sdamien{ 1994156321Sdamien uint32_t val; 1995156321Sdamien int ntries; 1996156321Sdamien 1997175938Ssephe for (ntries = 0; ntries < 100; ntries++) { 1998175938Ssephe if (!(RAL_READ(sc, RT2560_BBPCSR) & RT2560_BBP_BUSY)) 1999175938Ssephe break; 2000175938Ssephe DELAY(1); 2001175938Ssephe } 2002175938Ssephe if (ntries == 100) { 2003175938Ssephe device_printf(sc->sc_dev, "could not read from BBP\n"); 2004175938Ssephe return 0; 2005175938Ssephe } 2006175938Ssephe 2007156321Sdamien val = RT2560_BBP_BUSY | reg << 8; 2008156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR, val); 2009156321Sdamien 2010156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2011156321Sdamien val = RAL_READ(sc, RT2560_BBPCSR); 2012156321Sdamien if (!(val & RT2560_BBP_BUSY)) 2013156321Sdamien return val & 0xff; 2014156321Sdamien DELAY(1); 2015156321Sdamien } 2016156321Sdamien 2017156321Sdamien device_printf(sc->sc_dev, "could not read from BBP\n"); 2018156321Sdamien return 0; 2019156321Sdamien} 2020156321Sdamien 2021156321Sdamienstatic void 2022156321Sdamienrt2560_rf_write(struct rt2560_softc *sc, uint8_t reg, uint32_t val) 2023156321Sdamien{ 2024156321Sdamien uint32_t tmp; 2025156321Sdamien int ntries; 2026156321Sdamien 2027156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2028156321Sdamien if (!(RAL_READ(sc, RT2560_RFCSR) & RT2560_RF_BUSY)) 2029156321Sdamien break; 2030156321Sdamien DELAY(1); 2031156321Sdamien } 2032156321Sdamien if (ntries == 100) { 2033156321Sdamien device_printf(sc->sc_dev, "could not write to RF\n"); 2034156321Sdamien return; 2035156321Sdamien } 2036156321Sdamien 2037156321Sdamien tmp = RT2560_RF_BUSY | RT2560_RF_20BIT | (val & 0xfffff) << 2 | 2038156321Sdamien (reg & 0x3); 2039156321Sdamien RAL_WRITE(sc, RT2560_RFCSR, tmp); 2040156321Sdamien 2041156321Sdamien /* remember last written value in sc */ 2042156321Sdamien sc->rf_regs[reg] = val; 2043156321Sdamien 2044178354Ssam DPRINTFN(sc, 15, "RF R[%u] <- 0x%05x\n", reg & 0x3, val & 0xfffff); 2045156321Sdamien} 2046156321Sdamien 2047156321Sdamienstatic void 2048156321Sdamienrt2560_set_chan(struct rt2560_softc *sc, struct ieee80211_channel *c) 2049156321Sdamien{ 2050287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2051156321Sdamien uint8_t power, tmp; 2052156321Sdamien u_int i, chan; 2053156321Sdamien 2054156321Sdamien chan = ieee80211_chan2ieee(ic, c); 2055178354Ssam KASSERT(chan != 0 && chan != IEEE80211_CHAN_ANY, ("chan 0x%x", chan)); 2056156321Sdamien 2057156321Sdamien if (IEEE80211_IS_CHAN_2GHZ(c)) 2058156321Sdamien power = min(sc->txpow[chan - 1], 31); 2059156321Sdamien else 2060156321Sdamien power = 31; 2061156321Sdamien 2062156321Sdamien /* adjust txpower using ifconfig settings */ 2063156321Sdamien power -= (100 - ic->ic_txpowlimit) / 8; 2064156321Sdamien 2065178354Ssam DPRINTFN(sc, 2, "setting channel to %u, txpower to %u\n", chan, power); 2066156321Sdamien 2067156321Sdamien switch (sc->rf_rev) { 2068156321Sdamien case RT2560_RF_2522: 2069156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x00814); 2070156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2522_r2[chan - 1]); 2071156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2072156321Sdamien break; 2073156321Sdamien 2074156321Sdamien case RT2560_RF_2523: 2075156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08804); 2076156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2523_r2[chan - 1]); 2077156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x38044); 2078156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2079156321Sdamien break; 2080156321Sdamien 2081156321Sdamien case RT2560_RF_2524: 2082156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x0c808); 2083156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2524_r2[chan - 1]); 2084156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2085156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2086156321Sdamien break; 2087156321Sdamien 2088156321Sdamien case RT2560_RF_2525: 2089156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2090156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_hi_r2[chan - 1]); 2091156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2092156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2093156321Sdamien 2094156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2095156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_r2[chan - 1]); 2096156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2097156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2098156321Sdamien break; 2099156321Sdamien 2100156321Sdamien case RT2560_RF_2525E: 2101156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2102156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525e_r2[chan - 1]); 2103156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2104156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00286 : 0x00282); 2105156321Sdamien break; 2106156321Sdamien 2107156321Sdamien case RT2560_RF_2526: 2108156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_hi_r2[chan - 1]); 2109156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); 2110156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08804); 2111156321Sdamien 2112156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_r2[chan - 1]); 2113156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2114156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); 2115156321Sdamien break; 2116156321Sdamien 2117156321Sdamien /* dual-band RF */ 2118156321Sdamien case RT2560_RF_5222: 2119156321Sdamien for (i = 0; rt2560_rf5222[i].chan != chan; i++); 2120156321Sdamien 2121156321Sdamien rt2560_rf_write(sc, RAL_RF1, rt2560_rf5222[i].r1); 2122156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf5222[i].r2); 2123156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2124156321Sdamien rt2560_rf_write(sc, RAL_RF4, rt2560_rf5222[i].r4); 2125156321Sdamien break; 2126170530Ssam default: 2127170530Ssam printf("unknown ral rev=%d\n", sc->rf_rev); 2128156321Sdamien } 2129156321Sdamien 2130178354Ssam /* XXX */ 2131178354Ssam if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { 2132156321Sdamien /* set Japan filter bit for channel 14 */ 2133156321Sdamien tmp = rt2560_bbp_read(sc, 70); 2134156321Sdamien 2135156321Sdamien tmp &= ~RT2560_JAPAN_FILTER; 2136156321Sdamien if (chan == 14) 2137156321Sdamien tmp |= RT2560_JAPAN_FILTER; 2138156321Sdamien 2139156321Sdamien rt2560_bbp_write(sc, 70, tmp); 2140156321Sdamien 2141156321Sdamien /* clear CRC errors */ 2142156321Sdamien RAL_READ(sc, RT2560_CNT0); 2143156321Sdamien } 2144156321Sdamien} 2145156321Sdamien 2146170530Ssamstatic void 2147300752Savosrt2560_getradiocaps(struct ieee80211com *ic, 2148300752Savos int maxchans, int *nchans, struct ieee80211_channel chans[]) 2149300752Savos{ 2150300752Savos struct rt2560_softc *sc = ic->ic_softc; 2151300752Savos uint8_t bands[IEEE80211_MODE_BYTES]; 2152300752Savos 2153300752Savos memset(bands, 0, sizeof(bands)); 2154300752Savos setbit(bands, IEEE80211_MODE_11B); 2155300752Savos setbit(bands, IEEE80211_MODE_11G); 2156343976Savos ieee80211_add_channels_default_2ghz(chans, maxchans, nchans, bands, 0); 2157300752Savos 2158300752Savos if (sc->rf_rev == RT2560_RF_5222) { 2159300752Savos setbit(bands, IEEE80211_MODE_11A); 2160300752Savos ieee80211_add_channel_list_5ghz(chans, maxchans, nchans, 2161300752Savos rt2560_chan_5ghz, nitems(rt2560_chan_5ghz), bands, 0); 2162300752Savos } 2163300752Savos} 2164300752Savos 2165300752Savosstatic void 2166170530Ssamrt2560_set_channel(struct ieee80211com *ic) 2167170530Ssam{ 2168287197Sglebius struct rt2560_softc *sc = ic->ic_softc; 2169170530Ssam 2170170530Ssam RAL_LOCK(sc); 2171170530Ssam rt2560_set_chan(sc, ic->ic_curchan); 2172170530Ssam RAL_UNLOCK(sc); 2173170530Ssam 2174170530Ssam} 2175170530Ssam 2176156321Sdamien#if 0 2177156321Sdamien/* 2178156321Sdamien * Disable RF auto-tuning. 2179156321Sdamien */ 2180156321Sdamienstatic void 2181156321Sdamienrt2560_disable_rf_tune(struct rt2560_softc *sc) 2182156321Sdamien{ 2183156321Sdamien uint32_t tmp; 2184156321Sdamien 2185156321Sdamien if (sc->rf_rev != RT2560_RF_2523) { 2186156321Sdamien tmp = sc->rf_regs[RAL_RF1] & ~RAL_RF1_AUTOTUNE; 2187156321Sdamien rt2560_rf_write(sc, RAL_RF1, tmp); 2188156321Sdamien } 2189156321Sdamien 2190156321Sdamien tmp = sc->rf_regs[RAL_RF3] & ~RAL_RF3_AUTOTUNE; 2191156321Sdamien rt2560_rf_write(sc, RAL_RF3, tmp); 2192156321Sdamien 2193178354Ssam DPRINTFN(sc, 2, "%s", "disabling RF autotune\n"); 2194156321Sdamien} 2195156321Sdamien#endif 2196156321Sdamien 2197156321Sdamien/* 2198156321Sdamien * Refer to IEEE Std 802.11-1999 pp. 123 for more information on TSF 2199156321Sdamien * synchronization. 2200156321Sdamien */ 2201156321Sdamienstatic void 2202156321Sdamienrt2560_enable_tsf_sync(struct rt2560_softc *sc) 2203156321Sdamien{ 2204287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2205178354Ssam struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2206156321Sdamien uint16_t logcwmin, preload; 2207156321Sdamien uint32_t tmp; 2208156321Sdamien 2209156321Sdamien /* first, disable TSF synchronization */ 2210156321Sdamien RAL_WRITE(sc, RT2560_CSR14, 0); 2211156321Sdamien 2212178354Ssam tmp = 16 * vap->iv_bss->ni_intval; 2213156321Sdamien RAL_WRITE(sc, RT2560_CSR12, tmp); 2214156321Sdamien 2215156321Sdamien RAL_WRITE(sc, RT2560_CSR13, 0); 2216156321Sdamien 2217156321Sdamien logcwmin = 5; 2218178354Ssam preload = (vap->iv_opmode == IEEE80211_M_STA) ? 384 : 1024; 2219156321Sdamien tmp = logcwmin << 16 | preload; 2220156321Sdamien RAL_WRITE(sc, RT2560_BCNOCSR, tmp); 2221156321Sdamien 2222156321Sdamien /* finally, enable TSF synchronization */ 2223156321Sdamien tmp = RT2560_ENABLE_TSF | RT2560_ENABLE_TBCN; 2224156321Sdamien if (ic->ic_opmode == IEEE80211_M_STA) 2225156321Sdamien tmp |= RT2560_ENABLE_TSF_SYNC(1); 2226156321Sdamien else 2227156321Sdamien tmp |= RT2560_ENABLE_TSF_SYNC(2) | 2228156321Sdamien RT2560_ENABLE_BEACON_GENERATOR; 2229156321Sdamien RAL_WRITE(sc, RT2560_CSR14, tmp); 2230156321Sdamien 2231178354Ssam DPRINTF(sc, "%s", "enabling TSF synchronization\n"); 2232156321Sdamien} 2233156321Sdamien 2234156321Sdamienstatic void 2235192468Ssamrt2560_enable_tsf(struct rt2560_softc *sc) 2236192468Ssam{ 2237192468Ssam RAL_WRITE(sc, RT2560_CSR14, 0); 2238192468Ssam RAL_WRITE(sc, RT2560_CSR14, 2239192468Ssam RT2560_ENABLE_TSF_SYNC(2) | RT2560_ENABLE_TSF); 2240192468Ssam} 2241192468Ssam 2242192468Ssamstatic void 2243156321Sdamienrt2560_update_plcp(struct rt2560_softc *sc) 2244156321Sdamien{ 2245287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2246156321Sdamien 2247156321Sdamien /* no short preamble for 1Mbps */ 2248156321Sdamien RAL_WRITE(sc, RT2560_PLCP1MCSR, 0x00700400); 2249156321Sdamien 2250156321Sdamien if (!(ic->ic_flags & IEEE80211_F_SHPREAMBLE)) { 2251156321Sdamien /* values taken from the reference driver */ 2252156321Sdamien RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380401); 2253156321Sdamien RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x00150402); 2254156321Sdamien RAL_WRITE(sc, RT2560_PLCP11MCSR, 0x000b8403); 2255156321Sdamien } else { 2256156321Sdamien /* same values as above or'ed 0x8 */ 2257156321Sdamien RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380409); 2258156321Sdamien RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x0015040a); 2259156321Sdamien RAL_WRITE(sc, RT2560_PLCP11MCSR, 0x000b840b); 2260156321Sdamien } 2261156321Sdamien 2262178354Ssam DPRINTF(sc, "updating PLCP for %s preamble\n", 2263178354Ssam (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? "short" : "long"); 2264156321Sdamien} 2265156321Sdamien 2266156321Sdamien/* 2267156321Sdamien * This function can be called by ieee80211_set_shortslottime(). Refer to 2268156321Sdamien * IEEE Std 802.11-1999 pp. 85 to know how these values are computed. 2269156321Sdamien */ 2270156321Sdamienstatic void 2271283540Sglebiusrt2560_update_slot(struct ieee80211com *ic) 2272156321Sdamien{ 2273283540Sglebius struct rt2560_softc *sc = ic->ic_softc; 2274156321Sdamien uint8_t slottime; 2275156321Sdamien uint16_t tx_sifs, tx_pifs, tx_difs, eifs; 2276156321Sdamien uint32_t tmp; 2277156321Sdamien 2278175938Ssephe#ifndef FORCE_SLOTTIME 2279292165Savos slottime = IEEE80211_GET_SLOTTIME(ic); 2280175938Ssephe#else 2281175938Ssephe /* 2282175938Ssephe * Setting slot time according to "short slot time" capability 2283175938Ssephe * in beacon/probe_resp seems to cause problem to acknowledge 2284175938Ssephe * certain AP's data frames transimitted at CCK/DS rates: the 2285175938Ssephe * problematic AP keeps retransmitting data frames, probably 2286175938Ssephe * because MAC level acks are not received by hardware. 2287175938Ssephe * So we cheat a little bit here by claiming we are capable of 2288175938Ssephe * "short slot time" but setting hardware slot time to the normal 2289175938Ssephe * slot time. ral(4) does not seem to have trouble to receive 2290175938Ssephe * frames transmitted using short slot time even if hardware 2291175938Ssephe * slot time is set to normal slot time. If we didn't use this 2292175938Ssephe * trick, we would have to claim that short slot time is not 2293175938Ssephe * supported; this would give relative poor RX performance 2294175938Ssephe * (-1Mb~-2Mb lower) and the _whole_ BSS would stop using short 2295175938Ssephe * slot time. 2296175938Ssephe */ 2297292165Savos slottime = IEEE80211_DUR_SLOT; 2298175938Ssephe#endif 2299156321Sdamien 2300156321Sdamien /* update the MAC slot boundaries */ 2301156321Sdamien tx_sifs = RAL_SIFS - RT2560_TXRX_TURNAROUND; 2302156321Sdamien tx_pifs = tx_sifs + slottime; 2303292165Savos tx_difs = IEEE80211_DUR_DIFS(tx_sifs, slottime); 2304156321Sdamien eifs = (ic->ic_curmode == IEEE80211_MODE_11B) ? 364 : 60; 2305156321Sdamien 2306156321Sdamien tmp = RAL_READ(sc, RT2560_CSR11); 2307156321Sdamien tmp = (tmp & ~0x1f00) | slottime << 8; 2308156321Sdamien RAL_WRITE(sc, RT2560_CSR11, tmp); 2309156321Sdamien 2310156321Sdamien tmp = tx_pifs << 16 | tx_sifs; 2311156321Sdamien RAL_WRITE(sc, RT2560_CSR18, tmp); 2312156321Sdamien 2313156321Sdamien tmp = eifs << 16 | tx_difs; 2314156321Sdamien RAL_WRITE(sc, RT2560_CSR19, tmp); 2315156321Sdamien 2316178354Ssam DPRINTF(sc, "setting slottime to %uus\n", slottime); 2317156321Sdamien} 2318156321Sdamien 2319156321Sdamienstatic void 2320220502Sbschmidtrt2560_set_basicrates(struct rt2560_softc *sc, 2321220502Sbschmidt const struct ieee80211_rateset *rs) 2322156321Sdamien{ 2323287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2324220502Sbschmidt uint32_t mask = 0; 2325220502Sbschmidt uint8_t rate; 2326220502Sbschmidt int i; 2327156321Sdamien 2328220502Sbschmidt for (i = 0; i < rs->rs_nrates; i++) { 2329220502Sbschmidt rate = rs->rs_rates[i]; 2330220502Sbschmidt 2331220502Sbschmidt if (!(rate & IEEE80211_RATE_BASIC)) 2332220502Sbschmidt continue; 2333220502Sbschmidt 2334288087Sadrian mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt, 2335288087Sadrian IEEE80211_RV(rate)); 2336156321Sdamien } 2337220502Sbschmidt 2338220502Sbschmidt RAL_WRITE(sc, RT2560_ARSP_PLCP_1, mask); 2339220502Sbschmidt 2340220502Sbschmidt DPRINTF(sc, "Setting basic rate mask to 0x%x\n", mask); 2341156321Sdamien} 2342156321Sdamien 2343156321Sdamienstatic void 2344156321Sdamienrt2560_update_led(struct rt2560_softc *sc, int led1, int led2) 2345156321Sdamien{ 2346156321Sdamien uint32_t tmp; 2347156321Sdamien 2348156321Sdamien /* set ON period to 70ms and OFF period to 30ms */ 2349156321Sdamien tmp = led1 << 16 | led2 << 17 | 70 << 8 | 30; 2350156321Sdamien RAL_WRITE(sc, RT2560_LEDCSR, tmp); 2351156321Sdamien} 2352156321Sdamien 2353156321Sdamienstatic void 2354170530Ssamrt2560_set_bssid(struct rt2560_softc *sc, const uint8_t *bssid) 2355156321Sdamien{ 2356156321Sdamien uint32_t tmp; 2357156321Sdamien 2358156321Sdamien tmp = bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24; 2359156321Sdamien RAL_WRITE(sc, RT2560_CSR5, tmp); 2360156321Sdamien 2361156321Sdamien tmp = bssid[4] | bssid[5] << 8; 2362156321Sdamien RAL_WRITE(sc, RT2560_CSR6, tmp); 2363156321Sdamien 2364178354Ssam DPRINTF(sc, "setting BSSID to %6D\n", bssid, ":"); 2365156321Sdamien} 2366156321Sdamien 2367156321Sdamienstatic void 2368287197Sglebiusrt2560_set_macaddr(struct rt2560_softc *sc, const uint8_t *addr) 2369156321Sdamien{ 2370156321Sdamien uint32_t tmp; 2371156321Sdamien 2372156321Sdamien tmp = addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24; 2373156321Sdamien RAL_WRITE(sc, RT2560_CSR3, tmp); 2374156321Sdamien 2375156321Sdamien tmp = addr[4] | addr[5] << 8; 2376156321Sdamien RAL_WRITE(sc, RT2560_CSR4, tmp); 2377156321Sdamien 2378178354Ssam DPRINTF(sc, "setting MAC address to %6D\n", addr, ":"); 2379156321Sdamien} 2380156321Sdamien 2381156321Sdamienstatic void 2382156321Sdamienrt2560_get_macaddr(struct rt2560_softc *sc, uint8_t *addr) 2383156321Sdamien{ 2384156321Sdamien uint32_t tmp; 2385156321Sdamien 2386156321Sdamien tmp = RAL_READ(sc, RT2560_CSR3); 2387156321Sdamien addr[0] = tmp & 0xff; 2388156321Sdamien addr[1] = (tmp >> 8) & 0xff; 2389156321Sdamien addr[2] = (tmp >> 16) & 0xff; 2390156321Sdamien addr[3] = (tmp >> 24); 2391156321Sdamien 2392156321Sdamien tmp = RAL_READ(sc, RT2560_CSR4); 2393156321Sdamien addr[4] = tmp & 0xff; 2394156321Sdamien addr[5] = (tmp >> 8) & 0xff; 2395156321Sdamien} 2396156321Sdamien 2397156321Sdamienstatic void 2398283540Sglebiusrt2560_update_promisc(struct ieee80211com *ic) 2399156321Sdamien{ 2400283540Sglebius struct rt2560_softc *sc = ic->ic_softc; 2401156321Sdamien uint32_t tmp; 2402156321Sdamien 2403156321Sdamien tmp = RAL_READ(sc, RT2560_RXCSR0); 2404156321Sdamien 2405156321Sdamien tmp &= ~RT2560_DROP_NOT_TO_ME; 2406287197Sglebius if (ic->ic_promisc == 0) 2407156321Sdamien tmp |= RT2560_DROP_NOT_TO_ME; 2408156321Sdamien 2409156321Sdamien RAL_WRITE(sc, RT2560_RXCSR0, tmp); 2410156321Sdamien 2411283540Sglebius DPRINTF(sc, "%s promiscuous mode\n", 2412287197Sglebius (ic->ic_promisc > 0) ? "entering" : "leaving"); 2413156321Sdamien} 2414156321Sdamien 2415156321Sdamienstatic const char * 2416156321Sdamienrt2560_get_rf(int rev) 2417156321Sdamien{ 2418156321Sdamien switch (rev) { 2419156321Sdamien case RT2560_RF_2522: return "RT2522"; 2420156321Sdamien case RT2560_RF_2523: return "RT2523"; 2421156321Sdamien case RT2560_RF_2524: return "RT2524"; 2422156321Sdamien case RT2560_RF_2525: return "RT2525"; 2423156321Sdamien case RT2560_RF_2525E: return "RT2525e"; 2424156321Sdamien case RT2560_RF_2526: return "RT2526"; 2425156321Sdamien case RT2560_RF_5222: return "RT5222"; 2426156321Sdamien default: return "unknown"; 2427156321Sdamien } 2428156321Sdamien} 2429156321Sdamien 2430156321Sdamienstatic void 2431175938Ssephert2560_read_config(struct rt2560_softc *sc) 2432156321Sdamien{ 2433156321Sdamien uint16_t val; 2434156321Sdamien int i; 2435156321Sdamien 2436156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_CONFIG0); 2437156321Sdamien sc->rf_rev = (val >> 11) & 0x7; 2438156321Sdamien sc->hw_radio = (val >> 10) & 0x1; 2439156321Sdamien sc->led_mode = (val >> 6) & 0x7; 2440156321Sdamien sc->rx_ant = (val >> 4) & 0x3; 2441156321Sdamien sc->tx_ant = (val >> 2) & 0x3; 2442156321Sdamien sc->nb_ant = val & 0x3; 2443156321Sdamien 2444156321Sdamien /* read default values for BBP registers */ 2445156321Sdamien for (i = 0; i < 16; i++) { 2446156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_BBP_BASE + i); 2447175938Ssephe if (val == 0 || val == 0xffff) 2448175938Ssephe continue; 2449175938Ssephe 2450156321Sdamien sc->bbp_prom[i].reg = val >> 8; 2451156321Sdamien sc->bbp_prom[i].val = val & 0xff; 2452156321Sdamien } 2453156321Sdamien 2454156321Sdamien /* read Tx power for all b/g channels */ 2455156321Sdamien for (i = 0; i < 14 / 2; i++) { 2456156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_TXPOWER + i); 2457175938Ssephe sc->txpow[i * 2] = val & 0xff; 2458175938Ssephe sc->txpow[i * 2 + 1] = val >> 8; 2459156321Sdamien } 2460175938Ssephe for (i = 0; i < 14; ++i) { 2461175938Ssephe if (sc->txpow[i] > 31) 2462175938Ssephe sc->txpow[i] = 24; 2463175938Ssephe } 2464170530Ssam 2465170530Ssam val = rt2560_eeprom_read(sc, RT2560_EEPROM_CALIBRATE); 2466170530Ssam if ((val & 0xff) == 0xff) 2467170530Ssam sc->rssi_corr = RT2560_DEFAULT_RSSI_CORR; 2468170530Ssam else 2469170530Ssam sc->rssi_corr = val & 0xff; 2470178354Ssam DPRINTF(sc, "rssi correction %d, calibrate 0x%02x\n", 2471178354Ssam sc->rssi_corr, val); 2472156321Sdamien} 2473156321Sdamien 2474170530Ssam 2475170530Ssamstatic void 2476170530Ssamrt2560_scan_start(struct ieee80211com *ic) 2477170530Ssam{ 2478287197Sglebius struct rt2560_softc *sc = ic->ic_softc; 2479170530Ssam 2480170530Ssam /* abort TSF synchronization */ 2481170530Ssam RAL_WRITE(sc, RT2560_CSR14, 0); 2482287197Sglebius rt2560_set_bssid(sc, ieee80211broadcastaddr); 2483170530Ssam} 2484170530Ssam 2485170530Ssamstatic void 2486170530Ssamrt2560_scan_end(struct ieee80211com *ic) 2487170530Ssam{ 2488287197Sglebius struct rt2560_softc *sc = ic->ic_softc; 2489178354Ssam struct ieee80211vap *vap = ic->ic_scan->ss_vap; 2490170530Ssam 2491170530Ssam rt2560_enable_tsf_sync(sc); 2492170530Ssam /* XXX keep local copy */ 2493178354Ssam rt2560_set_bssid(sc, vap->iv_bss->ni_bssid); 2494170530Ssam} 2495170530Ssam 2496156321Sdamienstatic int 2497156321Sdamienrt2560_bbp_init(struct rt2560_softc *sc) 2498156321Sdamien{ 2499156321Sdamien int i, ntries; 2500156321Sdamien 2501156321Sdamien /* wait for BBP to be ready */ 2502156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2503156321Sdamien if (rt2560_bbp_read(sc, RT2560_BBP_VERSION) != 0) 2504156321Sdamien break; 2505156321Sdamien DELAY(1); 2506156321Sdamien } 2507156321Sdamien if (ntries == 100) { 2508156321Sdamien device_printf(sc->sc_dev, "timeout waiting for BBP\n"); 2509156321Sdamien return EIO; 2510156321Sdamien } 2511156321Sdamien 2512156321Sdamien /* initialize BBP registers to default values */ 2513288087Sadrian for (i = 0; i < nitems(rt2560_def_bbp); i++) { 2514156321Sdamien rt2560_bbp_write(sc, rt2560_def_bbp[i].reg, 2515156321Sdamien rt2560_def_bbp[i].val); 2516156321Sdamien } 2517175938Ssephe 2518156321Sdamien /* initialize BBP registers to values stored in EEPROM */ 2519156321Sdamien for (i = 0; i < 16; i++) { 2520175938Ssephe if (sc->bbp_prom[i].reg == 0 && sc->bbp_prom[i].val == 0) 2521175938Ssephe break; 2522156321Sdamien rt2560_bbp_write(sc, sc->bbp_prom[i].reg, sc->bbp_prom[i].val); 2523156321Sdamien } 2524175938Ssephe rt2560_bbp_write(sc, 17, 0x48); /* XXX restore bbp17 */ 2525156321Sdamien 2526156321Sdamien return 0; 2527156321Sdamien} 2528156321Sdamien 2529156321Sdamienstatic void 2530156321Sdamienrt2560_set_txantenna(struct rt2560_softc *sc, int antenna) 2531156321Sdamien{ 2532156321Sdamien uint32_t tmp; 2533156321Sdamien uint8_t tx; 2534156321Sdamien 2535156321Sdamien tx = rt2560_bbp_read(sc, RT2560_BBP_TX) & ~RT2560_BBP_ANTMASK; 2536156321Sdamien if (antenna == 1) 2537156321Sdamien tx |= RT2560_BBP_ANTA; 2538156321Sdamien else if (antenna == 2) 2539156321Sdamien tx |= RT2560_BBP_ANTB; 2540156321Sdamien else 2541156321Sdamien tx |= RT2560_BBP_DIVERSITY; 2542156321Sdamien 2543156321Sdamien /* need to force I/Q flip for RF 2525e, 2526 and 5222 */ 2544156321Sdamien if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526 || 2545156321Sdamien sc->rf_rev == RT2560_RF_5222) 2546156321Sdamien tx |= RT2560_BBP_FLIPIQ; 2547156321Sdamien 2548156321Sdamien rt2560_bbp_write(sc, RT2560_BBP_TX, tx); 2549156321Sdamien 2550156321Sdamien /* update values for CCK and OFDM in BBPCSR1 */ 2551156321Sdamien tmp = RAL_READ(sc, RT2560_BBPCSR1) & ~0x00070007; 2552156321Sdamien tmp |= (tx & 0x7) << 16 | (tx & 0x7); 2553156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR1, tmp); 2554156321Sdamien} 2555156321Sdamien 2556156321Sdamienstatic void 2557156321Sdamienrt2560_set_rxantenna(struct rt2560_softc *sc, int antenna) 2558156321Sdamien{ 2559156321Sdamien uint8_t rx; 2560156321Sdamien 2561156321Sdamien rx = rt2560_bbp_read(sc, RT2560_BBP_RX) & ~RT2560_BBP_ANTMASK; 2562156321Sdamien if (antenna == 1) 2563156321Sdamien rx |= RT2560_BBP_ANTA; 2564156321Sdamien else if (antenna == 2) 2565156321Sdamien rx |= RT2560_BBP_ANTB; 2566156321Sdamien else 2567156321Sdamien rx |= RT2560_BBP_DIVERSITY; 2568156321Sdamien 2569156321Sdamien /* need to force no I/Q flip for RF 2525e and 2526 */ 2570156321Sdamien if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526) 2571156321Sdamien rx &= ~RT2560_BBP_FLIPIQ; 2572156321Sdamien 2573156321Sdamien rt2560_bbp_write(sc, RT2560_BBP_RX, rx); 2574156321Sdamien} 2575156321Sdamien 2576156321Sdamienstatic void 2577178354Ssamrt2560_init_locked(struct rt2560_softc *sc) 2578156321Sdamien{ 2579287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2580287197Sglebius struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2581156321Sdamien uint32_t tmp; 2582156321Sdamien int i; 2583156321Sdamien 2584178354Ssam RAL_LOCK_ASSERT(sc); 2585156975Sdamien 2586178354Ssam rt2560_stop_locked(sc); 2587170530Ssam 2588156321Sdamien /* setup tx rings */ 2589156321Sdamien tmp = RT2560_PRIO_RING_COUNT << 24 | 2590156321Sdamien RT2560_ATIM_RING_COUNT << 16 | 2591156321Sdamien RT2560_TX_RING_COUNT << 8 | 2592156321Sdamien RT2560_TX_DESC_SIZE; 2593156321Sdamien 2594156321Sdamien /* rings must be initialized in this exact order */ 2595156321Sdamien RAL_WRITE(sc, RT2560_TXCSR2, tmp); 2596156321Sdamien RAL_WRITE(sc, RT2560_TXCSR3, sc->txq.physaddr); 2597156321Sdamien RAL_WRITE(sc, RT2560_TXCSR5, sc->prioq.physaddr); 2598156321Sdamien RAL_WRITE(sc, RT2560_TXCSR4, sc->atimq.physaddr); 2599156321Sdamien RAL_WRITE(sc, RT2560_TXCSR6, sc->bcnq.physaddr); 2600156321Sdamien 2601156321Sdamien /* setup rx ring */ 2602156321Sdamien tmp = RT2560_RX_RING_COUNT << 8 | RT2560_RX_DESC_SIZE; 2603156321Sdamien 2604156321Sdamien RAL_WRITE(sc, RT2560_RXCSR1, tmp); 2605156321Sdamien RAL_WRITE(sc, RT2560_RXCSR2, sc->rxq.physaddr); 2606156321Sdamien 2607156321Sdamien /* initialize MAC registers to default values */ 2608288087Sadrian for (i = 0; i < nitems(rt2560_def_mac); i++) 2609156321Sdamien RAL_WRITE(sc, rt2560_def_mac[i].reg, rt2560_def_mac[i].val); 2610156321Sdamien 2611287197Sglebius rt2560_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); 2612156321Sdamien 2613156321Sdamien /* set basic rate set (will be updated later) */ 2614156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x153); 2615156321Sdamien 2616283540Sglebius rt2560_update_slot(ic); 2617156321Sdamien rt2560_update_plcp(sc); 2618156321Sdamien rt2560_update_led(sc, 0, 0); 2619156321Sdamien 2620156321Sdamien RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 2621156321Sdamien RAL_WRITE(sc, RT2560_CSR1, RT2560_HOST_READY); 2622156321Sdamien 2623156321Sdamien if (rt2560_bbp_init(sc) != 0) { 2624213268Sjhb rt2560_stop_locked(sc); 2625156321Sdamien return; 2626156321Sdamien } 2627156321Sdamien 2628175938Ssephe rt2560_set_txantenna(sc, sc->tx_ant); 2629175938Ssephe rt2560_set_rxantenna(sc, sc->rx_ant); 2630175938Ssephe 2631156321Sdamien /* set default BSS channel */ 2632156321Sdamien rt2560_set_chan(sc, ic->ic_curchan); 2633156321Sdamien 2634156321Sdamien /* kick Rx */ 2635156321Sdamien tmp = RT2560_DROP_PHY_ERROR | RT2560_DROP_CRC_ERROR; 2636156321Sdamien if (ic->ic_opmode != IEEE80211_M_MONITOR) { 2637156321Sdamien tmp |= RT2560_DROP_CTL | RT2560_DROP_VERSION_ERROR; 2638195618Srpaulo if (ic->ic_opmode != IEEE80211_M_HOSTAP && 2639195618Srpaulo ic->ic_opmode != IEEE80211_M_MBSS) 2640156321Sdamien tmp |= RT2560_DROP_TODS; 2641287197Sglebius if (ic->ic_promisc == 0) 2642156321Sdamien tmp |= RT2560_DROP_NOT_TO_ME; 2643156321Sdamien } 2644156321Sdamien RAL_WRITE(sc, RT2560_RXCSR0, tmp); 2645156321Sdamien 2646156321Sdamien /* clear old FCS and Rx FIFO errors */ 2647156321Sdamien RAL_READ(sc, RT2560_CNT0); 2648156321Sdamien RAL_READ(sc, RT2560_CNT4); 2649156321Sdamien 2650156321Sdamien /* clear any pending interrupts */ 2651156321Sdamien RAL_WRITE(sc, RT2560_CSR7, 0xffffffff); 2652156321Sdamien 2653156321Sdamien /* enable interrupts */ 2654156321Sdamien RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); 2655156321Sdamien 2656287197Sglebius sc->sc_flags |= RT2560_F_RUNNING; 2657156321Sdamien 2658175938Ssephe callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); 2659178354Ssam} 2660175938Ssephe 2661178354Ssamstatic void 2662178354Ssamrt2560_init(void *priv) 2663178354Ssam{ 2664178354Ssam struct rt2560_softc *sc = priv; 2665287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2666156975Sdamien 2667178354Ssam RAL_LOCK(sc); 2668178354Ssam rt2560_init_locked(sc); 2669156975Sdamien RAL_UNLOCK(sc); 2670178354Ssam 2671287197Sglebius if (sc->sc_flags & RT2560_F_RUNNING) 2672178931Sthompsa ieee80211_start_all(ic); /* start all vap's */ 2673156321Sdamien} 2674156321Sdamien 2675178354Ssamstatic void 2676178354Ssamrt2560_stop_locked(struct rt2560_softc *sc) 2677156321Sdamien{ 2678170530Ssam volatile int *flags = &sc->sc_flags; 2679156321Sdamien 2680178354Ssam RAL_LOCK_ASSERT(sc); 2681156321Sdamien 2682178354Ssam while (*flags & RT2560_F_INPUT_RUNNING) 2683178354Ssam msleep(sc, &sc->sc_mtx, 0, "ralrunning", hz/10); 2684175938Ssephe 2685175938Ssephe callout_stop(&sc->watchdog_ch); 2686178354Ssam sc->sc_tx_timer = 0; 2687175938Ssephe 2688287197Sglebius if (sc->sc_flags & RT2560_F_RUNNING) { 2689287197Sglebius sc->sc_flags &= ~RT2560_F_RUNNING; 2690156975Sdamien 2691170530Ssam /* abort Tx */ 2692170530Ssam RAL_WRITE(sc, RT2560_TXCSR0, RT2560_ABORT_TX); 2693170530Ssam 2694170530Ssam /* disable Rx */ 2695170530Ssam RAL_WRITE(sc, RT2560_RXCSR0, RT2560_DISABLE_RX); 2696156321Sdamien 2697170530Ssam /* reset ASIC (imply reset BBP) */ 2698170530Ssam RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 2699170530Ssam RAL_WRITE(sc, RT2560_CSR1, 0); 2700156321Sdamien 2701170530Ssam /* disable interrupts */ 2702170530Ssam RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 2703170530Ssam 2704170530Ssam /* reset Tx and Rx rings */ 2705170530Ssam rt2560_reset_tx_ring(sc, &sc->txq); 2706170530Ssam rt2560_reset_tx_ring(sc, &sc->atimq); 2707170530Ssam rt2560_reset_tx_ring(sc, &sc->prioq); 2708170530Ssam rt2560_reset_tx_ring(sc, &sc->bcnq); 2709170530Ssam rt2560_reset_rx_ring(sc, &sc->rxq); 2710170530Ssam } 2711178354Ssam} 2712175938Ssephe 2713178354Ssamvoid 2714178354Ssamrt2560_stop(void *arg) 2715178354Ssam{ 2716178354Ssam struct rt2560_softc *sc = arg; 2717178354Ssam 2718178354Ssam RAL_LOCK(sc); 2719178354Ssam rt2560_stop_locked(sc); 2720170530Ssam RAL_UNLOCK(sc); 2721156321Sdamien} 2722160691Ssam 2723160691Ssamstatic int 2724160691Ssamrt2560_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 2725160691Ssam const struct ieee80211_bpf_params *params) 2726160691Ssam{ 2727160691Ssam struct ieee80211com *ic = ni->ni_ic; 2728287197Sglebius struct rt2560_softc *sc = ic->ic_softc; 2729160691Ssam 2730160691Ssam RAL_LOCK(sc); 2731160691Ssam 2732160691Ssam /* prevent management frames from being sent if we're not ready */ 2733287197Sglebius if (!(sc->sc_flags & RT2560_F_RUNNING)) { 2734160691Ssam RAL_UNLOCK(sc); 2735168860Ssephe m_freem(m); 2736160691Ssam return ENETDOWN; 2737160691Ssam } 2738160691Ssam if (sc->prioq.queued >= RT2560_PRIO_RING_COUNT) { 2739160691Ssam RAL_UNLOCK(sc); 2740168860Ssephe m_freem(m); 2741160691Ssam return ENOBUFS; /* XXX */ 2742160691Ssam } 2743160691Ssam 2744160691Ssam if (params == NULL) { 2745160691Ssam /* 2746160691Ssam * Legacy path; interpret frame contents to decide 2747160691Ssam * precisely how to send the frame. 2748160691Ssam */ 2749160691Ssam if (rt2560_tx_mgt(sc, m, ni) != 0) 2750160691Ssam goto bad; 2751160691Ssam } else { 2752160691Ssam /* 2753160691Ssam * Caller supplied explicit parameters to use in 2754160691Ssam * sending the frame. 2755160691Ssam */ 2756160691Ssam if (rt2560_tx_raw(sc, m, ni, params)) 2757160691Ssam goto bad; 2758160691Ssam } 2759160691Ssam sc->sc_tx_timer = 5; 2760160691Ssam 2761160691Ssam RAL_UNLOCK(sc); 2762160691Ssam 2763160691Ssam return 0; 2764160691Ssambad: 2765160691Ssam RAL_UNLOCK(sc); 2766160691Ssam return EIO; /* XXX */ 2767160691Ssam} 2768