rt2560.c revision 179643
1156321Sdamien/* $FreeBSD: head/sys/dev/ral/rt2560.c 179643 2008-06-07 18:38:02Z sam $ */ 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: head/sys/dev/ral/rt2560.c 179643 2008-06-07 18:38:02Z sam $"); 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> 48156321Sdamien#include <net/if_arp.h> 49156321Sdamien#include <net/ethernet.h> 50156321Sdamien#include <net/if_dl.h> 51156321Sdamien#include <net/if_media.h> 52156321Sdamien#include <net/if_types.h> 53156321Sdamien 54156321Sdamien#include <net80211/ieee80211_var.h> 55178354Ssam#include <net80211/ieee80211_phy.h> 56156321Sdamien#include <net80211/ieee80211_radiotap.h> 57170530Ssam#include <net80211/ieee80211_regdomain.h> 58178354Ssam#include <net80211/ieee80211_amrr.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 *, 89178354Ssam const char name[IFNAMSIZ], int unit, int opmode, 90178354Ssam int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], 91178354Ssam const uint8_t mac[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 *); 107179643Ssamstatic struct ieee80211_node *rt2560_node_alloc(struct ieee80211vap *, 108179643Ssam const uint8_t [IEEE80211_ADDR_LEN]); 109178354Ssamstatic void rt2560_newassoc(struct ieee80211_node *, int); 110178354Ssamstatic int rt2560_newstate(struct ieee80211vap *, 111156321Sdamien enum ieee80211_state, int); 112156321Sdamienstatic uint16_t rt2560_eeprom_read(struct rt2560_softc *, uint8_t); 113156321Sdamienstatic void rt2560_encryption_intr(struct rt2560_softc *); 114156321Sdamienstatic void rt2560_tx_intr(struct rt2560_softc *); 115156321Sdamienstatic void rt2560_prio_intr(struct rt2560_softc *); 116156321Sdamienstatic void rt2560_decryption_intr(struct rt2560_softc *); 117156321Sdamienstatic void rt2560_rx_intr(struct rt2560_softc *); 118178354Ssamstatic void rt2560_beacon_update(struct ieee80211vap *, int item); 119156321Sdamienstatic void rt2560_beacon_expire(struct rt2560_softc *); 120156321Sdamienstatic void rt2560_wakeup_expire(struct rt2560_softc *); 121170530Ssamstatic void rt2560_scan_start(struct ieee80211com *); 122170530Ssamstatic void rt2560_scan_end(struct ieee80211com *); 123170530Ssamstatic void rt2560_set_channel(struct ieee80211com *); 124156321Sdamienstatic void rt2560_setup_tx_desc(struct rt2560_softc *, 125156321Sdamien struct rt2560_tx_desc *, uint32_t, int, int, int, 126156321Sdamien bus_addr_t); 127156321Sdamienstatic int rt2560_tx_bcn(struct rt2560_softc *, struct mbuf *, 128156321Sdamien struct ieee80211_node *); 129156321Sdamienstatic int rt2560_tx_mgt(struct rt2560_softc *, struct mbuf *, 130156321Sdamien struct ieee80211_node *); 131156321Sdamienstatic int rt2560_tx_data(struct rt2560_softc *, struct mbuf *, 132156321Sdamien struct ieee80211_node *); 133178354Ssamstatic void rt2560_start_locked(struct ifnet *); 134156321Sdamienstatic void rt2560_start(struct ifnet *); 135165352Sbmsstatic void rt2560_watchdog(void *); 136156321Sdamienstatic int rt2560_ioctl(struct ifnet *, u_long, caddr_t); 137156321Sdamienstatic void rt2560_bbp_write(struct rt2560_softc *, uint8_t, 138156321Sdamien uint8_t); 139156321Sdamienstatic uint8_t rt2560_bbp_read(struct rt2560_softc *, uint8_t); 140156321Sdamienstatic void rt2560_rf_write(struct rt2560_softc *, uint8_t, 141156321Sdamien uint32_t); 142156321Sdamienstatic void rt2560_set_chan(struct rt2560_softc *, 143156321Sdamien struct ieee80211_channel *); 144156321Sdamien#if 0 145156321Sdamienstatic void rt2560_disable_rf_tune(struct rt2560_softc *); 146156321Sdamien#endif 147156321Sdamienstatic void rt2560_enable_tsf_sync(struct rt2560_softc *); 148156321Sdamienstatic void rt2560_update_plcp(struct rt2560_softc *); 149156321Sdamienstatic void rt2560_update_slot(struct ifnet *); 150156321Sdamienstatic void rt2560_set_basicrates(struct rt2560_softc *); 151156321Sdamienstatic void rt2560_update_led(struct rt2560_softc *, int, int); 152170530Ssamstatic void rt2560_set_bssid(struct rt2560_softc *, const uint8_t *); 153156321Sdamienstatic void rt2560_set_macaddr(struct rt2560_softc *, uint8_t *); 154156321Sdamienstatic void rt2560_get_macaddr(struct rt2560_softc *, uint8_t *); 155178354Ssamstatic void rt2560_update_promisc(struct ifnet *); 156156321Sdamienstatic const char *rt2560_get_rf(int); 157175938Ssephestatic void rt2560_read_config(struct rt2560_softc *); 158156321Sdamienstatic int rt2560_bbp_init(struct rt2560_softc *); 159156321Sdamienstatic void rt2560_set_txantenna(struct rt2560_softc *, int); 160156321Sdamienstatic void rt2560_set_rxantenna(struct rt2560_softc *, int); 161178354Ssamstatic void rt2560_init_locked(struct rt2560_softc *); 162156321Sdamienstatic void rt2560_init(void *); 163178354Ssamstatic void rt2560_stop_locked(struct rt2560_softc *); 164160691Ssamstatic int rt2560_raw_xmit(struct ieee80211_node *, struct mbuf *, 165160691Ssam const struct ieee80211_bpf_params *); 166156321Sdamien 167156321Sdamienstatic const struct { 168156321Sdamien uint32_t reg; 169156321Sdamien uint32_t val; 170156321Sdamien} rt2560_def_mac[] = { 171156321Sdamien RT2560_DEF_MAC 172156321Sdamien}; 173156321Sdamien 174156321Sdamienstatic const struct { 175156321Sdamien uint8_t reg; 176156321Sdamien uint8_t val; 177156321Sdamien} rt2560_def_bbp[] = { 178156321Sdamien RT2560_DEF_BBP 179156321Sdamien}; 180156321Sdamien 181156321Sdamienstatic const uint32_t rt2560_rf2522_r2[] = RT2560_RF2522_R2; 182156321Sdamienstatic const uint32_t rt2560_rf2523_r2[] = RT2560_RF2523_R2; 183156321Sdamienstatic const uint32_t rt2560_rf2524_r2[] = RT2560_RF2524_R2; 184156321Sdamienstatic const uint32_t rt2560_rf2525_r2[] = RT2560_RF2525_R2; 185156321Sdamienstatic const uint32_t rt2560_rf2525_hi_r2[] = RT2560_RF2525_HI_R2; 186156321Sdamienstatic const uint32_t rt2560_rf2525e_r2[] = RT2560_RF2525E_R2; 187156321Sdamienstatic const uint32_t rt2560_rf2526_r2[] = RT2560_RF2526_R2; 188156321Sdamienstatic const uint32_t rt2560_rf2526_hi_r2[] = RT2560_RF2526_HI_R2; 189156321Sdamien 190156321Sdamienstatic const struct { 191156321Sdamien uint8_t chan; 192156321Sdamien uint32_t r1, r2, r4; 193156321Sdamien} rt2560_rf5222[] = { 194156321Sdamien RT2560_RF5222 195156321Sdamien}; 196156321Sdamien 197156321Sdamienint 198156321Sdamienrt2560_attach(device_t dev, int id) 199156321Sdamien{ 200156321Sdamien struct rt2560_softc *sc = device_get_softc(dev); 201178354Ssam struct ieee80211com *ic; 202156321Sdamien struct ifnet *ifp; 203178354Ssam int error; 204178354Ssam uint8_t bands; 205156321Sdamien 206156321Sdamien sc->sc_dev = dev; 207156321Sdamien 208156321Sdamien mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 209156321Sdamien MTX_DEF | MTX_RECURSE); 210156321Sdamien 211165352Sbms callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0); 212156321Sdamien 213156321Sdamien /* retrieve RT2560 rev. no */ 214156321Sdamien sc->asic_rev = RAL_READ(sc, RT2560_CSR0); 215156321Sdamien 216156321Sdamien /* retrieve RF rev. no and various other things from EEPROM */ 217175938Ssephe rt2560_read_config(sc); 218156321Sdamien 219156321Sdamien device_printf(dev, "MAC/BBP RT2560 (rev 0x%02x), RF %s\n", 220156321Sdamien sc->asic_rev, rt2560_get_rf(sc->rf_rev)); 221156321Sdamien 222156321Sdamien /* 223156321Sdamien * Allocate Tx and Rx rings. 224156321Sdamien */ 225156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->txq, RT2560_TX_RING_COUNT); 226156321Sdamien if (error != 0) { 227156321Sdamien device_printf(sc->sc_dev, "could not allocate Tx ring\n"); 228156321Sdamien goto fail1; 229156321Sdamien } 230156321Sdamien 231156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->atimq, RT2560_ATIM_RING_COUNT); 232156321Sdamien if (error != 0) { 233156321Sdamien device_printf(sc->sc_dev, "could not allocate ATIM ring\n"); 234156321Sdamien goto fail2; 235156321Sdamien } 236156321Sdamien 237156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->prioq, RT2560_PRIO_RING_COUNT); 238156321Sdamien if (error != 0) { 239156321Sdamien device_printf(sc->sc_dev, "could not allocate Prio ring\n"); 240156321Sdamien goto fail3; 241156321Sdamien } 242156321Sdamien 243156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->bcnq, RT2560_BEACON_RING_COUNT); 244156321Sdamien if (error != 0) { 245156321Sdamien device_printf(sc->sc_dev, "could not allocate Beacon ring\n"); 246156321Sdamien goto fail4; 247156321Sdamien } 248156321Sdamien 249156321Sdamien error = rt2560_alloc_rx_ring(sc, &sc->rxq, RT2560_RX_RING_COUNT); 250156321Sdamien if (error != 0) { 251156321Sdamien device_printf(sc->sc_dev, "could not allocate Rx ring\n"); 252156321Sdamien goto fail5; 253156321Sdamien } 254156321Sdamien 255178354Ssam ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); 256156321Sdamien if (ifp == NULL) { 257156321Sdamien device_printf(sc->sc_dev, "can not if_alloc()\n"); 258156321Sdamien goto fail6; 259156321Sdamien } 260178354Ssam ic = ifp->if_l2com; 261156321Sdamien 262178354Ssam /* retrieve MAC address */ 263178354Ssam rt2560_get_macaddr(sc, ic->ic_myaddr); 264178354Ssam 265156321Sdamien ifp->if_softc = sc; 266156321Sdamien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 267156321Sdamien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 268156321Sdamien ifp->if_init = rt2560_init; 269156321Sdamien ifp->if_ioctl = rt2560_ioctl; 270156321Sdamien ifp->if_start = rt2560_start; 271156321Sdamien IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 272156321Sdamien ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 273156321Sdamien IFQ_SET_READY(&ifp->if_snd); 274156321Sdamien 275156321Sdamien ic->ic_ifp = ifp; 276178354Ssam ic->ic_opmode = IEEE80211_M_STA; 277156321Sdamien ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 278156321Sdamien 279156321Sdamien /* set device capabilities */ 280156321Sdamien ic->ic_caps = 281178957Ssam IEEE80211_C_STA /* station mode */ 282178957Ssam | IEEE80211_C_IBSS /* ibss, nee adhoc, mode */ 283178354Ssam | IEEE80211_C_HOSTAP /* hostap mode */ 284178354Ssam | IEEE80211_C_MONITOR /* monitor mode */ 285178354Ssam | IEEE80211_C_AHDEMO /* adhoc demo mode */ 286178354Ssam | IEEE80211_C_WDS /* 4-address traffic works */ 287178354Ssam | IEEE80211_C_SHPREAMBLE /* short preamble supported */ 288178354Ssam | IEEE80211_C_SHSLOT /* short slot time supported */ 289178354Ssam | IEEE80211_C_WPA /* capable of WPA1+WPA2 */ 290178354Ssam | IEEE80211_C_BGSCAN /* capable of bg scanning */ 291178354Ssam#ifdef notyet 292178354Ssam | IEEE80211_C_TXFRAG /* handle tx frags */ 293178354Ssam#endif 294178354Ssam ; 295156321Sdamien 296170530Ssam bands = 0; 297170530Ssam setbit(&bands, IEEE80211_MODE_11B); 298170530Ssam setbit(&bands, IEEE80211_MODE_11G); 299170530Ssam if (sc->rf_rev == RT2560_RF_5222) 300170530Ssam setbit(&bands, IEEE80211_MODE_11A); 301178354Ssam ieee80211_init_channels(ic, NULL, &bands); 302156321Sdamien 303156321Sdamien ieee80211_ifattach(ic); 304178354Ssam ic->ic_newassoc = rt2560_newassoc; 305178354Ssam ic->ic_raw_xmit = rt2560_raw_xmit; 306178354Ssam ic->ic_updateslot = rt2560_update_slot; 307178354Ssam ic->ic_update_promisc = rt2560_update_promisc; 308178354Ssam ic->ic_node_alloc = rt2560_node_alloc; 309170530Ssam ic->ic_scan_start = rt2560_scan_start; 310170530Ssam ic->ic_scan_end = rt2560_scan_end; 311170530Ssam ic->ic_set_channel = rt2560_set_channel; 312156321Sdamien 313178354Ssam ic->ic_vap_create = rt2560_vap_create; 314178354Ssam ic->ic_vap_delete = rt2560_vap_delete; 315156321Sdamien 316178354Ssam bpfattach(ifp, DLT_IEEE802_11_RADIO, 317178354Ssam sizeof (struct ieee80211_frame) + sizeof (sc->sc_txtap)); 318156321Sdamien 319171086Skevlo sc->sc_rxtap_len = sizeof sc->sc_rxtap; 320156321Sdamien sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); 321156321Sdamien sc->sc_rxtap.wr_ihdr.it_present = htole32(RT2560_RX_RADIOTAP_PRESENT); 322156321Sdamien 323171086Skevlo sc->sc_txtap_len = sizeof sc->sc_txtap; 324156321Sdamien sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); 325156321Sdamien sc->sc_txtap.wt_ihdr.it_present = htole32(RT2560_TX_RADIOTAP_PRESENT); 326156321Sdamien 327156321Sdamien /* 328156321Sdamien * Add a few sysctl knobs. 329156321Sdamien */ 330178354Ssam#ifdef RAL_DEBUG 331156321Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 332156321Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 333178354Ssam "debug", CTLFLAG_RW, &sc->sc_debug, 0, "debug msgs"); 334178354Ssam#endif 335178354Ssam SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 336178354Ssam SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 337156321Sdamien "txantenna", CTLFLAG_RW, &sc->tx_ant, 0, "tx antenna (0=auto)"); 338156321Sdamien 339156321Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 340156321Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 341156321Sdamien "rxantenna", CTLFLAG_RW, &sc->rx_ant, 0, "rx antenna (0=auto)"); 342156321Sdamien 343156321Sdamien if (bootverbose) 344156321Sdamien ieee80211_announce(ic); 345156321Sdamien 346156321Sdamien return 0; 347156321Sdamien 348156321Sdamienfail6: rt2560_free_rx_ring(sc, &sc->rxq); 349156321Sdamienfail5: rt2560_free_tx_ring(sc, &sc->bcnq); 350156321Sdamienfail4: rt2560_free_tx_ring(sc, &sc->prioq); 351156321Sdamienfail3: rt2560_free_tx_ring(sc, &sc->atimq); 352156321Sdamienfail2: rt2560_free_tx_ring(sc, &sc->txq); 353156321Sdamienfail1: mtx_destroy(&sc->sc_mtx); 354156321Sdamien 355156321Sdamien return ENXIO; 356156321Sdamien} 357156321Sdamien 358156321Sdamienint 359156321Sdamienrt2560_detach(void *xsc) 360156321Sdamien{ 361156321Sdamien struct rt2560_softc *sc = xsc; 362178354Ssam struct ifnet *ifp = sc->sc_ifp; 363178354Ssam struct ieee80211com *ic = ifp->if_l2com; 364170530Ssam 365156321Sdamien rt2560_stop(sc); 366156321Sdamien 367156321Sdamien bpfdetach(ifp); 368156321Sdamien ieee80211_ifdetach(ic); 369156321Sdamien 370156321Sdamien rt2560_free_tx_ring(sc, &sc->txq); 371156321Sdamien rt2560_free_tx_ring(sc, &sc->atimq); 372156321Sdamien rt2560_free_tx_ring(sc, &sc->prioq); 373156321Sdamien rt2560_free_tx_ring(sc, &sc->bcnq); 374156321Sdamien rt2560_free_rx_ring(sc, &sc->rxq); 375156321Sdamien 376156321Sdamien if_free(ifp); 377156321Sdamien 378156321Sdamien mtx_destroy(&sc->sc_mtx); 379156321Sdamien 380156321Sdamien return 0; 381156321Sdamien} 382156321Sdamien 383178354Ssamstatic struct ieee80211vap * 384178354Ssamrt2560_vap_create(struct ieee80211com *ic, 385178354Ssam const char name[IFNAMSIZ], int unit, int opmode, int flags, 386178354Ssam const uint8_t bssid[IEEE80211_ADDR_LEN], 387178354Ssam const uint8_t mac[IEEE80211_ADDR_LEN]) 388178354Ssam{ 389178354Ssam struct ifnet *ifp = ic->ic_ifp; 390178354Ssam struct rt2560_vap *rvp; 391178354Ssam struct ieee80211vap *vap; 392178354Ssam 393178354Ssam switch (opmode) { 394178354Ssam case IEEE80211_M_STA: 395178354Ssam case IEEE80211_M_IBSS: 396178354Ssam case IEEE80211_M_AHDEMO: 397178354Ssam case IEEE80211_M_MONITOR: 398178354Ssam case IEEE80211_M_HOSTAP: 399178354Ssam if (!TAILQ_EMPTY(&ic->ic_vaps)) { 400178354Ssam if_printf(ifp, "only 1 vap supported\n"); 401178354Ssam return NULL; 402178354Ssam } 403178354Ssam if (opmode == IEEE80211_M_STA) 404178354Ssam flags |= IEEE80211_CLONE_NOBEACONS; 405178354Ssam break; 406178354Ssam case IEEE80211_M_WDS: 407178354Ssam if (TAILQ_EMPTY(&ic->ic_vaps) || 408178354Ssam ic->ic_opmode != IEEE80211_M_HOSTAP) { 409178354Ssam if_printf(ifp, "wds only supported in ap mode\n"); 410178354Ssam return NULL; 411178354Ssam } 412178354Ssam /* 413178354Ssam * Silently remove any request for a unique 414178354Ssam * bssid; WDS vap's always share the local 415178354Ssam * mac address. 416178354Ssam */ 417178354Ssam flags &= ~IEEE80211_CLONE_BSSID; 418178354Ssam break; 419178354Ssam default: 420178354Ssam if_printf(ifp, "unknown opmode %d\n", opmode); 421178354Ssam return NULL; 422178354Ssam } 423178354Ssam rvp = (struct rt2560_vap *) malloc(sizeof(struct rt2560_vap), 424178354Ssam M_80211_VAP, M_NOWAIT | M_ZERO); 425178354Ssam if (rvp == NULL) 426178354Ssam return NULL; 427178354Ssam vap = &rvp->ral_vap; 428178354Ssam ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); 429178354Ssam 430178354Ssam /* override state transition machine */ 431178354Ssam rvp->ral_newstate = vap->iv_newstate; 432178354Ssam vap->iv_newstate = rt2560_newstate; 433178354Ssam vap->iv_update_beacon = rt2560_beacon_update; 434178354Ssam 435178354Ssam ieee80211_amrr_init(&rvp->amrr, vap, 436178354Ssam IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, 437178354Ssam IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD, 438178354Ssam 500 /* ms */); 439178354Ssam 440178354Ssam /* complete setup */ 441178354Ssam ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); 442178354Ssam if (TAILQ_FIRST(&ic->ic_vaps) == vap) 443178354Ssam ic->ic_opmode = opmode; 444178354Ssam return vap; 445178354Ssam} 446178354Ssam 447178354Ssamstatic void 448178354Ssamrt2560_vap_delete(struct ieee80211vap *vap) 449178354Ssam{ 450178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 451178354Ssam 452178354Ssam ieee80211_amrr_cleanup(&rvp->amrr); 453178354Ssam ieee80211_vap_detach(vap); 454178354Ssam free(rvp, M_80211_VAP); 455178354Ssam} 456178354Ssam 457156321Sdamienvoid 458156321Sdamienrt2560_resume(void *xsc) 459156321Sdamien{ 460156321Sdamien struct rt2560_softc *sc = xsc; 461178354Ssam struct ifnet *ifp = sc->sc_ifp; 462156321Sdamien 463178354Ssam if (ifp->if_flags & IFF_UP) 464178354Ssam rt2560_init(sc); 465156321Sdamien} 466156321Sdamien 467156321Sdamienstatic void 468156321Sdamienrt2560_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 469156321Sdamien{ 470156321Sdamien if (error != 0) 471156321Sdamien return; 472156321Sdamien 473156321Sdamien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 474156321Sdamien 475156321Sdamien *(bus_addr_t *)arg = segs[0].ds_addr; 476156321Sdamien} 477156321Sdamien 478156321Sdamienstatic int 479156321Sdamienrt2560_alloc_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring, 480156321Sdamien int count) 481156321Sdamien{ 482156321Sdamien int i, error; 483156321Sdamien 484156321Sdamien ring->count = count; 485156321Sdamien ring->queued = 0; 486156321Sdamien ring->cur = ring->next = 0; 487156321Sdamien ring->cur_encrypt = ring->next_encrypt = 0; 488156321Sdamien 489171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 4, 0, 490171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 491171535Skevlo count * RT2560_TX_DESC_SIZE, 1, count * RT2560_TX_DESC_SIZE, 492171535Skevlo 0, NULL, NULL, &ring->desc_dmat); 493156321Sdamien if (error != 0) { 494156321Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 495156321Sdamien goto fail; 496156321Sdamien } 497156321Sdamien 498156321Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 499156321Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 500156321Sdamien if (error != 0) { 501156321Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 502156321Sdamien goto fail; 503156321Sdamien } 504156321Sdamien 505156321Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 506156321Sdamien count * RT2560_TX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr, 507156321Sdamien 0); 508156321Sdamien if (error != 0) { 509156321Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 510156321Sdamien goto fail; 511156321Sdamien } 512156321Sdamien 513156321Sdamien ring->data = malloc(count * sizeof (struct rt2560_tx_data), M_DEVBUF, 514156321Sdamien M_NOWAIT | M_ZERO); 515156321Sdamien if (ring->data == NULL) { 516156321Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 517156321Sdamien error = ENOMEM; 518156321Sdamien goto fail; 519156321Sdamien } 520156321Sdamien 521171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 522171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 523171535Skevlo MCLBYTES, RT2560_MAX_SCATTER, MCLBYTES, 0, NULL, NULL, 524171535Skevlo &ring->data_dmat); 525156321Sdamien if (error != 0) { 526156321Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 527156321Sdamien goto fail; 528156321Sdamien } 529156321Sdamien 530156321Sdamien for (i = 0; i < count; i++) { 531156321Sdamien error = bus_dmamap_create(ring->data_dmat, 0, 532156321Sdamien &ring->data[i].map); 533156321Sdamien if (error != 0) { 534156321Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 535156321Sdamien goto fail; 536156321Sdamien } 537156321Sdamien } 538156321Sdamien 539156321Sdamien return 0; 540156321Sdamien 541156321Sdamienfail: rt2560_free_tx_ring(sc, ring); 542156321Sdamien return error; 543156321Sdamien} 544156321Sdamien 545156321Sdamienstatic void 546156321Sdamienrt2560_reset_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) 547156321Sdamien{ 548156321Sdamien struct rt2560_tx_desc *desc; 549156321Sdamien struct rt2560_tx_data *data; 550156321Sdamien int i; 551156321Sdamien 552156321Sdamien for (i = 0; i < ring->count; i++) { 553156321Sdamien desc = &ring->desc[i]; 554156321Sdamien data = &ring->data[i]; 555156321Sdamien 556156321Sdamien if (data->m != NULL) { 557156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 558156321Sdamien BUS_DMASYNC_POSTWRITE); 559156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 560156321Sdamien m_freem(data->m); 561156321Sdamien data->m = NULL; 562156321Sdamien } 563156321Sdamien 564156321Sdamien if (data->ni != NULL) { 565156321Sdamien ieee80211_free_node(data->ni); 566156321Sdamien data->ni = NULL; 567156321Sdamien } 568156321Sdamien 569156321Sdamien desc->flags = 0; 570156321Sdamien } 571156321Sdamien 572156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 573156321Sdamien 574156321Sdamien ring->queued = 0; 575156321Sdamien ring->cur = ring->next = 0; 576156321Sdamien ring->cur_encrypt = ring->next_encrypt = 0; 577156321Sdamien} 578156321Sdamien 579156321Sdamienstatic void 580156321Sdamienrt2560_free_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) 581156321Sdamien{ 582156321Sdamien struct rt2560_tx_data *data; 583156321Sdamien int i; 584156321Sdamien 585156321Sdamien if (ring->desc != NULL) { 586156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 587156321Sdamien BUS_DMASYNC_POSTWRITE); 588156321Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 589156321Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 590156321Sdamien } 591156321Sdamien 592156321Sdamien if (ring->desc_dmat != NULL) 593156321Sdamien bus_dma_tag_destroy(ring->desc_dmat); 594156321Sdamien 595156321Sdamien if (ring->data != NULL) { 596156321Sdamien for (i = 0; i < ring->count; i++) { 597156321Sdamien data = &ring->data[i]; 598156321Sdamien 599156321Sdamien if (data->m != NULL) { 600156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 601156321Sdamien BUS_DMASYNC_POSTWRITE); 602156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 603156321Sdamien m_freem(data->m); 604156321Sdamien } 605156321Sdamien 606156321Sdamien if (data->ni != NULL) 607156321Sdamien ieee80211_free_node(data->ni); 608156321Sdamien 609156321Sdamien if (data->map != NULL) 610156321Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 611156321Sdamien } 612156321Sdamien 613156321Sdamien free(ring->data, M_DEVBUF); 614156321Sdamien } 615156321Sdamien 616156321Sdamien if (ring->data_dmat != NULL) 617156321Sdamien bus_dma_tag_destroy(ring->data_dmat); 618156321Sdamien} 619156321Sdamien 620156321Sdamienstatic int 621156321Sdamienrt2560_alloc_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring, 622156321Sdamien int count) 623156321Sdamien{ 624156321Sdamien struct rt2560_rx_desc *desc; 625156321Sdamien struct rt2560_rx_data *data; 626156321Sdamien bus_addr_t physaddr; 627156321Sdamien int i, error; 628156321Sdamien 629156321Sdamien ring->count = count; 630156321Sdamien ring->cur = ring->next = 0; 631156321Sdamien ring->cur_decrypt = 0; 632156321Sdamien 633171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 4, 0, 634171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 635171535Skevlo count * RT2560_RX_DESC_SIZE, 1, count * RT2560_RX_DESC_SIZE, 636171535Skevlo 0, NULL, NULL, &ring->desc_dmat); 637156321Sdamien if (error != 0) { 638156321Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 639156321Sdamien goto fail; 640156321Sdamien } 641156321Sdamien 642156321Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 643156321Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 644156321Sdamien if (error != 0) { 645156321Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 646156321Sdamien goto fail; 647156321Sdamien } 648156321Sdamien 649156321Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 650156321Sdamien count * RT2560_RX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr, 651156321Sdamien 0); 652156321Sdamien if (error != 0) { 653156321Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 654156321Sdamien goto fail; 655156321Sdamien } 656156321Sdamien 657156321Sdamien ring->data = malloc(count * sizeof (struct rt2560_rx_data), M_DEVBUF, 658156321Sdamien M_NOWAIT | M_ZERO); 659156321Sdamien if (ring->data == NULL) { 660156321Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 661156321Sdamien error = ENOMEM; 662156321Sdamien goto fail; 663156321Sdamien } 664156321Sdamien 665156321Sdamien /* 666156321Sdamien * Pre-allocate Rx buffers and populate Rx ring. 667156321Sdamien */ 668171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 669171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 670171535Skevlo 1, MCLBYTES, 0, NULL, NULL, &ring->data_dmat); 671156321Sdamien if (error != 0) { 672156321Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 673156321Sdamien goto fail; 674156321Sdamien } 675156321Sdamien 676156321Sdamien for (i = 0; i < count; i++) { 677156321Sdamien desc = &sc->rxq.desc[i]; 678156321Sdamien data = &sc->rxq.data[i]; 679156321Sdamien 680156321Sdamien error = bus_dmamap_create(ring->data_dmat, 0, &data->map); 681156321Sdamien if (error != 0) { 682156321Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 683156321Sdamien goto fail; 684156321Sdamien } 685156321Sdamien 686156321Sdamien data->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 687156321Sdamien if (data->m == NULL) { 688156321Sdamien device_printf(sc->sc_dev, 689156321Sdamien "could not allocate rx mbuf\n"); 690156321Sdamien error = ENOMEM; 691156321Sdamien goto fail; 692156321Sdamien } 693156321Sdamien 694156321Sdamien error = bus_dmamap_load(ring->data_dmat, data->map, 695156321Sdamien mtod(data->m, void *), MCLBYTES, rt2560_dma_map_addr, 696156321Sdamien &physaddr, 0); 697156321Sdamien if (error != 0) { 698156321Sdamien device_printf(sc->sc_dev, 699156321Sdamien "could not load rx buf DMA map"); 700156321Sdamien goto fail; 701156321Sdamien } 702156321Sdamien 703156321Sdamien desc->flags = htole32(RT2560_RX_BUSY); 704156321Sdamien desc->physaddr = htole32(physaddr); 705156321Sdamien } 706156321Sdamien 707156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 708156321Sdamien 709156321Sdamien return 0; 710156321Sdamien 711156321Sdamienfail: rt2560_free_rx_ring(sc, ring); 712156321Sdamien return error; 713156321Sdamien} 714156321Sdamien 715156321Sdamienstatic void 716156321Sdamienrt2560_reset_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) 717156321Sdamien{ 718156321Sdamien int i; 719156321Sdamien 720156321Sdamien for (i = 0; i < ring->count; i++) { 721156321Sdamien ring->desc[i].flags = htole32(RT2560_RX_BUSY); 722156321Sdamien ring->data[i].drop = 0; 723156321Sdamien } 724156321Sdamien 725156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 726156321Sdamien 727156321Sdamien ring->cur = ring->next = 0; 728156321Sdamien ring->cur_decrypt = 0; 729156321Sdamien} 730156321Sdamien 731156321Sdamienstatic void 732156321Sdamienrt2560_free_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) 733156321Sdamien{ 734156321Sdamien struct rt2560_rx_data *data; 735156321Sdamien int i; 736156321Sdamien 737156321Sdamien if (ring->desc != NULL) { 738156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 739156321Sdamien BUS_DMASYNC_POSTWRITE); 740156321Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 741156321Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 742156321Sdamien } 743156321Sdamien 744156321Sdamien if (ring->desc_dmat != NULL) 745156321Sdamien bus_dma_tag_destroy(ring->desc_dmat); 746156321Sdamien 747156321Sdamien if (ring->data != NULL) { 748156321Sdamien for (i = 0; i < ring->count; i++) { 749156321Sdamien data = &ring->data[i]; 750156321Sdamien 751156321Sdamien if (data->m != NULL) { 752156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 753156321Sdamien BUS_DMASYNC_POSTREAD); 754156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 755156321Sdamien m_freem(data->m); 756156321Sdamien } 757156321Sdamien 758156321Sdamien if (data->map != NULL) 759156321Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 760156321Sdamien } 761156321Sdamien 762156321Sdamien free(ring->data, M_DEVBUF); 763156321Sdamien } 764156321Sdamien 765156321Sdamien if (ring->data_dmat != NULL) 766156321Sdamien bus_dma_tag_destroy(ring->data_dmat); 767156321Sdamien} 768156321Sdamien 769156321Sdamienstatic struct ieee80211_node * 770179643Ssamrt2560_node_alloc(struct ieee80211vap *vap, 771179643Ssam const uint8_t mac[IEEE80211_ADDR_LEN]) 772156321Sdamien{ 773156321Sdamien struct rt2560_node *rn; 774156321Sdamien 775156321Sdamien rn = malloc(sizeof (struct rt2560_node), M_80211_NODE, 776156321Sdamien M_NOWAIT | M_ZERO); 777156321Sdamien 778156321Sdamien return (rn != NULL) ? &rn->ni : NULL; 779156321Sdamien} 780156321Sdamien 781156321Sdamienstatic void 782178354Ssamrt2560_newassoc(struct ieee80211_node *ni, int isnew) 783156321Sdamien{ 784178354Ssam struct ieee80211vap *vap = ni->ni_vap; 785156321Sdamien 786178354Ssam ieee80211_amrr_node_init(&RT2560_VAP(vap)->amrr, 787178354Ssam &RT2560_NODE(ni)->amrr, ni); 788156321Sdamien} 789156321Sdamien 790156321Sdamienstatic int 791178354Ssamrt2560_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 792156321Sdamien{ 793178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 794178354Ssam struct ifnet *ifp = vap->iv_ic->ic_ifp; 795178354Ssam struct rt2560_softc *sc = ifp->if_softc; 796178354Ssam int error; 797156321Sdamien 798178354Ssam if (nstate == IEEE80211_S_INIT && vap->iv_state == IEEE80211_S_RUN) { 799178354Ssam /* abort TSF synchronization */ 800178354Ssam RAL_WRITE(sc, RT2560_CSR14, 0); 801156321Sdamien 802178354Ssam /* turn association led off */ 803178354Ssam rt2560_update_led(sc, 0, 0); 804178354Ssam } 805156321Sdamien 806178354Ssam error = rvp->ral_newstate(vap, nstate, arg); 807156321Sdamien 808178354Ssam if (error == 0 && nstate == IEEE80211_S_RUN) { 809178354Ssam struct ieee80211_node *ni = vap->iv_bss; 810178354Ssam struct mbuf *m; 811156321Sdamien 812178354Ssam if (vap->iv_opmode != IEEE80211_M_MONITOR) { 813156321Sdamien rt2560_update_plcp(sc); 814156321Sdamien rt2560_set_basicrates(sc); 815156321Sdamien rt2560_set_bssid(sc, ni->ni_bssid); 816156321Sdamien } 817156321Sdamien 818178354Ssam if (vap->iv_opmode == IEEE80211_M_HOSTAP || 819178354Ssam vap->iv_opmode == IEEE80211_M_IBSS) { 820178354Ssam m = ieee80211_beacon_alloc(ni, &rvp->ral_bo); 821156321Sdamien if (m == NULL) { 822178354Ssam if_printf(ifp, "could not allocate beacon\n"); 823178354Ssam return ENOBUFS; 824156321Sdamien } 825156321Sdamien ieee80211_ref_node(ni); 826156321Sdamien error = rt2560_tx_bcn(sc, m, ni); 827156321Sdamien if (error != 0) 828178354Ssam return error; 829156321Sdamien } 830156321Sdamien 831156321Sdamien /* turn assocation led on */ 832156321Sdamien rt2560_update_led(sc, 1, 0); 833156321Sdamien 834178354Ssam if (vap->iv_opmode != IEEE80211_M_MONITOR) { 835178354Ssam if (vap->iv_opmode == IEEE80211_M_STA) { 836178354Ssam /* fake a join to init the tx rate */ 837178354Ssam rt2560_newassoc(ni, 1); 838178354Ssam } 839156321Sdamien rt2560_enable_tsf_sync(sc); 840156321Sdamien } 841156321Sdamien } 842178354Ssam return error; 843156321Sdamien} 844156321Sdamien 845156321Sdamien/* 846156321Sdamien * Read 16 bits at address 'addr' from the serial EEPROM (either 93C46 or 847156321Sdamien * 93C66). 848156321Sdamien */ 849156321Sdamienstatic uint16_t 850156321Sdamienrt2560_eeprom_read(struct rt2560_softc *sc, uint8_t addr) 851156321Sdamien{ 852156321Sdamien uint32_t tmp; 853156321Sdamien uint16_t val; 854156321Sdamien int n; 855156321Sdamien 856156321Sdamien /* clock C once before the first command */ 857156321Sdamien RT2560_EEPROM_CTL(sc, 0); 858156321Sdamien 859156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 860156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 861156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 862156321Sdamien 863156321Sdamien /* write start bit (1) */ 864156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D); 865156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C); 866156321Sdamien 867156321Sdamien /* write READ opcode (10) */ 868156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D); 869156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C); 870156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 871156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 872156321Sdamien 873156321Sdamien /* write address (A5-A0 or A7-A0) */ 874156321Sdamien n = (RAL_READ(sc, RT2560_CSR21) & RT2560_93C46) ? 5 : 7; 875156321Sdamien for (; n >= 0; n--) { 876156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | 877156321Sdamien (((addr >> n) & 1) << RT2560_SHIFT_D)); 878156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | 879156321Sdamien (((addr >> n) & 1) << RT2560_SHIFT_D) | RT2560_C); 880156321Sdamien } 881156321Sdamien 882156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 883156321Sdamien 884156321Sdamien /* read data Q15-Q0 */ 885156321Sdamien val = 0; 886156321Sdamien for (n = 15; n >= 0; n--) { 887156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 888156321Sdamien tmp = RAL_READ(sc, RT2560_CSR21); 889156321Sdamien val |= ((tmp & RT2560_Q) >> RT2560_SHIFT_Q) << n; 890156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 891156321Sdamien } 892156321Sdamien 893156321Sdamien RT2560_EEPROM_CTL(sc, 0); 894156321Sdamien 895156321Sdamien /* clear Chip Select and clock C */ 896156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 897156321Sdamien RT2560_EEPROM_CTL(sc, 0); 898156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_C); 899156321Sdamien 900156321Sdamien return val; 901156321Sdamien} 902156321Sdamien 903156321Sdamien/* 904156321Sdamien * Some frames were processed by the hardware cipher engine and are ready for 905156321Sdamien * transmission. 906156321Sdamien */ 907156321Sdamienstatic void 908156321Sdamienrt2560_encryption_intr(struct rt2560_softc *sc) 909156321Sdamien{ 910156321Sdamien struct rt2560_tx_desc *desc; 911156321Sdamien int hw; 912156321Sdamien 913156321Sdamien /* retrieve last descriptor index processed by cipher engine */ 914156321Sdamien hw = RAL_READ(sc, RT2560_SECCSR1) - sc->txq.physaddr; 915156321Sdamien hw /= RT2560_TX_DESC_SIZE; 916156321Sdamien 917156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 918156321Sdamien BUS_DMASYNC_POSTREAD); 919156321Sdamien 920175938Ssephe while (sc->txq.next_encrypt != hw) { 921175938Ssephe if (sc->txq.next_encrypt == sc->txq.cur_encrypt) { 922175938Ssephe printf("hw encrypt %d, cur_encrypt %d\n", hw, 923175938Ssephe sc->txq.cur_encrypt); 924175938Ssephe break; 925175938Ssephe } 926175938Ssephe 927156321Sdamien desc = &sc->txq.desc[sc->txq.next_encrypt]; 928156321Sdamien 929156321Sdamien if ((le32toh(desc->flags) & RT2560_TX_BUSY) || 930156321Sdamien (le32toh(desc->flags) & RT2560_TX_CIPHER_BUSY)) 931156321Sdamien break; 932156321Sdamien 933156321Sdamien /* for TKIP, swap eiv field to fix a bug in ASIC */ 934156321Sdamien if ((le32toh(desc->flags) & RT2560_TX_CIPHER_MASK) == 935156321Sdamien RT2560_TX_CIPHER_TKIP) 936156321Sdamien desc->eiv = bswap32(desc->eiv); 937156321Sdamien 938156321Sdamien /* mark the frame ready for transmission */ 939175938Ssephe desc->flags |= htole32(RT2560_TX_VALID); 940175938Ssephe desc->flags |= htole32(RT2560_TX_BUSY); 941156321Sdamien 942178354Ssam DPRINTFN(sc, 15, "encryption done idx=%u\n", 943178354Ssam sc->txq.next_encrypt); 944156321Sdamien 945156321Sdamien sc->txq.next_encrypt = 946156321Sdamien (sc->txq.next_encrypt + 1) % RT2560_TX_RING_COUNT; 947156321Sdamien } 948156321Sdamien 949156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 950156321Sdamien BUS_DMASYNC_PREWRITE); 951156321Sdamien 952156321Sdamien /* kick Tx */ 953156321Sdamien RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_TX); 954156321Sdamien} 955156321Sdamien 956156321Sdamienstatic void 957156321Sdamienrt2560_tx_intr(struct rt2560_softc *sc) 958156321Sdamien{ 959178354Ssam struct ifnet *ifp = sc->sc_ifp; 960156321Sdamien struct rt2560_tx_desc *desc; 961156321Sdamien struct rt2560_tx_data *data; 962156321Sdamien struct rt2560_node *rn; 963178354Ssam struct mbuf *m; 964178354Ssam uint32_t flags; 965178354Ssam int retrycnt; 966156321Sdamien 967156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 968156321Sdamien BUS_DMASYNC_POSTREAD); 969156321Sdamien 970156321Sdamien for (;;) { 971156321Sdamien desc = &sc->txq.desc[sc->txq.next]; 972156321Sdamien data = &sc->txq.data[sc->txq.next]; 973156321Sdamien 974178354Ssam flags = le32toh(desc->flags); 975178354Ssam if ((flags & RT2560_TX_BUSY) || 976178354Ssam (flags & RT2560_TX_CIPHER_BUSY) || 977178354Ssam !(flags & RT2560_TX_VALID)) 978156321Sdamien break; 979156321Sdamien 980156321Sdamien rn = (struct rt2560_node *)data->ni; 981178354Ssam m = data->m; 982156321Sdamien 983178354Ssam switch (flags & RT2560_TX_RESULT_MASK) { 984156321Sdamien case RT2560_TX_SUCCESS: 985178354Ssam DPRINTFN(sc, 10, "%s\n", "data frame sent successfully"); 986178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 987178354Ssam ieee80211_amrr_tx_complete(&rn->amrr, 988178354Ssam IEEE80211_AMRR_SUCCESS, 0); 989156321Sdamien ifp->if_opackets++; 990156321Sdamien break; 991156321Sdamien 992156321Sdamien case RT2560_TX_SUCCESS_RETRY: 993178354Ssam retrycnt = RT2560_TX_RETRYCNT(flags); 994178354Ssam 995178354Ssam DPRINTFN(sc, 9, "data frame sent after %u retries\n", 996178354Ssam retrycnt); 997178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 998178354Ssam ieee80211_amrr_tx_complete(&rn->amrr, 999178354Ssam IEEE80211_AMRR_SUCCESS, retrycnt); 1000156321Sdamien ifp->if_opackets++; 1001156321Sdamien break; 1002156321Sdamien 1003156321Sdamien case RT2560_TX_FAIL_RETRY: 1004178354Ssam retrycnt = RT2560_TX_RETRYCNT(flags); 1005178354Ssam 1006178354Ssam DPRINTFN(sc, 9, "data frame failed after %d retries\n", 1007178354Ssam retrycnt); 1008178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 1009178354Ssam ieee80211_amrr_tx_complete(&rn->amrr, 1010178354Ssam IEEE80211_AMRR_FAILURE, retrycnt); 1011156321Sdamien ifp->if_oerrors++; 1012156321Sdamien break; 1013156321Sdamien 1014156321Sdamien case RT2560_TX_FAIL_INVALID: 1015156321Sdamien case RT2560_TX_FAIL_OTHER: 1016156321Sdamien default: 1017156321Sdamien device_printf(sc->sc_dev, "sending data frame failed " 1018178354Ssam "0x%08x\n", flags); 1019156321Sdamien ifp->if_oerrors++; 1020156321Sdamien } 1021156321Sdamien 1022156321Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, 1023156321Sdamien BUS_DMASYNC_POSTWRITE); 1024156321Sdamien bus_dmamap_unload(sc->txq.data_dmat, data->map); 1025178354Ssam m_freem(m); 1026156321Sdamien data->m = NULL; 1027156321Sdamien ieee80211_free_node(data->ni); 1028156321Sdamien data->ni = NULL; 1029156321Sdamien 1030156321Sdamien /* descriptor is no longer valid */ 1031156321Sdamien desc->flags &= ~htole32(RT2560_TX_VALID); 1032156321Sdamien 1033178354Ssam DPRINTFN(sc, 15, "tx done idx=%u\n", sc->txq.next); 1034156321Sdamien 1035156321Sdamien sc->txq.queued--; 1036156321Sdamien sc->txq.next = (sc->txq.next + 1) % RT2560_TX_RING_COUNT; 1037156321Sdamien } 1038156321Sdamien 1039156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 1040156321Sdamien BUS_DMASYNC_PREWRITE); 1041156321Sdamien 1042175938Ssephe if (sc->prioq.queued == 0 && sc->txq.queued == 0) 1043175938Ssephe sc->sc_tx_timer = 0; 1044175938Ssephe 1045175938Ssephe if (sc->txq.queued < RT2560_TX_RING_COUNT - 1) { 1046175938Ssephe sc->sc_flags &= ~RT2560_F_DATA_OACTIVE; 1047175938Ssephe if ((sc->sc_flags & 1048175938Ssephe (RT2560_F_DATA_OACTIVE | RT2560_F_PRIO_OACTIVE)) == 0) 1049175938Ssephe ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1050178354Ssam rt2560_start_locked(ifp); 1051175938Ssephe } 1052156321Sdamien} 1053156321Sdamien 1054156321Sdamienstatic void 1055156321Sdamienrt2560_prio_intr(struct rt2560_softc *sc) 1056156321Sdamien{ 1057178354Ssam struct ifnet *ifp = sc->sc_ifp; 1058156321Sdamien struct rt2560_tx_desc *desc; 1059156321Sdamien struct rt2560_tx_data *data; 1060170530Ssam struct ieee80211_node *ni; 1061170530Ssam struct mbuf *m; 1062170530Ssam int flags; 1063156321Sdamien 1064156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1065156321Sdamien BUS_DMASYNC_POSTREAD); 1066156321Sdamien 1067156321Sdamien for (;;) { 1068156321Sdamien desc = &sc->prioq.desc[sc->prioq.next]; 1069156321Sdamien data = &sc->prioq.data[sc->prioq.next]; 1070156321Sdamien 1071170530Ssam flags = le32toh(desc->flags); 1072170530Ssam if ((flags & RT2560_TX_BUSY) || (flags & RT2560_TX_VALID) == 0) 1073156321Sdamien break; 1074156321Sdamien 1075170530Ssam switch (flags & RT2560_TX_RESULT_MASK) { 1076156321Sdamien case RT2560_TX_SUCCESS: 1077178354Ssam DPRINTFN(sc, 10, "%s\n", "mgt frame sent successfully"); 1078156321Sdamien break; 1079156321Sdamien 1080156321Sdamien case RT2560_TX_SUCCESS_RETRY: 1081178354Ssam DPRINTFN(sc, 9, "mgt frame sent after %u retries\n", 1082178354Ssam (flags >> 5) & 0x7); 1083156321Sdamien break; 1084156321Sdamien 1085156321Sdamien case RT2560_TX_FAIL_RETRY: 1086178354Ssam DPRINTFN(sc, 9, "%s\n", 1087178354Ssam "sending mgt frame failed (too much retries)"); 1088156321Sdamien break; 1089156321Sdamien 1090156321Sdamien case RT2560_TX_FAIL_INVALID: 1091156321Sdamien case RT2560_TX_FAIL_OTHER: 1092156321Sdamien default: 1093156321Sdamien device_printf(sc->sc_dev, "sending mgt frame failed " 1094170530Ssam "0x%08x\n", flags); 1095170530Ssam break; 1096156321Sdamien } 1097156321Sdamien 1098156321Sdamien bus_dmamap_sync(sc->prioq.data_dmat, data->map, 1099156321Sdamien BUS_DMASYNC_POSTWRITE); 1100156321Sdamien bus_dmamap_unload(sc->prioq.data_dmat, data->map); 1101170530Ssam 1102170530Ssam m = data->m; 1103156321Sdamien data->m = NULL; 1104170530Ssam ni = data->ni; 1105156321Sdamien data->ni = NULL; 1106156321Sdamien 1107156321Sdamien /* descriptor is no longer valid */ 1108156321Sdamien desc->flags &= ~htole32(RT2560_TX_VALID); 1109156321Sdamien 1110178354Ssam DPRINTFN(sc, 15, "prio done idx=%u\n", sc->prioq.next); 1111156321Sdamien 1112156321Sdamien sc->prioq.queued--; 1113156321Sdamien sc->prioq.next = (sc->prioq.next + 1) % RT2560_PRIO_RING_COUNT; 1114170530Ssam 1115170530Ssam if (m->m_flags & M_TXCB) 1116170530Ssam ieee80211_process_callback(ni, m, 1117170530Ssam (flags & RT2560_TX_RESULT_MASK) &~ 1118170530Ssam (RT2560_TX_SUCCESS | RT2560_TX_SUCCESS_RETRY)); 1119170530Ssam m_freem(m); 1120170530Ssam ieee80211_free_node(ni); 1121156321Sdamien } 1122156321Sdamien 1123156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1124156321Sdamien BUS_DMASYNC_PREWRITE); 1125156321Sdamien 1126175938Ssephe if (sc->prioq.queued == 0 && sc->txq.queued == 0) 1127175938Ssephe sc->sc_tx_timer = 0; 1128175938Ssephe 1129175938Ssephe if (sc->prioq.queued < RT2560_PRIO_RING_COUNT) { 1130175938Ssephe sc->sc_flags &= ~RT2560_F_PRIO_OACTIVE; 1131175938Ssephe if ((sc->sc_flags & 1132175938Ssephe (RT2560_F_DATA_OACTIVE | RT2560_F_PRIO_OACTIVE)) == 0) 1133175938Ssephe ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1134178354Ssam rt2560_start_locked(ifp); 1135175938Ssephe } 1136156321Sdamien} 1137156321Sdamien 1138156321Sdamien/* 1139156321Sdamien * Some frames were processed by the hardware cipher engine and are ready for 1140178354Ssam * handoff to the IEEE802.11 layer. 1141156321Sdamien */ 1142156321Sdamienstatic void 1143156321Sdamienrt2560_decryption_intr(struct rt2560_softc *sc) 1144156321Sdamien{ 1145178354Ssam struct ifnet *ifp = sc->sc_ifp; 1146178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1147156321Sdamien struct rt2560_rx_desc *desc; 1148156321Sdamien struct rt2560_rx_data *data; 1149156321Sdamien bus_addr_t physaddr; 1150156321Sdamien struct ieee80211_frame *wh; 1151156321Sdamien struct ieee80211_node *ni; 1152156321Sdamien struct mbuf *mnew, *m; 1153156321Sdamien int hw, error; 1154156321Sdamien 1155156321Sdamien /* retrieve last decriptor index processed by cipher engine */ 1156156321Sdamien hw = RAL_READ(sc, RT2560_SECCSR0) - sc->rxq.physaddr; 1157156321Sdamien hw /= RT2560_RX_DESC_SIZE; 1158156321Sdamien 1159156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1160156321Sdamien BUS_DMASYNC_POSTREAD); 1161156321Sdamien 1162156321Sdamien for (; sc->rxq.cur_decrypt != hw;) { 1163156321Sdamien desc = &sc->rxq.desc[sc->rxq.cur_decrypt]; 1164156321Sdamien data = &sc->rxq.data[sc->rxq.cur_decrypt]; 1165156321Sdamien 1166156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_BUSY) || 1167156321Sdamien (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY)) 1168156321Sdamien break; 1169156321Sdamien 1170156321Sdamien if (data->drop) { 1171156321Sdamien ifp->if_ierrors++; 1172156321Sdamien goto skip; 1173156321Sdamien } 1174156321Sdamien 1175156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_CIPHER_MASK) != 0 && 1176156321Sdamien (le32toh(desc->flags) & RT2560_RX_ICV_ERROR)) { 1177156321Sdamien ifp->if_ierrors++; 1178156321Sdamien goto skip; 1179156321Sdamien } 1180156321Sdamien 1181156321Sdamien /* 1182156321Sdamien * Try to allocate a new mbuf for this ring element and load it 1183156321Sdamien * before processing the current mbuf. If the ring element 1184156321Sdamien * cannot be loaded, drop the received packet and reuse the old 1185156321Sdamien * mbuf. In the unlikely case that the old mbuf can't be 1186156321Sdamien * reloaded either, explicitly panic. 1187156321Sdamien */ 1188156321Sdamien mnew = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1189156321Sdamien if (mnew == NULL) { 1190156321Sdamien ifp->if_ierrors++; 1191156321Sdamien goto skip; 1192156321Sdamien } 1193156321Sdamien 1194156321Sdamien bus_dmamap_sync(sc->rxq.data_dmat, data->map, 1195156321Sdamien BUS_DMASYNC_POSTREAD); 1196156321Sdamien bus_dmamap_unload(sc->rxq.data_dmat, data->map); 1197156321Sdamien 1198156321Sdamien error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 1199156321Sdamien mtod(mnew, void *), MCLBYTES, rt2560_dma_map_addr, 1200156321Sdamien &physaddr, 0); 1201156321Sdamien if (error != 0) { 1202156321Sdamien m_freem(mnew); 1203156321Sdamien 1204156321Sdamien /* try to reload the old mbuf */ 1205156321Sdamien error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 1206156321Sdamien mtod(data->m, void *), MCLBYTES, 1207156321Sdamien rt2560_dma_map_addr, &physaddr, 0); 1208156321Sdamien if (error != 0) { 1209156321Sdamien /* very unlikely that it will fail... */ 1210156321Sdamien panic("%s: could not load old rx mbuf", 1211156321Sdamien device_get_name(sc->sc_dev)); 1212156321Sdamien } 1213156321Sdamien ifp->if_ierrors++; 1214156321Sdamien goto skip; 1215156321Sdamien } 1216156321Sdamien 1217156321Sdamien /* 1218156321Sdamien * New mbuf successfully loaded, update Rx ring and continue 1219156321Sdamien * processing. 1220156321Sdamien */ 1221156321Sdamien m = data->m; 1222156321Sdamien data->m = mnew; 1223156321Sdamien desc->physaddr = htole32(physaddr); 1224156321Sdamien 1225156321Sdamien /* finalize mbuf */ 1226156321Sdamien m->m_pkthdr.rcvif = ifp; 1227156321Sdamien m->m_pkthdr.len = m->m_len = 1228156321Sdamien (le32toh(desc->flags) >> 16) & 0xfff; 1229156321Sdamien 1230178354Ssam if (bpf_peers_present(ifp->if_bpf)) { 1231156321Sdamien struct rt2560_rx_radiotap_header *tap = &sc->sc_rxtap; 1232156321Sdamien uint32_t tsf_lo, tsf_hi; 1233156321Sdamien 1234156321Sdamien /* get timestamp (low and high 32 bits) */ 1235156321Sdamien tsf_hi = RAL_READ(sc, RT2560_CSR17); 1236156321Sdamien tsf_lo = RAL_READ(sc, RT2560_CSR16); 1237156321Sdamien 1238156321Sdamien tap->wr_tsf = 1239156321Sdamien htole64(((uint64_t)tsf_hi << 32) | tsf_lo); 1240156321Sdamien tap->wr_flags = 0; 1241178354Ssam tap->wr_rate = ieee80211_plcp2rate(desc->rate, 1242178958Ssam (desc->flags & htole32(RT2560_RX_OFDM)) ? 1243178958Ssam IEEE80211_T_OFDM : IEEE80211_T_CCK); 1244156321Sdamien tap->wr_antenna = sc->rx_ant; 1245170530Ssam tap->wr_antsignal = RT2560_RSSI(sc, desc->rssi); 1246156321Sdamien 1247178354Ssam bpf_mtap2(ifp->if_bpf, tap, sc->sc_rxtap_len, m); 1248156321Sdamien } 1249156321Sdamien 1250175938Ssephe sc->sc_flags |= RT2560_F_INPUT_RUNNING; 1251170530Ssam RAL_UNLOCK(sc); 1252156321Sdamien wh = mtod(m, struct ieee80211_frame *); 1253156321Sdamien ni = ieee80211_find_rxnode(ic, 1254156321Sdamien (struct ieee80211_frame_min *)wh); 1255178354Ssam if (ni != NULL) { 1256178354Ssam (void) ieee80211_input(ni, m, 1257178354Ssam RT2560_RSSI(sc, desc->rssi), RT2560_NOISE_FLOOR, 0); 1258178354Ssam ieee80211_free_node(ni); 1259178354Ssam } else 1260178354Ssam (void) ieee80211_input_all(ic, m, 1261178354Ssam RT2560_RSSI(sc, desc->rssi), RT2560_NOISE_FLOOR, 0); 1262156321Sdamien 1263170530Ssam RAL_LOCK(sc); 1264175938Ssephe sc->sc_flags &= ~RT2560_F_INPUT_RUNNING; 1265156321Sdamienskip: desc->flags = htole32(RT2560_RX_BUSY); 1266156321Sdamien 1267178354Ssam DPRINTFN(sc, 15, "decryption done idx=%u\n", sc->rxq.cur_decrypt); 1268156321Sdamien 1269156321Sdamien sc->rxq.cur_decrypt = 1270156321Sdamien (sc->rxq.cur_decrypt + 1) % RT2560_RX_RING_COUNT; 1271156321Sdamien } 1272156321Sdamien 1273156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1274156321Sdamien BUS_DMASYNC_PREWRITE); 1275156321Sdamien} 1276156321Sdamien 1277156321Sdamien/* 1278156321Sdamien * Some frames were received. Pass them to the hardware cipher engine before 1279156321Sdamien * sending them to the 802.11 layer. 1280156321Sdamien */ 1281156321Sdamienstatic void 1282156321Sdamienrt2560_rx_intr(struct rt2560_softc *sc) 1283156321Sdamien{ 1284156321Sdamien struct rt2560_rx_desc *desc; 1285156321Sdamien struct rt2560_rx_data *data; 1286156321Sdamien 1287156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1288156321Sdamien BUS_DMASYNC_POSTREAD); 1289156321Sdamien 1290156321Sdamien for (;;) { 1291156321Sdamien desc = &sc->rxq.desc[sc->rxq.cur]; 1292156321Sdamien data = &sc->rxq.data[sc->rxq.cur]; 1293156321Sdamien 1294156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_BUSY) || 1295156321Sdamien (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY)) 1296156321Sdamien break; 1297156321Sdamien 1298156321Sdamien data->drop = 0; 1299156321Sdamien 1300156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_PHY_ERROR) || 1301156321Sdamien (le32toh(desc->flags) & RT2560_RX_CRC_ERROR)) { 1302156321Sdamien /* 1303156321Sdamien * This should not happen since we did not request 1304156321Sdamien * to receive those frames when we filled RXCSR0. 1305156321Sdamien */ 1306178354Ssam DPRINTFN(sc, 5, "PHY or CRC error flags 0x%08x\n", 1307178354Ssam le32toh(desc->flags)); 1308156321Sdamien data->drop = 1; 1309156321Sdamien } 1310156321Sdamien 1311156321Sdamien if (((le32toh(desc->flags) >> 16) & 0xfff) > MCLBYTES) { 1312178354Ssam DPRINTFN(sc, 5, "%s\n", "bad length"); 1313156321Sdamien data->drop = 1; 1314156321Sdamien } 1315156321Sdamien 1316156321Sdamien /* mark the frame for decryption */ 1317156321Sdamien desc->flags |= htole32(RT2560_RX_CIPHER_BUSY); 1318156321Sdamien 1319178354Ssam DPRINTFN(sc, 15, "rx done idx=%u\n", sc->rxq.cur); 1320156321Sdamien 1321156321Sdamien sc->rxq.cur = (sc->rxq.cur + 1) % RT2560_RX_RING_COUNT; 1322156321Sdamien } 1323156321Sdamien 1324156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1325156321Sdamien BUS_DMASYNC_PREWRITE); 1326156321Sdamien 1327156321Sdamien /* kick decrypt */ 1328156321Sdamien RAL_WRITE(sc, RT2560_SECCSR0, RT2560_KICK_DECRYPT); 1329156321Sdamien} 1330156321Sdamien 1331172211Ssamstatic void 1332178354Ssamrt2560_beacon_update(struct ieee80211vap *vap, int item) 1333172211Ssam{ 1334178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 1335178354Ssam struct ieee80211_beacon_offsets *bo = &rvp->ral_bo; 1336172211Ssam 1337172211Ssam setbit(bo->bo_flags, item); 1338172211Ssam} 1339172211Ssam 1340156321Sdamien/* 1341156321Sdamien * This function is called periodically in IBSS mode when a new beacon must be 1342156321Sdamien * sent out. 1343156321Sdamien */ 1344156321Sdamienstatic void 1345156321Sdamienrt2560_beacon_expire(struct rt2560_softc *sc) 1346156321Sdamien{ 1347178354Ssam struct ifnet *ifp = sc->sc_ifp; 1348178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1349178354Ssam struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 1350178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 1351156321Sdamien struct rt2560_tx_data *data; 1352156321Sdamien 1353156321Sdamien if (ic->ic_opmode != IEEE80211_M_IBSS && 1354156321Sdamien ic->ic_opmode != IEEE80211_M_HOSTAP) 1355170530Ssam return; 1356156321Sdamien 1357156321Sdamien data = &sc->bcnq.data[sc->bcnq.next]; 1358170530Ssam /* 1359170530Ssam * Don't send beacon if bsschan isn't set 1360170530Ssam */ 1361170530Ssam if (data->ni == NULL) 1362170530Ssam return; 1363156321Sdamien 1364156321Sdamien bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_POSTWRITE); 1365156321Sdamien bus_dmamap_unload(sc->bcnq.data_dmat, data->map); 1366156321Sdamien 1367178354Ssam /* XXX 1 =>'s mcast frames which means all PS sta's will wakeup! */ 1368178354Ssam ieee80211_beacon_update(data->ni, &rvp->ral_bo, data->m, 1); 1369156321Sdamien 1370156321Sdamien rt2560_tx_bcn(sc, data->m, data->ni); 1371156321Sdamien 1372178354Ssam DPRINTFN(sc, 15, "%s", "beacon expired\n"); 1373156321Sdamien 1374156321Sdamien sc->bcnq.next = (sc->bcnq.next + 1) % RT2560_BEACON_RING_COUNT; 1375156321Sdamien} 1376156321Sdamien 1377156321Sdamien/* ARGSUSED */ 1378156321Sdamienstatic void 1379156321Sdamienrt2560_wakeup_expire(struct rt2560_softc *sc) 1380156321Sdamien{ 1381178354Ssam DPRINTFN(sc, 2, "%s", "wakeup expired\n"); 1382156321Sdamien} 1383156321Sdamien 1384156321Sdamienvoid 1385156321Sdamienrt2560_intr(void *arg) 1386156321Sdamien{ 1387156321Sdamien struct rt2560_softc *sc = arg; 1388156975Sdamien struct ifnet *ifp = sc->sc_ifp; 1389156321Sdamien uint32_t r; 1390156321Sdamien 1391156321Sdamien RAL_LOCK(sc); 1392156321Sdamien 1393156321Sdamien /* disable interrupts */ 1394156321Sdamien RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 1395156321Sdamien 1396156975Sdamien /* don't re-enable interrupts if we're shutting down */ 1397156975Sdamien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1398156975Sdamien RAL_UNLOCK(sc); 1399156975Sdamien return; 1400156975Sdamien } 1401156975Sdamien 1402156321Sdamien r = RAL_READ(sc, RT2560_CSR7); 1403156321Sdamien RAL_WRITE(sc, RT2560_CSR7, r); 1404156321Sdamien 1405156321Sdamien if (r & RT2560_BEACON_EXPIRE) 1406156321Sdamien rt2560_beacon_expire(sc); 1407156321Sdamien 1408156321Sdamien if (r & RT2560_WAKEUP_EXPIRE) 1409156321Sdamien rt2560_wakeup_expire(sc); 1410156321Sdamien 1411156321Sdamien if (r & RT2560_ENCRYPTION_DONE) 1412156321Sdamien rt2560_encryption_intr(sc); 1413156321Sdamien 1414156321Sdamien if (r & RT2560_TX_DONE) 1415156321Sdamien rt2560_tx_intr(sc); 1416156321Sdamien 1417156321Sdamien if (r & RT2560_PRIO_DONE) 1418156321Sdamien rt2560_prio_intr(sc); 1419156321Sdamien 1420156321Sdamien if (r & RT2560_DECRYPTION_DONE) 1421156321Sdamien rt2560_decryption_intr(sc); 1422156321Sdamien 1423175938Ssephe if (r & RT2560_RX_DONE) { 1424156321Sdamien rt2560_rx_intr(sc); 1425175938Ssephe rt2560_encryption_intr(sc); 1426175938Ssephe } 1427156321Sdamien 1428156321Sdamien /* re-enable interrupts */ 1429156321Sdamien RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); 1430156321Sdamien 1431156321Sdamien RAL_UNLOCK(sc); 1432156321Sdamien} 1433156321Sdamien 1434156321Sdamien#define RAL_SIFS 10 /* us */ 1435156321Sdamien 1436156321Sdamien#define RT2560_TXRX_TURNAROUND 10 /* us */ 1437156321Sdamien 1438178958Ssamstatic uint8_t 1439178958Ssamrt2560_plcp_signal(int rate) 1440178958Ssam{ 1441178958Ssam switch (rate) { 1442178958Ssam /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ 1443178958Ssam case 12: return 0xb; 1444178958Ssam case 18: return 0xf; 1445178958Ssam case 24: return 0xa; 1446178958Ssam case 36: return 0xe; 1447178958Ssam case 48: return 0x9; 1448178958Ssam case 72: return 0xd; 1449178958Ssam case 96: return 0x8; 1450178958Ssam case 108: return 0xc; 1451178958Ssam 1452178958Ssam /* CCK rates (NB: not IEEE std, device-specific) */ 1453178958Ssam case 2: return 0x0; 1454178958Ssam case 4: return 0x1; 1455178958Ssam case 11: return 0x2; 1456178958Ssam case 22: return 0x3; 1457178958Ssam } 1458178958Ssam return 0xff; /* XXX unsupported/unknown rate */ 1459178958Ssam} 1460178958Ssam 1461156321Sdamienstatic void 1462156321Sdamienrt2560_setup_tx_desc(struct rt2560_softc *sc, struct rt2560_tx_desc *desc, 1463156321Sdamien uint32_t flags, int len, int rate, int encrypt, bus_addr_t physaddr) 1464156321Sdamien{ 1465178354Ssam struct ifnet *ifp = sc->sc_ifp; 1466178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1467156321Sdamien uint16_t plcp_length; 1468156321Sdamien int remainder; 1469156321Sdamien 1470156321Sdamien desc->flags = htole32(flags); 1471156321Sdamien desc->flags |= htole32(len << 16); 1472156321Sdamien 1473156321Sdamien desc->physaddr = htole32(physaddr); 1474156321Sdamien desc->wme = htole16( 1475156321Sdamien RT2560_AIFSN(2) | 1476156321Sdamien RT2560_LOGCWMIN(3) | 1477156321Sdamien RT2560_LOGCWMAX(8)); 1478156321Sdamien 1479156321Sdamien /* setup PLCP fields */ 1480178958Ssam desc->plcp_signal = rt2560_plcp_signal(rate); 1481156321Sdamien desc->plcp_service = 4; 1482156321Sdamien 1483156321Sdamien len += IEEE80211_CRC_LEN; 1484178354Ssam if (ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) { 1485156321Sdamien desc->flags |= htole32(RT2560_TX_OFDM); 1486156321Sdamien 1487156321Sdamien plcp_length = len & 0xfff; 1488156321Sdamien desc->plcp_length_hi = plcp_length >> 6; 1489156321Sdamien desc->plcp_length_lo = plcp_length & 0x3f; 1490156321Sdamien } else { 1491156321Sdamien plcp_length = (16 * len + rate - 1) / rate; 1492156321Sdamien if (rate == 22) { 1493156321Sdamien remainder = (16 * len) % 22; 1494156321Sdamien if (remainder != 0 && remainder < 7) 1495156321Sdamien desc->plcp_service |= RT2560_PLCP_LENGEXT; 1496156321Sdamien } 1497156321Sdamien desc->plcp_length_hi = plcp_length >> 8; 1498156321Sdamien desc->plcp_length_lo = plcp_length & 0xff; 1499156321Sdamien 1500156321Sdamien if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 1501156321Sdamien desc->plcp_signal |= 0x08; 1502156321Sdamien } 1503175938Ssephe 1504175938Ssephe if (!encrypt) 1505175938Ssephe desc->flags |= htole32(RT2560_TX_VALID); 1506175938Ssephe desc->flags |= encrypt ? htole32(RT2560_TX_CIPHER_BUSY) 1507175938Ssephe : htole32(RT2560_TX_BUSY); 1508156321Sdamien} 1509156321Sdamien 1510156321Sdamienstatic int 1511156321Sdamienrt2560_tx_bcn(struct rt2560_softc *sc, struct mbuf *m0, 1512156321Sdamien struct ieee80211_node *ni) 1513156321Sdamien{ 1514178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1515178354Ssam struct ieee80211com *ic = ni->ni_ic; 1516178354Ssam struct ifnet *ifp = sc->sc_ifp; 1517156321Sdamien struct rt2560_tx_desc *desc; 1518156321Sdamien struct rt2560_tx_data *data; 1519156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1520156321Sdamien int nsegs, rate, error; 1521156321Sdamien 1522156321Sdamien desc = &sc->bcnq.desc[sc->bcnq.cur]; 1523156321Sdamien data = &sc->bcnq.data[sc->bcnq.cur]; 1524156321Sdamien 1525178354Ssam /* XXX maybe a separate beacon rate? */ 1526178354Ssam rate = vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)].mgmtrate; 1527156321Sdamien 1528156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->bcnq.data_dmat, data->map, m0, 1529156321Sdamien segs, &nsegs, BUS_DMA_NOWAIT); 1530156321Sdamien if (error != 0) { 1531156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1532156321Sdamien error); 1533156321Sdamien m_freem(m0); 1534156321Sdamien return error; 1535156321Sdamien } 1536156321Sdamien 1537178354Ssam if (bpf_peers_present(ifp->if_bpf)) { 1538156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1539156321Sdamien 1540156321Sdamien tap->wt_flags = 0; 1541156321Sdamien tap->wt_rate = rate; 1542156321Sdamien tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 1543156321Sdamien tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 1544156321Sdamien tap->wt_antenna = sc->tx_ant; 1545156321Sdamien 1546178354Ssam bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); 1547156321Sdamien } 1548156321Sdamien 1549156321Sdamien data->m = m0; 1550156321Sdamien data->ni = ni; 1551156321Sdamien 1552156321Sdamien rt2560_setup_tx_desc(sc, desc, RT2560_TX_IFS_NEWBACKOFF | 1553156321Sdamien RT2560_TX_TIMESTAMP, m0->m_pkthdr.len, rate, 0, segs->ds_addr); 1554156321Sdamien 1555178354Ssam DPRINTFN(sc, 10, "sending beacon frame len=%u idx=%u rate=%u\n", 1556178354Ssam m0->m_pkthdr.len, sc->bcnq.cur, rate); 1557156321Sdamien 1558156321Sdamien bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1559156321Sdamien bus_dmamap_sync(sc->bcnq.desc_dmat, sc->bcnq.desc_map, 1560156321Sdamien BUS_DMASYNC_PREWRITE); 1561156321Sdamien 1562156321Sdamien sc->bcnq.cur = (sc->bcnq.cur + 1) % RT2560_BEACON_RING_COUNT; 1563156321Sdamien 1564156321Sdamien return 0; 1565156321Sdamien} 1566156321Sdamien 1567156321Sdamienstatic int 1568156321Sdamienrt2560_tx_mgt(struct rt2560_softc *sc, struct mbuf *m0, 1569156321Sdamien struct ieee80211_node *ni) 1570156321Sdamien{ 1571178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1572178354Ssam struct ieee80211com *ic = ni->ni_ic; 1573178354Ssam struct ifnet *ifp = sc->sc_ifp; 1574156321Sdamien struct rt2560_tx_desc *desc; 1575156321Sdamien struct rt2560_tx_data *data; 1576156321Sdamien struct ieee80211_frame *wh; 1577173386Skevlo struct ieee80211_key *k; 1578156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1579156321Sdamien uint16_t dur; 1580156321Sdamien uint32_t flags = 0; 1581156321Sdamien int nsegs, rate, error; 1582156321Sdamien 1583156321Sdamien desc = &sc->prioq.desc[sc->prioq.cur]; 1584156321Sdamien data = &sc->prioq.data[sc->prioq.cur]; 1585156321Sdamien 1586178354Ssam rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate; 1587156321Sdamien 1588173386Skevlo wh = mtod(m0, struct ieee80211_frame *); 1589173386Skevlo 1590173386Skevlo if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1591178354Ssam k = ieee80211_crypto_encap(ni, m0); 1592173386Skevlo if (k == NULL) { 1593173386Skevlo m_freem(m0); 1594173386Skevlo return ENOBUFS; 1595173386Skevlo } 1596173386Skevlo } 1597173386Skevlo 1598156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, 1599156321Sdamien segs, &nsegs, 0); 1600156321Sdamien if (error != 0) { 1601156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1602156321Sdamien error); 1603156321Sdamien m_freem(m0); 1604156321Sdamien return error; 1605156321Sdamien } 1606156321Sdamien 1607178354Ssam if (bpf_peers_present(ifp->if_bpf)) { 1608156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1609156321Sdamien 1610156321Sdamien tap->wt_flags = 0; 1611156321Sdamien tap->wt_rate = rate; 1612156321Sdamien tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 1613156321Sdamien tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 1614156321Sdamien tap->wt_antenna = sc->tx_ant; 1615156321Sdamien 1616178354Ssam bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); 1617156321Sdamien } 1618156321Sdamien 1619156321Sdamien data->m = m0; 1620156321Sdamien data->ni = ni; 1621178354Ssam /* management frames are not taken into account for amrr */ 1622178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1623156321Sdamien 1624156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1625156321Sdamien 1626156321Sdamien if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1627156321Sdamien flags |= RT2560_TX_ACK; 1628156321Sdamien 1629178354Ssam dur = ieee80211_ack_duration(sc->sc_rates, 1630178354Ssam rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); 1631156321Sdamien *(uint16_t *)wh->i_dur = htole16(dur); 1632156321Sdamien 1633156321Sdamien /* tell hardware to add timestamp for probe responses */ 1634156321Sdamien if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 1635156321Sdamien IEEE80211_FC0_TYPE_MGT && 1636156321Sdamien (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 1637156321Sdamien IEEE80211_FC0_SUBTYPE_PROBE_RESP) 1638156321Sdamien flags |= RT2560_TX_TIMESTAMP; 1639156321Sdamien } 1640156321Sdamien 1641156321Sdamien rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 0, 1642156321Sdamien segs->ds_addr); 1643156321Sdamien 1644156321Sdamien bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1645156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1646156321Sdamien BUS_DMASYNC_PREWRITE); 1647156321Sdamien 1648178354Ssam DPRINTFN(sc, 10, "sending mgt frame len=%u idx=%u rate=%u\n", 1649178354Ssam m0->m_pkthdr.len, sc->prioq.cur, rate); 1650156321Sdamien 1651156321Sdamien /* kick prio */ 1652156321Sdamien sc->prioq.queued++; 1653156321Sdamien sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; 1654156321Sdamien RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); 1655156321Sdamien 1656156321Sdamien return 0; 1657156321Sdamien} 1658156321Sdamien 1659160691Ssamstatic int 1660178354Ssamrt2560_sendprot(struct rt2560_softc *sc, 1661178354Ssam const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) 1662178354Ssam{ 1663178354Ssam struct ieee80211com *ic = ni->ni_ic; 1664178354Ssam const struct ieee80211_frame *wh; 1665178354Ssam struct rt2560_tx_desc *desc; 1666178354Ssam struct rt2560_tx_data *data; 1667178354Ssam struct mbuf *mprot; 1668178354Ssam int protrate, ackrate, pktlen, flags, isshort, error; 1669178354Ssam uint16_t dur; 1670178354Ssam bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1671178354Ssam int nsegs; 1672178354Ssam 1673178354Ssam KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, 1674178354Ssam ("protection %d", prot)); 1675178354Ssam 1676178354Ssam wh = mtod(m, const struct ieee80211_frame *); 1677178354Ssam pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; 1678178354Ssam 1679178354Ssam protrate = ieee80211_ctl_rate(sc->sc_rates, rate); 1680178354Ssam ackrate = ieee80211_ack_rate(sc->sc_rates, rate); 1681178354Ssam 1682178354Ssam isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; 1683178948Ssam dur = ieee80211_compute_duration(sc->sc_rates, pktlen, rate, isshort) 1684178354Ssam + ieee80211_ack_duration(sc->sc_rates, rate, isshort); 1685178354Ssam flags = RT2560_TX_MORE_FRAG; 1686178354Ssam if (prot == IEEE80211_PROT_RTSCTS) { 1687178354Ssam /* NB: CTS is the same size as an ACK */ 1688178354Ssam dur += ieee80211_ack_duration(sc->sc_rates, rate, isshort); 1689178354Ssam flags |= RT2560_TX_ACK; 1690178354Ssam mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); 1691178354Ssam } else { 1692178354Ssam mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); 1693178354Ssam } 1694178354Ssam if (mprot == NULL) { 1695178354Ssam /* XXX stat + msg */ 1696178354Ssam return ENOBUFS; 1697178354Ssam } 1698178354Ssam 1699178354Ssam desc = &sc->txq.desc[sc->txq.cur_encrypt]; 1700178354Ssam data = &sc->txq.data[sc->txq.cur_encrypt]; 1701178354Ssam 1702178354Ssam error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, 1703178354Ssam mprot, segs, &nsegs, 0); 1704178354Ssam if (error != 0) { 1705178354Ssam device_printf(sc->sc_dev, 1706178354Ssam "could not map mbuf (error %d)\n", error); 1707178354Ssam m_freem(mprot); 1708178354Ssam return error; 1709178354Ssam } 1710178354Ssam 1711178354Ssam data->m = mprot; 1712178354Ssam data->ni = ieee80211_ref_node(ni); 1713178354Ssam /* ctl frames are not taken into account for amrr */ 1714178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1715178354Ssam 1716178354Ssam rt2560_setup_tx_desc(sc, desc, flags, mprot->m_pkthdr.len, protrate, 1, 1717178354Ssam segs->ds_addr); 1718178354Ssam 1719178354Ssam bus_dmamap_sync(sc->txq.data_dmat, data->map, 1720178354Ssam BUS_DMASYNC_PREWRITE); 1721178354Ssam 1722178354Ssam sc->txq.queued++; 1723178354Ssam sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; 1724178354Ssam 1725178354Ssam return 0; 1726178354Ssam} 1727178354Ssam 1728178354Ssamstatic int 1729160691Ssamrt2560_tx_raw(struct rt2560_softc *sc, struct mbuf *m0, 1730160691Ssam struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) 1731160691Ssam{ 1732178354Ssam struct ifnet *ifp = sc->sc_ifp; 1733178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1734160691Ssam struct rt2560_tx_desc *desc; 1735160691Ssam struct rt2560_tx_data *data; 1736160691Ssam bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1737160691Ssam uint32_t flags; 1738160691Ssam int nsegs, rate, error; 1739160691Ssam 1740160691Ssam desc = &sc->prioq.desc[sc->prioq.cur]; 1741160691Ssam data = &sc->prioq.data[sc->prioq.cur]; 1742160691Ssam 1743160691Ssam rate = params->ibp_rate0 & IEEE80211_RATE_VAL; 1744160691Ssam /* XXX validate */ 1745168860Ssephe if (rate == 0) { 1746178354Ssam /* XXX fall back to mcast/mgmt rate? */ 1747168860Ssephe m_freem(m0); 1748160691Ssam return EINVAL; 1749168860Ssephe } 1750160691Ssam 1751178354Ssam flags = 0; 1752178354Ssam if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) 1753178354Ssam flags |= RT2560_TX_ACK; 1754178354Ssam if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { 1755178354Ssam error = rt2560_sendprot(sc, m0, ni, 1756178354Ssam params->ibp_flags & IEEE80211_BPF_RTS ? 1757178354Ssam IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, 1758178354Ssam rate); 1759178354Ssam if (error) { 1760178354Ssam m_freem(m0); 1761178354Ssam return error; 1762178354Ssam } 1763178354Ssam flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; 1764178354Ssam } 1765178354Ssam 1766160691Ssam error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, 1767160691Ssam segs, &nsegs, 0); 1768160691Ssam if (error != 0) { 1769160691Ssam device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1770160691Ssam error); 1771160691Ssam m_freem(m0); 1772160691Ssam return error; 1773160691Ssam } 1774160691Ssam 1775178354Ssam if (bpf_peers_present(ifp->if_bpf)) { 1776160691Ssam struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1777160691Ssam 1778160691Ssam tap->wt_flags = 0; 1779160691Ssam tap->wt_rate = rate; 1780160691Ssam tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 1781160691Ssam tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 1782160691Ssam tap->wt_antenna = sc->tx_ant; 1783160691Ssam 1784178354Ssam bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); 1785160691Ssam } 1786160691Ssam 1787160691Ssam data->m = m0; 1788160691Ssam data->ni = ni; 1789160691Ssam 1790160691Ssam /* XXX need to setup descriptor ourself */ 1791160691Ssam rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, 1792160691Ssam rate, (params->ibp_flags & IEEE80211_BPF_CRYPTO) != 0, 1793160691Ssam segs->ds_addr); 1794160691Ssam 1795160691Ssam bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1796160691Ssam bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1797160691Ssam BUS_DMASYNC_PREWRITE); 1798160691Ssam 1799178354Ssam DPRINTFN(sc, 10, "sending raw frame len=%u idx=%u rate=%u\n", 1800178354Ssam m0->m_pkthdr.len, sc->prioq.cur, rate); 1801160691Ssam 1802160691Ssam /* kick prio */ 1803160691Ssam sc->prioq.queued++; 1804160691Ssam sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; 1805160691Ssam RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); 1806160691Ssam 1807160691Ssam return 0; 1808160691Ssam} 1809160691Ssam 1810156321Sdamienstatic int 1811156321Sdamienrt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0, 1812156321Sdamien struct ieee80211_node *ni) 1813156321Sdamien{ 1814178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1815178354Ssam struct ieee80211com *ic = ni->ni_ic; 1816178354Ssam struct ifnet *ifp = sc->sc_ifp; 1817156321Sdamien struct rt2560_tx_desc *desc; 1818156321Sdamien struct rt2560_tx_data *data; 1819156321Sdamien struct ieee80211_frame *wh; 1820178354Ssam const struct ieee80211_txparam *tp; 1821156321Sdamien struct ieee80211_key *k; 1822156321Sdamien struct mbuf *mnew; 1823156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1824156321Sdamien uint16_t dur; 1825178354Ssam uint32_t flags; 1826156321Sdamien int nsegs, rate, error; 1827156321Sdamien 1828156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1829156321Sdamien 1830178354Ssam tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; 1831178354Ssam if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1832178354Ssam rate = tp->mcastrate; 1833178354Ssam } else if (m0->m_flags & M_EAPOL) { 1834178354Ssam rate = tp->mgmtrate; 1835178354Ssam } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 1836178354Ssam rate = tp->ucastrate; 1837156321Sdamien } else { 1838178354Ssam (void) ieee80211_amrr_choose(ni, &RT2560_NODE(ni)->amrr); 1839178354Ssam rate = ni->ni_txrate; 1840156321Sdamien } 1841156321Sdamien 1842156321Sdamien if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1843178354Ssam k = ieee80211_crypto_encap(ni, m0); 1844156321Sdamien if (k == NULL) { 1845156321Sdamien m_freem(m0); 1846156321Sdamien return ENOBUFS; 1847156321Sdamien } 1848156321Sdamien 1849156321Sdamien /* packet header may have moved, reset our local pointer */ 1850156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1851156321Sdamien } 1852156321Sdamien 1853178354Ssam flags = 0; 1854178354Ssam if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1855178354Ssam int prot = IEEE80211_PROT_NONE; 1856178354Ssam if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) 1857178354Ssam prot = IEEE80211_PROT_RTSCTS; 1858178354Ssam else if ((ic->ic_flags & IEEE80211_F_USEPROT) && 1859178354Ssam ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) 1860178354Ssam prot = ic->ic_protmode; 1861178354Ssam if (prot != IEEE80211_PROT_NONE) { 1862178354Ssam error = rt2560_sendprot(sc, m0, ni, prot, rate); 1863178354Ssam if (error) { 1864178354Ssam m_freem(m0); 1865178354Ssam return error; 1866178354Ssam } 1867178354Ssam flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; 1868156321Sdamien } 1869156321Sdamien } 1870156321Sdamien 1871156321Sdamien data = &sc->txq.data[sc->txq.cur_encrypt]; 1872156321Sdamien desc = &sc->txq.desc[sc->txq.cur_encrypt]; 1873156321Sdamien 1874156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, m0, 1875156321Sdamien segs, &nsegs, 0); 1876156321Sdamien if (error != 0 && error != EFBIG) { 1877156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1878156321Sdamien error); 1879156321Sdamien m_freem(m0); 1880156321Sdamien return error; 1881156321Sdamien } 1882156321Sdamien if (error != 0) { 1883156321Sdamien mnew = m_defrag(m0, M_DONTWAIT); 1884156321Sdamien if (mnew == NULL) { 1885156321Sdamien device_printf(sc->sc_dev, 1886156321Sdamien "could not defragment mbuf\n"); 1887156321Sdamien m_freem(m0); 1888156321Sdamien return ENOBUFS; 1889156321Sdamien } 1890156321Sdamien m0 = mnew; 1891156321Sdamien 1892156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, 1893156321Sdamien m0, segs, &nsegs, 0); 1894156321Sdamien if (error != 0) { 1895156321Sdamien device_printf(sc->sc_dev, 1896156321Sdamien "could not map mbuf (error %d)\n", error); 1897156321Sdamien m_freem(m0); 1898156321Sdamien return error; 1899156321Sdamien } 1900156321Sdamien 1901156321Sdamien /* packet header may have moved, reset our local pointer */ 1902156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1903156321Sdamien } 1904156321Sdamien 1905178354Ssam if (bpf_peers_present(ifp->if_bpf)) { 1906156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1907156321Sdamien 1908156321Sdamien tap->wt_flags = 0; 1909156321Sdamien tap->wt_rate = rate; 1910156321Sdamien tap->wt_antenna = sc->tx_ant; 1911156321Sdamien 1912178354Ssam bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); 1913156321Sdamien } 1914156321Sdamien 1915156321Sdamien data->m = m0; 1916156321Sdamien data->ni = ni; 1917156321Sdamien 1918156321Sdamien /* remember link conditions for rate adaptation algorithm */ 1919178354Ssam if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) { 1920178354Ssam data->rix = ni->ni_txrate; 1921178354Ssam /* XXX probably need last rssi value and not avg */ 1922178354Ssam data->rssi = ic->ic_node_getrssi(ni); 1923156321Sdamien } else 1924178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1925156321Sdamien 1926156321Sdamien if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1927156321Sdamien flags |= RT2560_TX_ACK; 1928156321Sdamien 1929178354Ssam dur = ieee80211_ack_duration(sc->sc_rates, 1930178354Ssam rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); 1931156321Sdamien *(uint16_t *)wh->i_dur = htole16(dur); 1932156321Sdamien } 1933156321Sdamien 1934156321Sdamien rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 1, 1935156321Sdamien segs->ds_addr); 1936156321Sdamien 1937156321Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1938156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 1939156321Sdamien BUS_DMASYNC_PREWRITE); 1940156321Sdamien 1941178354Ssam DPRINTFN(sc, 10, "sending data frame len=%u idx=%u rate=%u\n", 1942178354Ssam m0->m_pkthdr.len, sc->txq.cur_encrypt, rate); 1943156321Sdamien 1944156321Sdamien /* kick encrypt */ 1945156321Sdamien sc->txq.queued++; 1946156321Sdamien sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; 1947156321Sdamien RAL_WRITE(sc, RT2560_SECCSR1, RT2560_KICK_ENCRYPT); 1948156321Sdamien 1949156321Sdamien return 0; 1950156321Sdamien} 1951156321Sdamien 1952156321Sdamienstatic void 1953178354Ssamrt2560_start_locked(struct ifnet *ifp) 1954156321Sdamien{ 1955156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 1956178354Ssam struct mbuf *m; 1957156321Sdamien struct ieee80211_node *ni; 1958156321Sdamien 1959178354Ssam RAL_LOCK_ASSERT(sc); 1960156321Sdamien 1961156321Sdamien for (;;) { 1962178354Ssam IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 1963178354Ssam if (m == NULL) 1964178354Ssam break; 1965178354Ssam if (sc->txq.queued >= RT2560_TX_RING_COUNT - 1) { 1966178354Ssam IFQ_DRV_PREPEND(&ifp->if_snd, m); 1967178354Ssam ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1968178354Ssam sc->sc_flags |= RT2560_F_DATA_OACTIVE; 1969178354Ssam break; 1970178354Ssam } 1971156321Sdamien 1972178354Ssam ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; 1973178354Ssam m = ieee80211_encap(ni, m); 1974178354Ssam if (m == NULL) { 1975178354Ssam ieee80211_free_node(ni); 1976178354Ssam ifp->if_oerrors++; 1977178354Ssam continue; 1978178354Ssam } 1979156321Sdamien 1980178354Ssam if (rt2560_tx_data(sc, m, ni) != 0) { 1981178354Ssam ieee80211_free_node(ni); 1982178354Ssam ifp->if_oerrors++; 1983178354Ssam break; 1984156321Sdamien } 1985156321Sdamien 1986156321Sdamien sc->sc_tx_timer = 5; 1987156321Sdamien } 1988178354Ssam} 1989156321Sdamien 1990178354Ssamstatic void 1991178354Ssamrt2560_start(struct ifnet *ifp) 1992178354Ssam{ 1993178354Ssam struct rt2560_softc *sc = ifp->if_softc; 1994178354Ssam 1995178354Ssam RAL_LOCK(sc); 1996178354Ssam rt2560_start_locked(ifp); 1997156321Sdamien RAL_UNLOCK(sc); 1998156321Sdamien} 1999156321Sdamien 2000156321Sdamienstatic void 2001165352Sbmsrt2560_watchdog(void *arg) 2002156321Sdamien{ 2003167470Ssam struct rt2560_softc *sc = arg; 2004175938Ssephe struct ifnet *ifp = sc->sc_ifp; 2005156321Sdamien 2006178354Ssam RAL_LOCK_ASSERT(sc); 2007178354Ssam 2008178354Ssam KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, ("not running")); 2009178354Ssam 2010178354Ssam if (sc->sc_invalid) /* card ejected */ 2011175938Ssephe return; 2012175938Ssephe 2013175938Ssephe rt2560_encryption_intr(sc); 2014175938Ssephe rt2560_tx_intr(sc); 2015175938Ssephe 2016178354Ssam if (sc->sc_tx_timer > 0 && --sc->sc_tx_timer == 0) { 2017178354Ssam if_printf(ifp, "device timeout\n"); 2018178354Ssam rt2560_init_locked(sc); 2019178354Ssam ifp->if_oerrors++; 2020178354Ssam /* NB: callout is reset in rt2560_init() */ 2021178354Ssam return; 2022156321Sdamien } 2023175938Ssephe callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); 2024156321Sdamien} 2025156321Sdamien 2026156321Sdamienstatic int 2027156321Sdamienrt2560_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 2028156321Sdamien{ 2029156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 2030178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2031178354Ssam struct ifreq *ifr = (struct ifreq *) data; 2032178354Ssam int error = 0, startall = 0; 2033156321Sdamien 2034156321Sdamien switch (cmd) { 2035156321Sdamien case SIOCSIFFLAGS: 2036178704Sthompsa RAL_LOCK(sc); 2037156321Sdamien if (ifp->if_flags & IFF_UP) { 2038178354Ssam if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 2039178354Ssam rt2560_init_locked(sc); 2040178354Ssam startall = 1; 2041178354Ssam } else 2042178354Ssam rt2560_update_promisc(ifp); 2043156321Sdamien } else { 2044156321Sdamien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2045178354Ssam rt2560_stop_locked(sc); 2046156321Sdamien } 2047178704Sthompsa RAL_UNLOCK(sc); 2048178704Sthompsa if (startall) 2049178704Sthompsa ieee80211_start_all(ic); 2050156321Sdamien break; 2051178354Ssam case SIOCGIFMEDIA: 2052178354Ssam error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); 2053178354Ssam break; 2054178704Sthompsa case SIOCGIFADDR: 2055178354Ssam error = ether_ioctl(ifp, cmd, data); 2056178354Ssam break; 2057178704Sthompsa default: 2058178704Sthompsa error = EINVAL; 2059178704Sthompsa break; 2060156321Sdamien } 2061156321Sdamien return error; 2062156321Sdamien} 2063156321Sdamien 2064156321Sdamienstatic void 2065156321Sdamienrt2560_bbp_write(struct rt2560_softc *sc, uint8_t reg, uint8_t val) 2066156321Sdamien{ 2067156321Sdamien uint32_t tmp; 2068156321Sdamien int ntries; 2069156321Sdamien 2070156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2071156321Sdamien if (!(RAL_READ(sc, RT2560_BBPCSR) & RT2560_BBP_BUSY)) 2072156321Sdamien break; 2073156321Sdamien DELAY(1); 2074156321Sdamien } 2075156321Sdamien if (ntries == 100) { 2076156321Sdamien device_printf(sc->sc_dev, "could not write to BBP\n"); 2077156321Sdamien return; 2078156321Sdamien } 2079156321Sdamien 2080156321Sdamien tmp = RT2560_BBP_WRITE | RT2560_BBP_BUSY | reg << 8 | val; 2081156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR, tmp); 2082156321Sdamien 2083178354Ssam DPRINTFN(sc, 15, "BBP R%u <- 0x%02x\n", reg, val); 2084156321Sdamien} 2085156321Sdamien 2086156321Sdamienstatic uint8_t 2087156321Sdamienrt2560_bbp_read(struct rt2560_softc *sc, uint8_t reg) 2088156321Sdamien{ 2089156321Sdamien uint32_t val; 2090156321Sdamien int ntries; 2091156321Sdamien 2092175938Ssephe for (ntries = 0; ntries < 100; ntries++) { 2093175938Ssephe if (!(RAL_READ(sc, RT2560_BBPCSR) & RT2560_BBP_BUSY)) 2094175938Ssephe break; 2095175938Ssephe DELAY(1); 2096175938Ssephe } 2097175938Ssephe if (ntries == 100) { 2098175938Ssephe device_printf(sc->sc_dev, "could not read from BBP\n"); 2099175938Ssephe return 0; 2100175938Ssephe } 2101175938Ssephe 2102156321Sdamien val = RT2560_BBP_BUSY | reg << 8; 2103156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR, val); 2104156321Sdamien 2105156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2106156321Sdamien val = RAL_READ(sc, RT2560_BBPCSR); 2107156321Sdamien if (!(val & RT2560_BBP_BUSY)) 2108156321Sdamien return val & 0xff; 2109156321Sdamien DELAY(1); 2110156321Sdamien } 2111156321Sdamien 2112156321Sdamien device_printf(sc->sc_dev, "could not read from BBP\n"); 2113156321Sdamien return 0; 2114156321Sdamien} 2115156321Sdamien 2116156321Sdamienstatic void 2117156321Sdamienrt2560_rf_write(struct rt2560_softc *sc, uint8_t reg, uint32_t val) 2118156321Sdamien{ 2119156321Sdamien uint32_t tmp; 2120156321Sdamien int ntries; 2121156321Sdamien 2122156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2123156321Sdamien if (!(RAL_READ(sc, RT2560_RFCSR) & RT2560_RF_BUSY)) 2124156321Sdamien break; 2125156321Sdamien DELAY(1); 2126156321Sdamien } 2127156321Sdamien if (ntries == 100) { 2128156321Sdamien device_printf(sc->sc_dev, "could not write to RF\n"); 2129156321Sdamien return; 2130156321Sdamien } 2131156321Sdamien 2132156321Sdamien tmp = RT2560_RF_BUSY | RT2560_RF_20BIT | (val & 0xfffff) << 2 | 2133156321Sdamien (reg & 0x3); 2134156321Sdamien RAL_WRITE(sc, RT2560_RFCSR, tmp); 2135156321Sdamien 2136156321Sdamien /* remember last written value in sc */ 2137156321Sdamien sc->rf_regs[reg] = val; 2138156321Sdamien 2139178354Ssam DPRINTFN(sc, 15, "RF R[%u] <- 0x%05x\n", reg & 0x3, val & 0xfffff); 2140156321Sdamien} 2141156321Sdamien 2142156321Sdamienstatic void 2143156321Sdamienrt2560_set_chan(struct rt2560_softc *sc, struct ieee80211_channel *c) 2144156321Sdamien{ 2145178354Ssam struct ifnet *ifp = sc->sc_ifp; 2146178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2147156321Sdamien uint8_t power, tmp; 2148156321Sdamien u_int i, chan; 2149156321Sdamien 2150156321Sdamien chan = ieee80211_chan2ieee(ic, c); 2151178354Ssam KASSERT(chan != 0 && chan != IEEE80211_CHAN_ANY, ("chan 0x%x", chan)); 2152156321Sdamien 2153178354Ssam sc->sc_rates = ieee80211_get_ratetable(c); 2154178354Ssam 2155156321Sdamien if (IEEE80211_IS_CHAN_2GHZ(c)) 2156156321Sdamien power = min(sc->txpow[chan - 1], 31); 2157156321Sdamien else 2158156321Sdamien power = 31; 2159156321Sdamien 2160156321Sdamien /* adjust txpower using ifconfig settings */ 2161156321Sdamien power -= (100 - ic->ic_txpowlimit) / 8; 2162156321Sdamien 2163178354Ssam DPRINTFN(sc, 2, "setting channel to %u, txpower to %u\n", chan, power); 2164156321Sdamien 2165156321Sdamien switch (sc->rf_rev) { 2166156321Sdamien case RT2560_RF_2522: 2167156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x00814); 2168156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2522_r2[chan - 1]); 2169156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2170156321Sdamien break; 2171156321Sdamien 2172156321Sdamien case RT2560_RF_2523: 2173156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08804); 2174156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2523_r2[chan - 1]); 2175156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x38044); 2176156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2177156321Sdamien break; 2178156321Sdamien 2179156321Sdamien case RT2560_RF_2524: 2180156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x0c808); 2181156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2524_r2[chan - 1]); 2182156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2183156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2184156321Sdamien break; 2185156321Sdamien 2186156321Sdamien case RT2560_RF_2525: 2187156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2188156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_hi_r2[chan - 1]); 2189156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2190156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2191156321Sdamien 2192156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2193156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_r2[chan - 1]); 2194156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2195156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2196156321Sdamien break; 2197156321Sdamien 2198156321Sdamien case RT2560_RF_2525E: 2199156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2200156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525e_r2[chan - 1]); 2201156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2202156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00286 : 0x00282); 2203156321Sdamien break; 2204156321Sdamien 2205156321Sdamien case RT2560_RF_2526: 2206156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_hi_r2[chan - 1]); 2207156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); 2208156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08804); 2209156321Sdamien 2210156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_r2[chan - 1]); 2211156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2212156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); 2213156321Sdamien break; 2214156321Sdamien 2215156321Sdamien /* dual-band RF */ 2216156321Sdamien case RT2560_RF_5222: 2217156321Sdamien for (i = 0; rt2560_rf5222[i].chan != chan; i++); 2218156321Sdamien 2219156321Sdamien rt2560_rf_write(sc, RAL_RF1, rt2560_rf5222[i].r1); 2220156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf5222[i].r2); 2221156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2222156321Sdamien rt2560_rf_write(sc, RAL_RF4, rt2560_rf5222[i].r4); 2223156321Sdamien break; 2224170530Ssam default: 2225170530Ssam printf("unknown ral rev=%d\n", sc->rf_rev); 2226156321Sdamien } 2227156321Sdamien 2228178354Ssam /* XXX */ 2229178354Ssam if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { 2230156321Sdamien /* set Japan filter bit for channel 14 */ 2231156321Sdamien tmp = rt2560_bbp_read(sc, 70); 2232156321Sdamien 2233156321Sdamien tmp &= ~RT2560_JAPAN_FILTER; 2234156321Sdamien if (chan == 14) 2235156321Sdamien tmp |= RT2560_JAPAN_FILTER; 2236156321Sdamien 2237156321Sdamien rt2560_bbp_write(sc, 70, tmp); 2238156321Sdamien 2239156321Sdamien /* clear CRC errors */ 2240156321Sdamien RAL_READ(sc, RT2560_CNT0); 2241156321Sdamien } 2242156321Sdamien} 2243156321Sdamien 2244170530Ssamstatic void 2245170530Ssamrt2560_set_channel(struct ieee80211com *ic) 2246170530Ssam{ 2247170530Ssam struct ifnet *ifp = ic->ic_ifp; 2248170530Ssam struct rt2560_softc *sc = ifp->if_softc; 2249170530Ssam 2250170530Ssam RAL_LOCK(sc); 2251170530Ssam rt2560_set_chan(sc, ic->ic_curchan); 2252178354Ssam 2253178354Ssam sc->sc_txtap.wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 2254178354Ssam sc->sc_txtap.wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 2255178354Ssam sc->sc_rxtap.wr_chan_freq = htole16(ic->ic_curchan->ic_freq); 2256178354Ssam sc->sc_rxtap.wr_chan_flags = htole16(ic->ic_curchan->ic_flags); 2257170530Ssam RAL_UNLOCK(sc); 2258170530Ssam 2259170530Ssam} 2260170530Ssam 2261156321Sdamien#if 0 2262156321Sdamien/* 2263156321Sdamien * Disable RF auto-tuning. 2264156321Sdamien */ 2265156321Sdamienstatic void 2266156321Sdamienrt2560_disable_rf_tune(struct rt2560_softc *sc) 2267156321Sdamien{ 2268156321Sdamien uint32_t tmp; 2269156321Sdamien 2270156321Sdamien if (sc->rf_rev != RT2560_RF_2523) { 2271156321Sdamien tmp = sc->rf_regs[RAL_RF1] & ~RAL_RF1_AUTOTUNE; 2272156321Sdamien rt2560_rf_write(sc, RAL_RF1, tmp); 2273156321Sdamien } 2274156321Sdamien 2275156321Sdamien tmp = sc->rf_regs[RAL_RF3] & ~RAL_RF3_AUTOTUNE; 2276156321Sdamien rt2560_rf_write(sc, RAL_RF3, tmp); 2277156321Sdamien 2278178354Ssam DPRINTFN(sc, 2, "%s", "disabling RF autotune\n"); 2279156321Sdamien} 2280156321Sdamien#endif 2281156321Sdamien 2282156321Sdamien/* 2283156321Sdamien * Refer to IEEE Std 802.11-1999 pp. 123 for more information on TSF 2284156321Sdamien * synchronization. 2285156321Sdamien */ 2286156321Sdamienstatic void 2287156321Sdamienrt2560_enable_tsf_sync(struct rt2560_softc *sc) 2288156321Sdamien{ 2289178354Ssam struct ifnet *ifp = sc->sc_ifp; 2290178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2291178354Ssam struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2292156321Sdamien uint16_t logcwmin, preload; 2293156321Sdamien uint32_t tmp; 2294156321Sdamien 2295156321Sdamien /* first, disable TSF synchronization */ 2296156321Sdamien RAL_WRITE(sc, RT2560_CSR14, 0); 2297156321Sdamien 2298178354Ssam tmp = 16 * vap->iv_bss->ni_intval; 2299156321Sdamien RAL_WRITE(sc, RT2560_CSR12, tmp); 2300156321Sdamien 2301156321Sdamien RAL_WRITE(sc, RT2560_CSR13, 0); 2302156321Sdamien 2303156321Sdamien logcwmin = 5; 2304178354Ssam preload = (vap->iv_opmode == IEEE80211_M_STA) ? 384 : 1024; 2305156321Sdamien tmp = logcwmin << 16 | preload; 2306156321Sdamien RAL_WRITE(sc, RT2560_BCNOCSR, tmp); 2307156321Sdamien 2308156321Sdamien /* finally, enable TSF synchronization */ 2309156321Sdamien tmp = RT2560_ENABLE_TSF | RT2560_ENABLE_TBCN; 2310156321Sdamien if (ic->ic_opmode == IEEE80211_M_STA) 2311156321Sdamien tmp |= RT2560_ENABLE_TSF_SYNC(1); 2312156321Sdamien else 2313156321Sdamien tmp |= RT2560_ENABLE_TSF_SYNC(2) | 2314156321Sdamien RT2560_ENABLE_BEACON_GENERATOR; 2315156321Sdamien RAL_WRITE(sc, RT2560_CSR14, tmp); 2316156321Sdamien 2317178354Ssam DPRINTF(sc, "%s", "enabling TSF synchronization\n"); 2318156321Sdamien} 2319156321Sdamien 2320156321Sdamienstatic void 2321156321Sdamienrt2560_update_plcp(struct rt2560_softc *sc) 2322156321Sdamien{ 2323178354Ssam struct ifnet *ifp = sc->sc_ifp; 2324178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2325156321Sdamien 2326156321Sdamien /* no short preamble for 1Mbps */ 2327156321Sdamien RAL_WRITE(sc, RT2560_PLCP1MCSR, 0x00700400); 2328156321Sdamien 2329156321Sdamien if (!(ic->ic_flags & IEEE80211_F_SHPREAMBLE)) { 2330156321Sdamien /* values taken from the reference driver */ 2331156321Sdamien RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380401); 2332156321Sdamien RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x00150402); 2333156321Sdamien RAL_WRITE(sc, RT2560_PLCP11MCSR, 0x000b8403); 2334156321Sdamien } else { 2335156321Sdamien /* same values as above or'ed 0x8 */ 2336156321Sdamien RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380409); 2337156321Sdamien RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x0015040a); 2338156321Sdamien RAL_WRITE(sc, RT2560_PLCP11MCSR, 0x000b840b); 2339156321Sdamien } 2340156321Sdamien 2341178354Ssam DPRINTF(sc, "updating PLCP for %s preamble\n", 2342178354Ssam (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? "short" : "long"); 2343156321Sdamien} 2344156321Sdamien 2345156321Sdamien/* 2346156321Sdamien * This function can be called by ieee80211_set_shortslottime(). Refer to 2347156321Sdamien * IEEE Std 802.11-1999 pp. 85 to know how these values are computed. 2348156321Sdamien */ 2349156321Sdamienstatic void 2350156321Sdamienrt2560_update_slot(struct ifnet *ifp) 2351156321Sdamien{ 2352156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 2353178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2354156321Sdamien uint8_t slottime; 2355156321Sdamien uint16_t tx_sifs, tx_pifs, tx_difs, eifs; 2356156321Sdamien uint32_t tmp; 2357156321Sdamien 2358175938Ssephe#ifndef FORCE_SLOTTIME 2359156321Sdamien slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; 2360175938Ssephe#else 2361175938Ssephe /* 2362175938Ssephe * Setting slot time according to "short slot time" capability 2363175938Ssephe * in beacon/probe_resp seems to cause problem to acknowledge 2364175938Ssephe * certain AP's data frames transimitted at CCK/DS rates: the 2365175938Ssephe * problematic AP keeps retransmitting data frames, probably 2366175938Ssephe * because MAC level acks are not received by hardware. 2367175938Ssephe * So we cheat a little bit here by claiming we are capable of 2368175938Ssephe * "short slot time" but setting hardware slot time to the normal 2369175938Ssephe * slot time. ral(4) does not seem to have trouble to receive 2370175938Ssephe * frames transmitted using short slot time even if hardware 2371175938Ssephe * slot time is set to normal slot time. If we didn't use this 2372175938Ssephe * trick, we would have to claim that short slot time is not 2373175938Ssephe * supported; this would give relative poor RX performance 2374175938Ssephe * (-1Mb~-2Mb lower) and the _whole_ BSS would stop using short 2375175938Ssephe * slot time. 2376175938Ssephe */ 2377175938Ssephe slottime = 20; 2378175938Ssephe#endif 2379156321Sdamien 2380156321Sdamien /* update the MAC slot boundaries */ 2381156321Sdamien tx_sifs = RAL_SIFS - RT2560_TXRX_TURNAROUND; 2382156321Sdamien tx_pifs = tx_sifs + slottime; 2383156321Sdamien tx_difs = tx_sifs + 2 * slottime; 2384156321Sdamien eifs = (ic->ic_curmode == IEEE80211_MODE_11B) ? 364 : 60; 2385156321Sdamien 2386156321Sdamien tmp = RAL_READ(sc, RT2560_CSR11); 2387156321Sdamien tmp = (tmp & ~0x1f00) | slottime << 8; 2388156321Sdamien RAL_WRITE(sc, RT2560_CSR11, tmp); 2389156321Sdamien 2390156321Sdamien tmp = tx_pifs << 16 | tx_sifs; 2391156321Sdamien RAL_WRITE(sc, RT2560_CSR18, tmp); 2392156321Sdamien 2393156321Sdamien tmp = eifs << 16 | tx_difs; 2394156321Sdamien RAL_WRITE(sc, RT2560_CSR19, tmp); 2395156321Sdamien 2396178354Ssam DPRINTF(sc, "setting slottime to %uus\n", slottime); 2397156321Sdamien} 2398156321Sdamien 2399156321Sdamienstatic void 2400156321Sdamienrt2560_set_basicrates(struct rt2560_softc *sc) 2401156321Sdamien{ 2402178354Ssam struct ifnet *ifp = sc->sc_ifp; 2403178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2404156321Sdamien 2405156321Sdamien /* update basic rate set */ 2406156321Sdamien if (ic->ic_curmode == IEEE80211_MODE_11B) { 2407156321Sdamien /* 11b basic rates: 1, 2Mbps */ 2408156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x3); 2409156321Sdamien } else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) { 2410156321Sdamien /* 11a basic rates: 6, 12, 24Mbps */ 2411156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x150); 2412156321Sdamien } else { 2413156321Sdamien /* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */ 2414156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x15f); 2415156321Sdamien } 2416156321Sdamien} 2417156321Sdamien 2418156321Sdamienstatic void 2419156321Sdamienrt2560_update_led(struct rt2560_softc *sc, int led1, int led2) 2420156321Sdamien{ 2421156321Sdamien uint32_t tmp; 2422156321Sdamien 2423156321Sdamien /* set ON period to 70ms and OFF period to 30ms */ 2424156321Sdamien tmp = led1 << 16 | led2 << 17 | 70 << 8 | 30; 2425156321Sdamien RAL_WRITE(sc, RT2560_LEDCSR, tmp); 2426156321Sdamien} 2427156321Sdamien 2428156321Sdamienstatic void 2429170530Ssamrt2560_set_bssid(struct rt2560_softc *sc, const uint8_t *bssid) 2430156321Sdamien{ 2431156321Sdamien uint32_t tmp; 2432156321Sdamien 2433156321Sdamien tmp = bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24; 2434156321Sdamien RAL_WRITE(sc, RT2560_CSR5, tmp); 2435156321Sdamien 2436156321Sdamien tmp = bssid[4] | bssid[5] << 8; 2437156321Sdamien RAL_WRITE(sc, RT2560_CSR6, tmp); 2438156321Sdamien 2439178354Ssam DPRINTF(sc, "setting BSSID to %6D\n", bssid, ":"); 2440156321Sdamien} 2441156321Sdamien 2442156321Sdamienstatic void 2443156321Sdamienrt2560_set_macaddr(struct rt2560_softc *sc, uint8_t *addr) 2444156321Sdamien{ 2445156321Sdamien uint32_t tmp; 2446156321Sdamien 2447156321Sdamien tmp = addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24; 2448156321Sdamien RAL_WRITE(sc, RT2560_CSR3, tmp); 2449156321Sdamien 2450156321Sdamien tmp = addr[4] | addr[5] << 8; 2451156321Sdamien RAL_WRITE(sc, RT2560_CSR4, tmp); 2452156321Sdamien 2453178354Ssam DPRINTF(sc, "setting MAC address to %6D\n", addr, ":"); 2454156321Sdamien} 2455156321Sdamien 2456156321Sdamienstatic void 2457156321Sdamienrt2560_get_macaddr(struct rt2560_softc *sc, uint8_t *addr) 2458156321Sdamien{ 2459156321Sdamien uint32_t tmp; 2460156321Sdamien 2461156321Sdamien tmp = RAL_READ(sc, RT2560_CSR3); 2462156321Sdamien addr[0] = tmp & 0xff; 2463156321Sdamien addr[1] = (tmp >> 8) & 0xff; 2464156321Sdamien addr[2] = (tmp >> 16) & 0xff; 2465156321Sdamien addr[3] = (tmp >> 24); 2466156321Sdamien 2467156321Sdamien tmp = RAL_READ(sc, RT2560_CSR4); 2468156321Sdamien addr[4] = tmp & 0xff; 2469156321Sdamien addr[5] = (tmp >> 8) & 0xff; 2470156321Sdamien} 2471156321Sdamien 2472156321Sdamienstatic void 2473178354Ssamrt2560_update_promisc(struct ifnet *ifp) 2474156321Sdamien{ 2475178354Ssam struct rt2560_softc *sc = ifp->if_softc; 2476156321Sdamien uint32_t tmp; 2477156321Sdamien 2478156321Sdamien tmp = RAL_READ(sc, RT2560_RXCSR0); 2479156321Sdamien 2480156321Sdamien tmp &= ~RT2560_DROP_NOT_TO_ME; 2481156321Sdamien if (!(ifp->if_flags & IFF_PROMISC)) 2482156321Sdamien tmp |= RT2560_DROP_NOT_TO_ME; 2483156321Sdamien 2484156321Sdamien RAL_WRITE(sc, RT2560_RXCSR0, tmp); 2485156321Sdamien 2486178354Ssam DPRINTF(sc, "%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ? 2487178354Ssam "entering" : "leaving"); 2488156321Sdamien} 2489156321Sdamien 2490156321Sdamienstatic const char * 2491156321Sdamienrt2560_get_rf(int rev) 2492156321Sdamien{ 2493156321Sdamien switch (rev) { 2494156321Sdamien case RT2560_RF_2522: return "RT2522"; 2495156321Sdamien case RT2560_RF_2523: return "RT2523"; 2496156321Sdamien case RT2560_RF_2524: return "RT2524"; 2497156321Sdamien case RT2560_RF_2525: return "RT2525"; 2498156321Sdamien case RT2560_RF_2525E: return "RT2525e"; 2499156321Sdamien case RT2560_RF_2526: return "RT2526"; 2500156321Sdamien case RT2560_RF_5222: return "RT5222"; 2501156321Sdamien default: return "unknown"; 2502156321Sdamien } 2503156321Sdamien} 2504156321Sdamien 2505156321Sdamienstatic void 2506175938Ssephert2560_read_config(struct rt2560_softc *sc) 2507156321Sdamien{ 2508156321Sdamien uint16_t val; 2509156321Sdamien int i; 2510156321Sdamien 2511156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_CONFIG0); 2512156321Sdamien sc->rf_rev = (val >> 11) & 0x7; 2513156321Sdamien sc->hw_radio = (val >> 10) & 0x1; 2514156321Sdamien sc->led_mode = (val >> 6) & 0x7; 2515156321Sdamien sc->rx_ant = (val >> 4) & 0x3; 2516156321Sdamien sc->tx_ant = (val >> 2) & 0x3; 2517156321Sdamien sc->nb_ant = val & 0x3; 2518156321Sdamien 2519156321Sdamien /* read default values for BBP registers */ 2520156321Sdamien for (i = 0; i < 16; i++) { 2521156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_BBP_BASE + i); 2522175938Ssephe if (val == 0 || val == 0xffff) 2523175938Ssephe continue; 2524175938Ssephe 2525156321Sdamien sc->bbp_prom[i].reg = val >> 8; 2526156321Sdamien sc->bbp_prom[i].val = val & 0xff; 2527156321Sdamien } 2528156321Sdamien 2529156321Sdamien /* read Tx power for all b/g channels */ 2530156321Sdamien for (i = 0; i < 14 / 2; i++) { 2531156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_TXPOWER + i); 2532175938Ssephe sc->txpow[i * 2] = val & 0xff; 2533175938Ssephe sc->txpow[i * 2 + 1] = val >> 8; 2534156321Sdamien } 2535175938Ssephe for (i = 0; i < 14; ++i) { 2536175938Ssephe if (sc->txpow[i] > 31) 2537175938Ssephe sc->txpow[i] = 24; 2538175938Ssephe } 2539170530Ssam 2540170530Ssam val = rt2560_eeprom_read(sc, RT2560_EEPROM_CALIBRATE); 2541170530Ssam if ((val & 0xff) == 0xff) 2542170530Ssam sc->rssi_corr = RT2560_DEFAULT_RSSI_CORR; 2543170530Ssam else 2544170530Ssam sc->rssi_corr = val & 0xff; 2545178354Ssam DPRINTF(sc, "rssi correction %d, calibrate 0x%02x\n", 2546178354Ssam sc->rssi_corr, val); 2547156321Sdamien} 2548156321Sdamien 2549170530Ssam 2550170530Ssamstatic void 2551170530Ssamrt2560_scan_start(struct ieee80211com *ic) 2552170530Ssam{ 2553170530Ssam struct ifnet *ifp = ic->ic_ifp; 2554170530Ssam struct rt2560_softc *sc = ifp->if_softc; 2555170530Ssam 2556170530Ssam /* abort TSF synchronization */ 2557170530Ssam RAL_WRITE(sc, RT2560_CSR14, 0); 2558170530Ssam rt2560_set_bssid(sc, ifp->if_broadcastaddr); 2559170530Ssam} 2560170530Ssam 2561170530Ssamstatic void 2562170530Ssamrt2560_scan_end(struct ieee80211com *ic) 2563170530Ssam{ 2564170530Ssam struct ifnet *ifp = ic->ic_ifp; 2565170530Ssam struct rt2560_softc *sc = ifp->if_softc; 2566178354Ssam struct ieee80211vap *vap = ic->ic_scan->ss_vap; 2567170530Ssam 2568170530Ssam rt2560_enable_tsf_sync(sc); 2569170530Ssam /* XXX keep local copy */ 2570178354Ssam rt2560_set_bssid(sc, vap->iv_bss->ni_bssid); 2571170530Ssam} 2572170530Ssam 2573156321Sdamienstatic int 2574156321Sdamienrt2560_bbp_init(struct rt2560_softc *sc) 2575156321Sdamien{ 2576156321Sdamien#define N(a) (sizeof (a) / sizeof ((a)[0])) 2577156321Sdamien int i, ntries; 2578156321Sdamien 2579156321Sdamien /* wait for BBP to be ready */ 2580156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2581156321Sdamien if (rt2560_bbp_read(sc, RT2560_BBP_VERSION) != 0) 2582156321Sdamien break; 2583156321Sdamien DELAY(1); 2584156321Sdamien } 2585156321Sdamien if (ntries == 100) { 2586156321Sdamien device_printf(sc->sc_dev, "timeout waiting for BBP\n"); 2587156321Sdamien return EIO; 2588156321Sdamien } 2589156321Sdamien 2590156321Sdamien /* initialize BBP registers to default values */ 2591156321Sdamien for (i = 0; i < N(rt2560_def_bbp); i++) { 2592156321Sdamien rt2560_bbp_write(sc, rt2560_def_bbp[i].reg, 2593156321Sdamien rt2560_def_bbp[i].val); 2594156321Sdamien } 2595175938Ssephe 2596156321Sdamien /* initialize BBP registers to values stored in EEPROM */ 2597156321Sdamien for (i = 0; i < 16; i++) { 2598175938Ssephe if (sc->bbp_prom[i].reg == 0 && sc->bbp_prom[i].val == 0) 2599175938Ssephe break; 2600156321Sdamien rt2560_bbp_write(sc, sc->bbp_prom[i].reg, sc->bbp_prom[i].val); 2601156321Sdamien } 2602175938Ssephe rt2560_bbp_write(sc, 17, 0x48); /* XXX restore bbp17 */ 2603156321Sdamien 2604156321Sdamien return 0; 2605156321Sdamien#undef N 2606156321Sdamien} 2607156321Sdamien 2608156321Sdamienstatic void 2609156321Sdamienrt2560_set_txantenna(struct rt2560_softc *sc, int antenna) 2610156321Sdamien{ 2611156321Sdamien uint32_t tmp; 2612156321Sdamien uint8_t tx; 2613156321Sdamien 2614156321Sdamien tx = rt2560_bbp_read(sc, RT2560_BBP_TX) & ~RT2560_BBP_ANTMASK; 2615156321Sdamien if (antenna == 1) 2616156321Sdamien tx |= RT2560_BBP_ANTA; 2617156321Sdamien else if (antenna == 2) 2618156321Sdamien tx |= RT2560_BBP_ANTB; 2619156321Sdamien else 2620156321Sdamien tx |= RT2560_BBP_DIVERSITY; 2621156321Sdamien 2622156321Sdamien /* need to force I/Q flip for RF 2525e, 2526 and 5222 */ 2623156321Sdamien if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526 || 2624156321Sdamien sc->rf_rev == RT2560_RF_5222) 2625156321Sdamien tx |= RT2560_BBP_FLIPIQ; 2626156321Sdamien 2627156321Sdamien rt2560_bbp_write(sc, RT2560_BBP_TX, tx); 2628156321Sdamien 2629156321Sdamien /* update values for CCK and OFDM in BBPCSR1 */ 2630156321Sdamien tmp = RAL_READ(sc, RT2560_BBPCSR1) & ~0x00070007; 2631156321Sdamien tmp |= (tx & 0x7) << 16 | (tx & 0x7); 2632156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR1, tmp); 2633156321Sdamien} 2634156321Sdamien 2635156321Sdamienstatic void 2636156321Sdamienrt2560_set_rxantenna(struct rt2560_softc *sc, int antenna) 2637156321Sdamien{ 2638156321Sdamien uint8_t rx; 2639156321Sdamien 2640156321Sdamien rx = rt2560_bbp_read(sc, RT2560_BBP_RX) & ~RT2560_BBP_ANTMASK; 2641156321Sdamien if (antenna == 1) 2642156321Sdamien rx |= RT2560_BBP_ANTA; 2643156321Sdamien else if (antenna == 2) 2644156321Sdamien rx |= RT2560_BBP_ANTB; 2645156321Sdamien else 2646156321Sdamien rx |= RT2560_BBP_DIVERSITY; 2647156321Sdamien 2648156321Sdamien /* need to force no I/Q flip for RF 2525e and 2526 */ 2649156321Sdamien if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526) 2650156321Sdamien rx &= ~RT2560_BBP_FLIPIQ; 2651156321Sdamien 2652156321Sdamien rt2560_bbp_write(sc, RT2560_BBP_RX, rx); 2653156321Sdamien} 2654156321Sdamien 2655156321Sdamienstatic void 2656178354Ssamrt2560_init_locked(struct rt2560_softc *sc) 2657156321Sdamien{ 2658156321Sdamien#define N(a) (sizeof (a) / sizeof ((a)[0])) 2659178354Ssam struct ifnet *ifp = sc->sc_ifp; 2660178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2661156321Sdamien uint32_t tmp; 2662156321Sdamien int i; 2663156321Sdamien 2664178354Ssam RAL_LOCK_ASSERT(sc); 2665156975Sdamien 2666178354Ssam rt2560_stop_locked(sc); 2667170530Ssam 2668156321Sdamien /* setup tx rings */ 2669156321Sdamien tmp = RT2560_PRIO_RING_COUNT << 24 | 2670156321Sdamien RT2560_ATIM_RING_COUNT << 16 | 2671156321Sdamien RT2560_TX_RING_COUNT << 8 | 2672156321Sdamien RT2560_TX_DESC_SIZE; 2673156321Sdamien 2674156321Sdamien /* rings must be initialized in this exact order */ 2675156321Sdamien RAL_WRITE(sc, RT2560_TXCSR2, tmp); 2676156321Sdamien RAL_WRITE(sc, RT2560_TXCSR3, sc->txq.physaddr); 2677156321Sdamien RAL_WRITE(sc, RT2560_TXCSR5, sc->prioq.physaddr); 2678156321Sdamien RAL_WRITE(sc, RT2560_TXCSR4, sc->atimq.physaddr); 2679156321Sdamien RAL_WRITE(sc, RT2560_TXCSR6, sc->bcnq.physaddr); 2680156321Sdamien 2681156321Sdamien /* setup rx ring */ 2682156321Sdamien tmp = RT2560_RX_RING_COUNT << 8 | RT2560_RX_DESC_SIZE; 2683156321Sdamien 2684156321Sdamien RAL_WRITE(sc, RT2560_RXCSR1, tmp); 2685156321Sdamien RAL_WRITE(sc, RT2560_RXCSR2, sc->rxq.physaddr); 2686156321Sdamien 2687156321Sdamien /* initialize MAC registers to default values */ 2688156321Sdamien for (i = 0; i < N(rt2560_def_mac); i++) 2689156321Sdamien RAL_WRITE(sc, rt2560_def_mac[i].reg, rt2560_def_mac[i].val); 2690156321Sdamien 2691156321Sdamien IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp)); 2692156321Sdamien rt2560_set_macaddr(sc, ic->ic_myaddr); 2693156321Sdamien 2694156321Sdamien /* set basic rate set (will be updated later) */ 2695156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x153); 2696156321Sdamien 2697156321Sdamien rt2560_update_slot(ifp); 2698156321Sdamien rt2560_update_plcp(sc); 2699156321Sdamien rt2560_update_led(sc, 0, 0); 2700156321Sdamien 2701156321Sdamien RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 2702156321Sdamien RAL_WRITE(sc, RT2560_CSR1, RT2560_HOST_READY); 2703156321Sdamien 2704156321Sdamien if (rt2560_bbp_init(sc) != 0) { 2705156321Sdamien rt2560_stop(sc); 2706156975Sdamien RAL_UNLOCK(sc); 2707156321Sdamien return; 2708156321Sdamien } 2709156321Sdamien 2710175938Ssephe rt2560_set_txantenna(sc, sc->tx_ant); 2711175938Ssephe rt2560_set_rxantenna(sc, sc->rx_ant); 2712175938Ssephe 2713156321Sdamien /* set default BSS channel */ 2714156321Sdamien rt2560_set_chan(sc, ic->ic_curchan); 2715156321Sdamien 2716156321Sdamien /* kick Rx */ 2717156321Sdamien tmp = RT2560_DROP_PHY_ERROR | RT2560_DROP_CRC_ERROR; 2718156321Sdamien if (ic->ic_opmode != IEEE80211_M_MONITOR) { 2719156321Sdamien tmp |= RT2560_DROP_CTL | RT2560_DROP_VERSION_ERROR; 2720156321Sdamien if (ic->ic_opmode != IEEE80211_M_HOSTAP) 2721156321Sdamien tmp |= RT2560_DROP_TODS; 2722156321Sdamien if (!(ifp->if_flags & IFF_PROMISC)) 2723156321Sdamien tmp |= RT2560_DROP_NOT_TO_ME; 2724156321Sdamien } 2725156321Sdamien RAL_WRITE(sc, RT2560_RXCSR0, tmp); 2726156321Sdamien 2727156321Sdamien /* clear old FCS and Rx FIFO errors */ 2728156321Sdamien RAL_READ(sc, RT2560_CNT0); 2729156321Sdamien RAL_READ(sc, RT2560_CNT4); 2730156321Sdamien 2731156321Sdamien /* clear any pending interrupts */ 2732156321Sdamien RAL_WRITE(sc, RT2560_CSR7, 0xffffffff); 2733156321Sdamien 2734156321Sdamien /* enable interrupts */ 2735156321Sdamien RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); 2736156321Sdamien 2737156321Sdamien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2738156321Sdamien ifp->if_drv_flags |= IFF_DRV_RUNNING; 2739156321Sdamien 2740175938Ssephe callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); 2741178354Ssam#undef N 2742178354Ssam} 2743175938Ssephe 2744178354Ssamstatic void 2745178354Ssamrt2560_init(void *priv) 2746178354Ssam{ 2747178354Ssam struct rt2560_softc *sc = priv; 2748178354Ssam struct ifnet *ifp = sc->sc_ifp; 2749178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2750156975Sdamien 2751178354Ssam RAL_LOCK(sc); 2752178354Ssam rt2560_init_locked(sc); 2753156975Sdamien RAL_UNLOCK(sc); 2754178354Ssam 2755178931Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2756178931Sthompsa ieee80211_start_all(ic); /* start all vap's */ 2757156321Sdamien} 2758156321Sdamien 2759178354Ssamstatic void 2760178354Ssamrt2560_stop_locked(struct rt2560_softc *sc) 2761156321Sdamien{ 2762178354Ssam struct ifnet *ifp = sc->sc_ifp; 2763170530Ssam volatile int *flags = &sc->sc_flags; 2764156321Sdamien 2765178354Ssam RAL_LOCK_ASSERT(sc); 2766156321Sdamien 2767178354Ssam while (*flags & RT2560_F_INPUT_RUNNING) 2768178354Ssam msleep(sc, &sc->sc_mtx, 0, "ralrunning", hz/10); 2769175938Ssephe 2770175938Ssephe callout_stop(&sc->watchdog_ch); 2771178354Ssam sc->sc_tx_timer = 0; 2772175938Ssephe 2773170530Ssam if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 2774170530Ssam ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2775156975Sdamien 2776170530Ssam /* abort Tx */ 2777170530Ssam RAL_WRITE(sc, RT2560_TXCSR0, RT2560_ABORT_TX); 2778170530Ssam 2779170530Ssam /* disable Rx */ 2780170530Ssam RAL_WRITE(sc, RT2560_RXCSR0, RT2560_DISABLE_RX); 2781156321Sdamien 2782170530Ssam /* reset ASIC (imply reset BBP) */ 2783170530Ssam RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 2784170530Ssam RAL_WRITE(sc, RT2560_CSR1, 0); 2785156321Sdamien 2786170530Ssam /* disable interrupts */ 2787170530Ssam RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 2788170530Ssam 2789170530Ssam /* reset Tx and Rx rings */ 2790170530Ssam rt2560_reset_tx_ring(sc, &sc->txq); 2791170530Ssam rt2560_reset_tx_ring(sc, &sc->atimq); 2792170530Ssam rt2560_reset_tx_ring(sc, &sc->prioq); 2793170530Ssam rt2560_reset_tx_ring(sc, &sc->bcnq); 2794170530Ssam rt2560_reset_rx_ring(sc, &sc->rxq); 2795170530Ssam } 2796175938Ssephe sc->sc_flags &= ~(RT2560_F_PRIO_OACTIVE | RT2560_F_DATA_OACTIVE); 2797178354Ssam} 2798175938Ssephe 2799178354Ssamvoid 2800178354Ssamrt2560_stop(void *arg) 2801178354Ssam{ 2802178354Ssam struct rt2560_softc *sc = arg; 2803178354Ssam 2804178354Ssam RAL_LOCK(sc); 2805178354Ssam rt2560_stop_locked(sc); 2806170530Ssam RAL_UNLOCK(sc); 2807156321Sdamien} 2808160691Ssam 2809160691Ssamstatic int 2810160691Ssamrt2560_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 2811160691Ssam const struct ieee80211_bpf_params *params) 2812160691Ssam{ 2813160691Ssam struct ieee80211com *ic = ni->ni_ic; 2814160691Ssam struct ifnet *ifp = ic->ic_ifp; 2815160691Ssam struct rt2560_softc *sc = ifp->if_softc; 2816160691Ssam 2817160691Ssam RAL_LOCK(sc); 2818160691Ssam 2819160691Ssam /* prevent management frames from being sent if we're not ready */ 2820160691Ssam if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2821160691Ssam RAL_UNLOCK(sc); 2822168860Ssephe m_freem(m); 2823168860Ssephe ieee80211_free_node(ni); 2824160691Ssam return ENETDOWN; 2825160691Ssam } 2826160691Ssam if (sc->prioq.queued >= RT2560_PRIO_RING_COUNT) { 2827160691Ssam ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2828178354Ssam sc->sc_flags |= RT2560_F_PRIO_OACTIVE; 2829160691Ssam RAL_UNLOCK(sc); 2830168860Ssephe m_freem(m); 2831168860Ssephe ieee80211_free_node(ni); 2832160691Ssam return ENOBUFS; /* XXX */ 2833160691Ssam } 2834160691Ssam 2835160691Ssam ifp->if_opackets++; 2836160691Ssam 2837160691Ssam if (params == NULL) { 2838160691Ssam /* 2839160691Ssam * Legacy path; interpret frame contents to decide 2840160691Ssam * precisely how to send the frame. 2841160691Ssam */ 2842160691Ssam if (rt2560_tx_mgt(sc, m, ni) != 0) 2843160691Ssam goto bad; 2844160691Ssam } else { 2845160691Ssam /* 2846160691Ssam * Caller supplied explicit parameters to use in 2847160691Ssam * sending the frame. 2848160691Ssam */ 2849160691Ssam if (rt2560_tx_raw(sc, m, ni, params)) 2850160691Ssam goto bad; 2851160691Ssam } 2852160691Ssam sc->sc_tx_timer = 5; 2853160691Ssam 2854160691Ssam RAL_UNLOCK(sc); 2855160691Ssam 2856160691Ssam return 0; 2857160691Ssambad: 2858160691Ssam ifp->if_oerrors++; 2859160905Ssam ieee80211_free_node(ni); 2860160691Ssam RAL_UNLOCK(sc); 2861160691Ssam return EIO; /* XXX */ 2862160691Ssam} 2863