rt2560.c revision 178948
1156321Sdamien/* $FreeBSD: head/sys/dev/ral/rt2560.c 178948 2008-05-11 22:11:01Z 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 178948 2008-05-11 22:11:01Z 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 *); 107156321Sdamienstatic struct ieee80211_node *rt2560_node_alloc( 108156321Sdamien struct ieee80211_node_table *); 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 = 281178354Ssam IEEE80211_C_IBSS /* ibss, nee adhoc, mode */ 282178354Ssam | IEEE80211_C_HOSTAP /* hostap mode */ 283178354Ssam | IEEE80211_C_MONITOR /* monitor mode */ 284178354Ssam | IEEE80211_C_AHDEMO /* adhoc demo mode */ 285178354Ssam | IEEE80211_C_WDS /* 4-address traffic works */ 286178354Ssam | IEEE80211_C_SHPREAMBLE /* short preamble supported */ 287178354Ssam | IEEE80211_C_SHSLOT /* short slot time supported */ 288178354Ssam | IEEE80211_C_WPA /* capable of WPA1+WPA2 */ 289178354Ssam | IEEE80211_C_BGSCAN /* capable of bg scanning */ 290178354Ssam#ifdef notyet 291178354Ssam | IEEE80211_C_TXFRAG /* handle tx frags */ 292178354Ssam#endif 293178354Ssam ; 294156321Sdamien 295170530Ssam bands = 0; 296170530Ssam setbit(&bands, IEEE80211_MODE_11B); 297170530Ssam setbit(&bands, IEEE80211_MODE_11G); 298170530Ssam if (sc->rf_rev == RT2560_RF_5222) 299170530Ssam setbit(&bands, IEEE80211_MODE_11A); 300178354Ssam ieee80211_init_channels(ic, NULL, &bands); 301156321Sdamien 302156321Sdamien ieee80211_ifattach(ic); 303178354Ssam ic->ic_newassoc = rt2560_newassoc; 304178354Ssam ic->ic_raw_xmit = rt2560_raw_xmit; 305178354Ssam ic->ic_updateslot = rt2560_update_slot; 306178354Ssam ic->ic_update_promisc = rt2560_update_promisc; 307178354Ssam ic->ic_node_alloc = rt2560_node_alloc; 308170530Ssam ic->ic_scan_start = rt2560_scan_start; 309170530Ssam ic->ic_scan_end = rt2560_scan_end; 310170530Ssam ic->ic_set_channel = rt2560_set_channel; 311156321Sdamien 312178354Ssam ic->ic_vap_create = rt2560_vap_create; 313178354Ssam ic->ic_vap_delete = rt2560_vap_delete; 314156321Sdamien 315178354Ssam bpfattach(ifp, DLT_IEEE802_11_RADIO, 316178354Ssam sizeof (struct ieee80211_frame) + sizeof (sc->sc_txtap)); 317156321Sdamien 318171086Skevlo sc->sc_rxtap_len = sizeof sc->sc_rxtap; 319156321Sdamien sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); 320156321Sdamien sc->sc_rxtap.wr_ihdr.it_present = htole32(RT2560_RX_RADIOTAP_PRESENT); 321156321Sdamien 322171086Skevlo sc->sc_txtap_len = sizeof sc->sc_txtap; 323156321Sdamien sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); 324156321Sdamien sc->sc_txtap.wt_ihdr.it_present = htole32(RT2560_TX_RADIOTAP_PRESENT); 325156321Sdamien 326156321Sdamien /* 327156321Sdamien * Add a few sysctl knobs. 328156321Sdamien */ 329178354Ssam#ifdef RAL_DEBUG 330156321Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 331156321Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 332178354Ssam "debug", CTLFLAG_RW, &sc->sc_debug, 0, "debug msgs"); 333178354Ssam#endif 334178354Ssam SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 335178354Ssam SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 336156321Sdamien "txantenna", CTLFLAG_RW, &sc->tx_ant, 0, "tx antenna (0=auto)"); 337156321Sdamien 338156321Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 339156321Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 340156321Sdamien "rxantenna", CTLFLAG_RW, &sc->rx_ant, 0, "rx antenna (0=auto)"); 341156321Sdamien 342156321Sdamien if (bootverbose) 343156321Sdamien ieee80211_announce(ic); 344156321Sdamien 345156321Sdamien return 0; 346156321Sdamien 347156321Sdamienfail6: rt2560_free_rx_ring(sc, &sc->rxq); 348156321Sdamienfail5: rt2560_free_tx_ring(sc, &sc->bcnq); 349156321Sdamienfail4: rt2560_free_tx_ring(sc, &sc->prioq); 350156321Sdamienfail3: rt2560_free_tx_ring(sc, &sc->atimq); 351156321Sdamienfail2: rt2560_free_tx_ring(sc, &sc->txq); 352156321Sdamienfail1: mtx_destroy(&sc->sc_mtx); 353156321Sdamien 354156321Sdamien return ENXIO; 355156321Sdamien} 356156321Sdamien 357156321Sdamienint 358156321Sdamienrt2560_detach(void *xsc) 359156321Sdamien{ 360156321Sdamien struct rt2560_softc *sc = xsc; 361178354Ssam struct ifnet *ifp = sc->sc_ifp; 362178354Ssam struct ieee80211com *ic = ifp->if_l2com; 363170530Ssam 364156321Sdamien rt2560_stop(sc); 365156321Sdamien 366156321Sdamien bpfdetach(ifp); 367156321Sdamien ieee80211_ifdetach(ic); 368156321Sdamien 369156321Sdamien rt2560_free_tx_ring(sc, &sc->txq); 370156321Sdamien rt2560_free_tx_ring(sc, &sc->atimq); 371156321Sdamien rt2560_free_tx_ring(sc, &sc->prioq); 372156321Sdamien rt2560_free_tx_ring(sc, &sc->bcnq); 373156321Sdamien rt2560_free_rx_ring(sc, &sc->rxq); 374156321Sdamien 375156321Sdamien if_free(ifp); 376156321Sdamien 377156321Sdamien mtx_destroy(&sc->sc_mtx); 378156321Sdamien 379156321Sdamien return 0; 380156321Sdamien} 381156321Sdamien 382178354Ssamstatic struct ieee80211vap * 383178354Ssamrt2560_vap_create(struct ieee80211com *ic, 384178354Ssam const char name[IFNAMSIZ], int unit, int opmode, int flags, 385178354Ssam const uint8_t bssid[IEEE80211_ADDR_LEN], 386178354Ssam const uint8_t mac[IEEE80211_ADDR_LEN]) 387178354Ssam{ 388178354Ssam struct ifnet *ifp = ic->ic_ifp; 389178354Ssam struct rt2560_vap *rvp; 390178354Ssam struct ieee80211vap *vap; 391178354Ssam 392178354Ssam switch (opmode) { 393178354Ssam case IEEE80211_M_STA: 394178354Ssam case IEEE80211_M_IBSS: 395178354Ssam case IEEE80211_M_AHDEMO: 396178354Ssam case IEEE80211_M_MONITOR: 397178354Ssam case IEEE80211_M_HOSTAP: 398178354Ssam if (!TAILQ_EMPTY(&ic->ic_vaps)) { 399178354Ssam if_printf(ifp, "only 1 vap supported\n"); 400178354Ssam return NULL; 401178354Ssam } 402178354Ssam if (opmode == IEEE80211_M_STA) 403178354Ssam flags |= IEEE80211_CLONE_NOBEACONS; 404178354Ssam break; 405178354Ssam case IEEE80211_M_WDS: 406178354Ssam if (TAILQ_EMPTY(&ic->ic_vaps) || 407178354Ssam ic->ic_opmode != IEEE80211_M_HOSTAP) { 408178354Ssam if_printf(ifp, "wds only supported in ap mode\n"); 409178354Ssam return NULL; 410178354Ssam } 411178354Ssam /* 412178354Ssam * Silently remove any request for a unique 413178354Ssam * bssid; WDS vap's always share the local 414178354Ssam * mac address. 415178354Ssam */ 416178354Ssam flags &= ~IEEE80211_CLONE_BSSID; 417178354Ssam break; 418178354Ssam default: 419178354Ssam if_printf(ifp, "unknown opmode %d\n", opmode); 420178354Ssam return NULL; 421178354Ssam } 422178354Ssam rvp = (struct rt2560_vap *) malloc(sizeof(struct rt2560_vap), 423178354Ssam M_80211_VAP, M_NOWAIT | M_ZERO); 424178354Ssam if (rvp == NULL) 425178354Ssam return NULL; 426178354Ssam vap = &rvp->ral_vap; 427178354Ssam ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); 428178354Ssam 429178354Ssam /* override state transition machine */ 430178354Ssam rvp->ral_newstate = vap->iv_newstate; 431178354Ssam vap->iv_newstate = rt2560_newstate; 432178354Ssam vap->iv_update_beacon = rt2560_beacon_update; 433178354Ssam 434178354Ssam ieee80211_amrr_init(&rvp->amrr, vap, 435178354Ssam IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, 436178354Ssam IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD, 437178354Ssam 500 /* ms */); 438178354Ssam 439178354Ssam /* complete setup */ 440178354Ssam ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); 441178354Ssam if (TAILQ_FIRST(&ic->ic_vaps) == vap) 442178354Ssam ic->ic_opmode = opmode; 443178354Ssam return vap; 444178354Ssam} 445178354Ssam 446178354Ssamstatic void 447178354Ssamrt2560_vap_delete(struct ieee80211vap *vap) 448178354Ssam{ 449178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 450178354Ssam 451178354Ssam ieee80211_amrr_cleanup(&rvp->amrr); 452178354Ssam ieee80211_vap_detach(vap); 453178354Ssam free(rvp, M_80211_VAP); 454178354Ssam} 455178354Ssam 456156321Sdamienvoid 457156321Sdamienrt2560_resume(void *xsc) 458156321Sdamien{ 459156321Sdamien struct rt2560_softc *sc = xsc; 460178354Ssam struct ifnet *ifp = sc->sc_ifp; 461156321Sdamien 462178354Ssam if (ifp->if_flags & IFF_UP) 463178354Ssam rt2560_init(sc); 464156321Sdamien} 465156321Sdamien 466156321Sdamienstatic void 467156321Sdamienrt2560_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 468156321Sdamien{ 469156321Sdamien if (error != 0) 470156321Sdamien return; 471156321Sdamien 472156321Sdamien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 473156321Sdamien 474156321Sdamien *(bus_addr_t *)arg = segs[0].ds_addr; 475156321Sdamien} 476156321Sdamien 477156321Sdamienstatic int 478156321Sdamienrt2560_alloc_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring, 479156321Sdamien int count) 480156321Sdamien{ 481156321Sdamien int i, error; 482156321Sdamien 483156321Sdamien ring->count = count; 484156321Sdamien ring->queued = 0; 485156321Sdamien ring->cur = ring->next = 0; 486156321Sdamien ring->cur_encrypt = ring->next_encrypt = 0; 487156321Sdamien 488171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 4, 0, 489171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 490171535Skevlo count * RT2560_TX_DESC_SIZE, 1, count * RT2560_TX_DESC_SIZE, 491171535Skevlo 0, NULL, NULL, &ring->desc_dmat); 492156321Sdamien if (error != 0) { 493156321Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 494156321Sdamien goto fail; 495156321Sdamien } 496156321Sdamien 497156321Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 498156321Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 499156321Sdamien if (error != 0) { 500156321Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 501156321Sdamien goto fail; 502156321Sdamien } 503156321Sdamien 504156321Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 505156321Sdamien count * RT2560_TX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr, 506156321Sdamien 0); 507156321Sdamien if (error != 0) { 508156321Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 509156321Sdamien goto fail; 510156321Sdamien } 511156321Sdamien 512156321Sdamien ring->data = malloc(count * sizeof (struct rt2560_tx_data), M_DEVBUF, 513156321Sdamien M_NOWAIT | M_ZERO); 514156321Sdamien if (ring->data == NULL) { 515156321Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 516156321Sdamien error = ENOMEM; 517156321Sdamien goto fail; 518156321Sdamien } 519156321Sdamien 520171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 521171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 522171535Skevlo MCLBYTES, RT2560_MAX_SCATTER, MCLBYTES, 0, NULL, NULL, 523171535Skevlo &ring->data_dmat); 524156321Sdamien if (error != 0) { 525156321Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 526156321Sdamien goto fail; 527156321Sdamien } 528156321Sdamien 529156321Sdamien for (i = 0; i < count; i++) { 530156321Sdamien error = bus_dmamap_create(ring->data_dmat, 0, 531156321Sdamien &ring->data[i].map); 532156321Sdamien if (error != 0) { 533156321Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 534156321Sdamien goto fail; 535156321Sdamien } 536156321Sdamien } 537156321Sdamien 538156321Sdamien return 0; 539156321Sdamien 540156321Sdamienfail: rt2560_free_tx_ring(sc, ring); 541156321Sdamien return error; 542156321Sdamien} 543156321Sdamien 544156321Sdamienstatic void 545156321Sdamienrt2560_reset_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) 546156321Sdamien{ 547156321Sdamien struct rt2560_tx_desc *desc; 548156321Sdamien struct rt2560_tx_data *data; 549156321Sdamien int i; 550156321Sdamien 551156321Sdamien for (i = 0; i < ring->count; i++) { 552156321Sdamien desc = &ring->desc[i]; 553156321Sdamien data = &ring->data[i]; 554156321Sdamien 555156321Sdamien if (data->m != NULL) { 556156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 557156321Sdamien BUS_DMASYNC_POSTWRITE); 558156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 559156321Sdamien m_freem(data->m); 560156321Sdamien data->m = NULL; 561156321Sdamien } 562156321Sdamien 563156321Sdamien if (data->ni != NULL) { 564156321Sdamien ieee80211_free_node(data->ni); 565156321Sdamien data->ni = NULL; 566156321Sdamien } 567156321Sdamien 568156321Sdamien desc->flags = 0; 569156321Sdamien } 570156321Sdamien 571156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 572156321Sdamien 573156321Sdamien ring->queued = 0; 574156321Sdamien ring->cur = ring->next = 0; 575156321Sdamien ring->cur_encrypt = ring->next_encrypt = 0; 576156321Sdamien} 577156321Sdamien 578156321Sdamienstatic void 579156321Sdamienrt2560_free_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) 580156321Sdamien{ 581156321Sdamien struct rt2560_tx_data *data; 582156321Sdamien int i; 583156321Sdamien 584156321Sdamien if (ring->desc != NULL) { 585156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 586156321Sdamien BUS_DMASYNC_POSTWRITE); 587156321Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 588156321Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 589156321Sdamien } 590156321Sdamien 591156321Sdamien if (ring->desc_dmat != NULL) 592156321Sdamien bus_dma_tag_destroy(ring->desc_dmat); 593156321Sdamien 594156321Sdamien if (ring->data != NULL) { 595156321Sdamien for (i = 0; i < ring->count; i++) { 596156321Sdamien data = &ring->data[i]; 597156321Sdamien 598156321Sdamien if (data->m != NULL) { 599156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 600156321Sdamien BUS_DMASYNC_POSTWRITE); 601156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 602156321Sdamien m_freem(data->m); 603156321Sdamien } 604156321Sdamien 605156321Sdamien if (data->ni != NULL) 606156321Sdamien ieee80211_free_node(data->ni); 607156321Sdamien 608156321Sdamien if (data->map != NULL) 609156321Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 610156321Sdamien } 611156321Sdamien 612156321Sdamien free(ring->data, M_DEVBUF); 613156321Sdamien } 614156321Sdamien 615156321Sdamien if (ring->data_dmat != NULL) 616156321Sdamien bus_dma_tag_destroy(ring->data_dmat); 617156321Sdamien} 618156321Sdamien 619156321Sdamienstatic int 620156321Sdamienrt2560_alloc_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring, 621156321Sdamien int count) 622156321Sdamien{ 623156321Sdamien struct rt2560_rx_desc *desc; 624156321Sdamien struct rt2560_rx_data *data; 625156321Sdamien bus_addr_t physaddr; 626156321Sdamien int i, error; 627156321Sdamien 628156321Sdamien ring->count = count; 629156321Sdamien ring->cur = ring->next = 0; 630156321Sdamien ring->cur_decrypt = 0; 631156321Sdamien 632171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 4, 0, 633171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 634171535Skevlo count * RT2560_RX_DESC_SIZE, 1, count * RT2560_RX_DESC_SIZE, 635171535Skevlo 0, NULL, NULL, &ring->desc_dmat); 636156321Sdamien if (error != 0) { 637156321Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 638156321Sdamien goto fail; 639156321Sdamien } 640156321Sdamien 641156321Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 642156321Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 643156321Sdamien if (error != 0) { 644156321Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 645156321Sdamien goto fail; 646156321Sdamien } 647156321Sdamien 648156321Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 649156321Sdamien count * RT2560_RX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr, 650156321Sdamien 0); 651156321Sdamien if (error != 0) { 652156321Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 653156321Sdamien goto fail; 654156321Sdamien } 655156321Sdamien 656156321Sdamien ring->data = malloc(count * sizeof (struct rt2560_rx_data), M_DEVBUF, 657156321Sdamien M_NOWAIT | M_ZERO); 658156321Sdamien if (ring->data == NULL) { 659156321Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 660156321Sdamien error = ENOMEM; 661156321Sdamien goto fail; 662156321Sdamien } 663156321Sdamien 664156321Sdamien /* 665156321Sdamien * Pre-allocate Rx buffers and populate Rx ring. 666156321Sdamien */ 667171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 668171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 669171535Skevlo 1, MCLBYTES, 0, NULL, NULL, &ring->data_dmat); 670156321Sdamien if (error != 0) { 671156321Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 672156321Sdamien goto fail; 673156321Sdamien } 674156321Sdamien 675156321Sdamien for (i = 0; i < count; i++) { 676156321Sdamien desc = &sc->rxq.desc[i]; 677156321Sdamien data = &sc->rxq.data[i]; 678156321Sdamien 679156321Sdamien error = bus_dmamap_create(ring->data_dmat, 0, &data->map); 680156321Sdamien if (error != 0) { 681156321Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 682156321Sdamien goto fail; 683156321Sdamien } 684156321Sdamien 685156321Sdamien data->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 686156321Sdamien if (data->m == NULL) { 687156321Sdamien device_printf(sc->sc_dev, 688156321Sdamien "could not allocate rx mbuf\n"); 689156321Sdamien error = ENOMEM; 690156321Sdamien goto fail; 691156321Sdamien } 692156321Sdamien 693156321Sdamien error = bus_dmamap_load(ring->data_dmat, data->map, 694156321Sdamien mtod(data->m, void *), MCLBYTES, rt2560_dma_map_addr, 695156321Sdamien &physaddr, 0); 696156321Sdamien if (error != 0) { 697156321Sdamien device_printf(sc->sc_dev, 698156321Sdamien "could not load rx buf DMA map"); 699156321Sdamien goto fail; 700156321Sdamien } 701156321Sdamien 702156321Sdamien desc->flags = htole32(RT2560_RX_BUSY); 703156321Sdamien desc->physaddr = htole32(physaddr); 704156321Sdamien } 705156321Sdamien 706156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 707156321Sdamien 708156321Sdamien return 0; 709156321Sdamien 710156321Sdamienfail: rt2560_free_rx_ring(sc, ring); 711156321Sdamien return error; 712156321Sdamien} 713156321Sdamien 714156321Sdamienstatic void 715156321Sdamienrt2560_reset_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) 716156321Sdamien{ 717156321Sdamien int i; 718156321Sdamien 719156321Sdamien for (i = 0; i < ring->count; i++) { 720156321Sdamien ring->desc[i].flags = htole32(RT2560_RX_BUSY); 721156321Sdamien ring->data[i].drop = 0; 722156321Sdamien } 723156321Sdamien 724156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 725156321Sdamien 726156321Sdamien ring->cur = ring->next = 0; 727156321Sdamien ring->cur_decrypt = 0; 728156321Sdamien} 729156321Sdamien 730156321Sdamienstatic void 731156321Sdamienrt2560_free_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) 732156321Sdamien{ 733156321Sdamien struct rt2560_rx_data *data; 734156321Sdamien int i; 735156321Sdamien 736156321Sdamien if (ring->desc != NULL) { 737156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 738156321Sdamien BUS_DMASYNC_POSTWRITE); 739156321Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 740156321Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 741156321Sdamien } 742156321Sdamien 743156321Sdamien if (ring->desc_dmat != NULL) 744156321Sdamien bus_dma_tag_destroy(ring->desc_dmat); 745156321Sdamien 746156321Sdamien if (ring->data != NULL) { 747156321Sdamien for (i = 0; i < ring->count; i++) { 748156321Sdamien data = &ring->data[i]; 749156321Sdamien 750156321Sdamien if (data->m != NULL) { 751156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 752156321Sdamien BUS_DMASYNC_POSTREAD); 753156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 754156321Sdamien m_freem(data->m); 755156321Sdamien } 756156321Sdamien 757156321Sdamien if (data->map != NULL) 758156321Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 759156321Sdamien } 760156321Sdamien 761156321Sdamien free(ring->data, M_DEVBUF); 762156321Sdamien } 763156321Sdamien 764156321Sdamien if (ring->data_dmat != NULL) 765156321Sdamien bus_dma_tag_destroy(ring->data_dmat); 766156321Sdamien} 767156321Sdamien 768156321Sdamienstatic struct ieee80211_node * 769156321Sdamienrt2560_node_alloc(struct ieee80211_node_table *nt) 770156321Sdamien{ 771156321Sdamien struct rt2560_node *rn; 772156321Sdamien 773156321Sdamien rn = malloc(sizeof (struct rt2560_node), M_80211_NODE, 774156321Sdamien M_NOWAIT | M_ZERO); 775156321Sdamien 776156321Sdamien return (rn != NULL) ? &rn->ni : NULL; 777156321Sdamien} 778156321Sdamien 779156321Sdamienstatic void 780178354Ssamrt2560_newassoc(struct ieee80211_node *ni, int isnew) 781156321Sdamien{ 782178354Ssam struct ieee80211vap *vap = ni->ni_vap; 783156321Sdamien 784178354Ssam ieee80211_amrr_node_init(&RT2560_VAP(vap)->amrr, 785178354Ssam &RT2560_NODE(ni)->amrr, ni); 786156321Sdamien} 787156321Sdamien 788156321Sdamienstatic int 789178354Ssamrt2560_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 790156321Sdamien{ 791178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 792178354Ssam struct ifnet *ifp = vap->iv_ic->ic_ifp; 793178354Ssam struct rt2560_softc *sc = ifp->if_softc; 794178354Ssam int error; 795156321Sdamien 796178354Ssam if (nstate == IEEE80211_S_INIT && vap->iv_state == IEEE80211_S_RUN) { 797178354Ssam /* abort TSF synchronization */ 798178354Ssam RAL_WRITE(sc, RT2560_CSR14, 0); 799156321Sdamien 800178354Ssam /* turn association led off */ 801178354Ssam rt2560_update_led(sc, 0, 0); 802178354Ssam } 803156321Sdamien 804178354Ssam error = rvp->ral_newstate(vap, nstate, arg); 805156321Sdamien 806178354Ssam if (error == 0 && nstate == IEEE80211_S_RUN) { 807178354Ssam struct ieee80211_node *ni = vap->iv_bss; 808178354Ssam struct mbuf *m; 809156321Sdamien 810178354Ssam if (vap->iv_opmode != IEEE80211_M_MONITOR) { 811156321Sdamien rt2560_update_plcp(sc); 812156321Sdamien rt2560_set_basicrates(sc); 813156321Sdamien rt2560_set_bssid(sc, ni->ni_bssid); 814156321Sdamien } 815156321Sdamien 816178354Ssam if (vap->iv_opmode == IEEE80211_M_HOSTAP || 817178354Ssam vap->iv_opmode == IEEE80211_M_IBSS) { 818178354Ssam m = ieee80211_beacon_alloc(ni, &rvp->ral_bo); 819156321Sdamien if (m == NULL) { 820178354Ssam if_printf(ifp, "could not allocate beacon\n"); 821178354Ssam return ENOBUFS; 822156321Sdamien } 823156321Sdamien ieee80211_ref_node(ni); 824156321Sdamien error = rt2560_tx_bcn(sc, m, ni); 825156321Sdamien if (error != 0) 826178354Ssam return error; 827156321Sdamien } 828156321Sdamien 829156321Sdamien /* turn assocation led on */ 830156321Sdamien rt2560_update_led(sc, 1, 0); 831156321Sdamien 832178354Ssam if (vap->iv_opmode != IEEE80211_M_MONITOR) { 833178354Ssam if (vap->iv_opmode == IEEE80211_M_STA) { 834178354Ssam /* fake a join to init the tx rate */ 835178354Ssam rt2560_newassoc(ni, 1); 836178354Ssam } 837156321Sdamien rt2560_enable_tsf_sync(sc); 838156321Sdamien } 839156321Sdamien } 840178354Ssam return error; 841156321Sdamien} 842156321Sdamien 843156321Sdamien/* 844156321Sdamien * Read 16 bits at address 'addr' from the serial EEPROM (either 93C46 or 845156321Sdamien * 93C66). 846156321Sdamien */ 847156321Sdamienstatic uint16_t 848156321Sdamienrt2560_eeprom_read(struct rt2560_softc *sc, uint8_t addr) 849156321Sdamien{ 850156321Sdamien uint32_t tmp; 851156321Sdamien uint16_t val; 852156321Sdamien int n; 853156321Sdamien 854156321Sdamien /* clock C once before the first command */ 855156321Sdamien RT2560_EEPROM_CTL(sc, 0); 856156321Sdamien 857156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 858156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 859156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 860156321Sdamien 861156321Sdamien /* write start bit (1) */ 862156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D); 863156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C); 864156321Sdamien 865156321Sdamien /* write READ opcode (10) */ 866156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D); 867156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C); 868156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 869156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 870156321Sdamien 871156321Sdamien /* write address (A5-A0 or A7-A0) */ 872156321Sdamien n = (RAL_READ(sc, RT2560_CSR21) & RT2560_93C46) ? 5 : 7; 873156321Sdamien for (; n >= 0; n--) { 874156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | 875156321Sdamien (((addr >> n) & 1) << RT2560_SHIFT_D)); 876156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | 877156321Sdamien (((addr >> n) & 1) << RT2560_SHIFT_D) | RT2560_C); 878156321Sdamien } 879156321Sdamien 880156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 881156321Sdamien 882156321Sdamien /* read data Q15-Q0 */ 883156321Sdamien val = 0; 884156321Sdamien for (n = 15; n >= 0; n--) { 885156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 886156321Sdamien tmp = RAL_READ(sc, RT2560_CSR21); 887156321Sdamien val |= ((tmp & RT2560_Q) >> RT2560_SHIFT_Q) << n; 888156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 889156321Sdamien } 890156321Sdamien 891156321Sdamien RT2560_EEPROM_CTL(sc, 0); 892156321Sdamien 893156321Sdamien /* clear Chip Select and clock C */ 894156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 895156321Sdamien RT2560_EEPROM_CTL(sc, 0); 896156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_C); 897156321Sdamien 898156321Sdamien return val; 899156321Sdamien} 900156321Sdamien 901156321Sdamien/* 902156321Sdamien * Some frames were processed by the hardware cipher engine and are ready for 903156321Sdamien * transmission. 904156321Sdamien */ 905156321Sdamienstatic void 906156321Sdamienrt2560_encryption_intr(struct rt2560_softc *sc) 907156321Sdamien{ 908156321Sdamien struct rt2560_tx_desc *desc; 909156321Sdamien int hw; 910156321Sdamien 911156321Sdamien /* retrieve last descriptor index processed by cipher engine */ 912156321Sdamien hw = RAL_READ(sc, RT2560_SECCSR1) - sc->txq.physaddr; 913156321Sdamien hw /= RT2560_TX_DESC_SIZE; 914156321Sdamien 915156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 916156321Sdamien BUS_DMASYNC_POSTREAD); 917156321Sdamien 918175938Ssephe while (sc->txq.next_encrypt != hw) { 919175938Ssephe if (sc->txq.next_encrypt == sc->txq.cur_encrypt) { 920175938Ssephe printf("hw encrypt %d, cur_encrypt %d\n", hw, 921175938Ssephe sc->txq.cur_encrypt); 922175938Ssephe break; 923175938Ssephe } 924175938Ssephe 925156321Sdamien desc = &sc->txq.desc[sc->txq.next_encrypt]; 926156321Sdamien 927156321Sdamien if ((le32toh(desc->flags) & RT2560_TX_BUSY) || 928156321Sdamien (le32toh(desc->flags) & RT2560_TX_CIPHER_BUSY)) 929156321Sdamien break; 930156321Sdamien 931156321Sdamien /* for TKIP, swap eiv field to fix a bug in ASIC */ 932156321Sdamien if ((le32toh(desc->flags) & RT2560_TX_CIPHER_MASK) == 933156321Sdamien RT2560_TX_CIPHER_TKIP) 934156321Sdamien desc->eiv = bswap32(desc->eiv); 935156321Sdamien 936156321Sdamien /* mark the frame ready for transmission */ 937175938Ssephe desc->flags |= htole32(RT2560_TX_VALID); 938175938Ssephe desc->flags |= htole32(RT2560_TX_BUSY); 939156321Sdamien 940178354Ssam DPRINTFN(sc, 15, "encryption done idx=%u\n", 941178354Ssam sc->txq.next_encrypt); 942156321Sdamien 943156321Sdamien sc->txq.next_encrypt = 944156321Sdamien (sc->txq.next_encrypt + 1) % RT2560_TX_RING_COUNT; 945156321Sdamien } 946156321Sdamien 947156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 948156321Sdamien BUS_DMASYNC_PREWRITE); 949156321Sdamien 950156321Sdamien /* kick Tx */ 951156321Sdamien RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_TX); 952156321Sdamien} 953156321Sdamien 954156321Sdamienstatic void 955156321Sdamienrt2560_tx_intr(struct rt2560_softc *sc) 956156321Sdamien{ 957178354Ssam struct ifnet *ifp = sc->sc_ifp; 958156321Sdamien struct rt2560_tx_desc *desc; 959156321Sdamien struct rt2560_tx_data *data; 960156321Sdamien struct rt2560_node *rn; 961178354Ssam struct mbuf *m; 962178354Ssam uint32_t flags; 963178354Ssam int retrycnt; 964156321Sdamien 965156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 966156321Sdamien BUS_DMASYNC_POSTREAD); 967156321Sdamien 968156321Sdamien for (;;) { 969156321Sdamien desc = &sc->txq.desc[sc->txq.next]; 970156321Sdamien data = &sc->txq.data[sc->txq.next]; 971156321Sdamien 972178354Ssam flags = le32toh(desc->flags); 973178354Ssam if ((flags & RT2560_TX_BUSY) || 974178354Ssam (flags & RT2560_TX_CIPHER_BUSY) || 975178354Ssam !(flags & RT2560_TX_VALID)) 976156321Sdamien break; 977156321Sdamien 978156321Sdamien rn = (struct rt2560_node *)data->ni; 979178354Ssam m = data->m; 980156321Sdamien 981178354Ssam switch (flags & RT2560_TX_RESULT_MASK) { 982156321Sdamien case RT2560_TX_SUCCESS: 983178354Ssam DPRINTFN(sc, 10, "%s\n", "data frame sent successfully"); 984178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 985178354Ssam ieee80211_amrr_tx_complete(&rn->amrr, 986178354Ssam IEEE80211_AMRR_SUCCESS, 0); 987156321Sdamien ifp->if_opackets++; 988156321Sdamien break; 989156321Sdamien 990156321Sdamien case RT2560_TX_SUCCESS_RETRY: 991178354Ssam retrycnt = RT2560_TX_RETRYCNT(flags); 992178354Ssam 993178354Ssam DPRINTFN(sc, 9, "data frame sent after %u retries\n", 994178354Ssam retrycnt); 995178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 996178354Ssam ieee80211_amrr_tx_complete(&rn->amrr, 997178354Ssam IEEE80211_AMRR_SUCCESS, retrycnt); 998156321Sdamien ifp->if_opackets++; 999156321Sdamien break; 1000156321Sdamien 1001156321Sdamien case RT2560_TX_FAIL_RETRY: 1002178354Ssam retrycnt = RT2560_TX_RETRYCNT(flags); 1003178354Ssam 1004178354Ssam DPRINTFN(sc, 9, "data frame failed after %d retries\n", 1005178354Ssam retrycnt); 1006178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 1007178354Ssam ieee80211_amrr_tx_complete(&rn->amrr, 1008178354Ssam IEEE80211_AMRR_FAILURE, retrycnt); 1009156321Sdamien ifp->if_oerrors++; 1010156321Sdamien break; 1011156321Sdamien 1012156321Sdamien case RT2560_TX_FAIL_INVALID: 1013156321Sdamien case RT2560_TX_FAIL_OTHER: 1014156321Sdamien default: 1015156321Sdamien device_printf(sc->sc_dev, "sending data frame failed " 1016178354Ssam "0x%08x\n", flags); 1017156321Sdamien ifp->if_oerrors++; 1018156321Sdamien } 1019156321Sdamien 1020156321Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, 1021156321Sdamien BUS_DMASYNC_POSTWRITE); 1022156321Sdamien bus_dmamap_unload(sc->txq.data_dmat, data->map); 1023178354Ssam m_freem(m); 1024156321Sdamien data->m = NULL; 1025156321Sdamien ieee80211_free_node(data->ni); 1026156321Sdamien data->ni = NULL; 1027156321Sdamien 1028156321Sdamien /* descriptor is no longer valid */ 1029156321Sdamien desc->flags &= ~htole32(RT2560_TX_VALID); 1030156321Sdamien 1031178354Ssam DPRINTFN(sc, 15, "tx done idx=%u\n", sc->txq.next); 1032156321Sdamien 1033156321Sdamien sc->txq.queued--; 1034156321Sdamien sc->txq.next = (sc->txq.next + 1) % RT2560_TX_RING_COUNT; 1035156321Sdamien } 1036156321Sdamien 1037156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 1038156321Sdamien BUS_DMASYNC_PREWRITE); 1039156321Sdamien 1040175938Ssephe if (sc->prioq.queued == 0 && sc->txq.queued == 0) 1041175938Ssephe sc->sc_tx_timer = 0; 1042175938Ssephe 1043175938Ssephe if (sc->txq.queued < RT2560_TX_RING_COUNT - 1) { 1044175938Ssephe sc->sc_flags &= ~RT2560_F_DATA_OACTIVE; 1045175938Ssephe if ((sc->sc_flags & 1046175938Ssephe (RT2560_F_DATA_OACTIVE | RT2560_F_PRIO_OACTIVE)) == 0) 1047175938Ssephe ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1048178354Ssam rt2560_start_locked(ifp); 1049175938Ssephe } 1050156321Sdamien} 1051156321Sdamien 1052156321Sdamienstatic void 1053156321Sdamienrt2560_prio_intr(struct rt2560_softc *sc) 1054156321Sdamien{ 1055178354Ssam struct ifnet *ifp = sc->sc_ifp; 1056156321Sdamien struct rt2560_tx_desc *desc; 1057156321Sdamien struct rt2560_tx_data *data; 1058170530Ssam struct ieee80211_node *ni; 1059170530Ssam struct mbuf *m; 1060170530Ssam int flags; 1061156321Sdamien 1062156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1063156321Sdamien BUS_DMASYNC_POSTREAD); 1064156321Sdamien 1065156321Sdamien for (;;) { 1066156321Sdamien desc = &sc->prioq.desc[sc->prioq.next]; 1067156321Sdamien data = &sc->prioq.data[sc->prioq.next]; 1068156321Sdamien 1069170530Ssam flags = le32toh(desc->flags); 1070170530Ssam if ((flags & RT2560_TX_BUSY) || (flags & RT2560_TX_VALID) == 0) 1071156321Sdamien break; 1072156321Sdamien 1073170530Ssam switch (flags & RT2560_TX_RESULT_MASK) { 1074156321Sdamien case RT2560_TX_SUCCESS: 1075178354Ssam DPRINTFN(sc, 10, "%s\n", "mgt frame sent successfully"); 1076156321Sdamien break; 1077156321Sdamien 1078156321Sdamien case RT2560_TX_SUCCESS_RETRY: 1079178354Ssam DPRINTFN(sc, 9, "mgt frame sent after %u retries\n", 1080178354Ssam (flags >> 5) & 0x7); 1081156321Sdamien break; 1082156321Sdamien 1083156321Sdamien case RT2560_TX_FAIL_RETRY: 1084178354Ssam DPRINTFN(sc, 9, "%s\n", 1085178354Ssam "sending mgt frame failed (too much retries)"); 1086156321Sdamien break; 1087156321Sdamien 1088156321Sdamien case RT2560_TX_FAIL_INVALID: 1089156321Sdamien case RT2560_TX_FAIL_OTHER: 1090156321Sdamien default: 1091156321Sdamien device_printf(sc->sc_dev, "sending mgt frame failed " 1092170530Ssam "0x%08x\n", flags); 1093170530Ssam break; 1094156321Sdamien } 1095156321Sdamien 1096156321Sdamien bus_dmamap_sync(sc->prioq.data_dmat, data->map, 1097156321Sdamien BUS_DMASYNC_POSTWRITE); 1098156321Sdamien bus_dmamap_unload(sc->prioq.data_dmat, data->map); 1099170530Ssam 1100170530Ssam m = data->m; 1101156321Sdamien data->m = NULL; 1102170530Ssam ni = data->ni; 1103156321Sdamien data->ni = NULL; 1104156321Sdamien 1105156321Sdamien /* descriptor is no longer valid */ 1106156321Sdamien desc->flags &= ~htole32(RT2560_TX_VALID); 1107156321Sdamien 1108178354Ssam DPRINTFN(sc, 15, "prio done idx=%u\n", sc->prioq.next); 1109156321Sdamien 1110156321Sdamien sc->prioq.queued--; 1111156321Sdamien sc->prioq.next = (sc->prioq.next + 1) % RT2560_PRIO_RING_COUNT; 1112170530Ssam 1113170530Ssam if (m->m_flags & M_TXCB) 1114170530Ssam ieee80211_process_callback(ni, m, 1115170530Ssam (flags & RT2560_TX_RESULT_MASK) &~ 1116170530Ssam (RT2560_TX_SUCCESS | RT2560_TX_SUCCESS_RETRY)); 1117170530Ssam m_freem(m); 1118170530Ssam ieee80211_free_node(ni); 1119156321Sdamien } 1120156321Sdamien 1121156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1122156321Sdamien BUS_DMASYNC_PREWRITE); 1123156321Sdamien 1124175938Ssephe if (sc->prioq.queued == 0 && sc->txq.queued == 0) 1125175938Ssephe sc->sc_tx_timer = 0; 1126175938Ssephe 1127175938Ssephe if (sc->prioq.queued < RT2560_PRIO_RING_COUNT) { 1128175938Ssephe sc->sc_flags &= ~RT2560_F_PRIO_OACTIVE; 1129175938Ssephe if ((sc->sc_flags & 1130175938Ssephe (RT2560_F_DATA_OACTIVE | RT2560_F_PRIO_OACTIVE)) == 0) 1131175938Ssephe ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1132178354Ssam rt2560_start_locked(ifp); 1133175938Ssephe } 1134156321Sdamien} 1135156321Sdamien 1136156321Sdamien/* 1137156321Sdamien * Some frames were processed by the hardware cipher engine and are ready for 1138178354Ssam * handoff to the IEEE802.11 layer. 1139156321Sdamien */ 1140156321Sdamienstatic void 1141156321Sdamienrt2560_decryption_intr(struct rt2560_softc *sc) 1142156321Sdamien{ 1143178354Ssam struct ifnet *ifp = sc->sc_ifp; 1144178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1145156321Sdamien struct rt2560_rx_desc *desc; 1146156321Sdamien struct rt2560_rx_data *data; 1147156321Sdamien bus_addr_t physaddr; 1148156321Sdamien struct ieee80211_frame *wh; 1149156321Sdamien struct ieee80211_node *ni; 1150156321Sdamien struct mbuf *mnew, *m; 1151156321Sdamien int hw, error; 1152156321Sdamien 1153156321Sdamien /* retrieve last decriptor index processed by cipher engine */ 1154156321Sdamien hw = RAL_READ(sc, RT2560_SECCSR0) - sc->rxq.physaddr; 1155156321Sdamien hw /= RT2560_RX_DESC_SIZE; 1156156321Sdamien 1157156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1158156321Sdamien BUS_DMASYNC_POSTREAD); 1159156321Sdamien 1160156321Sdamien for (; sc->rxq.cur_decrypt != hw;) { 1161156321Sdamien desc = &sc->rxq.desc[sc->rxq.cur_decrypt]; 1162156321Sdamien data = &sc->rxq.data[sc->rxq.cur_decrypt]; 1163156321Sdamien 1164156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_BUSY) || 1165156321Sdamien (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY)) 1166156321Sdamien break; 1167156321Sdamien 1168156321Sdamien if (data->drop) { 1169156321Sdamien ifp->if_ierrors++; 1170156321Sdamien goto skip; 1171156321Sdamien } 1172156321Sdamien 1173156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_CIPHER_MASK) != 0 && 1174156321Sdamien (le32toh(desc->flags) & RT2560_RX_ICV_ERROR)) { 1175156321Sdamien ifp->if_ierrors++; 1176156321Sdamien goto skip; 1177156321Sdamien } 1178156321Sdamien 1179156321Sdamien /* 1180156321Sdamien * Try to allocate a new mbuf for this ring element and load it 1181156321Sdamien * before processing the current mbuf. If the ring element 1182156321Sdamien * cannot be loaded, drop the received packet and reuse the old 1183156321Sdamien * mbuf. In the unlikely case that the old mbuf can't be 1184156321Sdamien * reloaded either, explicitly panic. 1185156321Sdamien */ 1186156321Sdamien mnew = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1187156321Sdamien if (mnew == NULL) { 1188156321Sdamien ifp->if_ierrors++; 1189156321Sdamien goto skip; 1190156321Sdamien } 1191156321Sdamien 1192156321Sdamien bus_dmamap_sync(sc->rxq.data_dmat, data->map, 1193156321Sdamien BUS_DMASYNC_POSTREAD); 1194156321Sdamien bus_dmamap_unload(sc->rxq.data_dmat, data->map); 1195156321Sdamien 1196156321Sdamien error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 1197156321Sdamien mtod(mnew, void *), MCLBYTES, rt2560_dma_map_addr, 1198156321Sdamien &physaddr, 0); 1199156321Sdamien if (error != 0) { 1200156321Sdamien m_freem(mnew); 1201156321Sdamien 1202156321Sdamien /* try to reload the old mbuf */ 1203156321Sdamien error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 1204156321Sdamien mtod(data->m, void *), MCLBYTES, 1205156321Sdamien rt2560_dma_map_addr, &physaddr, 0); 1206156321Sdamien if (error != 0) { 1207156321Sdamien /* very unlikely that it will fail... */ 1208156321Sdamien panic("%s: could not load old rx mbuf", 1209156321Sdamien device_get_name(sc->sc_dev)); 1210156321Sdamien } 1211156321Sdamien ifp->if_ierrors++; 1212156321Sdamien goto skip; 1213156321Sdamien } 1214156321Sdamien 1215156321Sdamien /* 1216156321Sdamien * New mbuf successfully loaded, update Rx ring and continue 1217156321Sdamien * processing. 1218156321Sdamien */ 1219156321Sdamien m = data->m; 1220156321Sdamien data->m = mnew; 1221156321Sdamien desc->physaddr = htole32(physaddr); 1222156321Sdamien 1223156321Sdamien /* finalize mbuf */ 1224156321Sdamien m->m_pkthdr.rcvif = ifp; 1225156321Sdamien m->m_pkthdr.len = m->m_len = 1226156321Sdamien (le32toh(desc->flags) >> 16) & 0xfff; 1227156321Sdamien 1228178354Ssam if (bpf_peers_present(ifp->if_bpf)) { 1229156321Sdamien struct rt2560_rx_radiotap_header *tap = &sc->sc_rxtap; 1230156321Sdamien uint32_t tsf_lo, tsf_hi; 1231156321Sdamien 1232156321Sdamien /* get timestamp (low and high 32 bits) */ 1233156321Sdamien tsf_hi = RAL_READ(sc, RT2560_CSR17); 1234156321Sdamien tsf_lo = RAL_READ(sc, RT2560_CSR16); 1235156321Sdamien 1236156321Sdamien tap->wr_tsf = 1237156321Sdamien htole64(((uint64_t)tsf_hi << 32) | tsf_lo); 1238156321Sdamien tap->wr_flags = 0; 1239178354Ssam tap->wr_rate = ieee80211_plcp2rate(desc->rate, 1240178354Ssam le32toh(desc->flags) & RT2560_RX_OFDM); 1241156321Sdamien tap->wr_antenna = sc->rx_ant; 1242170530Ssam tap->wr_antsignal = RT2560_RSSI(sc, desc->rssi); 1243156321Sdamien 1244178354Ssam bpf_mtap2(ifp->if_bpf, tap, sc->sc_rxtap_len, m); 1245156321Sdamien } 1246156321Sdamien 1247175938Ssephe sc->sc_flags |= RT2560_F_INPUT_RUNNING; 1248170530Ssam RAL_UNLOCK(sc); 1249156321Sdamien wh = mtod(m, struct ieee80211_frame *); 1250156321Sdamien ni = ieee80211_find_rxnode(ic, 1251156321Sdamien (struct ieee80211_frame_min *)wh); 1252178354Ssam if (ni != NULL) { 1253178354Ssam (void) ieee80211_input(ni, m, 1254178354Ssam RT2560_RSSI(sc, desc->rssi), RT2560_NOISE_FLOOR, 0); 1255178354Ssam ieee80211_free_node(ni); 1256178354Ssam } else 1257178354Ssam (void) ieee80211_input_all(ic, m, 1258178354Ssam RT2560_RSSI(sc, desc->rssi), RT2560_NOISE_FLOOR, 0); 1259156321Sdamien 1260170530Ssam RAL_LOCK(sc); 1261175938Ssephe sc->sc_flags &= ~RT2560_F_INPUT_RUNNING; 1262156321Sdamienskip: desc->flags = htole32(RT2560_RX_BUSY); 1263156321Sdamien 1264178354Ssam DPRINTFN(sc, 15, "decryption done idx=%u\n", sc->rxq.cur_decrypt); 1265156321Sdamien 1266156321Sdamien sc->rxq.cur_decrypt = 1267156321Sdamien (sc->rxq.cur_decrypt + 1) % RT2560_RX_RING_COUNT; 1268156321Sdamien } 1269156321Sdamien 1270156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1271156321Sdamien BUS_DMASYNC_PREWRITE); 1272156321Sdamien} 1273156321Sdamien 1274156321Sdamien/* 1275156321Sdamien * Some frames were received. Pass them to the hardware cipher engine before 1276156321Sdamien * sending them to the 802.11 layer. 1277156321Sdamien */ 1278156321Sdamienstatic void 1279156321Sdamienrt2560_rx_intr(struct rt2560_softc *sc) 1280156321Sdamien{ 1281156321Sdamien struct rt2560_rx_desc *desc; 1282156321Sdamien struct rt2560_rx_data *data; 1283156321Sdamien 1284156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1285156321Sdamien BUS_DMASYNC_POSTREAD); 1286156321Sdamien 1287156321Sdamien for (;;) { 1288156321Sdamien desc = &sc->rxq.desc[sc->rxq.cur]; 1289156321Sdamien data = &sc->rxq.data[sc->rxq.cur]; 1290156321Sdamien 1291156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_BUSY) || 1292156321Sdamien (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY)) 1293156321Sdamien break; 1294156321Sdamien 1295156321Sdamien data->drop = 0; 1296156321Sdamien 1297156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_PHY_ERROR) || 1298156321Sdamien (le32toh(desc->flags) & RT2560_RX_CRC_ERROR)) { 1299156321Sdamien /* 1300156321Sdamien * This should not happen since we did not request 1301156321Sdamien * to receive those frames when we filled RXCSR0. 1302156321Sdamien */ 1303178354Ssam DPRINTFN(sc, 5, "PHY or CRC error flags 0x%08x\n", 1304178354Ssam le32toh(desc->flags)); 1305156321Sdamien data->drop = 1; 1306156321Sdamien } 1307156321Sdamien 1308156321Sdamien if (((le32toh(desc->flags) >> 16) & 0xfff) > MCLBYTES) { 1309178354Ssam DPRINTFN(sc, 5, "%s\n", "bad length"); 1310156321Sdamien data->drop = 1; 1311156321Sdamien } 1312156321Sdamien 1313156321Sdamien /* mark the frame for decryption */ 1314156321Sdamien desc->flags |= htole32(RT2560_RX_CIPHER_BUSY); 1315156321Sdamien 1316178354Ssam DPRINTFN(sc, 15, "rx done idx=%u\n", sc->rxq.cur); 1317156321Sdamien 1318156321Sdamien sc->rxq.cur = (sc->rxq.cur + 1) % RT2560_RX_RING_COUNT; 1319156321Sdamien } 1320156321Sdamien 1321156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1322156321Sdamien BUS_DMASYNC_PREWRITE); 1323156321Sdamien 1324156321Sdamien /* kick decrypt */ 1325156321Sdamien RAL_WRITE(sc, RT2560_SECCSR0, RT2560_KICK_DECRYPT); 1326156321Sdamien} 1327156321Sdamien 1328172211Ssamstatic void 1329178354Ssamrt2560_beacon_update(struct ieee80211vap *vap, int item) 1330172211Ssam{ 1331178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 1332178354Ssam struct ieee80211_beacon_offsets *bo = &rvp->ral_bo; 1333172211Ssam 1334172211Ssam setbit(bo->bo_flags, item); 1335172211Ssam} 1336172211Ssam 1337156321Sdamien/* 1338156321Sdamien * This function is called periodically in IBSS mode when a new beacon must be 1339156321Sdamien * sent out. 1340156321Sdamien */ 1341156321Sdamienstatic void 1342156321Sdamienrt2560_beacon_expire(struct rt2560_softc *sc) 1343156321Sdamien{ 1344178354Ssam struct ifnet *ifp = sc->sc_ifp; 1345178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1346178354Ssam struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 1347178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 1348156321Sdamien struct rt2560_tx_data *data; 1349156321Sdamien 1350156321Sdamien if (ic->ic_opmode != IEEE80211_M_IBSS && 1351156321Sdamien ic->ic_opmode != IEEE80211_M_HOSTAP) 1352170530Ssam return; 1353156321Sdamien 1354156321Sdamien data = &sc->bcnq.data[sc->bcnq.next]; 1355170530Ssam /* 1356170530Ssam * Don't send beacon if bsschan isn't set 1357170530Ssam */ 1358170530Ssam if (data->ni == NULL) 1359170530Ssam return; 1360156321Sdamien 1361156321Sdamien bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_POSTWRITE); 1362156321Sdamien bus_dmamap_unload(sc->bcnq.data_dmat, data->map); 1363156321Sdamien 1364178354Ssam /* XXX 1 =>'s mcast frames which means all PS sta's will wakeup! */ 1365178354Ssam ieee80211_beacon_update(data->ni, &rvp->ral_bo, data->m, 1); 1366156321Sdamien 1367156321Sdamien rt2560_tx_bcn(sc, data->m, data->ni); 1368156321Sdamien 1369178354Ssam DPRINTFN(sc, 15, "%s", "beacon expired\n"); 1370156321Sdamien 1371156321Sdamien sc->bcnq.next = (sc->bcnq.next + 1) % RT2560_BEACON_RING_COUNT; 1372156321Sdamien} 1373156321Sdamien 1374156321Sdamien/* ARGSUSED */ 1375156321Sdamienstatic void 1376156321Sdamienrt2560_wakeup_expire(struct rt2560_softc *sc) 1377156321Sdamien{ 1378178354Ssam DPRINTFN(sc, 2, "%s", "wakeup expired\n"); 1379156321Sdamien} 1380156321Sdamien 1381156321Sdamienvoid 1382156321Sdamienrt2560_intr(void *arg) 1383156321Sdamien{ 1384156321Sdamien struct rt2560_softc *sc = arg; 1385156975Sdamien struct ifnet *ifp = sc->sc_ifp; 1386156321Sdamien uint32_t r; 1387156321Sdamien 1388156321Sdamien RAL_LOCK(sc); 1389156321Sdamien 1390156321Sdamien /* disable interrupts */ 1391156321Sdamien RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 1392156321Sdamien 1393156975Sdamien /* don't re-enable interrupts if we're shutting down */ 1394156975Sdamien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1395156975Sdamien RAL_UNLOCK(sc); 1396156975Sdamien return; 1397156975Sdamien } 1398156975Sdamien 1399156321Sdamien r = RAL_READ(sc, RT2560_CSR7); 1400156321Sdamien RAL_WRITE(sc, RT2560_CSR7, r); 1401156321Sdamien 1402156321Sdamien if (r & RT2560_BEACON_EXPIRE) 1403156321Sdamien rt2560_beacon_expire(sc); 1404156321Sdamien 1405156321Sdamien if (r & RT2560_WAKEUP_EXPIRE) 1406156321Sdamien rt2560_wakeup_expire(sc); 1407156321Sdamien 1408156321Sdamien if (r & RT2560_ENCRYPTION_DONE) 1409156321Sdamien rt2560_encryption_intr(sc); 1410156321Sdamien 1411156321Sdamien if (r & RT2560_TX_DONE) 1412156321Sdamien rt2560_tx_intr(sc); 1413156321Sdamien 1414156321Sdamien if (r & RT2560_PRIO_DONE) 1415156321Sdamien rt2560_prio_intr(sc); 1416156321Sdamien 1417156321Sdamien if (r & RT2560_DECRYPTION_DONE) 1418156321Sdamien rt2560_decryption_intr(sc); 1419156321Sdamien 1420175938Ssephe if (r & RT2560_RX_DONE) { 1421156321Sdamien rt2560_rx_intr(sc); 1422175938Ssephe rt2560_encryption_intr(sc); 1423175938Ssephe } 1424156321Sdamien 1425156321Sdamien /* re-enable interrupts */ 1426156321Sdamien RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); 1427156321Sdamien 1428156321Sdamien RAL_UNLOCK(sc); 1429156321Sdamien} 1430156321Sdamien 1431156321Sdamien#define RAL_SIFS 10 /* us */ 1432156321Sdamien 1433156321Sdamien#define RT2560_TXRX_TURNAROUND 10 /* us */ 1434156321Sdamien 1435156321Sdamienstatic void 1436156321Sdamienrt2560_setup_tx_desc(struct rt2560_softc *sc, struct rt2560_tx_desc *desc, 1437156321Sdamien uint32_t flags, int len, int rate, int encrypt, bus_addr_t physaddr) 1438156321Sdamien{ 1439178354Ssam struct ifnet *ifp = sc->sc_ifp; 1440178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1441156321Sdamien uint16_t plcp_length; 1442156321Sdamien int remainder; 1443156321Sdamien 1444156321Sdamien desc->flags = htole32(flags); 1445156321Sdamien desc->flags |= htole32(len << 16); 1446156321Sdamien 1447156321Sdamien desc->physaddr = htole32(physaddr); 1448156321Sdamien desc->wme = htole16( 1449156321Sdamien RT2560_AIFSN(2) | 1450156321Sdamien RT2560_LOGCWMIN(3) | 1451156321Sdamien RT2560_LOGCWMAX(8)); 1452156321Sdamien 1453156321Sdamien /* setup PLCP fields */ 1454178354Ssam desc->plcp_signal = ieee80211_rate2plcp(rate); 1455156321Sdamien desc->plcp_service = 4; 1456156321Sdamien 1457156321Sdamien len += IEEE80211_CRC_LEN; 1458178354Ssam if (ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) { 1459156321Sdamien desc->flags |= htole32(RT2560_TX_OFDM); 1460156321Sdamien 1461156321Sdamien plcp_length = len & 0xfff; 1462156321Sdamien desc->plcp_length_hi = plcp_length >> 6; 1463156321Sdamien desc->plcp_length_lo = plcp_length & 0x3f; 1464156321Sdamien } else { 1465156321Sdamien plcp_length = (16 * len + rate - 1) / rate; 1466156321Sdamien if (rate == 22) { 1467156321Sdamien remainder = (16 * len) % 22; 1468156321Sdamien if (remainder != 0 && remainder < 7) 1469156321Sdamien desc->plcp_service |= RT2560_PLCP_LENGEXT; 1470156321Sdamien } 1471156321Sdamien desc->plcp_length_hi = plcp_length >> 8; 1472156321Sdamien desc->plcp_length_lo = plcp_length & 0xff; 1473156321Sdamien 1474156321Sdamien if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 1475156321Sdamien desc->plcp_signal |= 0x08; 1476156321Sdamien } 1477175938Ssephe 1478175938Ssephe if (!encrypt) 1479175938Ssephe desc->flags |= htole32(RT2560_TX_VALID); 1480175938Ssephe desc->flags |= encrypt ? htole32(RT2560_TX_CIPHER_BUSY) 1481175938Ssephe : htole32(RT2560_TX_BUSY); 1482156321Sdamien} 1483156321Sdamien 1484156321Sdamienstatic int 1485156321Sdamienrt2560_tx_bcn(struct rt2560_softc *sc, struct mbuf *m0, 1486156321Sdamien struct ieee80211_node *ni) 1487156321Sdamien{ 1488178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1489178354Ssam struct ieee80211com *ic = ni->ni_ic; 1490178354Ssam struct ifnet *ifp = sc->sc_ifp; 1491156321Sdamien struct rt2560_tx_desc *desc; 1492156321Sdamien struct rt2560_tx_data *data; 1493156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1494156321Sdamien int nsegs, rate, error; 1495156321Sdamien 1496156321Sdamien desc = &sc->bcnq.desc[sc->bcnq.cur]; 1497156321Sdamien data = &sc->bcnq.data[sc->bcnq.cur]; 1498156321Sdamien 1499178354Ssam /* XXX maybe a separate beacon rate? */ 1500178354Ssam rate = vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)].mgmtrate; 1501156321Sdamien 1502156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->bcnq.data_dmat, data->map, m0, 1503156321Sdamien segs, &nsegs, BUS_DMA_NOWAIT); 1504156321Sdamien if (error != 0) { 1505156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1506156321Sdamien error); 1507156321Sdamien m_freem(m0); 1508156321Sdamien return error; 1509156321Sdamien } 1510156321Sdamien 1511178354Ssam if (bpf_peers_present(ifp->if_bpf)) { 1512156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1513156321Sdamien 1514156321Sdamien tap->wt_flags = 0; 1515156321Sdamien tap->wt_rate = rate; 1516156321Sdamien tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 1517156321Sdamien tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 1518156321Sdamien tap->wt_antenna = sc->tx_ant; 1519156321Sdamien 1520178354Ssam bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); 1521156321Sdamien } 1522156321Sdamien 1523156321Sdamien data->m = m0; 1524156321Sdamien data->ni = ni; 1525156321Sdamien 1526156321Sdamien rt2560_setup_tx_desc(sc, desc, RT2560_TX_IFS_NEWBACKOFF | 1527156321Sdamien RT2560_TX_TIMESTAMP, m0->m_pkthdr.len, rate, 0, segs->ds_addr); 1528156321Sdamien 1529178354Ssam DPRINTFN(sc, 10, "sending beacon frame len=%u idx=%u rate=%u\n", 1530178354Ssam m0->m_pkthdr.len, sc->bcnq.cur, rate); 1531156321Sdamien 1532156321Sdamien bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1533156321Sdamien bus_dmamap_sync(sc->bcnq.desc_dmat, sc->bcnq.desc_map, 1534156321Sdamien BUS_DMASYNC_PREWRITE); 1535156321Sdamien 1536156321Sdamien sc->bcnq.cur = (sc->bcnq.cur + 1) % RT2560_BEACON_RING_COUNT; 1537156321Sdamien 1538156321Sdamien return 0; 1539156321Sdamien} 1540156321Sdamien 1541156321Sdamienstatic int 1542156321Sdamienrt2560_tx_mgt(struct rt2560_softc *sc, struct mbuf *m0, 1543156321Sdamien struct ieee80211_node *ni) 1544156321Sdamien{ 1545178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1546178354Ssam struct ieee80211com *ic = ni->ni_ic; 1547178354Ssam struct ifnet *ifp = sc->sc_ifp; 1548156321Sdamien struct rt2560_tx_desc *desc; 1549156321Sdamien struct rt2560_tx_data *data; 1550156321Sdamien struct ieee80211_frame *wh; 1551173386Skevlo struct ieee80211_key *k; 1552156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1553156321Sdamien uint16_t dur; 1554156321Sdamien uint32_t flags = 0; 1555156321Sdamien int nsegs, rate, error; 1556156321Sdamien 1557156321Sdamien desc = &sc->prioq.desc[sc->prioq.cur]; 1558156321Sdamien data = &sc->prioq.data[sc->prioq.cur]; 1559156321Sdamien 1560178354Ssam rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate; 1561156321Sdamien 1562173386Skevlo wh = mtod(m0, struct ieee80211_frame *); 1563173386Skevlo 1564173386Skevlo if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1565178354Ssam k = ieee80211_crypto_encap(ni, m0); 1566173386Skevlo if (k == NULL) { 1567173386Skevlo m_freem(m0); 1568173386Skevlo return ENOBUFS; 1569173386Skevlo } 1570173386Skevlo } 1571173386Skevlo 1572156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, 1573156321Sdamien segs, &nsegs, 0); 1574156321Sdamien if (error != 0) { 1575156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1576156321Sdamien error); 1577156321Sdamien m_freem(m0); 1578156321Sdamien return error; 1579156321Sdamien } 1580156321Sdamien 1581178354Ssam if (bpf_peers_present(ifp->if_bpf)) { 1582156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1583156321Sdamien 1584156321Sdamien tap->wt_flags = 0; 1585156321Sdamien tap->wt_rate = rate; 1586156321Sdamien tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 1587156321Sdamien tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 1588156321Sdamien tap->wt_antenna = sc->tx_ant; 1589156321Sdamien 1590178354Ssam bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); 1591156321Sdamien } 1592156321Sdamien 1593156321Sdamien data->m = m0; 1594156321Sdamien data->ni = ni; 1595178354Ssam /* management frames are not taken into account for amrr */ 1596178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1597156321Sdamien 1598156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1599156321Sdamien 1600156321Sdamien if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1601156321Sdamien flags |= RT2560_TX_ACK; 1602156321Sdamien 1603178354Ssam dur = ieee80211_ack_duration(sc->sc_rates, 1604178354Ssam rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); 1605156321Sdamien *(uint16_t *)wh->i_dur = htole16(dur); 1606156321Sdamien 1607156321Sdamien /* tell hardware to add timestamp for probe responses */ 1608156321Sdamien if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 1609156321Sdamien IEEE80211_FC0_TYPE_MGT && 1610156321Sdamien (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 1611156321Sdamien IEEE80211_FC0_SUBTYPE_PROBE_RESP) 1612156321Sdamien flags |= RT2560_TX_TIMESTAMP; 1613156321Sdamien } 1614156321Sdamien 1615156321Sdamien rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 0, 1616156321Sdamien segs->ds_addr); 1617156321Sdamien 1618156321Sdamien bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1619156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1620156321Sdamien BUS_DMASYNC_PREWRITE); 1621156321Sdamien 1622178354Ssam DPRINTFN(sc, 10, "sending mgt frame len=%u idx=%u rate=%u\n", 1623178354Ssam m0->m_pkthdr.len, sc->prioq.cur, rate); 1624156321Sdamien 1625156321Sdamien /* kick prio */ 1626156321Sdamien sc->prioq.queued++; 1627156321Sdamien sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; 1628156321Sdamien RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); 1629156321Sdamien 1630156321Sdamien return 0; 1631156321Sdamien} 1632156321Sdamien 1633160691Ssamstatic int 1634178354Ssamrt2560_sendprot(struct rt2560_softc *sc, 1635178354Ssam const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) 1636178354Ssam{ 1637178354Ssam struct ieee80211com *ic = ni->ni_ic; 1638178354Ssam const struct ieee80211_frame *wh; 1639178354Ssam struct rt2560_tx_desc *desc; 1640178354Ssam struct rt2560_tx_data *data; 1641178354Ssam struct mbuf *mprot; 1642178354Ssam int protrate, ackrate, pktlen, flags, isshort, error; 1643178354Ssam uint16_t dur; 1644178354Ssam bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1645178354Ssam int nsegs; 1646178354Ssam 1647178354Ssam KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, 1648178354Ssam ("protection %d", prot)); 1649178354Ssam 1650178354Ssam wh = mtod(m, const struct ieee80211_frame *); 1651178354Ssam pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; 1652178354Ssam 1653178354Ssam protrate = ieee80211_ctl_rate(sc->sc_rates, rate); 1654178354Ssam ackrate = ieee80211_ack_rate(sc->sc_rates, rate); 1655178354Ssam 1656178354Ssam isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; 1657178948Ssam dur = ieee80211_compute_duration(sc->sc_rates, pktlen, rate, isshort) 1658178354Ssam + ieee80211_ack_duration(sc->sc_rates, rate, isshort); 1659178354Ssam flags = RT2560_TX_MORE_FRAG; 1660178354Ssam if (prot == IEEE80211_PROT_RTSCTS) { 1661178354Ssam /* NB: CTS is the same size as an ACK */ 1662178354Ssam dur += ieee80211_ack_duration(sc->sc_rates, rate, isshort); 1663178354Ssam flags |= RT2560_TX_ACK; 1664178354Ssam mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); 1665178354Ssam } else { 1666178354Ssam mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); 1667178354Ssam } 1668178354Ssam if (mprot == NULL) { 1669178354Ssam /* XXX stat + msg */ 1670178354Ssam return ENOBUFS; 1671178354Ssam } 1672178354Ssam 1673178354Ssam desc = &sc->txq.desc[sc->txq.cur_encrypt]; 1674178354Ssam data = &sc->txq.data[sc->txq.cur_encrypt]; 1675178354Ssam 1676178354Ssam error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, 1677178354Ssam mprot, segs, &nsegs, 0); 1678178354Ssam if (error != 0) { 1679178354Ssam device_printf(sc->sc_dev, 1680178354Ssam "could not map mbuf (error %d)\n", error); 1681178354Ssam m_freem(mprot); 1682178354Ssam return error; 1683178354Ssam } 1684178354Ssam 1685178354Ssam data->m = mprot; 1686178354Ssam data->ni = ieee80211_ref_node(ni); 1687178354Ssam /* ctl frames are not taken into account for amrr */ 1688178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1689178354Ssam 1690178354Ssam rt2560_setup_tx_desc(sc, desc, flags, mprot->m_pkthdr.len, protrate, 1, 1691178354Ssam segs->ds_addr); 1692178354Ssam 1693178354Ssam bus_dmamap_sync(sc->txq.data_dmat, data->map, 1694178354Ssam BUS_DMASYNC_PREWRITE); 1695178354Ssam 1696178354Ssam sc->txq.queued++; 1697178354Ssam sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; 1698178354Ssam 1699178354Ssam return 0; 1700178354Ssam} 1701178354Ssam 1702178354Ssamstatic int 1703160691Ssamrt2560_tx_raw(struct rt2560_softc *sc, struct mbuf *m0, 1704160691Ssam struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) 1705160691Ssam{ 1706178354Ssam struct ifnet *ifp = sc->sc_ifp; 1707178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1708160691Ssam struct rt2560_tx_desc *desc; 1709160691Ssam struct rt2560_tx_data *data; 1710160691Ssam bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1711160691Ssam uint32_t flags; 1712160691Ssam int nsegs, rate, error; 1713160691Ssam 1714160691Ssam desc = &sc->prioq.desc[sc->prioq.cur]; 1715160691Ssam data = &sc->prioq.data[sc->prioq.cur]; 1716160691Ssam 1717160691Ssam rate = params->ibp_rate0 & IEEE80211_RATE_VAL; 1718160691Ssam /* XXX validate */ 1719168860Ssephe if (rate == 0) { 1720178354Ssam /* XXX fall back to mcast/mgmt rate? */ 1721168860Ssephe m_freem(m0); 1722160691Ssam return EINVAL; 1723168860Ssephe } 1724160691Ssam 1725178354Ssam flags = 0; 1726178354Ssam if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) 1727178354Ssam flags |= RT2560_TX_ACK; 1728178354Ssam if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { 1729178354Ssam error = rt2560_sendprot(sc, m0, ni, 1730178354Ssam params->ibp_flags & IEEE80211_BPF_RTS ? 1731178354Ssam IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, 1732178354Ssam rate); 1733178354Ssam if (error) { 1734178354Ssam m_freem(m0); 1735178354Ssam return error; 1736178354Ssam } 1737178354Ssam flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; 1738178354Ssam } 1739178354Ssam 1740160691Ssam error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, 1741160691Ssam segs, &nsegs, 0); 1742160691Ssam if (error != 0) { 1743160691Ssam device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1744160691Ssam error); 1745160691Ssam m_freem(m0); 1746160691Ssam return error; 1747160691Ssam } 1748160691Ssam 1749178354Ssam if (bpf_peers_present(ifp->if_bpf)) { 1750160691Ssam struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1751160691Ssam 1752160691Ssam tap->wt_flags = 0; 1753160691Ssam tap->wt_rate = rate; 1754160691Ssam tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 1755160691Ssam tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 1756160691Ssam tap->wt_antenna = sc->tx_ant; 1757160691Ssam 1758178354Ssam bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); 1759160691Ssam } 1760160691Ssam 1761160691Ssam data->m = m0; 1762160691Ssam data->ni = ni; 1763160691Ssam 1764160691Ssam /* XXX need to setup descriptor ourself */ 1765160691Ssam rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, 1766160691Ssam rate, (params->ibp_flags & IEEE80211_BPF_CRYPTO) != 0, 1767160691Ssam segs->ds_addr); 1768160691Ssam 1769160691Ssam bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1770160691Ssam bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1771160691Ssam BUS_DMASYNC_PREWRITE); 1772160691Ssam 1773178354Ssam DPRINTFN(sc, 10, "sending raw frame len=%u idx=%u rate=%u\n", 1774178354Ssam m0->m_pkthdr.len, sc->prioq.cur, rate); 1775160691Ssam 1776160691Ssam /* kick prio */ 1777160691Ssam sc->prioq.queued++; 1778160691Ssam sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; 1779160691Ssam RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); 1780160691Ssam 1781160691Ssam return 0; 1782160691Ssam} 1783160691Ssam 1784156321Sdamienstatic int 1785156321Sdamienrt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0, 1786156321Sdamien struct ieee80211_node *ni) 1787156321Sdamien{ 1788178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1789178354Ssam struct ieee80211com *ic = ni->ni_ic; 1790178354Ssam struct ifnet *ifp = sc->sc_ifp; 1791156321Sdamien struct rt2560_tx_desc *desc; 1792156321Sdamien struct rt2560_tx_data *data; 1793156321Sdamien struct ieee80211_frame *wh; 1794178354Ssam const struct ieee80211_txparam *tp; 1795156321Sdamien struct ieee80211_key *k; 1796156321Sdamien struct mbuf *mnew; 1797156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1798156321Sdamien uint16_t dur; 1799178354Ssam uint32_t flags; 1800156321Sdamien int nsegs, rate, error; 1801156321Sdamien 1802156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1803156321Sdamien 1804178354Ssam tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; 1805178354Ssam if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1806178354Ssam rate = tp->mcastrate; 1807178354Ssam } else if (m0->m_flags & M_EAPOL) { 1808178354Ssam rate = tp->mgmtrate; 1809178354Ssam } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 1810178354Ssam rate = tp->ucastrate; 1811156321Sdamien } else { 1812178354Ssam (void) ieee80211_amrr_choose(ni, &RT2560_NODE(ni)->amrr); 1813178354Ssam rate = ni->ni_txrate; 1814156321Sdamien } 1815156321Sdamien 1816156321Sdamien if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1817178354Ssam k = ieee80211_crypto_encap(ni, m0); 1818156321Sdamien if (k == NULL) { 1819156321Sdamien m_freem(m0); 1820156321Sdamien return ENOBUFS; 1821156321Sdamien } 1822156321Sdamien 1823156321Sdamien /* packet header may have moved, reset our local pointer */ 1824156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1825156321Sdamien } 1826156321Sdamien 1827178354Ssam flags = 0; 1828178354Ssam if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1829178354Ssam int prot = IEEE80211_PROT_NONE; 1830178354Ssam if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) 1831178354Ssam prot = IEEE80211_PROT_RTSCTS; 1832178354Ssam else if ((ic->ic_flags & IEEE80211_F_USEPROT) && 1833178354Ssam ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) 1834178354Ssam prot = ic->ic_protmode; 1835178354Ssam if (prot != IEEE80211_PROT_NONE) { 1836178354Ssam error = rt2560_sendprot(sc, m0, ni, prot, rate); 1837178354Ssam if (error) { 1838178354Ssam m_freem(m0); 1839178354Ssam return error; 1840178354Ssam } 1841178354Ssam flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; 1842156321Sdamien } 1843156321Sdamien } 1844156321Sdamien 1845156321Sdamien data = &sc->txq.data[sc->txq.cur_encrypt]; 1846156321Sdamien desc = &sc->txq.desc[sc->txq.cur_encrypt]; 1847156321Sdamien 1848156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, m0, 1849156321Sdamien segs, &nsegs, 0); 1850156321Sdamien if (error != 0 && error != EFBIG) { 1851156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1852156321Sdamien error); 1853156321Sdamien m_freem(m0); 1854156321Sdamien return error; 1855156321Sdamien } 1856156321Sdamien if (error != 0) { 1857156321Sdamien mnew = m_defrag(m0, M_DONTWAIT); 1858156321Sdamien if (mnew == NULL) { 1859156321Sdamien device_printf(sc->sc_dev, 1860156321Sdamien "could not defragment mbuf\n"); 1861156321Sdamien m_freem(m0); 1862156321Sdamien return ENOBUFS; 1863156321Sdamien } 1864156321Sdamien m0 = mnew; 1865156321Sdamien 1866156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, 1867156321Sdamien m0, segs, &nsegs, 0); 1868156321Sdamien if (error != 0) { 1869156321Sdamien device_printf(sc->sc_dev, 1870156321Sdamien "could not map mbuf (error %d)\n", error); 1871156321Sdamien m_freem(m0); 1872156321Sdamien return error; 1873156321Sdamien } 1874156321Sdamien 1875156321Sdamien /* packet header may have moved, reset our local pointer */ 1876156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1877156321Sdamien } 1878156321Sdamien 1879178354Ssam if (bpf_peers_present(ifp->if_bpf)) { 1880156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1881156321Sdamien 1882156321Sdamien tap->wt_flags = 0; 1883156321Sdamien tap->wt_rate = rate; 1884156321Sdamien tap->wt_antenna = sc->tx_ant; 1885156321Sdamien 1886178354Ssam bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); 1887156321Sdamien } 1888156321Sdamien 1889156321Sdamien data->m = m0; 1890156321Sdamien data->ni = ni; 1891156321Sdamien 1892156321Sdamien /* remember link conditions for rate adaptation algorithm */ 1893178354Ssam if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) { 1894178354Ssam data->rix = ni->ni_txrate; 1895178354Ssam /* XXX probably need last rssi value and not avg */ 1896178354Ssam data->rssi = ic->ic_node_getrssi(ni); 1897156321Sdamien } else 1898178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1899156321Sdamien 1900156321Sdamien if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1901156321Sdamien flags |= RT2560_TX_ACK; 1902156321Sdamien 1903178354Ssam dur = ieee80211_ack_duration(sc->sc_rates, 1904178354Ssam rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); 1905156321Sdamien *(uint16_t *)wh->i_dur = htole16(dur); 1906156321Sdamien } 1907156321Sdamien 1908156321Sdamien rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 1, 1909156321Sdamien segs->ds_addr); 1910156321Sdamien 1911156321Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1912156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 1913156321Sdamien BUS_DMASYNC_PREWRITE); 1914156321Sdamien 1915178354Ssam DPRINTFN(sc, 10, "sending data frame len=%u idx=%u rate=%u\n", 1916178354Ssam m0->m_pkthdr.len, sc->txq.cur_encrypt, rate); 1917156321Sdamien 1918156321Sdamien /* kick encrypt */ 1919156321Sdamien sc->txq.queued++; 1920156321Sdamien sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; 1921156321Sdamien RAL_WRITE(sc, RT2560_SECCSR1, RT2560_KICK_ENCRYPT); 1922156321Sdamien 1923156321Sdamien return 0; 1924156321Sdamien} 1925156321Sdamien 1926156321Sdamienstatic void 1927178354Ssamrt2560_start_locked(struct ifnet *ifp) 1928156321Sdamien{ 1929156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 1930178354Ssam struct mbuf *m; 1931156321Sdamien struct ieee80211_node *ni; 1932156321Sdamien 1933178354Ssam RAL_LOCK_ASSERT(sc); 1934156321Sdamien 1935156321Sdamien for (;;) { 1936178354Ssam IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 1937178354Ssam if (m == NULL) 1938178354Ssam break; 1939178354Ssam if (sc->txq.queued >= RT2560_TX_RING_COUNT - 1) { 1940178354Ssam IFQ_DRV_PREPEND(&ifp->if_snd, m); 1941178354Ssam ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1942178354Ssam sc->sc_flags |= RT2560_F_DATA_OACTIVE; 1943178354Ssam break; 1944178354Ssam } 1945156321Sdamien 1946178354Ssam ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; 1947178354Ssam m = ieee80211_encap(ni, m); 1948178354Ssam if (m == NULL) { 1949178354Ssam ieee80211_free_node(ni); 1950178354Ssam ifp->if_oerrors++; 1951178354Ssam continue; 1952178354Ssam } 1953156321Sdamien 1954178354Ssam if (rt2560_tx_data(sc, m, ni) != 0) { 1955178354Ssam ieee80211_free_node(ni); 1956178354Ssam ifp->if_oerrors++; 1957178354Ssam break; 1958156321Sdamien } 1959156321Sdamien 1960156321Sdamien sc->sc_tx_timer = 5; 1961156321Sdamien } 1962178354Ssam} 1963156321Sdamien 1964178354Ssamstatic void 1965178354Ssamrt2560_start(struct ifnet *ifp) 1966178354Ssam{ 1967178354Ssam struct rt2560_softc *sc = ifp->if_softc; 1968178354Ssam 1969178354Ssam RAL_LOCK(sc); 1970178354Ssam rt2560_start_locked(ifp); 1971156321Sdamien RAL_UNLOCK(sc); 1972156321Sdamien} 1973156321Sdamien 1974156321Sdamienstatic void 1975165352Sbmsrt2560_watchdog(void *arg) 1976156321Sdamien{ 1977167470Ssam struct rt2560_softc *sc = arg; 1978175938Ssephe struct ifnet *ifp = sc->sc_ifp; 1979156321Sdamien 1980178354Ssam RAL_LOCK_ASSERT(sc); 1981178354Ssam 1982178354Ssam KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, ("not running")); 1983178354Ssam 1984178354Ssam if (sc->sc_invalid) /* card ejected */ 1985175938Ssephe return; 1986175938Ssephe 1987175938Ssephe rt2560_encryption_intr(sc); 1988175938Ssephe rt2560_tx_intr(sc); 1989175938Ssephe 1990178354Ssam if (sc->sc_tx_timer > 0 && --sc->sc_tx_timer == 0) { 1991178354Ssam if_printf(ifp, "device timeout\n"); 1992178354Ssam rt2560_init_locked(sc); 1993178354Ssam ifp->if_oerrors++; 1994178354Ssam /* NB: callout is reset in rt2560_init() */ 1995178354Ssam return; 1996156321Sdamien } 1997175938Ssephe callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); 1998156321Sdamien} 1999156321Sdamien 2000156321Sdamienstatic int 2001156321Sdamienrt2560_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 2002156321Sdamien{ 2003156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 2004178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2005178354Ssam struct ifreq *ifr = (struct ifreq *) data; 2006178354Ssam int error = 0, startall = 0; 2007156321Sdamien 2008156321Sdamien switch (cmd) { 2009156321Sdamien case SIOCSIFFLAGS: 2010178704Sthompsa RAL_LOCK(sc); 2011156321Sdamien if (ifp->if_flags & IFF_UP) { 2012178354Ssam if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 2013178354Ssam rt2560_init_locked(sc); 2014178354Ssam startall = 1; 2015178354Ssam } else 2016178354Ssam rt2560_update_promisc(ifp); 2017156321Sdamien } else { 2018156321Sdamien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2019178354Ssam rt2560_stop_locked(sc); 2020156321Sdamien } 2021178704Sthompsa RAL_UNLOCK(sc); 2022178704Sthompsa if (startall) 2023178704Sthompsa ieee80211_start_all(ic); 2024156321Sdamien break; 2025178354Ssam case SIOCGIFMEDIA: 2026178354Ssam error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); 2027178354Ssam break; 2028178704Sthompsa case SIOCGIFADDR: 2029178354Ssam error = ether_ioctl(ifp, cmd, data); 2030178354Ssam break; 2031178704Sthompsa default: 2032178704Sthompsa error = EINVAL; 2033178704Sthompsa break; 2034156321Sdamien } 2035156321Sdamien return error; 2036156321Sdamien} 2037156321Sdamien 2038156321Sdamienstatic void 2039156321Sdamienrt2560_bbp_write(struct rt2560_softc *sc, uint8_t reg, uint8_t val) 2040156321Sdamien{ 2041156321Sdamien uint32_t tmp; 2042156321Sdamien int ntries; 2043156321Sdamien 2044156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2045156321Sdamien if (!(RAL_READ(sc, RT2560_BBPCSR) & RT2560_BBP_BUSY)) 2046156321Sdamien break; 2047156321Sdamien DELAY(1); 2048156321Sdamien } 2049156321Sdamien if (ntries == 100) { 2050156321Sdamien device_printf(sc->sc_dev, "could not write to BBP\n"); 2051156321Sdamien return; 2052156321Sdamien } 2053156321Sdamien 2054156321Sdamien tmp = RT2560_BBP_WRITE | RT2560_BBP_BUSY | reg << 8 | val; 2055156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR, tmp); 2056156321Sdamien 2057178354Ssam DPRINTFN(sc, 15, "BBP R%u <- 0x%02x\n", reg, val); 2058156321Sdamien} 2059156321Sdamien 2060156321Sdamienstatic uint8_t 2061156321Sdamienrt2560_bbp_read(struct rt2560_softc *sc, uint8_t reg) 2062156321Sdamien{ 2063156321Sdamien uint32_t val; 2064156321Sdamien int ntries; 2065156321Sdamien 2066175938Ssephe for (ntries = 0; ntries < 100; ntries++) { 2067175938Ssephe if (!(RAL_READ(sc, RT2560_BBPCSR) & RT2560_BBP_BUSY)) 2068175938Ssephe break; 2069175938Ssephe DELAY(1); 2070175938Ssephe } 2071175938Ssephe if (ntries == 100) { 2072175938Ssephe device_printf(sc->sc_dev, "could not read from BBP\n"); 2073175938Ssephe return 0; 2074175938Ssephe } 2075175938Ssephe 2076156321Sdamien val = RT2560_BBP_BUSY | reg << 8; 2077156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR, val); 2078156321Sdamien 2079156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2080156321Sdamien val = RAL_READ(sc, RT2560_BBPCSR); 2081156321Sdamien if (!(val & RT2560_BBP_BUSY)) 2082156321Sdamien return val & 0xff; 2083156321Sdamien DELAY(1); 2084156321Sdamien } 2085156321Sdamien 2086156321Sdamien device_printf(sc->sc_dev, "could not read from BBP\n"); 2087156321Sdamien return 0; 2088156321Sdamien} 2089156321Sdamien 2090156321Sdamienstatic void 2091156321Sdamienrt2560_rf_write(struct rt2560_softc *sc, uint8_t reg, uint32_t val) 2092156321Sdamien{ 2093156321Sdamien uint32_t tmp; 2094156321Sdamien int ntries; 2095156321Sdamien 2096156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2097156321Sdamien if (!(RAL_READ(sc, RT2560_RFCSR) & RT2560_RF_BUSY)) 2098156321Sdamien break; 2099156321Sdamien DELAY(1); 2100156321Sdamien } 2101156321Sdamien if (ntries == 100) { 2102156321Sdamien device_printf(sc->sc_dev, "could not write to RF\n"); 2103156321Sdamien return; 2104156321Sdamien } 2105156321Sdamien 2106156321Sdamien tmp = RT2560_RF_BUSY | RT2560_RF_20BIT | (val & 0xfffff) << 2 | 2107156321Sdamien (reg & 0x3); 2108156321Sdamien RAL_WRITE(sc, RT2560_RFCSR, tmp); 2109156321Sdamien 2110156321Sdamien /* remember last written value in sc */ 2111156321Sdamien sc->rf_regs[reg] = val; 2112156321Sdamien 2113178354Ssam DPRINTFN(sc, 15, "RF R[%u] <- 0x%05x\n", reg & 0x3, val & 0xfffff); 2114156321Sdamien} 2115156321Sdamien 2116156321Sdamienstatic void 2117156321Sdamienrt2560_set_chan(struct rt2560_softc *sc, struct ieee80211_channel *c) 2118156321Sdamien{ 2119178354Ssam struct ifnet *ifp = sc->sc_ifp; 2120178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2121156321Sdamien uint8_t power, tmp; 2122156321Sdamien u_int i, chan; 2123156321Sdamien 2124156321Sdamien chan = ieee80211_chan2ieee(ic, c); 2125178354Ssam KASSERT(chan != 0 && chan != IEEE80211_CHAN_ANY, ("chan 0x%x", chan)); 2126156321Sdamien 2127178354Ssam sc->sc_rates = ieee80211_get_ratetable(c); 2128178354Ssam 2129156321Sdamien if (IEEE80211_IS_CHAN_2GHZ(c)) 2130156321Sdamien power = min(sc->txpow[chan - 1], 31); 2131156321Sdamien else 2132156321Sdamien power = 31; 2133156321Sdamien 2134156321Sdamien /* adjust txpower using ifconfig settings */ 2135156321Sdamien power -= (100 - ic->ic_txpowlimit) / 8; 2136156321Sdamien 2137178354Ssam DPRINTFN(sc, 2, "setting channel to %u, txpower to %u\n", chan, power); 2138156321Sdamien 2139156321Sdamien switch (sc->rf_rev) { 2140156321Sdamien case RT2560_RF_2522: 2141156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x00814); 2142156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2522_r2[chan - 1]); 2143156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2144156321Sdamien break; 2145156321Sdamien 2146156321Sdamien case RT2560_RF_2523: 2147156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08804); 2148156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2523_r2[chan - 1]); 2149156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x38044); 2150156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2151156321Sdamien break; 2152156321Sdamien 2153156321Sdamien case RT2560_RF_2524: 2154156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x0c808); 2155156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2524_r2[chan - 1]); 2156156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2157156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2158156321Sdamien break; 2159156321Sdamien 2160156321Sdamien case RT2560_RF_2525: 2161156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2162156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_hi_r2[chan - 1]); 2163156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2164156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2165156321Sdamien 2166156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2167156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_r2[chan - 1]); 2168156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2169156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2170156321Sdamien break; 2171156321Sdamien 2172156321Sdamien case RT2560_RF_2525E: 2173156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2174156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525e_r2[chan - 1]); 2175156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2176156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00286 : 0x00282); 2177156321Sdamien break; 2178156321Sdamien 2179156321Sdamien case RT2560_RF_2526: 2180156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_hi_r2[chan - 1]); 2181156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); 2182156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08804); 2183156321Sdamien 2184156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_r2[chan - 1]); 2185156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2186156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); 2187156321Sdamien break; 2188156321Sdamien 2189156321Sdamien /* dual-band RF */ 2190156321Sdamien case RT2560_RF_5222: 2191156321Sdamien for (i = 0; rt2560_rf5222[i].chan != chan; i++); 2192156321Sdamien 2193156321Sdamien rt2560_rf_write(sc, RAL_RF1, rt2560_rf5222[i].r1); 2194156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf5222[i].r2); 2195156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2196156321Sdamien rt2560_rf_write(sc, RAL_RF4, rt2560_rf5222[i].r4); 2197156321Sdamien break; 2198170530Ssam default: 2199170530Ssam printf("unknown ral rev=%d\n", sc->rf_rev); 2200156321Sdamien } 2201156321Sdamien 2202178354Ssam /* XXX */ 2203178354Ssam if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { 2204156321Sdamien /* set Japan filter bit for channel 14 */ 2205156321Sdamien tmp = rt2560_bbp_read(sc, 70); 2206156321Sdamien 2207156321Sdamien tmp &= ~RT2560_JAPAN_FILTER; 2208156321Sdamien if (chan == 14) 2209156321Sdamien tmp |= RT2560_JAPAN_FILTER; 2210156321Sdamien 2211156321Sdamien rt2560_bbp_write(sc, 70, tmp); 2212156321Sdamien 2213156321Sdamien /* clear CRC errors */ 2214156321Sdamien RAL_READ(sc, RT2560_CNT0); 2215156321Sdamien } 2216156321Sdamien} 2217156321Sdamien 2218170530Ssamstatic void 2219170530Ssamrt2560_set_channel(struct ieee80211com *ic) 2220170530Ssam{ 2221170530Ssam struct ifnet *ifp = ic->ic_ifp; 2222170530Ssam struct rt2560_softc *sc = ifp->if_softc; 2223170530Ssam 2224170530Ssam RAL_LOCK(sc); 2225170530Ssam rt2560_set_chan(sc, ic->ic_curchan); 2226178354Ssam 2227178354Ssam sc->sc_txtap.wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 2228178354Ssam sc->sc_txtap.wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 2229178354Ssam sc->sc_rxtap.wr_chan_freq = htole16(ic->ic_curchan->ic_freq); 2230178354Ssam sc->sc_rxtap.wr_chan_flags = htole16(ic->ic_curchan->ic_flags); 2231170530Ssam RAL_UNLOCK(sc); 2232170530Ssam 2233170530Ssam} 2234170530Ssam 2235156321Sdamien#if 0 2236156321Sdamien/* 2237156321Sdamien * Disable RF auto-tuning. 2238156321Sdamien */ 2239156321Sdamienstatic void 2240156321Sdamienrt2560_disable_rf_tune(struct rt2560_softc *sc) 2241156321Sdamien{ 2242156321Sdamien uint32_t tmp; 2243156321Sdamien 2244156321Sdamien if (sc->rf_rev != RT2560_RF_2523) { 2245156321Sdamien tmp = sc->rf_regs[RAL_RF1] & ~RAL_RF1_AUTOTUNE; 2246156321Sdamien rt2560_rf_write(sc, RAL_RF1, tmp); 2247156321Sdamien } 2248156321Sdamien 2249156321Sdamien tmp = sc->rf_regs[RAL_RF3] & ~RAL_RF3_AUTOTUNE; 2250156321Sdamien rt2560_rf_write(sc, RAL_RF3, tmp); 2251156321Sdamien 2252178354Ssam DPRINTFN(sc, 2, "%s", "disabling RF autotune\n"); 2253156321Sdamien} 2254156321Sdamien#endif 2255156321Sdamien 2256156321Sdamien/* 2257156321Sdamien * Refer to IEEE Std 802.11-1999 pp. 123 for more information on TSF 2258156321Sdamien * synchronization. 2259156321Sdamien */ 2260156321Sdamienstatic void 2261156321Sdamienrt2560_enable_tsf_sync(struct rt2560_softc *sc) 2262156321Sdamien{ 2263178354Ssam struct ifnet *ifp = sc->sc_ifp; 2264178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2265178354Ssam struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2266156321Sdamien uint16_t logcwmin, preload; 2267156321Sdamien uint32_t tmp; 2268156321Sdamien 2269156321Sdamien /* first, disable TSF synchronization */ 2270156321Sdamien RAL_WRITE(sc, RT2560_CSR14, 0); 2271156321Sdamien 2272178354Ssam tmp = 16 * vap->iv_bss->ni_intval; 2273156321Sdamien RAL_WRITE(sc, RT2560_CSR12, tmp); 2274156321Sdamien 2275156321Sdamien RAL_WRITE(sc, RT2560_CSR13, 0); 2276156321Sdamien 2277156321Sdamien logcwmin = 5; 2278178354Ssam preload = (vap->iv_opmode == IEEE80211_M_STA) ? 384 : 1024; 2279156321Sdamien tmp = logcwmin << 16 | preload; 2280156321Sdamien RAL_WRITE(sc, RT2560_BCNOCSR, tmp); 2281156321Sdamien 2282156321Sdamien /* finally, enable TSF synchronization */ 2283156321Sdamien tmp = RT2560_ENABLE_TSF | RT2560_ENABLE_TBCN; 2284156321Sdamien if (ic->ic_opmode == IEEE80211_M_STA) 2285156321Sdamien tmp |= RT2560_ENABLE_TSF_SYNC(1); 2286156321Sdamien else 2287156321Sdamien tmp |= RT2560_ENABLE_TSF_SYNC(2) | 2288156321Sdamien RT2560_ENABLE_BEACON_GENERATOR; 2289156321Sdamien RAL_WRITE(sc, RT2560_CSR14, tmp); 2290156321Sdamien 2291178354Ssam DPRINTF(sc, "%s", "enabling TSF synchronization\n"); 2292156321Sdamien} 2293156321Sdamien 2294156321Sdamienstatic void 2295156321Sdamienrt2560_update_plcp(struct rt2560_softc *sc) 2296156321Sdamien{ 2297178354Ssam struct ifnet *ifp = sc->sc_ifp; 2298178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2299156321Sdamien 2300156321Sdamien /* no short preamble for 1Mbps */ 2301156321Sdamien RAL_WRITE(sc, RT2560_PLCP1MCSR, 0x00700400); 2302156321Sdamien 2303156321Sdamien if (!(ic->ic_flags & IEEE80211_F_SHPREAMBLE)) { 2304156321Sdamien /* values taken from the reference driver */ 2305156321Sdamien RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380401); 2306156321Sdamien RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x00150402); 2307156321Sdamien RAL_WRITE(sc, RT2560_PLCP11MCSR, 0x000b8403); 2308156321Sdamien } else { 2309156321Sdamien /* same values as above or'ed 0x8 */ 2310156321Sdamien RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380409); 2311156321Sdamien RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x0015040a); 2312156321Sdamien RAL_WRITE(sc, RT2560_PLCP11MCSR, 0x000b840b); 2313156321Sdamien } 2314156321Sdamien 2315178354Ssam DPRINTF(sc, "updating PLCP for %s preamble\n", 2316178354Ssam (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? "short" : "long"); 2317156321Sdamien} 2318156321Sdamien 2319156321Sdamien/* 2320156321Sdamien * This function can be called by ieee80211_set_shortslottime(). Refer to 2321156321Sdamien * IEEE Std 802.11-1999 pp. 85 to know how these values are computed. 2322156321Sdamien */ 2323156321Sdamienstatic void 2324156321Sdamienrt2560_update_slot(struct ifnet *ifp) 2325156321Sdamien{ 2326156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 2327178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2328156321Sdamien uint8_t slottime; 2329156321Sdamien uint16_t tx_sifs, tx_pifs, tx_difs, eifs; 2330156321Sdamien uint32_t tmp; 2331156321Sdamien 2332175938Ssephe#ifndef FORCE_SLOTTIME 2333156321Sdamien slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; 2334175938Ssephe#else 2335175938Ssephe /* 2336175938Ssephe * Setting slot time according to "short slot time" capability 2337175938Ssephe * in beacon/probe_resp seems to cause problem to acknowledge 2338175938Ssephe * certain AP's data frames transimitted at CCK/DS rates: the 2339175938Ssephe * problematic AP keeps retransmitting data frames, probably 2340175938Ssephe * because MAC level acks are not received by hardware. 2341175938Ssephe * So we cheat a little bit here by claiming we are capable of 2342175938Ssephe * "short slot time" but setting hardware slot time to the normal 2343175938Ssephe * slot time. ral(4) does not seem to have trouble to receive 2344175938Ssephe * frames transmitted using short slot time even if hardware 2345175938Ssephe * slot time is set to normal slot time. If we didn't use this 2346175938Ssephe * trick, we would have to claim that short slot time is not 2347175938Ssephe * supported; this would give relative poor RX performance 2348175938Ssephe * (-1Mb~-2Mb lower) and the _whole_ BSS would stop using short 2349175938Ssephe * slot time. 2350175938Ssephe */ 2351175938Ssephe slottime = 20; 2352175938Ssephe#endif 2353156321Sdamien 2354156321Sdamien /* update the MAC slot boundaries */ 2355156321Sdamien tx_sifs = RAL_SIFS - RT2560_TXRX_TURNAROUND; 2356156321Sdamien tx_pifs = tx_sifs + slottime; 2357156321Sdamien tx_difs = tx_sifs + 2 * slottime; 2358156321Sdamien eifs = (ic->ic_curmode == IEEE80211_MODE_11B) ? 364 : 60; 2359156321Sdamien 2360156321Sdamien tmp = RAL_READ(sc, RT2560_CSR11); 2361156321Sdamien tmp = (tmp & ~0x1f00) | slottime << 8; 2362156321Sdamien RAL_WRITE(sc, RT2560_CSR11, tmp); 2363156321Sdamien 2364156321Sdamien tmp = tx_pifs << 16 | tx_sifs; 2365156321Sdamien RAL_WRITE(sc, RT2560_CSR18, tmp); 2366156321Sdamien 2367156321Sdamien tmp = eifs << 16 | tx_difs; 2368156321Sdamien RAL_WRITE(sc, RT2560_CSR19, tmp); 2369156321Sdamien 2370178354Ssam DPRINTF(sc, "setting slottime to %uus\n", slottime); 2371156321Sdamien} 2372156321Sdamien 2373156321Sdamienstatic void 2374156321Sdamienrt2560_set_basicrates(struct rt2560_softc *sc) 2375156321Sdamien{ 2376178354Ssam struct ifnet *ifp = sc->sc_ifp; 2377178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2378156321Sdamien 2379156321Sdamien /* update basic rate set */ 2380156321Sdamien if (ic->ic_curmode == IEEE80211_MODE_11B) { 2381156321Sdamien /* 11b basic rates: 1, 2Mbps */ 2382156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x3); 2383156321Sdamien } else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) { 2384156321Sdamien /* 11a basic rates: 6, 12, 24Mbps */ 2385156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x150); 2386156321Sdamien } else { 2387156321Sdamien /* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */ 2388156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x15f); 2389156321Sdamien } 2390156321Sdamien} 2391156321Sdamien 2392156321Sdamienstatic void 2393156321Sdamienrt2560_update_led(struct rt2560_softc *sc, int led1, int led2) 2394156321Sdamien{ 2395156321Sdamien uint32_t tmp; 2396156321Sdamien 2397156321Sdamien /* set ON period to 70ms and OFF period to 30ms */ 2398156321Sdamien tmp = led1 << 16 | led2 << 17 | 70 << 8 | 30; 2399156321Sdamien RAL_WRITE(sc, RT2560_LEDCSR, tmp); 2400156321Sdamien} 2401156321Sdamien 2402156321Sdamienstatic void 2403170530Ssamrt2560_set_bssid(struct rt2560_softc *sc, const uint8_t *bssid) 2404156321Sdamien{ 2405156321Sdamien uint32_t tmp; 2406156321Sdamien 2407156321Sdamien tmp = bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24; 2408156321Sdamien RAL_WRITE(sc, RT2560_CSR5, tmp); 2409156321Sdamien 2410156321Sdamien tmp = bssid[4] | bssid[5] << 8; 2411156321Sdamien RAL_WRITE(sc, RT2560_CSR6, tmp); 2412156321Sdamien 2413178354Ssam DPRINTF(sc, "setting BSSID to %6D\n", bssid, ":"); 2414156321Sdamien} 2415156321Sdamien 2416156321Sdamienstatic void 2417156321Sdamienrt2560_set_macaddr(struct rt2560_softc *sc, uint8_t *addr) 2418156321Sdamien{ 2419156321Sdamien uint32_t tmp; 2420156321Sdamien 2421156321Sdamien tmp = addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24; 2422156321Sdamien RAL_WRITE(sc, RT2560_CSR3, tmp); 2423156321Sdamien 2424156321Sdamien tmp = addr[4] | addr[5] << 8; 2425156321Sdamien RAL_WRITE(sc, RT2560_CSR4, tmp); 2426156321Sdamien 2427178354Ssam DPRINTF(sc, "setting MAC address to %6D\n", addr, ":"); 2428156321Sdamien} 2429156321Sdamien 2430156321Sdamienstatic void 2431156321Sdamienrt2560_get_macaddr(struct rt2560_softc *sc, uint8_t *addr) 2432156321Sdamien{ 2433156321Sdamien uint32_t tmp; 2434156321Sdamien 2435156321Sdamien tmp = RAL_READ(sc, RT2560_CSR3); 2436156321Sdamien addr[0] = tmp & 0xff; 2437156321Sdamien addr[1] = (tmp >> 8) & 0xff; 2438156321Sdamien addr[2] = (tmp >> 16) & 0xff; 2439156321Sdamien addr[3] = (tmp >> 24); 2440156321Sdamien 2441156321Sdamien tmp = RAL_READ(sc, RT2560_CSR4); 2442156321Sdamien addr[4] = tmp & 0xff; 2443156321Sdamien addr[5] = (tmp >> 8) & 0xff; 2444156321Sdamien} 2445156321Sdamien 2446156321Sdamienstatic void 2447178354Ssamrt2560_update_promisc(struct ifnet *ifp) 2448156321Sdamien{ 2449178354Ssam struct rt2560_softc *sc = ifp->if_softc; 2450156321Sdamien uint32_t tmp; 2451156321Sdamien 2452156321Sdamien tmp = RAL_READ(sc, RT2560_RXCSR0); 2453156321Sdamien 2454156321Sdamien tmp &= ~RT2560_DROP_NOT_TO_ME; 2455156321Sdamien if (!(ifp->if_flags & IFF_PROMISC)) 2456156321Sdamien tmp |= RT2560_DROP_NOT_TO_ME; 2457156321Sdamien 2458156321Sdamien RAL_WRITE(sc, RT2560_RXCSR0, tmp); 2459156321Sdamien 2460178354Ssam DPRINTF(sc, "%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ? 2461178354Ssam "entering" : "leaving"); 2462156321Sdamien} 2463156321Sdamien 2464156321Sdamienstatic const char * 2465156321Sdamienrt2560_get_rf(int rev) 2466156321Sdamien{ 2467156321Sdamien switch (rev) { 2468156321Sdamien case RT2560_RF_2522: return "RT2522"; 2469156321Sdamien case RT2560_RF_2523: return "RT2523"; 2470156321Sdamien case RT2560_RF_2524: return "RT2524"; 2471156321Sdamien case RT2560_RF_2525: return "RT2525"; 2472156321Sdamien case RT2560_RF_2525E: return "RT2525e"; 2473156321Sdamien case RT2560_RF_2526: return "RT2526"; 2474156321Sdamien case RT2560_RF_5222: return "RT5222"; 2475156321Sdamien default: return "unknown"; 2476156321Sdamien } 2477156321Sdamien} 2478156321Sdamien 2479156321Sdamienstatic void 2480175938Ssephert2560_read_config(struct rt2560_softc *sc) 2481156321Sdamien{ 2482156321Sdamien uint16_t val; 2483156321Sdamien int i; 2484156321Sdamien 2485156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_CONFIG0); 2486156321Sdamien sc->rf_rev = (val >> 11) & 0x7; 2487156321Sdamien sc->hw_radio = (val >> 10) & 0x1; 2488156321Sdamien sc->led_mode = (val >> 6) & 0x7; 2489156321Sdamien sc->rx_ant = (val >> 4) & 0x3; 2490156321Sdamien sc->tx_ant = (val >> 2) & 0x3; 2491156321Sdamien sc->nb_ant = val & 0x3; 2492156321Sdamien 2493156321Sdamien /* read default values for BBP registers */ 2494156321Sdamien for (i = 0; i < 16; i++) { 2495156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_BBP_BASE + i); 2496175938Ssephe if (val == 0 || val == 0xffff) 2497175938Ssephe continue; 2498175938Ssephe 2499156321Sdamien sc->bbp_prom[i].reg = val >> 8; 2500156321Sdamien sc->bbp_prom[i].val = val & 0xff; 2501156321Sdamien } 2502156321Sdamien 2503156321Sdamien /* read Tx power for all b/g channels */ 2504156321Sdamien for (i = 0; i < 14 / 2; i++) { 2505156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_TXPOWER + i); 2506175938Ssephe sc->txpow[i * 2] = val & 0xff; 2507175938Ssephe sc->txpow[i * 2 + 1] = val >> 8; 2508156321Sdamien } 2509175938Ssephe for (i = 0; i < 14; ++i) { 2510175938Ssephe if (sc->txpow[i] > 31) 2511175938Ssephe sc->txpow[i] = 24; 2512175938Ssephe } 2513170530Ssam 2514170530Ssam val = rt2560_eeprom_read(sc, RT2560_EEPROM_CALIBRATE); 2515170530Ssam if ((val & 0xff) == 0xff) 2516170530Ssam sc->rssi_corr = RT2560_DEFAULT_RSSI_CORR; 2517170530Ssam else 2518170530Ssam sc->rssi_corr = val & 0xff; 2519178354Ssam DPRINTF(sc, "rssi correction %d, calibrate 0x%02x\n", 2520178354Ssam sc->rssi_corr, val); 2521156321Sdamien} 2522156321Sdamien 2523170530Ssam 2524170530Ssamstatic void 2525170530Ssamrt2560_scan_start(struct ieee80211com *ic) 2526170530Ssam{ 2527170530Ssam struct ifnet *ifp = ic->ic_ifp; 2528170530Ssam struct rt2560_softc *sc = ifp->if_softc; 2529170530Ssam 2530170530Ssam /* abort TSF synchronization */ 2531170530Ssam RAL_WRITE(sc, RT2560_CSR14, 0); 2532170530Ssam rt2560_set_bssid(sc, ifp->if_broadcastaddr); 2533170530Ssam} 2534170530Ssam 2535170530Ssamstatic void 2536170530Ssamrt2560_scan_end(struct ieee80211com *ic) 2537170530Ssam{ 2538170530Ssam struct ifnet *ifp = ic->ic_ifp; 2539170530Ssam struct rt2560_softc *sc = ifp->if_softc; 2540178354Ssam struct ieee80211vap *vap = ic->ic_scan->ss_vap; 2541170530Ssam 2542170530Ssam rt2560_enable_tsf_sync(sc); 2543170530Ssam /* XXX keep local copy */ 2544178354Ssam rt2560_set_bssid(sc, vap->iv_bss->ni_bssid); 2545170530Ssam} 2546170530Ssam 2547156321Sdamienstatic int 2548156321Sdamienrt2560_bbp_init(struct rt2560_softc *sc) 2549156321Sdamien{ 2550156321Sdamien#define N(a) (sizeof (a) / sizeof ((a)[0])) 2551156321Sdamien int i, ntries; 2552156321Sdamien 2553156321Sdamien /* wait for BBP to be ready */ 2554156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2555156321Sdamien if (rt2560_bbp_read(sc, RT2560_BBP_VERSION) != 0) 2556156321Sdamien break; 2557156321Sdamien DELAY(1); 2558156321Sdamien } 2559156321Sdamien if (ntries == 100) { 2560156321Sdamien device_printf(sc->sc_dev, "timeout waiting for BBP\n"); 2561156321Sdamien return EIO; 2562156321Sdamien } 2563156321Sdamien 2564156321Sdamien /* initialize BBP registers to default values */ 2565156321Sdamien for (i = 0; i < N(rt2560_def_bbp); i++) { 2566156321Sdamien rt2560_bbp_write(sc, rt2560_def_bbp[i].reg, 2567156321Sdamien rt2560_def_bbp[i].val); 2568156321Sdamien } 2569175938Ssephe 2570156321Sdamien /* initialize BBP registers to values stored in EEPROM */ 2571156321Sdamien for (i = 0; i < 16; i++) { 2572175938Ssephe if (sc->bbp_prom[i].reg == 0 && sc->bbp_prom[i].val == 0) 2573175938Ssephe break; 2574156321Sdamien rt2560_bbp_write(sc, sc->bbp_prom[i].reg, sc->bbp_prom[i].val); 2575156321Sdamien } 2576175938Ssephe rt2560_bbp_write(sc, 17, 0x48); /* XXX restore bbp17 */ 2577156321Sdamien 2578156321Sdamien return 0; 2579156321Sdamien#undef N 2580156321Sdamien} 2581156321Sdamien 2582156321Sdamienstatic void 2583156321Sdamienrt2560_set_txantenna(struct rt2560_softc *sc, int antenna) 2584156321Sdamien{ 2585156321Sdamien uint32_t tmp; 2586156321Sdamien uint8_t tx; 2587156321Sdamien 2588156321Sdamien tx = rt2560_bbp_read(sc, RT2560_BBP_TX) & ~RT2560_BBP_ANTMASK; 2589156321Sdamien if (antenna == 1) 2590156321Sdamien tx |= RT2560_BBP_ANTA; 2591156321Sdamien else if (antenna == 2) 2592156321Sdamien tx |= RT2560_BBP_ANTB; 2593156321Sdamien else 2594156321Sdamien tx |= RT2560_BBP_DIVERSITY; 2595156321Sdamien 2596156321Sdamien /* need to force I/Q flip for RF 2525e, 2526 and 5222 */ 2597156321Sdamien if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526 || 2598156321Sdamien sc->rf_rev == RT2560_RF_5222) 2599156321Sdamien tx |= RT2560_BBP_FLIPIQ; 2600156321Sdamien 2601156321Sdamien rt2560_bbp_write(sc, RT2560_BBP_TX, tx); 2602156321Sdamien 2603156321Sdamien /* update values for CCK and OFDM in BBPCSR1 */ 2604156321Sdamien tmp = RAL_READ(sc, RT2560_BBPCSR1) & ~0x00070007; 2605156321Sdamien tmp |= (tx & 0x7) << 16 | (tx & 0x7); 2606156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR1, tmp); 2607156321Sdamien} 2608156321Sdamien 2609156321Sdamienstatic void 2610156321Sdamienrt2560_set_rxantenna(struct rt2560_softc *sc, int antenna) 2611156321Sdamien{ 2612156321Sdamien uint8_t rx; 2613156321Sdamien 2614156321Sdamien rx = rt2560_bbp_read(sc, RT2560_BBP_RX) & ~RT2560_BBP_ANTMASK; 2615156321Sdamien if (antenna == 1) 2616156321Sdamien rx |= RT2560_BBP_ANTA; 2617156321Sdamien else if (antenna == 2) 2618156321Sdamien rx |= RT2560_BBP_ANTB; 2619156321Sdamien else 2620156321Sdamien rx |= RT2560_BBP_DIVERSITY; 2621156321Sdamien 2622156321Sdamien /* need to force no I/Q flip for RF 2525e and 2526 */ 2623156321Sdamien if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526) 2624156321Sdamien rx &= ~RT2560_BBP_FLIPIQ; 2625156321Sdamien 2626156321Sdamien rt2560_bbp_write(sc, RT2560_BBP_RX, rx); 2627156321Sdamien} 2628156321Sdamien 2629156321Sdamienstatic void 2630178354Ssamrt2560_init_locked(struct rt2560_softc *sc) 2631156321Sdamien{ 2632156321Sdamien#define N(a) (sizeof (a) / sizeof ((a)[0])) 2633178354Ssam struct ifnet *ifp = sc->sc_ifp; 2634178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2635156321Sdamien uint32_t tmp; 2636156321Sdamien int i; 2637156321Sdamien 2638178354Ssam RAL_LOCK_ASSERT(sc); 2639156975Sdamien 2640178354Ssam rt2560_stop_locked(sc); 2641170530Ssam 2642156321Sdamien /* setup tx rings */ 2643156321Sdamien tmp = RT2560_PRIO_RING_COUNT << 24 | 2644156321Sdamien RT2560_ATIM_RING_COUNT << 16 | 2645156321Sdamien RT2560_TX_RING_COUNT << 8 | 2646156321Sdamien RT2560_TX_DESC_SIZE; 2647156321Sdamien 2648156321Sdamien /* rings must be initialized in this exact order */ 2649156321Sdamien RAL_WRITE(sc, RT2560_TXCSR2, tmp); 2650156321Sdamien RAL_WRITE(sc, RT2560_TXCSR3, sc->txq.physaddr); 2651156321Sdamien RAL_WRITE(sc, RT2560_TXCSR5, sc->prioq.physaddr); 2652156321Sdamien RAL_WRITE(sc, RT2560_TXCSR4, sc->atimq.physaddr); 2653156321Sdamien RAL_WRITE(sc, RT2560_TXCSR6, sc->bcnq.physaddr); 2654156321Sdamien 2655156321Sdamien /* setup rx ring */ 2656156321Sdamien tmp = RT2560_RX_RING_COUNT << 8 | RT2560_RX_DESC_SIZE; 2657156321Sdamien 2658156321Sdamien RAL_WRITE(sc, RT2560_RXCSR1, tmp); 2659156321Sdamien RAL_WRITE(sc, RT2560_RXCSR2, sc->rxq.physaddr); 2660156321Sdamien 2661156321Sdamien /* initialize MAC registers to default values */ 2662156321Sdamien for (i = 0; i < N(rt2560_def_mac); i++) 2663156321Sdamien RAL_WRITE(sc, rt2560_def_mac[i].reg, rt2560_def_mac[i].val); 2664156321Sdamien 2665156321Sdamien IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp)); 2666156321Sdamien rt2560_set_macaddr(sc, ic->ic_myaddr); 2667156321Sdamien 2668156321Sdamien /* set basic rate set (will be updated later) */ 2669156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x153); 2670156321Sdamien 2671156321Sdamien rt2560_update_slot(ifp); 2672156321Sdamien rt2560_update_plcp(sc); 2673156321Sdamien rt2560_update_led(sc, 0, 0); 2674156321Sdamien 2675156321Sdamien RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 2676156321Sdamien RAL_WRITE(sc, RT2560_CSR1, RT2560_HOST_READY); 2677156321Sdamien 2678156321Sdamien if (rt2560_bbp_init(sc) != 0) { 2679156321Sdamien rt2560_stop(sc); 2680156975Sdamien RAL_UNLOCK(sc); 2681156321Sdamien return; 2682156321Sdamien } 2683156321Sdamien 2684175938Ssephe rt2560_set_txantenna(sc, sc->tx_ant); 2685175938Ssephe rt2560_set_rxantenna(sc, sc->rx_ant); 2686175938Ssephe 2687156321Sdamien /* set default BSS channel */ 2688156321Sdamien rt2560_set_chan(sc, ic->ic_curchan); 2689156321Sdamien 2690156321Sdamien /* kick Rx */ 2691156321Sdamien tmp = RT2560_DROP_PHY_ERROR | RT2560_DROP_CRC_ERROR; 2692156321Sdamien if (ic->ic_opmode != IEEE80211_M_MONITOR) { 2693156321Sdamien tmp |= RT2560_DROP_CTL | RT2560_DROP_VERSION_ERROR; 2694156321Sdamien if (ic->ic_opmode != IEEE80211_M_HOSTAP) 2695156321Sdamien tmp |= RT2560_DROP_TODS; 2696156321Sdamien if (!(ifp->if_flags & IFF_PROMISC)) 2697156321Sdamien tmp |= RT2560_DROP_NOT_TO_ME; 2698156321Sdamien } 2699156321Sdamien RAL_WRITE(sc, RT2560_RXCSR0, tmp); 2700156321Sdamien 2701156321Sdamien /* clear old FCS and Rx FIFO errors */ 2702156321Sdamien RAL_READ(sc, RT2560_CNT0); 2703156321Sdamien RAL_READ(sc, RT2560_CNT4); 2704156321Sdamien 2705156321Sdamien /* clear any pending interrupts */ 2706156321Sdamien RAL_WRITE(sc, RT2560_CSR7, 0xffffffff); 2707156321Sdamien 2708156321Sdamien /* enable interrupts */ 2709156321Sdamien RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); 2710156321Sdamien 2711156321Sdamien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2712156321Sdamien ifp->if_drv_flags |= IFF_DRV_RUNNING; 2713156321Sdamien 2714175938Ssephe callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); 2715178354Ssam#undef N 2716178354Ssam} 2717175938Ssephe 2718178354Ssamstatic void 2719178354Ssamrt2560_init(void *priv) 2720178354Ssam{ 2721178354Ssam struct rt2560_softc *sc = priv; 2722178354Ssam struct ifnet *ifp = sc->sc_ifp; 2723178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2724156975Sdamien 2725178354Ssam RAL_LOCK(sc); 2726178354Ssam rt2560_init_locked(sc); 2727156975Sdamien RAL_UNLOCK(sc); 2728178354Ssam 2729178931Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2730178931Sthompsa ieee80211_start_all(ic); /* start all vap's */ 2731156321Sdamien} 2732156321Sdamien 2733178354Ssamstatic void 2734178354Ssamrt2560_stop_locked(struct rt2560_softc *sc) 2735156321Sdamien{ 2736178354Ssam struct ifnet *ifp = sc->sc_ifp; 2737170530Ssam volatile int *flags = &sc->sc_flags; 2738156321Sdamien 2739178354Ssam RAL_LOCK_ASSERT(sc); 2740156321Sdamien 2741178354Ssam while (*flags & RT2560_F_INPUT_RUNNING) 2742178354Ssam msleep(sc, &sc->sc_mtx, 0, "ralrunning", hz/10); 2743175938Ssephe 2744175938Ssephe callout_stop(&sc->watchdog_ch); 2745178354Ssam sc->sc_tx_timer = 0; 2746175938Ssephe 2747170530Ssam if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 2748170530Ssam ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2749156975Sdamien 2750170530Ssam /* abort Tx */ 2751170530Ssam RAL_WRITE(sc, RT2560_TXCSR0, RT2560_ABORT_TX); 2752170530Ssam 2753170530Ssam /* disable Rx */ 2754170530Ssam RAL_WRITE(sc, RT2560_RXCSR0, RT2560_DISABLE_RX); 2755156321Sdamien 2756170530Ssam /* reset ASIC (imply reset BBP) */ 2757170530Ssam RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 2758170530Ssam RAL_WRITE(sc, RT2560_CSR1, 0); 2759156321Sdamien 2760170530Ssam /* disable interrupts */ 2761170530Ssam RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 2762170530Ssam 2763170530Ssam /* reset Tx and Rx rings */ 2764170530Ssam rt2560_reset_tx_ring(sc, &sc->txq); 2765170530Ssam rt2560_reset_tx_ring(sc, &sc->atimq); 2766170530Ssam rt2560_reset_tx_ring(sc, &sc->prioq); 2767170530Ssam rt2560_reset_tx_ring(sc, &sc->bcnq); 2768170530Ssam rt2560_reset_rx_ring(sc, &sc->rxq); 2769170530Ssam } 2770175938Ssephe sc->sc_flags &= ~(RT2560_F_PRIO_OACTIVE | RT2560_F_DATA_OACTIVE); 2771178354Ssam} 2772175938Ssephe 2773178354Ssamvoid 2774178354Ssamrt2560_stop(void *arg) 2775178354Ssam{ 2776178354Ssam struct rt2560_softc *sc = arg; 2777178354Ssam 2778178354Ssam RAL_LOCK(sc); 2779178354Ssam rt2560_stop_locked(sc); 2780170530Ssam RAL_UNLOCK(sc); 2781156321Sdamien} 2782160691Ssam 2783160691Ssamstatic int 2784160691Ssamrt2560_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 2785160691Ssam const struct ieee80211_bpf_params *params) 2786160691Ssam{ 2787160691Ssam struct ieee80211com *ic = ni->ni_ic; 2788160691Ssam struct ifnet *ifp = ic->ic_ifp; 2789160691Ssam struct rt2560_softc *sc = ifp->if_softc; 2790160691Ssam 2791160691Ssam RAL_LOCK(sc); 2792160691Ssam 2793160691Ssam /* prevent management frames from being sent if we're not ready */ 2794160691Ssam if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2795160691Ssam RAL_UNLOCK(sc); 2796168860Ssephe m_freem(m); 2797168860Ssephe ieee80211_free_node(ni); 2798160691Ssam return ENETDOWN; 2799160691Ssam } 2800160691Ssam if (sc->prioq.queued >= RT2560_PRIO_RING_COUNT) { 2801160691Ssam ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2802178354Ssam sc->sc_flags |= RT2560_F_PRIO_OACTIVE; 2803160691Ssam RAL_UNLOCK(sc); 2804168860Ssephe m_freem(m); 2805168860Ssephe ieee80211_free_node(ni); 2806160691Ssam return ENOBUFS; /* XXX */ 2807160691Ssam } 2808160691Ssam 2809160691Ssam ifp->if_opackets++; 2810160691Ssam 2811160691Ssam if (params == NULL) { 2812160691Ssam /* 2813160691Ssam * Legacy path; interpret frame contents to decide 2814160691Ssam * precisely how to send the frame. 2815160691Ssam */ 2816160691Ssam if (rt2560_tx_mgt(sc, m, ni) != 0) 2817160691Ssam goto bad; 2818160691Ssam } else { 2819160691Ssam /* 2820160691Ssam * Caller supplied explicit parameters to use in 2821160691Ssam * sending the frame. 2822160691Ssam */ 2823160691Ssam if (rt2560_tx_raw(sc, m, ni, params)) 2824160691Ssam goto bad; 2825160691Ssam } 2826160691Ssam sc->sc_tx_timer = 5; 2827160691Ssam 2828160691Ssam RAL_UNLOCK(sc); 2829160691Ssam 2830160691Ssam return 0; 2831160691Ssambad: 2832160691Ssam ifp->if_oerrors++; 2833160905Ssam ieee80211_free_node(ni); 2834160691Ssam RAL_UNLOCK(sc); 2835160691Ssam return EIO; /* XXX */ 2836160691Ssam} 2837