rt2560.c revision 190532
1156321Sdamien/* $FreeBSD: head/sys/dev/ral/rt2560.c 190532 2009-03-29 21:17:08Z 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 190532 2009-03-29 21:17:08Z 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> 55156321Sdamien#include <net80211/ieee80211_radiotap.h> 56170530Ssam#include <net80211/ieee80211_regdomain.h> 57178354Ssam#include <net80211/ieee80211_amrr.h> 58156321Sdamien 59156321Sdamien#include <netinet/in.h> 60156321Sdamien#include <netinet/in_systm.h> 61156321Sdamien#include <netinet/in_var.h> 62156321Sdamien#include <netinet/ip.h> 63156321Sdamien#include <netinet/if_ether.h> 64156321Sdamien 65156327Ssilby#include <dev/ral/rt2560reg.h> 66156327Ssilby#include <dev/ral/rt2560var.h> 67156321Sdamien 68170530Ssam#define RT2560_RSSI(sc, rssi) \ 69170530Ssam ((rssi) > (RT2560_NOISE_FLOOR + (sc)->rssi_corr) ? \ 70170530Ssam ((rssi) - RT2560_NOISE_FLOOR - (sc)->rssi_corr) : 0) 71170530Ssam 72178354Ssam#define RAL_DEBUG 73156321Sdamien#ifdef RAL_DEBUG 74178354Ssam#define DPRINTF(sc, fmt, ...) do { \ 75178354Ssam if (sc->sc_debug > 0) \ 76178354Ssam printf(fmt, __VA_ARGS__); \ 77178354Ssam} while (0) 78178354Ssam#define DPRINTFN(sc, n, fmt, ...) do { \ 79178354Ssam if (sc->sc_debug >= (n)) \ 80178354Ssam printf(fmt, __VA_ARGS__); \ 81178354Ssam} while (0) 82156321Sdamien#else 83178354Ssam#define DPRINTF(sc, fmt, ...) 84178354Ssam#define DPRINTFN(sc, n, fmt, ...) 85156321Sdamien#endif 86156321Sdamien 87178354Ssamstatic struct ieee80211vap *rt2560_vap_create(struct ieee80211com *, 88178354Ssam const char name[IFNAMSIZ], int unit, int opmode, 89178354Ssam int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], 90178354Ssam const uint8_t mac[IEEE80211_ADDR_LEN]); 91178354Ssamstatic void rt2560_vap_delete(struct ieee80211vap *); 92156321Sdamienstatic void rt2560_dma_map_addr(void *, bus_dma_segment_t *, int, 93156321Sdamien int); 94156321Sdamienstatic int rt2560_alloc_tx_ring(struct rt2560_softc *, 95156321Sdamien struct rt2560_tx_ring *, int); 96156321Sdamienstatic void rt2560_reset_tx_ring(struct rt2560_softc *, 97156321Sdamien struct rt2560_tx_ring *); 98156321Sdamienstatic void rt2560_free_tx_ring(struct rt2560_softc *, 99156321Sdamien struct rt2560_tx_ring *); 100156321Sdamienstatic int rt2560_alloc_rx_ring(struct rt2560_softc *, 101156321Sdamien struct rt2560_rx_ring *, int); 102156321Sdamienstatic void rt2560_reset_rx_ring(struct rt2560_softc *, 103156321Sdamien struct rt2560_rx_ring *); 104156321Sdamienstatic void rt2560_free_rx_ring(struct rt2560_softc *, 105156321Sdamien struct rt2560_rx_ring *); 106179643Ssamstatic struct ieee80211_node *rt2560_node_alloc(struct ieee80211vap *, 107179643Ssam const uint8_t [IEEE80211_ADDR_LEN]); 108178354Ssamstatic void rt2560_newassoc(struct ieee80211_node *, int); 109178354Ssamstatic int rt2560_newstate(struct ieee80211vap *, 110156321Sdamien enum ieee80211_state, int); 111156321Sdamienstatic uint16_t rt2560_eeprom_read(struct rt2560_softc *, uint8_t); 112156321Sdamienstatic void rt2560_encryption_intr(struct rt2560_softc *); 113156321Sdamienstatic void rt2560_tx_intr(struct rt2560_softc *); 114156321Sdamienstatic void rt2560_prio_intr(struct rt2560_softc *); 115156321Sdamienstatic void rt2560_decryption_intr(struct rt2560_softc *); 116156321Sdamienstatic void rt2560_rx_intr(struct rt2560_softc *); 117178354Ssamstatic void rt2560_beacon_update(struct ieee80211vap *, int item); 118156321Sdamienstatic void rt2560_beacon_expire(struct rt2560_softc *); 119156321Sdamienstatic void rt2560_wakeup_expire(struct rt2560_softc *); 120170530Ssamstatic void rt2560_scan_start(struct ieee80211com *); 121170530Ssamstatic void rt2560_scan_end(struct ieee80211com *); 122170530Ssamstatic void rt2560_set_channel(struct ieee80211com *); 123156321Sdamienstatic void rt2560_setup_tx_desc(struct rt2560_softc *, 124156321Sdamien struct rt2560_tx_desc *, uint32_t, int, int, int, 125156321Sdamien bus_addr_t); 126156321Sdamienstatic int rt2560_tx_bcn(struct rt2560_softc *, struct mbuf *, 127156321Sdamien struct ieee80211_node *); 128156321Sdamienstatic int rt2560_tx_mgt(struct rt2560_softc *, struct mbuf *, 129156321Sdamien struct ieee80211_node *); 130156321Sdamienstatic int rt2560_tx_data(struct rt2560_softc *, struct mbuf *, 131156321Sdamien struct ieee80211_node *); 132178354Ssamstatic void rt2560_start_locked(struct ifnet *); 133156321Sdamienstatic void rt2560_start(struct ifnet *); 134165352Sbmsstatic void rt2560_watchdog(void *); 135156321Sdamienstatic int rt2560_ioctl(struct ifnet *, u_long, caddr_t); 136156321Sdamienstatic void rt2560_bbp_write(struct rt2560_softc *, uint8_t, 137156321Sdamien uint8_t); 138156321Sdamienstatic uint8_t rt2560_bbp_read(struct rt2560_softc *, uint8_t); 139156321Sdamienstatic void rt2560_rf_write(struct rt2560_softc *, uint8_t, 140156321Sdamien uint32_t); 141156321Sdamienstatic void rt2560_set_chan(struct rt2560_softc *, 142156321Sdamien struct ieee80211_channel *); 143156321Sdamien#if 0 144156321Sdamienstatic void rt2560_disable_rf_tune(struct rt2560_softc *); 145156321Sdamien#endif 146156321Sdamienstatic void rt2560_enable_tsf_sync(struct rt2560_softc *); 147156321Sdamienstatic void rt2560_update_plcp(struct rt2560_softc *); 148156321Sdamienstatic void rt2560_update_slot(struct ifnet *); 149156321Sdamienstatic void rt2560_set_basicrates(struct rt2560_softc *); 150156321Sdamienstatic void rt2560_update_led(struct rt2560_softc *, int, int); 151170530Ssamstatic void rt2560_set_bssid(struct rt2560_softc *, const uint8_t *); 152156321Sdamienstatic void rt2560_set_macaddr(struct rt2560_softc *, uint8_t *); 153156321Sdamienstatic void rt2560_get_macaddr(struct rt2560_softc *, uint8_t *); 154178354Ssamstatic void rt2560_update_promisc(struct ifnet *); 155156321Sdamienstatic const char *rt2560_get_rf(int); 156175938Ssephestatic void rt2560_read_config(struct rt2560_softc *); 157156321Sdamienstatic int rt2560_bbp_init(struct rt2560_softc *); 158156321Sdamienstatic void rt2560_set_txantenna(struct rt2560_softc *, int); 159156321Sdamienstatic void rt2560_set_rxantenna(struct rt2560_softc *, int); 160178354Ssamstatic void rt2560_init_locked(struct rt2560_softc *); 161156321Sdamienstatic void rt2560_init(void *); 162178354Ssamstatic void rt2560_stop_locked(struct rt2560_softc *); 163160691Ssamstatic int rt2560_raw_xmit(struct ieee80211_node *, struct mbuf *, 164160691Ssam const struct ieee80211_bpf_params *); 165156321Sdamien 166156321Sdamienstatic const struct { 167156321Sdamien uint32_t reg; 168156321Sdamien uint32_t val; 169156321Sdamien} rt2560_def_mac[] = { 170156321Sdamien RT2560_DEF_MAC 171156321Sdamien}; 172156321Sdamien 173156321Sdamienstatic const struct { 174156321Sdamien uint8_t reg; 175156321Sdamien uint8_t val; 176156321Sdamien} rt2560_def_bbp[] = { 177156321Sdamien RT2560_DEF_BBP 178156321Sdamien}; 179156321Sdamien 180156321Sdamienstatic const uint32_t rt2560_rf2522_r2[] = RT2560_RF2522_R2; 181156321Sdamienstatic const uint32_t rt2560_rf2523_r2[] = RT2560_RF2523_R2; 182156321Sdamienstatic const uint32_t rt2560_rf2524_r2[] = RT2560_RF2524_R2; 183156321Sdamienstatic const uint32_t rt2560_rf2525_r2[] = RT2560_RF2525_R2; 184156321Sdamienstatic const uint32_t rt2560_rf2525_hi_r2[] = RT2560_RF2525_HI_R2; 185156321Sdamienstatic const uint32_t rt2560_rf2525e_r2[] = RT2560_RF2525E_R2; 186156321Sdamienstatic const uint32_t rt2560_rf2526_r2[] = RT2560_RF2526_R2; 187156321Sdamienstatic const uint32_t rt2560_rf2526_hi_r2[] = RT2560_RF2526_HI_R2; 188156321Sdamien 189156321Sdamienstatic const struct { 190156321Sdamien uint8_t chan; 191156321Sdamien uint32_t r1, r2, r4; 192156321Sdamien} rt2560_rf5222[] = { 193156321Sdamien RT2560_RF5222 194156321Sdamien}; 195156321Sdamien 196156321Sdamienint 197156321Sdamienrt2560_attach(device_t dev, int id) 198156321Sdamien{ 199156321Sdamien struct rt2560_softc *sc = device_get_softc(dev); 200178354Ssam struct ieee80211com *ic; 201156321Sdamien struct ifnet *ifp; 202178354Ssam int error; 203178354Ssam uint8_t bands; 204190526Ssam uint8_t macaddr[IEEE80211_ADDR_LEN]; 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 */ 263190526Ssam rt2560_get_macaddr(sc, macaddr); 264178354Ssam 265156321Sdamien ifp->if_softc = sc; 266156321Sdamien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 267156321Sdamien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 268156321Sdamien ifp->if_init = rt2560_init; 269156321Sdamien ifp->if_ioctl = rt2560_ioctl; 270156321Sdamien ifp->if_start = rt2560_start; 271156321Sdamien IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 272156321Sdamien ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 273156321Sdamien IFQ_SET_READY(&ifp->if_snd); 274156321Sdamien 275156321Sdamien ic->ic_ifp = ifp; 276178354Ssam ic->ic_opmode = IEEE80211_M_STA; 277156321Sdamien ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 278156321Sdamien 279156321Sdamien /* set device capabilities */ 280156321Sdamien ic->ic_caps = 281178957Ssam IEEE80211_C_STA /* station mode */ 282178957Ssam | IEEE80211_C_IBSS /* ibss, nee adhoc, mode */ 283178354Ssam | IEEE80211_C_HOSTAP /* hostap mode */ 284178354Ssam | IEEE80211_C_MONITOR /* monitor mode */ 285178354Ssam | IEEE80211_C_AHDEMO /* adhoc demo mode */ 286178354Ssam | IEEE80211_C_WDS /* 4-address traffic works */ 287178354Ssam | IEEE80211_C_SHPREAMBLE /* short preamble supported */ 288178354Ssam | IEEE80211_C_SHSLOT /* short slot time supported */ 289178354Ssam | IEEE80211_C_WPA /* capable of WPA1+WPA2 */ 290178354Ssam | IEEE80211_C_BGSCAN /* capable of bg scanning */ 291178354Ssam#ifdef notyet 292178354Ssam | IEEE80211_C_TXFRAG /* handle tx frags */ 293178354Ssam#endif 294178354Ssam ; 295156321Sdamien 296170530Ssam bands = 0; 297170530Ssam setbit(&bands, IEEE80211_MODE_11B); 298170530Ssam setbit(&bands, IEEE80211_MODE_11G); 299170530Ssam if (sc->rf_rev == RT2560_RF_5222) 300170530Ssam setbit(&bands, IEEE80211_MODE_11A); 301178354Ssam ieee80211_init_channels(ic, NULL, &bands); 302156321Sdamien 303190526Ssam ieee80211_ifattach(ic, macaddr); 304178354Ssam ic->ic_newassoc = rt2560_newassoc; 305178354Ssam ic->ic_raw_xmit = rt2560_raw_xmit; 306178354Ssam ic->ic_updateslot = rt2560_update_slot; 307178354Ssam ic->ic_update_promisc = rt2560_update_promisc; 308178354Ssam ic->ic_node_alloc = rt2560_node_alloc; 309170530Ssam ic->ic_scan_start = rt2560_scan_start; 310170530Ssam ic->ic_scan_end = rt2560_scan_end; 311170530Ssam ic->ic_set_channel = rt2560_set_channel; 312156321Sdamien 313178354Ssam ic->ic_vap_create = rt2560_vap_create; 314178354Ssam ic->ic_vap_delete = rt2560_vap_delete; 315156321Sdamien 316178354Ssam bpfattach(ifp, DLT_IEEE802_11_RADIO, 317178354Ssam sizeof (struct ieee80211_frame) + sizeof (sc->sc_txtap)); 318156321Sdamien 319171086Skevlo sc->sc_rxtap_len = sizeof sc->sc_rxtap; 320156321Sdamien sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); 321156321Sdamien sc->sc_rxtap.wr_ihdr.it_present = htole32(RT2560_RX_RADIOTAP_PRESENT); 322156321Sdamien 323171086Skevlo sc->sc_txtap_len = sizeof sc->sc_txtap; 324156321Sdamien sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); 325156321Sdamien sc->sc_txtap.wt_ihdr.it_present = htole32(RT2560_TX_RADIOTAP_PRESENT); 326156321Sdamien 327156321Sdamien /* 328156321Sdamien * Add a few sysctl knobs. 329156321Sdamien */ 330178354Ssam#ifdef RAL_DEBUG 331156321Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 332156321Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 333178354Ssam "debug", CTLFLAG_RW, &sc->sc_debug, 0, "debug msgs"); 334178354Ssam#endif 335178354Ssam SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 336178354Ssam SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 337156321Sdamien "txantenna", CTLFLAG_RW, &sc->tx_ant, 0, "tx antenna (0=auto)"); 338156321Sdamien 339156321Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 340156321Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 341156321Sdamien "rxantenna", CTLFLAG_RW, &sc->rx_ant, 0, "rx antenna (0=auto)"); 342156321Sdamien 343156321Sdamien if (bootverbose) 344156321Sdamien ieee80211_announce(ic); 345156321Sdamien 346156321Sdamien return 0; 347156321Sdamien 348156321Sdamienfail6: rt2560_free_rx_ring(sc, &sc->rxq); 349156321Sdamienfail5: rt2560_free_tx_ring(sc, &sc->bcnq); 350156321Sdamienfail4: rt2560_free_tx_ring(sc, &sc->prioq); 351156321Sdamienfail3: rt2560_free_tx_ring(sc, &sc->atimq); 352156321Sdamienfail2: rt2560_free_tx_ring(sc, &sc->txq); 353156321Sdamienfail1: mtx_destroy(&sc->sc_mtx); 354156321Sdamien 355156321Sdamien return ENXIO; 356156321Sdamien} 357156321Sdamien 358156321Sdamienint 359156321Sdamienrt2560_detach(void *xsc) 360156321Sdamien{ 361156321Sdamien struct rt2560_softc *sc = xsc; 362178354Ssam struct ifnet *ifp = sc->sc_ifp; 363178354Ssam struct ieee80211com *ic = ifp->if_l2com; 364170530Ssam 365156321Sdamien rt2560_stop(sc); 366156321Sdamien 367156321Sdamien bpfdetach(ifp); 368156321Sdamien ieee80211_ifdetach(ic); 369156321Sdamien 370156321Sdamien rt2560_free_tx_ring(sc, &sc->txq); 371156321Sdamien rt2560_free_tx_ring(sc, &sc->atimq); 372156321Sdamien rt2560_free_tx_ring(sc, &sc->prioq); 373156321Sdamien rt2560_free_tx_ring(sc, &sc->bcnq); 374156321Sdamien rt2560_free_rx_ring(sc, &sc->rxq); 375156321Sdamien 376156321Sdamien if_free(ifp); 377156321Sdamien 378156321Sdamien mtx_destroy(&sc->sc_mtx); 379156321Sdamien 380156321Sdamien return 0; 381156321Sdamien} 382156321Sdamien 383178354Ssamstatic struct ieee80211vap * 384178354Ssamrt2560_vap_create(struct ieee80211com *ic, 385178354Ssam const char name[IFNAMSIZ], int unit, int opmode, int flags, 386178354Ssam const uint8_t bssid[IEEE80211_ADDR_LEN], 387178354Ssam const uint8_t mac[IEEE80211_ADDR_LEN]) 388178354Ssam{ 389178354Ssam struct ifnet *ifp = ic->ic_ifp; 390178354Ssam struct rt2560_vap *rvp; 391178354Ssam struct ieee80211vap *vap; 392178354Ssam 393178354Ssam switch (opmode) { 394178354Ssam case IEEE80211_M_STA: 395178354Ssam case IEEE80211_M_IBSS: 396178354Ssam case IEEE80211_M_AHDEMO: 397178354Ssam case IEEE80211_M_MONITOR: 398178354Ssam case IEEE80211_M_HOSTAP: 399178354Ssam if (!TAILQ_EMPTY(&ic->ic_vaps)) { 400178354Ssam if_printf(ifp, "only 1 vap supported\n"); 401178354Ssam return NULL; 402178354Ssam } 403178354Ssam if (opmode == IEEE80211_M_STA) 404178354Ssam flags |= IEEE80211_CLONE_NOBEACONS; 405178354Ssam break; 406178354Ssam case IEEE80211_M_WDS: 407178354Ssam if (TAILQ_EMPTY(&ic->ic_vaps) || 408178354Ssam ic->ic_opmode != IEEE80211_M_HOSTAP) { 409178354Ssam if_printf(ifp, "wds only supported in ap mode\n"); 410178354Ssam return NULL; 411178354Ssam } 412178354Ssam /* 413178354Ssam * Silently remove any request for a unique 414178354Ssam * bssid; WDS vap's always share the local 415178354Ssam * mac address. 416178354Ssam */ 417178354Ssam flags &= ~IEEE80211_CLONE_BSSID; 418178354Ssam break; 419178354Ssam default: 420178354Ssam if_printf(ifp, "unknown opmode %d\n", opmode); 421178354Ssam return NULL; 422178354Ssam } 423178354Ssam rvp = (struct rt2560_vap *) malloc(sizeof(struct rt2560_vap), 424178354Ssam M_80211_VAP, M_NOWAIT | M_ZERO); 425178354Ssam if (rvp == NULL) 426178354Ssam return NULL; 427178354Ssam vap = &rvp->ral_vap; 428178354Ssam ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); 429178354Ssam 430178354Ssam /* override state transition machine */ 431178354Ssam rvp->ral_newstate = vap->iv_newstate; 432178354Ssam vap->iv_newstate = rt2560_newstate; 433178354Ssam vap->iv_update_beacon = rt2560_beacon_update; 434178354Ssam 435178354Ssam ieee80211_amrr_init(&rvp->amrr, vap, 436178354Ssam IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, 437178354Ssam IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD, 438178354Ssam 500 /* ms */); 439178354Ssam 440178354Ssam /* complete setup */ 441178354Ssam ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); 442178354Ssam if (TAILQ_FIRST(&ic->ic_vaps) == vap) 443178354Ssam ic->ic_opmode = opmode; 444178354Ssam return vap; 445178354Ssam} 446178354Ssam 447178354Ssamstatic void 448178354Ssamrt2560_vap_delete(struct ieee80211vap *vap) 449178354Ssam{ 450178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 451178354Ssam 452178354Ssam ieee80211_amrr_cleanup(&rvp->amrr); 453178354Ssam ieee80211_vap_detach(vap); 454178354Ssam free(rvp, M_80211_VAP); 455178354Ssam} 456178354Ssam 457156321Sdamienvoid 458156321Sdamienrt2560_resume(void *xsc) 459156321Sdamien{ 460156321Sdamien struct rt2560_softc *sc = xsc; 461178354Ssam struct ifnet *ifp = sc->sc_ifp; 462156321Sdamien 463178354Ssam if (ifp->if_flags & IFF_UP) 464178354Ssam rt2560_init(sc); 465156321Sdamien} 466156321Sdamien 467156321Sdamienstatic void 468156321Sdamienrt2560_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 469156321Sdamien{ 470156321Sdamien if (error != 0) 471156321Sdamien return; 472156321Sdamien 473156321Sdamien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 474156321Sdamien 475156321Sdamien *(bus_addr_t *)arg = segs[0].ds_addr; 476156321Sdamien} 477156321Sdamien 478156321Sdamienstatic int 479156321Sdamienrt2560_alloc_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring, 480156321Sdamien int count) 481156321Sdamien{ 482156321Sdamien int i, error; 483156321Sdamien 484156321Sdamien ring->count = count; 485156321Sdamien ring->queued = 0; 486156321Sdamien ring->cur = ring->next = 0; 487156321Sdamien ring->cur_encrypt = ring->next_encrypt = 0; 488156321Sdamien 489171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 4, 0, 490171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 491171535Skevlo count * RT2560_TX_DESC_SIZE, 1, count * RT2560_TX_DESC_SIZE, 492171535Skevlo 0, NULL, NULL, &ring->desc_dmat); 493156321Sdamien if (error != 0) { 494156321Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 495156321Sdamien goto fail; 496156321Sdamien } 497156321Sdamien 498156321Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 499156321Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 500156321Sdamien if (error != 0) { 501156321Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 502156321Sdamien goto fail; 503156321Sdamien } 504156321Sdamien 505156321Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 506156321Sdamien count * RT2560_TX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr, 507156321Sdamien 0); 508156321Sdamien if (error != 0) { 509156321Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 510156321Sdamien goto fail; 511156321Sdamien } 512156321Sdamien 513156321Sdamien ring->data = malloc(count * sizeof (struct rt2560_tx_data), M_DEVBUF, 514156321Sdamien M_NOWAIT | M_ZERO); 515156321Sdamien if (ring->data == NULL) { 516156321Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 517156321Sdamien error = ENOMEM; 518156321Sdamien goto fail; 519156321Sdamien } 520156321Sdamien 521171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 522171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 523171535Skevlo MCLBYTES, RT2560_MAX_SCATTER, MCLBYTES, 0, NULL, NULL, 524171535Skevlo &ring->data_dmat); 525156321Sdamien if (error != 0) { 526156321Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 527156321Sdamien goto fail; 528156321Sdamien } 529156321Sdamien 530156321Sdamien for (i = 0; i < count; i++) { 531156321Sdamien error = bus_dmamap_create(ring->data_dmat, 0, 532156321Sdamien &ring->data[i].map); 533156321Sdamien if (error != 0) { 534156321Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 535156321Sdamien goto fail; 536156321Sdamien } 537156321Sdamien } 538156321Sdamien 539156321Sdamien return 0; 540156321Sdamien 541156321Sdamienfail: rt2560_free_tx_ring(sc, ring); 542156321Sdamien return error; 543156321Sdamien} 544156321Sdamien 545156321Sdamienstatic void 546156321Sdamienrt2560_reset_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) 547156321Sdamien{ 548156321Sdamien struct rt2560_tx_desc *desc; 549156321Sdamien struct rt2560_tx_data *data; 550156321Sdamien int i; 551156321Sdamien 552156321Sdamien for (i = 0; i < ring->count; i++) { 553156321Sdamien desc = &ring->desc[i]; 554156321Sdamien data = &ring->data[i]; 555156321Sdamien 556156321Sdamien if (data->m != NULL) { 557156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 558156321Sdamien BUS_DMASYNC_POSTWRITE); 559156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 560156321Sdamien m_freem(data->m); 561156321Sdamien data->m = NULL; 562156321Sdamien } 563156321Sdamien 564156321Sdamien if (data->ni != NULL) { 565156321Sdamien ieee80211_free_node(data->ni); 566156321Sdamien data->ni = NULL; 567156321Sdamien } 568156321Sdamien 569156321Sdamien desc->flags = 0; 570156321Sdamien } 571156321Sdamien 572156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 573156321Sdamien 574156321Sdamien ring->queued = 0; 575156321Sdamien ring->cur = ring->next = 0; 576156321Sdamien ring->cur_encrypt = ring->next_encrypt = 0; 577156321Sdamien} 578156321Sdamien 579156321Sdamienstatic void 580156321Sdamienrt2560_free_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) 581156321Sdamien{ 582156321Sdamien struct rt2560_tx_data *data; 583156321Sdamien int i; 584156321Sdamien 585156321Sdamien if (ring->desc != NULL) { 586156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 587156321Sdamien BUS_DMASYNC_POSTWRITE); 588156321Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 589156321Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 590156321Sdamien } 591156321Sdamien 592156321Sdamien if (ring->desc_dmat != NULL) 593156321Sdamien bus_dma_tag_destroy(ring->desc_dmat); 594156321Sdamien 595156321Sdamien if (ring->data != NULL) { 596156321Sdamien for (i = 0; i < ring->count; i++) { 597156321Sdamien data = &ring->data[i]; 598156321Sdamien 599156321Sdamien if (data->m != NULL) { 600156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 601156321Sdamien BUS_DMASYNC_POSTWRITE); 602156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 603156321Sdamien m_freem(data->m); 604156321Sdamien } 605156321Sdamien 606156321Sdamien if (data->ni != NULL) 607156321Sdamien ieee80211_free_node(data->ni); 608156321Sdamien 609156321Sdamien if (data->map != NULL) 610156321Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 611156321Sdamien } 612156321Sdamien 613156321Sdamien free(ring->data, M_DEVBUF); 614156321Sdamien } 615156321Sdamien 616156321Sdamien if (ring->data_dmat != NULL) 617156321Sdamien bus_dma_tag_destroy(ring->data_dmat); 618156321Sdamien} 619156321Sdamien 620156321Sdamienstatic int 621156321Sdamienrt2560_alloc_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring, 622156321Sdamien int count) 623156321Sdamien{ 624156321Sdamien struct rt2560_rx_desc *desc; 625156321Sdamien struct rt2560_rx_data *data; 626156321Sdamien bus_addr_t physaddr; 627156321Sdamien int i, error; 628156321Sdamien 629156321Sdamien ring->count = count; 630156321Sdamien ring->cur = ring->next = 0; 631156321Sdamien ring->cur_decrypt = 0; 632156321Sdamien 633171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 4, 0, 634171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 635171535Skevlo count * RT2560_RX_DESC_SIZE, 1, count * RT2560_RX_DESC_SIZE, 636171535Skevlo 0, NULL, NULL, &ring->desc_dmat); 637156321Sdamien if (error != 0) { 638156321Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 639156321Sdamien goto fail; 640156321Sdamien } 641156321Sdamien 642156321Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 643156321Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 644156321Sdamien if (error != 0) { 645156321Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 646156321Sdamien goto fail; 647156321Sdamien } 648156321Sdamien 649156321Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 650156321Sdamien count * RT2560_RX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr, 651156321Sdamien 0); 652156321Sdamien if (error != 0) { 653156321Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 654156321Sdamien goto fail; 655156321Sdamien } 656156321Sdamien 657156321Sdamien ring->data = malloc(count * sizeof (struct rt2560_rx_data), M_DEVBUF, 658156321Sdamien M_NOWAIT | M_ZERO); 659156321Sdamien if (ring->data == NULL) { 660156321Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 661156321Sdamien error = ENOMEM; 662156321Sdamien goto fail; 663156321Sdamien } 664156321Sdamien 665156321Sdamien /* 666156321Sdamien * Pre-allocate Rx buffers and populate Rx ring. 667156321Sdamien */ 668171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 669171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 670171535Skevlo 1, MCLBYTES, 0, NULL, NULL, &ring->data_dmat); 671156321Sdamien if (error != 0) { 672156321Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 673156321Sdamien goto fail; 674156321Sdamien } 675156321Sdamien 676156321Sdamien for (i = 0; i < count; i++) { 677156321Sdamien desc = &sc->rxq.desc[i]; 678156321Sdamien data = &sc->rxq.data[i]; 679156321Sdamien 680156321Sdamien error = bus_dmamap_create(ring->data_dmat, 0, &data->map); 681156321Sdamien if (error != 0) { 682156321Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 683156321Sdamien goto fail; 684156321Sdamien } 685156321Sdamien 686156321Sdamien data->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 687156321Sdamien if (data->m == NULL) { 688156321Sdamien device_printf(sc->sc_dev, 689156321Sdamien "could not allocate rx mbuf\n"); 690156321Sdamien error = ENOMEM; 691156321Sdamien goto fail; 692156321Sdamien } 693156321Sdamien 694156321Sdamien error = bus_dmamap_load(ring->data_dmat, data->map, 695156321Sdamien mtod(data->m, void *), MCLBYTES, rt2560_dma_map_addr, 696156321Sdamien &physaddr, 0); 697156321Sdamien if (error != 0) { 698156321Sdamien device_printf(sc->sc_dev, 699156321Sdamien "could not load rx buf DMA map"); 700156321Sdamien goto fail; 701156321Sdamien } 702156321Sdamien 703156321Sdamien desc->flags = htole32(RT2560_RX_BUSY); 704156321Sdamien desc->physaddr = htole32(physaddr); 705156321Sdamien } 706156321Sdamien 707156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 708156321Sdamien 709156321Sdamien return 0; 710156321Sdamien 711156321Sdamienfail: rt2560_free_rx_ring(sc, ring); 712156321Sdamien return error; 713156321Sdamien} 714156321Sdamien 715156321Sdamienstatic void 716156321Sdamienrt2560_reset_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) 717156321Sdamien{ 718156321Sdamien int i; 719156321Sdamien 720156321Sdamien for (i = 0; i < ring->count; i++) { 721156321Sdamien ring->desc[i].flags = htole32(RT2560_RX_BUSY); 722156321Sdamien ring->data[i].drop = 0; 723156321Sdamien } 724156321Sdamien 725156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 726156321Sdamien 727156321Sdamien ring->cur = ring->next = 0; 728156321Sdamien ring->cur_decrypt = 0; 729156321Sdamien} 730156321Sdamien 731156321Sdamienstatic void 732156321Sdamienrt2560_free_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) 733156321Sdamien{ 734156321Sdamien struct rt2560_rx_data *data; 735156321Sdamien int i; 736156321Sdamien 737156321Sdamien if (ring->desc != NULL) { 738156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 739156321Sdamien BUS_DMASYNC_POSTWRITE); 740156321Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 741156321Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 742156321Sdamien } 743156321Sdamien 744156321Sdamien if (ring->desc_dmat != NULL) 745156321Sdamien bus_dma_tag_destroy(ring->desc_dmat); 746156321Sdamien 747156321Sdamien if (ring->data != NULL) { 748156321Sdamien for (i = 0; i < ring->count; i++) { 749156321Sdamien data = &ring->data[i]; 750156321Sdamien 751156321Sdamien if (data->m != NULL) { 752156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 753156321Sdamien BUS_DMASYNC_POSTREAD); 754156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 755156321Sdamien m_freem(data->m); 756156321Sdamien } 757156321Sdamien 758156321Sdamien if (data->map != NULL) 759156321Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 760156321Sdamien } 761156321Sdamien 762156321Sdamien free(ring->data, M_DEVBUF); 763156321Sdamien } 764156321Sdamien 765156321Sdamien if (ring->data_dmat != NULL) 766156321Sdamien bus_dma_tag_destroy(ring->data_dmat); 767156321Sdamien} 768156321Sdamien 769156321Sdamienstatic struct ieee80211_node * 770179643Ssamrt2560_node_alloc(struct ieee80211vap *vap, 771179643Ssam const uint8_t mac[IEEE80211_ADDR_LEN]) 772156321Sdamien{ 773156321Sdamien struct rt2560_node *rn; 774156321Sdamien 775156321Sdamien rn = malloc(sizeof (struct rt2560_node), M_80211_NODE, 776156321Sdamien M_NOWAIT | M_ZERO); 777156321Sdamien 778156321Sdamien return (rn != NULL) ? &rn->ni : NULL; 779156321Sdamien} 780156321Sdamien 781156321Sdamienstatic void 782178354Ssamrt2560_newassoc(struct ieee80211_node *ni, int isnew) 783156321Sdamien{ 784178354Ssam struct ieee80211vap *vap = ni->ni_vap; 785156321Sdamien 786178354Ssam ieee80211_amrr_node_init(&RT2560_VAP(vap)->amrr, 787178354Ssam &RT2560_NODE(ni)->amrr, ni); 788156321Sdamien} 789156321Sdamien 790156321Sdamienstatic int 791178354Ssamrt2560_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 792156321Sdamien{ 793178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 794178354Ssam struct ifnet *ifp = vap->iv_ic->ic_ifp; 795178354Ssam struct rt2560_softc *sc = ifp->if_softc; 796178354Ssam int error; 797156321Sdamien 798178354Ssam if (nstate == IEEE80211_S_INIT && vap->iv_state == IEEE80211_S_RUN) { 799178354Ssam /* abort TSF synchronization */ 800178354Ssam RAL_WRITE(sc, RT2560_CSR14, 0); 801156321Sdamien 802178354Ssam /* turn association led off */ 803178354Ssam rt2560_update_led(sc, 0, 0); 804178354Ssam } 805156321Sdamien 806178354Ssam error = rvp->ral_newstate(vap, nstate, arg); 807156321Sdamien 808178354Ssam if (error == 0 && nstate == IEEE80211_S_RUN) { 809178354Ssam struct ieee80211_node *ni = vap->iv_bss; 810178354Ssam struct mbuf *m; 811156321Sdamien 812178354Ssam if (vap->iv_opmode != IEEE80211_M_MONITOR) { 813156321Sdamien rt2560_update_plcp(sc); 814156321Sdamien rt2560_set_basicrates(sc); 815156321Sdamien rt2560_set_bssid(sc, ni->ni_bssid); 816156321Sdamien } 817156321Sdamien 818178354Ssam if (vap->iv_opmode == IEEE80211_M_HOSTAP || 819178354Ssam vap->iv_opmode == IEEE80211_M_IBSS) { 820178354Ssam m = ieee80211_beacon_alloc(ni, &rvp->ral_bo); 821156321Sdamien if (m == NULL) { 822178354Ssam if_printf(ifp, "could not allocate beacon\n"); 823178354Ssam return ENOBUFS; 824156321Sdamien } 825156321Sdamien ieee80211_ref_node(ni); 826156321Sdamien error = rt2560_tx_bcn(sc, m, ni); 827156321Sdamien if (error != 0) 828178354Ssam return error; 829156321Sdamien } 830156321Sdamien 831156321Sdamien /* turn assocation led on */ 832156321Sdamien rt2560_update_led(sc, 1, 0); 833156321Sdamien 834184345Ssam if (vap->iv_opmode != IEEE80211_M_MONITOR) 835156321Sdamien rt2560_enable_tsf_sync(sc); 836156321Sdamien } 837178354Ssam return error; 838156321Sdamien} 839156321Sdamien 840156321Sdamien/* 841156321Sdamien * Read 16 bits at address 'addr' from the serial EEPROM (either 93C46 or 842156321Sdamien * 93C66). 843156321Sdamien */ 844156321Sdamienstatic uint16_t 845156321Sdamienrt2560_eeprom_read(struct rt2560_softc *sc, uint8_t addr) 846156321Sdamien{ 847156321Sdamien uint32_t tmp; 848156321Sdamien uint16_t val; 849156321Sdamien int n; 850156321Sdamien 851156321Sdamien /* clock C once before the first command */ 852156321Sdamien RT2560_EEPROM_CTL(sc, 0); 853156321Sdamien 854156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 855156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 856156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 857156321Sdamien 858156321Sdamien /* write start bit (1) */ 859156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D); 860156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C); 861156321Sdamien 862156321Sdamien /* write READ opcode (10) */ 863156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D); 864156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C); 865156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 866156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 867156321Sdamien 868156321Sdamien /* write address (A5-A0 or A7-A0) */ 869156321Sdamien n = (RAL_READ(sc, RT2560_CSR21) & RT2560_93C46) ? 5 : 7; 870156321Sdamien for (; n >= 0; n--) { 871156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | 872156321Sdamien (((addr >> n) & 1) << RT2560_SHIFT_D)); 873156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | 874156321Sdamien (((addr >> n) & 1) << RT2560_SHIFT_D) | RT2560_C); 875156321Sdamien } 876156321Sdamien 877156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 878156321Sdamien 879156321Sdamien /* read data Q15-Q0 */ 880156321Sdamien val = 0; 881156321Sdamien for (n = 15; n >= 0; n--) { 882156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 883156321Sdamien tmp = RAL_READ(sc, RT2560_CSR21); 884156321Sdamien val |= ((tmp & RT2560_Q) >> RT2560_SHIFT_Q) << n; 885156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 886156321Sdamien } 887156321Sdamien 888156321Sdamien RT2560_EEPROM_CTL(sc, 0); 889156321Sdamien 890156321Sdamien /* clear Chip Select and clock C */ 891156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 892156321Sdamien RT2560_EEPROM_CTL(sc, 0); 893156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_C); 894156321Sdamien 895156321Sdamien return val; 896156321Sdamien} 897156321Sdamien 898156321Sdamien/* 899156321Sdamien * Some frames were processed by the hardware cipher engine and are ready for 900156321Sdamien * transmission. 901156321Sdamien */ 902156321Sdamienstatic void 903156321Sdamienrt2560_encryption_intr(struct rt2560_softc *sc) 904156321Sdamien{ 905156321Sdamien struct rt2560_tx_desc *desc; 906156321Sdamien int hw; 907156321Sdamien 908156321Sdamien /* retrieve last descriptor index processed by cipher engine */ 909156321Sdamien hw = RAL_READ(sc, RT2560_SECCSR1) - sc->txq.physaddr; 910156321Sdamien hw /= RT2560_TX_DESC_SIZE; 911156321Sdamien 912156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 913156321Sdamien BUS_DMASYNC_POSTREAD); 914156321Sdamien 915175938Ssephe while (sc->txq.next_encrypt != hw) { 916175938Ssephe if (sc->txq.next_encrypt == sc->txq.cur_encrypt) { 917175938Ssephe printf("hw encrypt %d, cur_encrypt %d\n", hw, 918175938Ssephe sc->txq.cur_encrypt); 919175938Ssephe break; 920175938Ssephe } 921175938Ssephe 922156321Sdamien desc = &sc->txq.desc[sc->txq.next_encrypt]; 923156321Sdamien 924156321Sdamien if ((le32toh(desc->flags) & RT2560_TX_BUSY) || 925156321Sdamien (le32toh(desc->flags) & RT2560_TX_CIPHER_BUSY)) 926156321Sdamien break; 927156321Sdamien 928156321Sdamien /* for TKIP, swap eiv field to fix a bug in ASIC */ 929156321Sdamien if ((le32toh(desc->flags) & RT2560_TX_CIPHER_MASK) == 930156321Sdamien RT2560_TX_CIPHER_TKIP) 931156321Sdamien desc->eiv = bswap32(desc->eiv); 932156321Sdamien 933156321Sdamien /* mark the frame ready for transmission */ 934175938Ssephe desc->flags |= htole32(RT2560_TX_VALID); 935175938Ssephe desc->flags |= htole32(RT2560_TX_BUSY); 936156321Sdamien 937178354Ssam DPRINTFN(sc, 15, "encryption done idx=%u\n", 938178354Ssam sc->txq.next_encrypt); 939156321Sdamien 940156321Sdamien sc->txq.next_encrypt = 941156321Sdamien (sc->txq.next_encrypt + 1) % RT2560_TX_RING_COUNT; 942156321Sdamien } 943156321Sdamien 944156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 945156321Sdamien BUS_DMASYNC_PREWRITE); 946156321Sdamien 947156321Sdamien /* kick Tx */ 948156321Sdamien RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_TX); 949156321Sdamien} 950156321Sdamien 951156321Sdamienstatic void 952156321Sdamienrt2560_tx_intr(struct rt2560_softc *sc) 953156321Sdamien{ 954178354Ssam struct ifnet *ifp = sc->sc_ifp; 955156321Sdamien struct rt2560_tx_desc *desc; 956156321Sdamien struct rt2560_tx_data *data; 957156321Sdamien struct rt2560_node *rn; 958178354Ssam struct mbuf *m; 959178354Ssam uint32_t flags; 960178354Ssam int retrycnt; 961156321Sdamien 962156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 963156321Sdamien BUS_DMASYNC_POSTREAD); 964156321Sdamien 965156321Sdamien for (;;) { 966156321Sdamien desc = &sc->txq.desc[sc->txq.next]; 967156321Sdamien data = &sc->txq.data[sc->txq.next]; 968156321Sdamien 969178354Ssam flags = le32toh(desc->flags); 970178354Ssam if ((flags & RT2560_TX_BUSY) || 971178354Ssam (flags & RT2560_TX_CIPHER_BUSY) || 972178354Ssam !(flags & RT2560_TX_VALID)) 973156321Sdamien break; 974156321Sdamien 975156321Sdamien rn = (struct rt2560_node *)data->ni; 976178354Ssam m = data->m; 977156321Sdamien 978178354Ssam switch (flags & RT2560_TX_RESULT_MASK) { 979156321Sdamien case RT2560_TX_SUCCESS: 980178354Ssam DPRINTFN(sc, 10, "%s\n", "data frame sent successfully"); 981178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 982178354Ssam ieee80211_amrr_tx_complete(&rn->amrr, 983178354Ssam IEEE80211_AMRR_SUCCESS, 0); 984156321Sdamien ifp->if_opackets++; 985156321Sdamien break; 986156321Sdamien 987156321Sdamien case RT2560_TX_SUCCESS_RETRY: 988178354Ssam retrycnt = RT2560_TX_RETRYCNT(flags); 989178354Ssam 990178354Ssam DPRINTFN(sc, 9, "data frame sent after %u retries\n", 991178354Ssam retrycnt); 992178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 993178354Ssam ieee80211_amrr_tx_complete(&rn->amrr, 994178354Ssam IEEE80211_AMRR_SUCCESS, retrycnt); 995156321Sdamien ifp->if_opackets++; 996156321Sdamien break; 997156321Sdamien 998156321Sdamien case RT2560_TX_FAIL_RETRY: 999178354Ssam retrycnt = RT2560_TX_RETRYCNT(flags); 1000178354Ssam 1001178354Ssam DPRINTFN(sc, 9, "data frame failed after %d retries\n", 1002178354Ssam retrycnt); 1003178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 1004178354Ssam ieee80211_amrr_tx_complete(&rn->amrr, 1005178354Ssam IEEE80211_AMRR_FAILURE, retrycnt); 1006156321Sdamien ifp->if_oerrors++; 1007156321Sdamien break; 1008156321Sdamien 1009156321Sdamien case RT2560_TX_FAIL_INVALID: 1010156321Sdamien case RT2560_TX_FAIL_OTHER: 1011156321Sdamien default: 1012156321Sdamien device_printf(sc->sc_dev, "sending data frame failed " 1013178354Ssam "0x%08x\n", flags); 1014156321Sdamien ifp->if_oerrors++; 1015156321Sdamien } 1016156321Sdamien 1017156321Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, 1018156321Sdamien BUS_DMASYNC_POSTWRITE); 1019156321Sdamien bus_dmamap_unload(sc->txq.data_dmat, data->map); 1020178354Ssam m_freem(m); 1021156321Sdamien data->m = NULL; 1022156321Sdamien ieee80211_free_node(data->ni); 1023156321Sdamien data->ni = NULL; 1024156321Sdamien 1025156321Sdamien /* descriptor is no longer valid */ 1026156321Sdamien desc->flags &= ~htole32(RT2560_TX_VALID); 1027156321Sdamien 1028178354Ssam DPRINTFN(sc, 15, "tx done idx=%u\n", sc->txq.next); 1029156321Sdamien 1030156321Sdamien sc->txq.queued--; 1031156321Sdamien sc->txq.next = (sc->txq.next + 1) % RT2560_TX_RING_COUNT; 1032156321Sdamien } 1033156321Sdamien 1034156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 1035156321Sdamien BUS_DMASYNC_PREWRITE); 1036156321Sdamien 1037175938Ssephe if (sc->prioq.queued == 0 && sc->txq.queued == 0) 1038175938Ssephe sc->sc_tx_timer = 0; 1039175938Ssephe 1040175938Ssephe if (sc->txq.queued < RT2560_TX_RING_COUNT - 1) { 1041175938Ssephe sc->sc_flags &= ~RT2560_F_DATA_OACTIVE; 1042175938Ssephe if ((sc->sc_flags & 1043175938Ssephe (RT2560_F_DATA_OACTIVE | RT2560_F_PRIO_OACTIVE)) == 0) 1044175938Ssephe ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1045178354Ssam rt2560_start_locked(ifp); 1046175938Ssephe } 1047156321Sdamien} 1048156321Sdamien 1049156321Sdamienstatic void 1050156321Sdamienrt2560_prio_intr(struct rt2560_softc *sc) 1051156321Sdamien{ 1052178354Ssam struct ifnet *ifp = sc->sc_ifp; 1053156321Sdamien struct rt2560_tx_desc *desc; 1054156321Sdamien struct rt2560_tx_data *data; 1055170530Ssam struct ieee80211_node *ni; 1056170530Ssam struct mbuf *m; 1057170530Ssam int flags; 1058156321Sdamien 1059156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1060156321Sdamien BUS_DMASYNC_POSTREAD); 1061156321Sdamien 1062156321Sdamien for (;;) { 1063156321Sdamien desc = &sc->prioq.desc[sc->prioq.next]; 1064156321Sdamien data = &sc->prioq.data[sc->prioq.next]; 1065156321Sdamien 1066170530Ssam flags = le32toh(desc->flags); 1067170530Ssam if ((flags & RT2560_TX_BUSY) || (flags & RT2560_TX_VALID) == 0) 1068156321Sdamien break; 1069156321Sdamien 1070170530Ssam switch (flags & RT2560_TX_RESULT_MASK) { 1071156321Sdamien case RT2560_TX_SUCCESS: 1072178354Ssam DPRINTFN(sc, 10, "%s\n", "mgt frame sent successfully"); 1073156321Sdamien break; 1074156321Sdamien 1075156321Sdamien case RT2560_TX_SUCCESS_RETRY: 1076178354Ssam DPRINTFN(sc, 9, "mgt frame sent after %u retries\n", 1077178354Ssam (flags >> 5) & 0x7); 1078156321Sdamien break; 1079156321Sdamien 1080156321Sdamien case RT2560_TX_FAIL_RETRY: 1081178354Ssam DPRINTFN(sc, 9, "%s\n", 1082178354Ssam "sending mgt frame failed (too much retries)"); 1083156321Sdamien break; 1084156321Sdamien 1085156321Sdamien case RT2560_TX_FAIL_INVALID: 1086156321Sdamien case RT2560_TX_FAIL_OTHER: 1087156321Sdamien default: 1088156321Sdamien device_printf(sc->sc_dev, "sending mgt frame failed " 1089170530Ssam "0x%08x\n", flags); 1090170530Ssam break; 1091156321Sdamien } 1092156321Sdamien 1093156321Sdamien bus_dmamap_sync(sc->prioq.data_dmat, data->map, 1094156321Sdamien BUS_DMASYNC_POSTWRITE); 1095156321Sdamien bus_dmamap_unload(sc->prioq.data_dmat, data->map); 1096170530Ssam 1097170530Ssam m = data->m; 1098156321Sdamien data->m = NULL; 1099170530Ssam ni = data->ni; 1100156321Sdamien data->ni = NULL; 1101156321Sdamien 1102156321Sdamien /* descriptor is no longer valid */ 1103156321Sdamien desc->flags &= ~htole32(RT2560_TX_VALID); 1104156321Sdamien 1105178354Ssam DPRINTFN(sc, 15, "prio done idx=%u\n", sc->prioq.next); 1106156321Sdamien 1107156321Sdamien sc->prioq.queued--; 1108156321Sdamien sc->prioq.next = (sc->prioq.next + 1) % RT2560_PRIO_RING_COUNT; 1109170530Ssam 1110170530Ssam if (m->m_flags & M_TXCB) 1111170530Ssam ieee80211_process_callback(ni, m, 1112170530Ssam (flags & RT2560_TX_RESULT_MASK) &~ 1113170530Ssam (RT2560_TX_SUCCESS | RT2560_TX_SUCCESS_RETRY)); 1114170530Ssam m_freem(m); 1115170530Ssam ieee80211_free_node(ni); 1116156321Sdamien } 1117156321Sdamien 1118156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1119156321Sdamien BUS_DMASYNC_PREWRITE); 1120156321Sdamien 1121175938Ssephe if (sc->prioq.queued == 0 && sc->txq.queued == 0) 1122175938Ssephe sc->sc_tx_timer = 0; 1123175938Ssephe 1124175938Ssephe if (sc->prioq.queued < RT2560_PRIO_RING_COUNT) { 1125175938Ssephe sc->sc_flags &= ~RT2560_F_PRIO_OACTIVE; 1126175938Ssephe if ((sc->sc_flags & 1127175938Ssephe (RT2560_F_DATA_OACTIVE | RT2560_F_PRIO_OACTIVE)) == 0) 1128175938Ssephe ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1129178354Ssam rt2560_start_locked(ifp); 1130175938Ssephe } 1131156321Sdamien} 1132156321Sdamien 1133156321Sdamien/* 1134156321Sdamien * Some frames were processed by the hardware cipher engine and are ready for 1135178354Ssam * handoff to the IEEE802.11 layer. 1136156321Sdamien */ 1137156321Sdamienstatic void 1138156321Sdamienrt2560_decryption_intr(struct rt2560_softc *sc) 1139156321Sdamien{ 1140178354Ssam struct ifnet *ifp = sc->sc_ifp; 1141178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1142156321Sdamien struct rt2560_rx_desc *desc; 1143156321Sdamien struct rt2560_rx_data *data; 1144156321Sdamien bus_addr_t physaddr; 1145156321Sdamien struct ieee80211_frame *wh; 1146156321Sdamien struct ieee80211_node *ni; 1147156321Sdamien struct mbuf *mnew, *m; 1148156321Sdamien int hw, error; 1149156321Sdamien 1150156321Sdamien /* retrieve last decriptor index processed by cipher engine */ 1151156321Sdamien hw = RAL_READ(sc, RT2560_SECCSR0) - sc->rxq.physaddr; 1152156321Sdamien hw /= RT2560_RX_DESC_SIZE; 1153156321Sdamien 1154156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1155156321Sdamien BUS_DMASYNC_POSTREAD); 1156156321Sdamien 1157156321Sdamien for (; sc->rxq.cur_decrypt != hw;) { 1158156321Sdamien desc = &sc->rxq.desc[sc->rxq.cur_decrypt]; 1159156321Sdamien data = &sc->rxq.data[sc->rxq.cur_decrypt]; 1160156321Sdamien 1161156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_BUSY) || 1162156321Sdamien (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY)) 1163156321Sdamien break; 1164156321Sdamien 1165156321Sdamien if (data->drop) { 1166156321Sdamien ifp->if_ierrors++; 1167156321Sdamien goto skip; 1168156321Sdamien } 1169156321Sdamien 1170156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_CIPHER_MASK) != 0 && 1171156321Sdamien (le32toh(desc->flags) & RT2560_RX_ICV_ERROR)) { 1172156321Sdamien ifp->if_ierrors++; 1173156321Sdamien goto skip; 1174156321Sdamien } 1175156321Sdamien 1176156321Sdamien /* 1177156321Sdamien * Try to allocate a new mbuf for this ring element and load it 1178156321Sdamien * before processing the current mbuf. If the ring element 1179156321Sdamien * cannot be loaded, drop the received packet and reuse the old 1180156321Sdamien * mbuf. In the unlikely case that the old mbuf can't be 1181156321Sdamien * reloaded either, explicitly panic. 1182156321Sdamien */ 1183156321Sdamien mnew = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1184156321Sdamien if (mnew == NULL) { 1185156321Sdamien ifp->if_ierrors++; 1186156321Sdamien goto skip; 1187156321Sdamien } 1188156321Sdamien 1189156321Sdamien bus_dmamap_sync(sc->rxq.data_dmat, data->map, 1190156321Sdamien BUS_DMASYNC_POSTREAD); 1191156321Sdamien bus_dmamap_unload(sc->rxq.data_dmat, data->map); 1192156321Sdamien 1193156321Sdamien error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 1194156321Sdamien mtod(mnew, void *), MCLBYTES, rt2560_dma_map_addr, 1195156321Sdamien &physaddr, 0); 1196156321Sdamien if (error != 0) { 1197156321Sdamien m_freem(mnew); 1198156321Sdamien 1199156321Sdamien /* try to reload the old mbuf */ 1200156321Sdamien error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 1201156321Sdamien mtod(data->m, void *), MCLBYTES, 1202156321Sdamien rt2560_dma_map_addr, &physaddr, 0); 1203156321Sdamien if (error != 0) { 1204156321Sdamien /* very unlikely that it will fail... */ 1205156321Sdamien panic("%s: could not load old rx mbuf", 1206156321Sdamien device_get_name(sc->sc_dev)); 1207156321Sdamien } 1208156321Sdamien ifp->if_ierrors++; 1209156321Sdamien goto skip; 1210156321Sdamien } 1211156321Sdamien 1212156321Sdamien /* 1213156321Sdamien * New mbuf successfully loaded, update Rx ring and continue 1214156321Sdamien * processing. 1215156321Sdamien */ 1216156321Sdamien m = data->m; 1217156321Sdamien data->m = mnew; 1218156321Sdamien desc->physaddr = htole32(physaddr); 1219156321Sdamien 1220156321Sdamien /* finalize mbuf */ 1221156321Sdamien m->m_pkthdr.rcvif = ifp; 1222156321Sdamien m->m_pkthdr.len = m->m_len = 1223156321Sdamien (le32toh(desc->flags) >> 16) & 0xfff; 1224156321Sdamien 1225178354Ssam if (bpf_peers_present(ifp->if_bpf)) { 1226156321Sdamien struct rt2560_rx_radiotap_header *tap = &sc->sc_rxtap; 1227156321Sdamien uint32_t tsf_lo, tsf_hi; 1228156321Sdamien 1229156321Sdamien /* get timestamp (low and high 32 bits) */ 1230156321Sdamien tsf_hi = RAL_READ(sc, RT2560_CSR17); 1231156321Sdamien tsf_lo = RAL_READ(sc, RT2560_CSR16); 1232156321Sdamien 1233156321Sdamien tap->wr_tsf = 1234156321Sdamien htole64(((uint64_t)tsf_hi << 32) | tsf_lo); 1235156321Sdamien tap->wr_flags = 0; 1236178354Ssam tap->wr_rate = ieee80211_plcp2rate(desc->rate, 1237178958Ssam (desc->flags & htole32(RT2560_RX_OFDM)) ? 1238178958Ssam IEEE80211_T_OFDM : IEEE80211_T_CCK); 1239156321Sdamien tap->wr_antenna = sc->rx_ant; 1240170530Ssam tap->wr_antsignal = RT2560_RSSI(sc, desc->rssi); 1241156321Sdamien 1242178354Ssam bpf_mtap2(ifp->if_bpf, tap, sc->sc_rxtap_len, m); 1243156321Sdamien } 1244156321Sdamien 1245175938Ssephe sc->sc_flags |= RT2560_F_INPUT_RUNNING; 1246170530Ssam RAL_UNLOCK(sc); 1247156321Sdamien wh = mtod(m, struct ieee80211_frame *); 1248156321Sdamien ni = ieee80211_find_rxnode(ic, 1249156321Sdamien (struct ieee80211_frame_min *)wh); 1250178354Ssam if (ni != NULL) { 1251178354Ssam (void) ieee80211_input(ni, m, 1252178354Ssam RT2560_RSSI(sc, desc->rssi), RT2560_NOISE_FLOOR, 0); 1253178354Ssam ieee80211_free_node(ni); 1254178354Ssam } else 1255178354Ssam (void) ieee80211_input_all(ic, m, 1256178354Ssam RT2560_RSSI(sc, desc->rssi), RT2560_NOISE_FLOOR, 0); 1257156321Sdamien 1258170530Ssam RAL_LOCK(sc); 1259175938Ssephe sc->sc_flags &= ~RT2560_F_INPUT_RUNNING; 1260156321Sdamienskip: desc->flags = htole32(RT2560_RX_BUSY); 1261156321Sdamien 1262178354Ssam DPRINTFN(sc, 15, "decryption done idx=%u\n", sc->rxq.cur_decrypt); 1263156321Sdamien 1264156321Sdamien sc->rxq.cur_decrypt = 1265156321Sdamien (sc->rxq.cur_decrypt + 1) % RT2560_RX_RING_COUNT; 1266156321Sdamien } 1267156321Sdamien 1268156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1269156321Sdamien BUS_DMASYNC_PREWRITE); 1270156321Sdamien} 1271156321Sdamien 1272156321Sdamien/* 1273156321Sdamien * Some frames were received. Pass them to the hardware cipher engine before 1274156321Sdamien * sending them to the 802.11 layer. 1275156321Sdamien */ 1276156321Sdamienstatic void 1277156321Sdamienrt2560_rx_intr(struct rt2560_softc *sc) 1278156321Sdamien{ 1279156321Sdamien struct rt2560_rx_desc *desc; 1280156321Sdamien struct rt2560_rx_data *data; 1281156321Sdamien 1282156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1283156321Sdamien BUS_DMASYNC_POSTREAD); 1284156321Sdamien 1285156321Sdamien for (;;) { 1286156321Sdamien desc = &sc->rxq.desc[sc->rxq.cur]; 1287156321Sdamien data = &sc->rxq.data[sc->rxq.cur]; 1288156321Sdamien 1289156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_BUSY) || 1290156321Sdamien (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY)) 1291156321Sdamien break; 1292156321Sdamien 1293156321Sdamien data->drop = 0; 1294156321Sdamien 1295156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_PHY_ERROR) || 1296156321Sdamien (le32toh(desc->flags) & RT2560_RX_CRC_ERROR)) { 1297156321Sdamien /* 1298156321Sdamien * This should not happen since we did not request 1299156321Sdamien * to receive those frames when we filled RXCSR0. 1300156321Sdamien */ 1301178354Ssam DPRINTFN(sc, 5, "PHY or CRC error flags 0x%08x\n", 1302178354Ssam le32toh(desc->flags)); 1303156321Sdamien data->drop = 1; 1304156321Sdamien } 1305156321Sdamien 1306156321Sdamien if (((le32toh(desc->flags) >> 16) & 0xfff) > MCLBYTES) { 1307178354Ssam DPRINTFN(sc, 5, "%s\n", "bad length"); 1308156321Sdamien data->drop = 1; 1309156321Sdamien } 1310156321Sdamien 1311156321Sdamien /* mark the frame for decryption */ 1312156321Sdamien desc->flags |= htole32(RT2560_RX_CIPHER_BUSY); 1313156321Sdamien 1314178354Ssam DPRINTFN(sc, 15, "rx done idx=%u\n", sc->rxq.cur); 1315156321Sdamien 1316156321Sdamien sc->rxq.cur = (sc->rxq.cur + 1) % RT2560_RX_RING_COUNT; 1317156321Sdamien } 1318156321Sdamien 1319156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1320156321Sdamien BUS_DMASYNC_PREWRITE); 1321156321Sdamien 1322156321Sdamien /* kick decrypt */ 1323156321Sdamien RAL_WRITE(sc, RT2560_SECCSR0, RT2560_KICK_DECRYPT); 1324156321Sdamien} 1325156321Sdamien 1326172211Ssamstatic void 1327178354Ssamrt2560_beacon_update(struct ieee80211vap *vap, int item) 1328172211Ssam{ 1329178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 1330178354Ssam struct ieee80211_beacon_offsets *bo = &rvp->ral_bo; 1331172211Ssam 1332172211Ssam setbit(bo->bo_flags, item); 1333172211Ssam} 1334172211Ssam 1335156321Sdamien/* 1336156321Sdamien * This function is called periodically in IBSS mode when a new beacon must be 1337156321Sdamien * sent out. 1338156321Sdamien */ 1339156321Sdamienstatic void 1340156321Sdamienrt2560_beacon_expire(struct rt2560_softc *sc) 1341156321Sdamien{ 1342178354Ssam struct ifnet *ifp = sc->sc_ifp; 1343178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1344178354Ssam struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 1345178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 1346156321Sdamien struct rt2560_tx_data *data; 1347156321Sdamien 1348156321Sdamien if (ic->ic_opmode != IEEE80211_M_IBSS && 1349156321Sdamien ic->ic_opmode != IEEE80211_M_HOSTAP) 1350170530Ssam return; 1351156321Sdamien 1352156321Sdamien data = &sc->bcnq.data[sc->bcnq.next]; 1353170530Ssam /* 1354170530Ssam * Don't send beacon if bsschan isn't set 1355170530Ssam */ 1356170530Ssam if (data->ni == NULL) 1357170530Ssam return; 1358156321Sdamien 1359156321Sdamien bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_POSTWRITE); 1360156321Sdamien bus_dmamap_unload(sc->bcnq.data_dmat, data->map); 1361156321Sdamien 1362178354Ssam /* XXX 1 =>'s mcast frames which means all PS sta's will wakeup! */ 1363178354Ssam ieee80211_beacon_update(data->ni, &rvp->ral_bo, data->m, 1); 1364156321Sdamien 1365156321Sdamien rt2560_tx_bcn(sc, data->m, data->ni); 1366156321Sdamien 1367178354Ssam DPRINTFN(sc, 15, "%s", "beacon expired\n"); 1368156321Sdamien 1369156321Sdamien sc->bcnq.next = (sc->bcnq.next + 1) % RT2560_BEACON_RING_COUNT; 1370156321Sdamien} 1371156321Sdamien 1372156321Sdamien/* ARGSUSED */ 1373156321Sdamienstatic void 1374156321Sdamienrt2560_wakeup_expire(struct rt2560_softc *sc) 1375156321Sdamien{ 1376178354Ssam DPRINTFN(sc, 2, "%s", "wakeup expired\n"); 1377156321Sdamien} 1378156321Sdamien 1379156321Sdamienvoid 1380156321Sdamienrt2560_intr(void *arg) 1381156321Sdamien{ 1382156321Sdamien struct rt2560_softc *sc = arg; 1383156975Sdamien struct ifnet *ifp = sc->sc_ifp; 1384156321Sdamien uint32_t r; 1385156321Sdamien 1386156321Sdamien RAL_LOCK(sc); 1387156321Sdamien 1388156321Sdamien /* disable interrupts */ 1389156321Sdamien RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 1390156321Sdamien 1391156975Sdamien /* don't re-enable interrupts if we're shutting down */ 1392156975Sdamien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1393156975Sdamien RAL_UNLOCK(sc); 1394156975Sdamien return; 1395156975Sdamien } 1396156975Sdamien 1397156321Sdamien r = RAL_READ(sc, RT2560_CSR7); 1398156321Sdamien RAL_WRITE(sc, RT2560_CSR7, r); 1399156321Sdamien 1400156321Sdamien if (r & RT2560_BEACON_EXPIRE) 1401156321Sdamien rt2560_beacon_expire(sc); 1402156321Sdamien 1403156321Sdamien if (r & RT2560_WAKEUP_EXPIRE) 1404156321Sdamien rt2560_wakeup_expire(sc); 1405156321Sdamien 1406156321Sdamien if (r & RT2560_ENCRYPTION_DONE) 1407156321Sdamien rt2560_encryption_intr(sc); 1408156321Sdamien 1409156321Sdamien if (r & RT2560_TX_DONE) 1410156321Sdamien rt2560_tx_intr(sc); 1411156321Sdamien 1412156321Sdamien if (r & RT2560_PRIO_DONE) 1413156321Sdamien rt2560_prio_intr(sc); 1414156321Sdamien 1415156321Sdamien if (r & RT2560_DECRYPTION_DONE) 1416156321Sdamien rt2560_decryption_intr(sc); 1417156321Sdamien 1418175938Ssephe if (r & RT2560_RX_DONE) { 1419156321Sdamien rt2560_rx_intr(sc); 1420175938Ssephe rt2560_encryption_intr(sc); 1421175938Ssephe } 1422156321Sdamien 1423156321Sdamien /* re-enable interrupts */ 1424156321Sdamien RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); 1425156321Sdamien 1426156321Sdamien RAL_UNLOCK(sc); 1427156321Sdamien} 1428156321Sdamien 1429156321Sdamien#define RAL_SIFS 10 /* us */ 1430156321Sdamien 1431156321Sdamien#define RT2560_TXRX_TURNAROUND 10 /* us */ 1432156321Sdamien 1433178958Ssamstatic uint8_t 1434178958Ssamrt2560_plcp_signal(int rate) 1435178958Ssam{ 1436178958Ssam switch (rate) { 1437178958Ssam /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ 1438178958Ssam case 12: return 0xb; 1439178958Ssam case 18: return 0xf; 1440178958Ssam case 24: return 0xa; 1441178958Ssam case 36: return 0xe; 1442178958Ssam case 48: return 0x9; 1443178958Ssam case 72: return 0xd; 1444178958Ssam case 96: return 0x8; 1445178958Ssam case 108: return 0xc; 1446178958Ssam 1447178958Ssam /* CCK rates (NB: not IEEE std, device-specific) */ 1448178958Ssam case 2: return 0x0; 1449178958Ssam case 4: return 0x1; 1450178958Ssam case 11: return 0x2; 1451178958Ssam case 22: return 0x3; 1452178958Ssam } 1453178958Ssam return 0xff; /* XXX unsupported/unknown rate */ 1454178958Ssam} 1455178958Ssam 1456156321Sdamienstatic void 1457156321Sdamienrt2560_setup_tx_desc(struct rt2560_softc *sc, struct rt2560_tx_desc *desc, 1458156321Sdamien uint32_t flags, int len, int rate, int encrypt, bus_addr_t physaddr) 1459156321Sdamien{ 1460178354Ssam struct ifnet *ifp = sc->sc_ifp; 1461178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1462156321Sdamien uint16_t plcp_length; 1463156321Sdamien int remainder; 1464156321Sdamien 1465156321Sdamien desc->flags = htole32(flags); 1466156321Sdamien desc->flags |= htole32(len << 16); 1467156321Sdamien 1468156321Sdamien desc->physaddr = htole32(physaddr); 1469156321Sdamien desc->wme = htole16( 1470156321Sdamien RT2560_AIFSN(2) | 1471156321Sdamien RT2560_LOGCWMIN(3) | 1472156321Sdamien RT2560_LOGCWMAX(8)); 1473156321Sdamien 1474156321Sdamien /* setup PLCP fields */ 1475178958Ssam desc->plcp_signal = rt2560_plcp_signal(rate); 1476156321Sdamien desc->plcp_service = 4; 1477156321Sdamien 1478156321Sdamien len += IEEE80211_CRC_LEN; 1479190532Ssam if (ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) { 1480156321Sdamien desc->flags |= htole32(RT2560_TX_OFDM); 1481156321Sdamien 1482156321Sdamien plcp_length = len & 0xfff; 1483156321Sdamien desc->plcp_length_hi = plcp_length >> 6; 1484156321Sdamien desc->plcp_length_lo = plcp_length & 0x3f; 1485156321Sdamien } else { 1486156321Sdamien plcp_length = (16 * len + rate - 1) / rate; 1487156321Sdamien if (rate == 22) { 1488156321Sdamien remainder = (16 * len) % 22; 1489156321Sdamien if (remainder != 0 && remainder < 7) 1490156321Sdamien desc->plcp_service |= RT2560_PLCP_LENGEXT; 1491156321Sdamien } 1492156321Sdamien desc->plcp_length_hi = plcp_length >> 8; 1493156321Sdamien desc->plcp_length_lo = plcp_length & 0xff; 1494156321Sdamien 1495156321Sdamien if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 1496156321Sdamien desc->plcp_signal |= 0x08; 1497156321Sdamien } 1498175938Ssephe 1499175938Ssephe if (!encrypt) 1500175938Ssephe desc->flags |= htole32(RT2560_TX_VALID); 1501175938Ssephe desc->flags |= encrypt ? htole32(RT2560_TX_CIPHER_BUSY) 1502175938Ssephe : htole32(RT2560_TX_BUSY); 1503156321Sdamien} 1504156321Sdamien 1505156321Sdamienstatic int 1506156321Sdamienrt2560_tx_bcn(struct rt2560_softc *sc, struct mbuf *m0, 1507156321Sdamien struct ieee80211_node *ni) 1508156321Sdamien{ 1509178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1510178354Ssam struct ieee80211com *ic = ni->ni_ic; 1511178354Ssam struct ifnet *ifp = sc->sc_ifp; 1512156321Sdamien struct rt2560_tx_desc *desc; 1513156321Sdamien struct rt2560_tx_data *data; 1514156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1515156321Sdamien int nsegs, rate, error; 1516156321Sdamien 1517156321Sdamien desc = &sc->bcnq.desc[sc->bcnq.cur]; 1518156321Sdamien data = &sc->bcnq.data[sc->bcnq.cur]; 1519156321Sdamien 1520178354Ssam /* XXX maybe a separate beacon rate? */ 1521178354Ssam rate = vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)].mgmtrate; 1522156321Sdamien 1523156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->bcnq.data_dmat, data->map, m0, 1524156321Sdamien segs, &nsegs, BUS_DMA_NOWAIT); 1525156321Sdamien if (error != 0) { 1526156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1527156321Sdamien error); 1528156321Sdamien m_freem(m0); 1529156321Sdamien return error; 1530156321Sdamien } 1531156321Sdamien 1532178354Ssam if (bpf_peers_present(ifp->if_bpf)) { 1533156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1534156321Sdamien 1535156321Sdamien tap->wt_flags = 0; 1536156321Sdamien tap->wt_rate = rate; 1537156321Sdamien tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 1538156321Sdamien tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 1539156321Sdamien tap->wt_antenna = sc->tx_ant; 1540156321Sdamien 1541178354Ssam bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); 1542156321Sdamien } 1543156321Sdamien 1544156321Sdamien data->m = m0; 1545156321Sdamien data->ni = ni; 1546156321Sdamien 1547156321Sdamien rt2560_setup_tx_desc(sc, desc, RT2560_TX_IFS_NEWBACKOFF | 1548156321Sdamien RT2560_TX_TIMESTAMP, m0->m_pkthdr.len, rate, 0, segs->ds_addr); 1549156321Sdamien 1550178354Ssam DPRINTFN(sc, 10, "sending beacon frame len=%u idx=%u rate=%u\n", 1551178354Ssam m0->m_pkthdr.len, sc->bcnq.cur, rate); 1552156321Sdamien 1553156321Sdamien bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1554156321Sdamien bus_dmamap_sync(sc->bcnq.desc_dmat, sc->bcnq.desc_map, 1555156321Sdamien BUS_DMASYNC_PREWRITE); 1556156321Sdamien 1557156321Sdamien sc->bcnq.cur = (sc->bcnq.cur + 1) % RT2560_BEACON_RING_COUNT; 1558156321Sdamien 1559156321Sdamien return 0; 1560156321Sdamien} 1561156321Sdamien 1562156321Sdamienstatic int 1563156321Sdamienrt2560_tx_mgt(struct rt2560_softc *sc, struct mbuf *m0, 1564156321Sdamien struct ieee80211_node *ni) 1565156321Sdamien{ 1566178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1567178354Ssam struct ieee80211com *ic = ni->ni_ic; 1568178354Ssam struct ifnet *ifp = sc->sc_ifp; 1569156321Sdamien struct rt2560_tx_desc *desc; 1570156321Sdamien struct rt2560_tx_data *data; 1571156321Sdamien struct ieee80211_frame *wh; 1572173386Skevlo struct ieee80211_key *k; 1573156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1574156321Sdamien uint16_t dur; 1575156321Sdamien uint32_t flags = 0; 1576156321Sdamien int nsegs, rate, error; 1577156321Sdamien 1578156321Sdamien desc = &sc->prioq.desc[sc->prioq.cur]; 1579156321Sdamien data = &sc->prioq.data[sc->prioq.cur]; 1580156321Sdamien 1581178354Ssam rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate; 1582156321Sdamien 1583173386Skevlo wh = mtod(m0, struct ieee80211_frame *); 1584173386Skevlo 1585173386Skevlo if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1586178354Ssam k = ieee80211_crypto_encap(ni, m0); 1587173386Skevlo if (k == NULL) { 1588173386Skevlo m_freem(m0); 1589173386Skevlo return ENOBUFS; 1590173386Skevlo } 1591173386Skevlo } 1592173386Skevlo 1593156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, 1594156321Sdamien segs, &nsegs, 0); 1595156321Sdamien if (error != 0) { 1596156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1597156321Sdamien error); 1598156321Sdamien m_freem(m0); 1599156321Sdamien return error; 1600156321Sdamien } 1601156321Sdamien 1602178354Ssam if (bpf_peers_present(ifp->if_bpf)) { 1603156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1604156321Sdamien 1605156321Sdamien tap->wt_flags = 0; 1606156321Sdamien tap->wt_rate = rate; 1607156321Sdamien tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 1608156321Sdamien tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 1609156321Sdamien tap->wt_antenna = sc->tx_ant; 1610156321Sdamien 1611178354Ssam bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); 1612156321Sdamien } 1613156321Sdamien 1614156321Sdamien data->m = m0; 1615156321Sdamien data->ni = ni; 1616178354Ssam /* management frames are not taken into account for amrr */ 1617178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1618156321Sdamien 1619156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1620156321Sdamien 1621156321Sdamien if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1622156321Sdamien flags |= RT2560_TX_ACK; 1623156321Sdamien 1624190532Ssam dur = ieee80211_ack_duration(ic->ic_rt, 1625178354Ssam rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); 1626156321Sdamien *(uint16_t *)wh->i_dur = htole16(dur); 1627156321Sdamien 1628156321Sdamien /* tell hardware to add timestamp for probe responses */ 1629156321Sdamien if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 1630156321Sdamien IEEE80211_FC0_TYPE_MGT && 1631156321Sdamien (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 1632156321Sdamien IEEE80211_FC0_SUBTYPE_PROBE_RESP) 1633156321Sdamien flags |= RT2560_TX_TIMESTAMP; 1634156321Sdamien } 1635156321Sdamien 1636156321Sdamien rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 0, 1637156321Sdamien segs->ds_addr); 1638156321Sdamien 1639156321Sdamien bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1640156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1641156321Sdamien BUS_DMASYNC_PREWRITE); 1642156321Sdamien 1643178354Ssam DPRINTFN(sc, 10, "sending mgt frame len=%u idx=%u rate=%u\n", 1644178354Ssam m0->m_pkthdr.len, sc->prioq.cur, rate); 1645156321Sdamien 1646156321Sdamien /* kick prio */ 1647156321Sdamien sc->prioq.queued++; 1648156321Sdamien sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; 1649156321Sdamien RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); 1650156321Sdamien 1651156321Sdamien return 0; 1652156321Sdamien} 1653156321Sdamien 1654160691Ssamstatic int 1655178354Ssamrt2560_sendprot(struct rt2560_softc *sc, 1656178354Ssam const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) 1657178354Ssam{ 1658178354Ssam struct ieee80211com *ic = ni->ni_ic; 1659178354Ssam const struct ieee80211_frame *wh; 1660178354Ssam struct rt2560_tx_desc *desc; 1661178354Ssam struct rt2560_tx_data *data; 1662178354Ssam struct mbuf *mprot; 1663178354Ssam int protrate, ackrate, pktlen, flags, isshort, error; 1664178354Ssam uint16_t dur; 1665178354Ssam bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1666178354Ssam int nsegs; 1667178354Ssam 1668178354Ssam KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, 1669178354Ssam ("protection %d", prot)); 1670178354Ssam 1671178354Ssam wh = mtod(m, const struct ieee80211_frame *); 1672178354Ssam pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; 1673178354Ssam 1674190532Ssam protrate = ieee80211_ctl_rate(ic->ic_rt, rate); 1675190532Ssam ackrate = ieee80211_ack_rate(ic->ic_rt, rate); 1676178354Ssam 1677178354Ssam isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; 1678190532Ssam dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort) 1679190532Ssam + ieee80211_ack_duration(ic->ic_rt, rate, isshort); 1680178354Ssam flags = RT2560_TX_MORE_FRAG; 1681178354Ssam if (prot == IEEE80211_PROT_RTSCTS) { 1682178354Ssam /* NB: CTS is the same size as an ACK */ 1683190532Ssam dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); 1684178354Ssam flags |= RT2560_TX_ACK; 1685178354Ssam mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); 1686178354Ssam } else { 1687178354Ssam mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); 1688178354Ssam } 1689178354Ssam if (mprot == NULL) { 1690178354Ssam /* XXX stat + msg */ 1691178354Ssam return ENOBUFS; 1692178354Ssam } 1693178354Ssam 1694178354Ssam desc = &sc->txq.desc[sc->txq.cur_encrypt]; 1695178354Ssam data = &sc->txq.data[sc->txq.cur_encrypt]; 1696178354Ssam 1697178354Ssam error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, 1698178354Ssam mprot, segs, &nsegs, 0); 1699178354Ssam if (error != 0) { 1700178354Ssam device_printf(sc->sc_dev, 1701178354Ssam "could not map mbuf (error %d)\n", error); 1702178354Ssam m_freem(mprot); 1703178354Ssam return error; 1704178354Ssam } 1705178354Ssam 1706178354Ssam data->m = mprot; 1707178354Ssam data->ni = ieee80211_ref_node(ni); 1708178354Ssam /* ctl frames are not taken into account for amrr */ 1709178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1710178354Ssam 1711178354Ssam rt2560_setup_tx_desc(sc, desc, flags, mprot->m_pkthdr.len, protrate, 1, 1712178354Ssam segs->ds_addr); 1713178354Ssam 1714178354Ssam bus_dmamap_sync(sc->txq.data_dmat, data->map, 1715178354Ssam BUS_DMASYNC_PREWRITE); 1716178354Ssam 1717178354Ssam sc->txq.queued++; 1718178354Ssam sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; 1719178354Ssam 1720178354Ssam return 0; 1721178354Ssam} 1722178354Ssam 1723178354Ssamstatic int 1724160691Ssamrt2560_tx_raw(struct rt2560_softc *sc, struct mbuf *m0, 1725160691Ssam struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) 1726160691Ssam{ 1727178354Ssam struct ifnet *ifp = sc->sc_ifp; 1728178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1729160691Ssam struct rt2560_tx_desc *desc; 1730160691Ssam struct rt2560_tx_data *data; 1731160691Ssam bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1732160691Ssam uint32_t flags; 1733160691Ssam int nsegs, rate, error; 1734160691Ssam 1735160691Ssam desc = &sc->prioq.desc[sc->prioq.cur]; 1736160691Ssam data = &sc->prioq.data[sc->prioq.cur]; 1737160691Ssam 1738160691Ssam rate = params->ibp_rate0 & IEEE80211_RATE_VAL; 1739160691Ssam /* XXX validate */ 1740168860Ssephe if (rate == 0) { 1741178354Ssam /* XXX fall back to mcast/mgmt rate? */ 1742168860Ssephe m_freem(m0); 1743160691Ssam return EINVAL; 1744168860Ssephe } 1745160691Ssam 1746178354Ssam flags = 0; 1747178354Ssam if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) 1748178354Ssam flags |= RT2560_TX_ACK; 1749178354Ssam if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { 1750178354Ssam error = rt2560_sendprot(sc, m0, ni, 1751178354Ssam params->ibp_flags & IEEE80211_BPF_RTS ? 1752178354Ssam IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, 1753178354Ssam rate); 1754178354Ssam if (error) { 1755178354Ssam m_freem(m0); 1756178354Ssam return error; 1757178354Ssam } 1758178354Ssam flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; 1759178354Ssam } 1760178354Ssam 1761160691Ssam error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, 1762160691Ssam segs, &nsegs, 0); 1763160691Ssam if (error != 0) { 1764160691Ssam device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1765160691Ssam error); 1766160691Ssam m_freem(m0); 1767160691Ssam return error; 1768160691Ssam } 1769160691Ssam 1770178354Ssam if (bpf_peers_present(ifp->if_bpf)) { 1771160691Ssam struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1772160691Ssam 1773160691Ssam tap->wt_flags = 0; 1774160691Ssam tap->wt_rate = rate; 1775160691Ssam tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 1776160691Ssam tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 1777160691Ssam tap->wt_antenna = sc->tx_ant; 1778160691Ssam 1779178354Ssam bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); 1780160691Ssam } 1781160691Ssam 1782160691Ssam data->m = m0; 1783160691Ssam data->ni = ni; 1784160691Ssam 1785160691Ssam /* XXX need to setup descriptor ourself */ 1786160691Ssam rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, 1787160691Ssam rate, (params->ibp_flags & IEEE80211_BPF_CRYPTO) != 0, 1788160691Ssam segs->ds_addr); 1789160691Ssam 1790160691Ssam bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1791160691Ssam bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1792160691Ssam BUS_DMASYNC_PREWRITE); 1793160691Ssam 1794178354Ssam DPRINTFN(sc, 10, "sending raw frame len=%u idx=%u rate=%u\n", 1795178354Ssam m0->m_pkthdr.len, sc->prioq.cur, rate); 1796160691Ssam 1797160691Ssam /* kick prio */ 1798160691Ssam sc->prioq.queued++; 1799160691Ssam sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; 1800160691Ssam RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); 1801160691Ssam 1802160691Ssam return 0; 1803160691Ssam} 1804160691Ssam 1805156321Sdamienstatic int 1806156321Sdamienrt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0, 1807156321Sdamien struct ieee80211_node *ni) 1808156321Sdamien{ 1809178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1810178354Ssam struct ieee80211com *ic = ni->ni_ic; 1811178354Ssam struct ifnet *ifp = sc->sc_ifp; 1812156321Sdamien struct rt2560_tx_desc *desc; 1813156321Sdamien struct rt2560_tx_data *data; 1814156321Sdamien struct ieee80211_frame *wh; 1815178354Ssam const struct ieee80211_txparam *tp; 1816156321Sdamien struct ieee80211_key *k; 1817156321Sdamien struct mbuf *mnew; 1818156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1819156321Sdamien uint16_t dur; 1820178354Ssam uint32_t flags; 1821156321Sdamien int nsegs, rate, error; 1822156321Sdamien 1823156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1824156321Sdamien 1825178354Ssam tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; 1826178354Ssam if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1827178354Ssam rate = tp->mcastrate; 1828178354Ssam } else if (m0->m_flags & M_EAPOL) { 1829178354Ssam rate = tp->mgmtrate; 1830178354Ssam } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 1831178354Ssam rate = tp->ucastrate; 1832156321Sdamien } else { 1833178354Ssam (void) ieee80211_amrr_choose(ni, &RT2560_NODE(ni)->amrr); 1834178354Ssam rate = ni->ni_txrate; 1835156321Sdamien } 1836156321Sdamien 1837156321Sdamien if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1838178354Ssam k = ieee80211_crypto_encap(ni, m0); 1839156321Sdamien if (k == NULL) { 1840156321Sdamien m_freem(m0); 1841156321Sdamien return ENOBUFS; 1842156321Sdamien } 1843156321Sdamien 1844156321Sdamien /* packet header may have moved, reset our local pointer */ 1845156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1846156321Sdamien } 1847156321Sdamien 1848178354Ssam flags = 0; 1849178354Ssam if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1850178354Ssam int prot = IEEE80211_PROT_NONE; 1851178354Ssam if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) 1852178354Ssam prot = IEEE80211_PROT_RTSCTS; 1853178354Ssam else if ((ic->ic_flags & IEEE80211_F_USEPROT) && 1854190532Ssam ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) 1855178354Ssam prot = ic->ic_protmode; 1856178354Ssam if (prot != IEEE80211_PROT_NONE) { 1857178354Ssam error = rt2560_sendprot(sc, m0, ni, prot, rate); 1858178354Ssam if (error) { 1859178354Ssam m_freem(m0); 1860178354Ssam return error; 1861178354Ssam } 1862178354Ssam flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; 1863156321Sdamien } 1864156321Sdamien } 1865156321Sdamien 1866156321Sdamien data = &sc->txq.data[sc->txq.cur_encrypt]; 1867156321Sdamien desc = &sc->txq.desc[sc->txq.cur_encrypt]; 1868156321Sdamien 1869156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, m0, 1870156321Sdamien segs, &nsegs, 0); 1871156321Sdamien if (error != 0 && error != EFBIG) { 1872156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1873156321Sdamien error); 1874156321Sdamien m_freem(m0); 1875156321Sdamien return error; 1876156321Sdamien } 1877156321Sdamien if (error != 0) { 1878156321Sdamien mnew = m_defrag(m0, M_DONTWAIT); 1879156321Sdamien if (mnew == NULL) { 1880156321Sdamien device_printf(sc->sc_dev, 1881156321Sdamien "could not defragment mbuf\n"); 1882156321Sdamien m_freem(m0); 1883156321Sdamien return ENOBUFS; 1884156321Sdamien } 1885156321Sdamien m0 = mnew; 1886156321Sdamien 1887156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, 1888156321Sdamien m0, segs, &nsegs, 0); 1889156321Sdamien if (error != 0) { 1890156321Sdamien device_printf(sc->sc_dev, 1891156321Sdamien "could not map mbuf (error %d)\n", error); 1892156321Sdamien m_freem(m0); 1893156321Sdamien return error; 1894156321Sdamien } 1895156321Sdamien 1896156321Sdamien /* packet header may have moved, reset our local pointer */ 1897156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1898156321Sdamien } 1899156321Sdamien 1900178354Ssam if (bpf_peers_present(ifp->if_bpf)) { 1901156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1902156321Sdamien 1903156321Sdamien tap->wt_flags = 0; 1904156321Sdamien tap->wt_rate = rate; 1905156321Sdamien tap->wt_antenna = sc->tx_ant; 1906156321Sdamien 1907178354Ssam bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); 1908156321Sdamien } 1909156321Sdamien 1910156321Sdamien data->m = m0; 1911156321Sdamien data->ni = ni; 1912156321Sdamien 1913156321Sdamien /* remember link conditions for rate adaptation algorithm */ 1914178354Ssam if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) { 1915178354Ssam data->rix = ni->ni_txrate; 1916178354Ssam /* XXX probably need last rssi value and not avg */ 1917178354Ssam data->rssi = ic->ic_node_getrssi(ni); 1918156321Sdamien } else 1919178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1920156321Sdamien 1921156321Sdamien if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1922156321Sdamien flags |= RT2560_TX_ACK; 1923156321Sdamien 1924190532Ssam dur = ieee80211_ack_duration(ic->ic_rt, 1925178354Ssam rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); 1926156321Sdamien *(uint16_t *)wh->i_dur = htole16(dur); 1927156321Sdamien } 1928156321Sdamien 1929156321Sdamien rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 1, 1930156321Sdamien segs->ds_addr); 1931156321Sdamien 1932156321Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1933156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 1934156321Sdamien BUS_DMASYNC_PREWRITE); 1935156321Sdamien 1936178354Ssam DPRINTFN(sc, 10, "sending data frame len=%u idx=%u rate=%u\n", 1937178354Ssam m0->m_pkthdr.len, sc->txq.cur_encrypt, rate); 1938156321Sdamien 1939156321Sdamien /* kick encrypt */ 1940156321Sdamien sc->txq.queued++; 1941156321Sdamien sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; 1942156321Sdamien RAL_WRITE(sc, RT2560_SECCSR1, RT2560_KICK_ENCRYPT); 1943156321Sdamien 1944156321Sdamien return 0; 1945156321Sdamien} 1946156321Sdamien 1947156321Sdamienstatic void 1948178354Ssamrt2560_start_locked(struct ifnet *ifp) 1949156321Sdamien{ 1950156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 1951178354Ssam struct mbuf *m; 1952156321Sdamien struct ieee80211_node *ni; 1953156321Sdamien 1954178354Ssam RAL_LOCK_ASSERT(sc); 1955156321Sdamien 1956156321Sdamien for (;;) { 1957178354Ssam IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 1958178354Ssam if (m == NULL) 1959178354Ssam break; 1960178354Ssam if (sc->txq.queued >= RT2560_TX_RING_COUNT - 1) { 1961178354Ssam IFQ_DRV_PREPEND(&ifp->if_snd, m); 1962178354Ssam ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1963178354Ssam sc->sc_flags |= RT2560_F_DATA_OACTIVE; 1964178354Ssam break; 1965178354Ssam } 1966156321Sdamien 1967178354Ssam ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; 1968178354Ssam m = ieee80211_encap(ni, m); 1969178354Ssam if (m == NULL) { 1970178354Ssam ieee80211_free_node(ni); 1971178354Ssam ifp->if_oerrors++; 1972178354Ssam continue; 1973178354Ssam } 1974156321Sdamien 1975178354Ssam if (rt2560_tx_data(sc, m, ni) != 0) { 1976178354Ssam ieee80211_free_node(ni); 1977178354Ssam ifp->if_oerrors++; 1978178354Ssam break; 1979156321Sdamien } 1980156321Sdamien 1981156321Sdamien sc->sc_tx_timer = 5; 1982156321Sdamien } 1983178354Ssam} 1984156321Sdamien 1985178354Ssamstatic void 1986178354Ssamrt2560_start(struct ifnet *ifp) 1987178354Ssam{ 1988178354Ssam struct rt2560_softc *sc = ifp->if_softc; 1989178354Ssam 1990178354Ssam RAL_LOCK(sc); 1991178354Ssam rt2560_start_locked(ifp); 1992156321Sdamien RAL_UNLOCK(sc); 1993156321Sdamien} 1994156321Sdamien 1995156321Sdamienstatic void 1996165352Sbmsrt2560_watchdog(void *arg) 1997156321Sdamien{ 1998167470Ssam struct rt2560_softc *sc = arg; 1999175938Ssephe struct ifnet *ifp = sc->sc_ifp; 2000156321Sdamien 2001178354Ssam RAL_LOCK_ASSERT(sc); 2002178354Ssam 2003178354Ssam KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, ("not running")); 2004178354Ssam 2005178354Ssam if (sc->sc_invalid) /* card ejected */ 2006175938Ssephe return; 2007175938Ssephe 2008175938Ssephe rt2560_encryption_intr(sc); 2009175938Ssephe rt2560_tx_intr(sc); 2010175938Ssephe 2011178354Ssam if (sc->sc_tx_timer > 0 && --sc->sc_tx_timer == 0) { 2012178354Ssam if_printf(ifp, "device timeout\n"); 2013178354Ssam rt2560_init_locked(sc); 2014178354Ssam ifp->if_oerrors++; 2015178354Ssam /* NB: callout is reset in rt2560_init() */ 2016178354Ssam return; 2017156321Sdamien } 2018175938Ssephe callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); 2019156321Sdamien} 2020156321Sdamien 2021156321Sdamienstatic int 2022156321Sdamienrt2560_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 2023156321Sdamien{ 2024156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 2025178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2026178354Ssam struct ifreq *ifr = (struct ifreq *) data; 2027178354Ssam int error = 0, startall = 0; 2028156321Sdamien 2029156321Sdamien switch (cmd) { 2030156321Sdamien case SIOCSIFFLAGS: 2031178704Sthompsa RAL_LOCK(sc); 2032156321Sdamien if (ifp->if_flags & IFF_UP) { 2033178354Ssam if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 2034178354Ssam rt2560_init_locked(sc); 2035178354Ssam startall = 1; 2036178354Ssam } else 2037178354Ssam rt2560_update_promisc(ifp); 2038156321Sdamien } else { 2039156321Sdamien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2040178354Ssam rt2560_stop_locked(sc); 2041156321Sdamien } 2042178704Sthompsa RAL_UNLOCK(sc); 2043178704Sthompsa if (startall) 2044178704Sthompsa ieee80211_start_all(ic); 2045156321Sdamien break; 2046178354Ssam case SIOCGIFMEDIA: 2047178354Ssam error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); 2048178354Ssam break; 2049178704Sthompsa case SIOCGIFADDR: 2050178354Ssam error = ether_ioctl(ifp, cmd, data); 2051178354Ssam break; 2052178704Sthompsa default: 2053178704Sthompsa error = EINVAL; 2054178704Sthompsa break; 2055156321Sdamien } 2056156321Sdamien return error; 2057156321Sdamien} 2058156321Sdamien 2059156321Sdamienstatic void 2060156321Sdamienrt2560_bbp_write(struct rt2560_softc *sc, uint8_t reg, uint8_t val) 2061156321Sdamien{ 2062156321Sdamien uint32_t tmp; 2063156321Sdamien int ntries; 2064156321Sdamien 2065156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2066156321Sdamien if (!(RAL_READ(sc, RT2560_BBPCSR) & RT2560_BBP_BUSY)) 2067156321Sdamien break; 2068156321Sdamien DELAY(1); 2069156321Sdamien } 2070156321Sdamien if (ntries == 100) { 2071156321Sdamien device_printf(sc->sc_dev, "could not write to BBP\n"); 2072156321Sdamien return; 2073156321Sdamien } 2074156321Sdamien 2075156321Sdamien tmp = RT2560_BBP_WRITE | RT2560_BBP_BUSY | reg << 8 | val; 2076156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR, tmp); 2077156321Sdamien 2078178354Ssam DPRINTFN(sc, 15, "BBP R%u <- 0x%02x\n", reg, val); 2079156321Sdamien} 2080156321Sdamien 2081156321Sdamienstatic uint8_t 2082156321Sdamienrt2560_bbp_read(struct rt2560_softc *sc, uint8_t reg) 2083156321Sdamien{ 2084156321Sdamien uint32_t val; 2085156321Sdamien int ntries; 2086156321Sdamien 2087175938Ssephe for (ntries = 0; ntries < 100; ntries++) { 2088175938Ssephe if (!(RAL_READ(sc, RT2560_BBPCSR) & RT2560_BBP_BUSY)) 2089175938Ssephe break; 2090175938Ssephe DELAY(1); 2091175938Ssephe } 2092175938Ssephe if (ntries == 100) { 2093175938Ssephe device_printf(sc->sc_dev, "could not read from BBP\n"); 2094175938Ssephe return 0; 2095175938Ssephe } 2096175938Ssephe 2097156321Sdamien val = RT2560_BBP_BUSY | reg << 8; 2098156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR, val); 2099156321Sdamien 2100156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2101156321Sdamien val = RAL_READ(sc, RT2560_BBPCSR); 2102156321Sdamien if (!(val & RT2560_BBP_BUSY)) 2103156321Sdamien return val & 0xff; 2104156321Sdamien DELAY(1); 2105156321Sdamien } 2106156321Sdamien 2107156321Sdamien device_printf(sc->sc_dev, "could not read from BBP\n"); 2108156321Sdamien return 0; 2109156321Sdamien} 2110156321Sdamien 2111156321Sdamienstatic void 2112156321Sdamienrt2560_rf_write(struct rt2560_softc *sc, uint8_t reg, uint32_t val) 2113156321Sdamien{ 2114156321Sdamien uint32_t tmp; 2115156321Sdamien int ntries; 2116156321Sdamien 2117156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2118156321Sdamien if (!(RAL_READ(sc, RT2560_RFCSR) & RT2560_RF_BUSY)) 2119156321Sdamien break; 2120156321Sdamien DELAY(1); 2121156321Sdamien } 2122156321Sdamien if (ntries == 100) { 2123156321Sdamien device_printf(sc->sc_dev, "could not write to RF\n"); 2124156321Sdamien return; 2125156321Sdamien } 2126156321Sdamien 2127156321Sdamien tmp = RT2560_RF_BUSY | RT2560_RF_20BIT | (val & 0xfffff) << 2 | 2128156321Sdamien (reg & 0x3); 2129156321Sdamien RAL_WRITE(sc, RT2560_RFCSR, tmp); 2130156321Sdamien 2131156321Sdamien /* remember last written value in sc */ 2132156321Sdamien sc->rf_regs[reg] = val; 2133156321Sdamien 2134178354Ssam DPRINTFN(sc, 15, "RF R[%u] <- 0x%05x\n", reg & 0x3, val & 0xfffff); 2135156321Sdamien} 2136156321Sdamien 2137156321Sdamienstatic void 2138156321Sdamienrt2560_set_chan(struct rt2560_softc *sc, struct ieee80211_channel *c) 2139156321Sdamien{ 2140178354Ssam struct ifnet *ifp = sc->sc_ifp; 2141178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2142156321Sdamien uint8_t power, tmp; 2143156321Sdamien u_int i, chan; 2144156321Sdamien 2145156321Sdamien chan = ieee80211_chan2ieee(ic, c); 2146178354Ssam KASSERT(chan != 0 && chan != IEEE80211_CHAN_ANY, ("chan 0x%x", chan)); 2147156321Sdamien 2148156321Sdamien if (IEEE80211_IS_CHAN_2GHZ(c)) 2149156321Sdamien power = min(sc->txpow[chan - 1], 31); 2150156321Sdamien else 2151156321Sdamien power = 31; 2152156321Sdamien 2153156321Sdamien /* adjust txpower using ifconfig settings */ 2154156321Sdamien power -= (100 - ic->ic_txpowlimit) / 8; 2155156321Sdamien 2156178354Ssam DPRINTFN(sc, 2, "setting channel to %u, txpower to %u\n", chan, power); 2157156321Sdamien 2158156321Sdamien switch (sc->rf_rev) { 2159156321Sdamien case RT2560_RF_2522: 2160156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x00814); 2161156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2522_r2[chan - 1]); 2162156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2163156321Sdamien break; 2164156321Sdamien 2165156321Sdamien case RT2560_RF_2523: 2166156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08804); 2167156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2523_r2[chan - 1]); 2168156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x38044); 2169156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2170156321Sdamien break; 2171156321Sdamien 2172156321Sdamien case RT2560_RF_2524: 2173156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x0c808); 2174156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2524_r2[chan - 1]); 2175156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2176156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2177156321Sdamien break; 2178156321Sdamien 2179156321Sdamien case RT2560_RF_2525: 2180156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2181156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_hi_r2[chan - 1]); 2182156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2183156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2184156321Sdamien 2185156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2186156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_r2[chan - 1]); 2187156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2188156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2189156321Sdamien break; 2190156321Sdamien 2191156321Sdamien case RT2560_RF_2525E: 2192156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2193156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525e_r2[chan - 1]); 2194156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2195156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00286 : 0x00282); 2196156321Sdamien break; 2197156321Sdamien 2198156321Sdamien case RT2560_RF_2526: 2199156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_hi_r2[chan - 1]); 2200156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); 2201156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08804); 2202156321Sdamien 2203156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_r2[chan - 1]); 2204156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2205156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); 2206156321Sdamien break; 2207156321Sdamien 2208156321Sdamien /* dual-band RF */ 2209156321Sdamien case RT2560_RF_5222: 2210156321Sdamien for (i = 0; rt2560_rf5222[i].chan != chan; i++); 2211156321Sdamien 2212156321Sdamien rt2560_rf_write(sc, RAL_RF1, rt2560_rf5222[i].r1); 2213156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf5222[i].r2); 2214156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2215156321Sdamien rt2560_rf_write(sc, RAL_RF4, rt2560_rf5222[i].r4); 2216156321Sdamien break; 2217170530Ssam default: 2218170530Ssam printf("unknown ral rev=%d\n", sc->rf_rev); 2219156321Sdamien } 2220156321Sdamien 2221178354Ssam /* XXX */ 2222178354Ssam if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { 2223156321Sdamien /* set Japan filter bit for channel 14 */ 2224156321Sdamien tmp = rt2560_bbp_read(sc, 70); 2225156321Sdamien 2226156321Sdamien tmp &= ~RT2560_JAPAN_FILTER; 2227156321Sdamien if (chan == 14) 2228156321Sdamien tmp |= RT2560_JAPAN_FILTER; 2229156321Sdamien 2230156321Sdamien rt2560_bbp_write(sc, 70, tmp); 2231156321Sdamien 2232156321Sdamien /* clear CRC errors */ 2233156321Sdamien RAL_READ(sc, RT2560_CNT0); 2234156321Sdamien } 2235156321Sdamien} 2236156321Sdamien 2237170530Ssamstatic void 2238170530Ssamrt2560_set_channel(struct ieee80211com *ic) 2239170530Ssam{ 2240170530Ssam struct ifnet *ifp = ic->ic_ifp; 2241170530Ssam struct rt2560_softc *sc = ifp->if_softc; 2242170530Ssam 2243170530Ssam RAL_LOCK(sc); 2244170530Ssam rt2560_set_chan(sc, ic->ic_curchan); 2245178354Ssam 2246178354Ssam sc->sc_txtap.wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 2247178354Ssam sc->sc_txtap.wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 2248178354Ssam sc->sc_rxtap.wr_chan_freq = htole16(ic->ic_curchan->ic_freq); 2249178354Ssam sc->sc_rxtap.wr_chan_flags = htole16(ic->ic_curchan->ic_flags); 2250170530Ssam RAL_UNLOCK(sc); 2251170530Ssam 2252170530Ssam} 2253170530Ssam 2254156321Sdamien#if 0 2255156321Sdamien/* 2256156321Sdamien * Disable RF auto-tuning. 2257156321Sdamien */ 2258156321Sdamienstatic void 2259156321Sdamienrt2560_disable_rf_tune(struct rt2560_softc *sc) 2260156321Sdamien{ 2261156321Sdamien uint32_t tmp; 2262156321Sdamien 2263156321Sdamien if (sc->rf_rev != RT2560_RF_2523) { 2264156321Sdamien tmp = sc->rf_regs[RAL_RF1] & ~RAL_RF1_AUTOTUNE; 2265156321Sdamien rt2560_rf_write(sc, RAL_RF1, tmp); 2266156321Sdamien } 2267156321Sdamien 2268156321Sdamien tmp = sc->rf_regs[RAL_RF3] & ~RAL_RF3_AUTOTUNE; 2269156321Sdamien rt2560_rf_write(sc, RAL_RF3, tmp); 2270156321Sdamien 2271178354Ssam DPRINTFN(sc, 2, "%s", "disabling RF autotune\n"); 2272156321Sdamien} 2273156321Sdamien#endif 2274156321Sdamien 2275156321Sdamien/* 2276156321Sdamien * Refer to IEEE Std 802.11-1999 pp. 123 for more information on TSF 2277156321Sdamien * synchronization. 2278156321Sdamien */ 2279156321Sdamienstatic void 2280156321Sdamienrt2560_enable_tsf_sync(struct rt2560_softc *sc) 2281156321Sdamien{ 2282178354Ssam struct ifnet *ifp = sc->sc_ifp; 2283178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2284178354Ssam struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2285156321Sdamien uint16_t logcwmin, preload; 2286156321Sdamien uint32_t tmp; 2287156321Sdamien 2288156321Sdamien /* first, disable TSF synchronization */ 2289156321Sdamien RAL_WRITE(sc, RT2560_CSR14, 0); 2290156321Sdamien 2291178354Ssam tmp = 16 * vap->iv_bss->ni_intval; 2292156321Sdamien RAL_WRITE(sc, RT2560_CSR12, tmp); 2293156321Sdamien 2294156321Sdamien RAL_WRITE(sc, RT2560_CSR13, 0); 2295156321Sdamien 2296156321Sdamien logcwmin = 5; 2297178354Ssam preload = (vap->iv_opmode == IEEE80211_M_STA) ? 384 : 1024; 2298156321Sdamien tmp = logcwmin << 16 | preload; 2299156321Sdamien RAL_WRITE(sc, RT2560_BCNOCSR, tmp); 2300156321Sdamien 2301156321Sdamien /* finally, enable TSF synchronization */ 2302156321Sdamien tmp = RT2560_ENABLE_TSF | RT2560_ENABLE_TBCN; 2303156321Sdamien if (ic->ic_opmode == IEEE80211_M_STA) 2304156321Sdamien tmp |= RT2560_ENABLE_TSF_SYNC(1); 2305156321Sdamien else 2306156321Sdamien tmp |= RT2560_ENABLE_TSF_SYNC(2) | 2307156321Sdamien RT2560_ENABLE_BEACON_GENERATOR; 2308156321Sdamien RAL_WRITE(sc, RT2560_CSR14, tmp); 2309156321Sdamien 2310178354Ssam DPRINTF(sc, "%s", "enabling TSF synchronization\n"); 2311156321Sdamien} 2312156321Sdamien 2313156321Sdamienstatic void 2314156321Sdamienrt2560_update_plcp(struct rt2560_softc *sc) 2315156321Sdamien{ 2316178354Ssam struct ifnet *ifp = sc->sc_ifp; 2317178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2318156321Sdamien 2319156321Sdamien /* no short preamble for 1Mbps */ 2320156321Sdamien RAL_WRITE(sc, RT2560_PLCP1MCSR, 0x00700400); 2321156321Sdamien 2322156321Sdamien if (!(ic->ic_flags & IEEE80211_F_SHPREAMBLE)) { 2323156321Sdamien /* values taken from the reference driver */ 2324156321Sdamien RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380401); 2325156321Sdamien RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x00150402); 2326156321Sdamien RAL_WRITE(sc, RT2560_PLCP11MCSR, 0x000b8403); 2327156321Sdamien } else { 2328156321Sdamien /* same values as above or'ed 0x8 */ 2329156321Sdamien RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380409); 2330156321Sdamien RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x0015040a); 2331156321Sdamien RAL_WRITE(sc, RT2560_PLCP11MCSR, 0x000b840b); 2332156321Sdamien } 2333156321Sdamien 2334178354Ssam DPRINTF(sc, "updating PLCP for %s preamble\n", 2335178354Ssam (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? "short" : "long"); 2336156321Sdamien} 2337156321Sdamien 2338156321Sdamien/* 2339156321Sdamien * This function can be called by ieee80211_set_shortslottime(). Refer to 2340156321Sdamien * IEEE Std 802.11-1999 pp. 85 to know how these values are computed. 2341156321Sdamien */ 2342156321Sdamienstatic void 2343156321Sdamienrt2560_update_slot(struct ifnet *ifp) 2344156321Sdamien{ 2345156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 2346178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2347156321Sdamien uint8_t slottime; 2348156321Sdamien uint16_t tx_sifs, tx_pifs, tx_difs, eifs; 2349156321Sdamien uint32_t tmp; 2350156321Sdamien 2351175938Ssephe#ifndef FORCE_SLOTTIME 2352156321Sdamien slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; 2353175938Ssephe#else 2354175938Ssephe /* 2355175938Ssephe * Setting slot time according to "short slot time" capability 2356175938Ssephe * in beacon/probe_resp seems to cause problem to acknowledge 2357175938Ssephe * certain AP's data frames transimitted at CCK/DS rates: the 2358175938Ssephe * problematic AP keeps retransmitting data frames, probably 2359175938Ssephe * because MAC level acks are not received by hardware. 2360175938Ssephe * So we cheat a little bit here by claiming we are capable of 2361175938Ssephe * "short slot time" but setting hardware slot time to the normal 2362175938Ssephe * slot time. ral(4) does not seem to have trouble to receive 2363175938Ssephe * frames transmitted using short slot time even if hardware 2364175938Ssephe * slot time is set to normal slot time. If we didn't use this 2365175938Ssephe * trick, we would have to claim that short slot time is not 2366175938Ssephe * supported; this would give relative poor RX performance 2367175938Ssephe * (-1Mb~-2Mb lower) and the _whole_ BSS would stop using short 2368175938Ssephe * slot time. 2369175938Ssephe */ 2370175938Ssephe slottime = 20; 2371175938Ssephe#endif 2372156321Sdamien 2373156321Sdamien /* update the MAC slot boundaries */ 2374156321Sdamien tx_sifs = RAL_SIFS - RT2560_TXRX_TURNAROUND; 2375156321Sdamien tx_pifs = tx_sifs + slottime; 2376156321Sdamien tx_difs = tx_sifs + 2 * slottime; 2377156321Sdamien eifs = (ic->ic_curmode == IEEE80211_MODE_11B) ? 364 : 60; 2378156321Sdamien 2379156321Sdamien tmp = RAL_READ(sc, RT2560_CSR11); 2380156321Sdamien tmp = (tmp & ~0x1f00) | slottime << 8; 2381156321Sdamien RAL_WRITE(sc, RT2560_CSR11, tmp); 2382156321Sdamien 2383156321Sdamien tmp = tx_pifs << 16 | tx_sifs; 2384156321Sdamien RAL_WRITE(sc, RT2560_CSR18, tmp); 2385156321Sdamien 2386156321Sdamien tmp = eifs << 16 | tx_difs; 2387156321Sdamien RAL_WRITE(sc, RT2560_CSR19, tmp); 2388156321Sdamien 2389178354Ssam DPRINTF(sc, "setting slottime to %uus\n", slottime); 2390156321Sdamien} 2391156321Sdamien 2392156321Sdamienstatic void 2393156321Sdamienrt2560_set_basicrates(struct rt2560_softc *sc) 2394156321Sdamien{ 2395178354Ssam struct ifnet *ifp = sc->sc_ifp; 2396178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2397156321Sdamien 2398156321Sdamien /* update basic rate set */ 2399156321Sdamien if (ic->ic_curmode == IEEE80211_MODE_11B) { 2400156321Sdamien /* 11b basic rates: 1, 2Mbps */ 2401156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x3); 2402156321Sdamien } else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) { 2403156321Sdamien /* 11a basic rates: 6, 12, 24Mbps */ 2404156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x150); 2405156321Sdamien } else { 2406156321Sdamien /* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */ 2407156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x15f); 2408156321Sdamien } 2409156321Sdamien} 2410156321Sdamien 2411156321Sdamienstatic void 2412156321Sdamienrt2560_update_led(struct rt2560_softc *sc, int led1, int led2) 2413156321Sdamien{ 2414156321Sdamien uint32_t tmp; 2415156321Sdamien 2416156321Sdamien /* set ON period to 70ms and OFF period to 30ms */ 2417156321Sdamien tmp = led1 << 16 | led2 << 17 | 70 << 8 | 30; 2418156321Sdamien RAL_WRITE(sc, RT2560_LEDCSR, tmp); 2419156321Sdamien} 2420156321Sdamien 2421156321Sdamienstatic void 2422170530Ssamrt2560_set_bssid(struct rt2560_softc *sc, const uint8_t *bssid) 2423156321Sdamien{ 2424156321Sdamien uint32_t tmp; 2425156321Sdamien 2426156321Sdamien tmp = bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24; 2427156321Sdamien RAL_WRITE(sc, RT2560_CSR5, tmp); 2428156321Sdamien 2429156321Sdamien tmp = bssid[4] | bssid[5] << 8; 2430156321Sdamien RAL_WRITE(sc, RT2560_CSR6, tmp); 2431156321Sdamien 2432178354Ssam DPRINTF(sc, "setting BSSID to %6D\n", bssid, ":"); 2433156321Sdamien} 2434156321Sdamien 2435156321Sdamienstatic void 2436156321Sdamienrt2560_set_macaddr(struct rt2560_softc *sc, uint8_t *addr) 2437156321Sdamien{ 2438156321Sdamien uint32_t tmp; 2439156321Sdamien 2440156321Sdamien tmp = addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24; 2441156321Sdamien RAL_WRITE(sc, RT2560_CSR3, tmp); 2442156321Sdamien 2443156321Sdamien tmp = addr[4] | addr[5] << 8; 2444156321Sdamien RAL_WRITE(sc, RT2560_CSR4, tmp); 2445156321Sdamien 2446178354Ssam DPRINTF(sc, "setting MAC address to %6D\n", addr, ":"); 2447156321Sdamien} 2448156321Sdamien 2449156321Sdamienstatic void 2450156321Sdamienrt2560_get_macaddr(struct rt2560_softc *sc, uint8_t *addr) 2451156321Sdamien{ 2452156321Sdamien uint32_t tmp; 2453156321Sdamien 2454156321Sdamien tmp = RAL_READ(sc, RT2560_CSR3); 2455156321Sdamien addr[0] = tmp & 0xff; 2456156321Sdamien addr[1] = (tmp >> 8) & 0xff; 2457156321Sdamien addr[2] = (tmp >> 16) & 0xff; 2458156321Sdamien addr[3] = (tmp >> 24); 2459156321Sdamien 2460156321Sdamien tmp = RAL_READ(sc, RT2560_CSR4); 2461156321Sdamien addr[4] = tmp & 0xff; 2462156321Sdamien addr[5] = (tmp >> 8) & 0xff; 2463156321Sdamien} 2464156321Sdamien 2465156321Sdamienstatic void 2466178354Ssamrt2560_update_promisc(struct ifnet *ifp) 2467156321Sdamien{ 2468178354Ssam struct rt2560_softc *sc = ifp->if_softc; 2469156321Sdamien uint32_t tmp; 2470156321Sdamien 2471156321Sdamien tmp = RAL_READ(sc, RT2560_RXCSR0); 2472156321Sdamien 2473156321Sdamien tmp &= ~RT2560_DROP_NOT_TO_ME; 2474156321Sdamien if (!(ifp->if_flags & IFF_PROMISC)) 2475156321Sdamien tmp |= RT2560_DROP_NOT_TO_ME; 2476156321Sdamien 2477156321Sdamien RAL_WRITE(sc, RT2560_RXCSR0, tmp); 2478156321Sdamien 2479178354Ssam DPRINTF(sc, "%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ? 2480178354Ssam "entering" : "leaving"); 2481156321Sdamien} 2482156321Sdamien 2483156321Sdamienstatic const char * 2484156321Sdamienrt2560_get_rf(int rev) 2485156321Sdamien{ 2486156321Sdamien switch (rev) { 2487156321Sdamien case RT2560_RF_2522: return "RT2522"; 2488156321Sdamien case RT2560_RF_2523: return "RT2523"; 2489156321Sdamien case RT2560_RF_2524: return "RT2524"; 2490156321Sdamien case RT2560_RF_2525: return "RT2525"; 2491156321Sdamien case RT2560_RF_2525E: return "RT2525e"; 2492156321Sdamien case RT2560_RF_2526: return "RT2526"; 2493156321Sdamien case RT2560_RF_5222: return "RT5222"; 2494156321Sdamien default: return "unknown"; 2495156321Sdamien } 2496156321Sdamien} 2497156321Sdamien 2498156321Sdamienstatic void 2499175938Ssephert2560_read_config(struct rt2560_softc *sc) 2500156321Sdamien{ 2501156321Sdamien uint16_t val; 2502156321Sdamien int i; 2503156321Sdamien 2504156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_CONFIG0); 2505156321Sdamien sc->rf_rev = (val >> 11) & 0x7; 2506156321Sdamien sc->hw_radio = (val >> 10) & 0x1; 2507156321Sdamien sc->led_mode = (val >> 6) & 0x7; 2508156321Sdamien sc->rx_ant = (val >> 4) & 0x3; 2509156321Sdamien sc->tx_ant = (val >> 2) & 0x3; 2510156321Sdamien sc->nb_ant = val & 0x3; 2511156321Sdamien 2512156321Sdamien /* read default values for BBP registers */ 2513156321Sdamien for (i = 0; i < 16; i++) { 2514156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_BBP_BASE + i); 2515175938Ssephe if (val == 0 || val == 0xffff) 2516175938Ssephe continue; 2517175938Ssephe 2518156321Sdamien sc->bbp_prom[i].reg = val >> 8; 2519156321Sdamien sc->bbp_prom[i].val = val & 0xff; 2520156321Sdamien } 2521156321Sdamien 2522156321Sdamien /* read Tx power for all b/g channels */ 2523156321Sdamien for (i = 0; i < 14 / 2; i++) { 2524156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_TXPOWER + i); 2525175938Ssephe sc->txpow[i * 2] = val & 0xff; 2526175938Ssephe sc->txpow[i * 2 + 1] = val >> 8; 2527156321Sdamien } 2528175938Ssephe for (i = 0; i < 14; ++i) { 2529175938Ssephe if (sc->txpow[i] > 31) 2530175938Ssephe sc->txpow[i] = 24; 2531175938Ssephe } 2532170530Ssam 2533170530Ssam val = rt2560_eeprom_read(sc, RT2560_EEPROM_CALIBRATE); 2534170530Ssam if ((val & 0xff) == 0xff) 2535170530Ssam sc->rssi_corr = RT2560_DEFAULT_RSSI_CORR; 2536170530Ssam else 2537170530Ssam sc->rssi_corr = val & 0xff; 2538178354Ssam DPRINTF(sc, "rssi correction %d, calibrate 0x%02x\n", 2539178354Ssam sc->rssi_corr, val); 2540156321Sdamien} 2541156321Sdamien 2542170530Ssam 2543170530Ssamstatic void 2544170530Ssamrt2560_scan_start(struct ieee80211com *ic) 2545170530Ssam{ 2546170530Ssam struct ifnet *ifp = ic->ic_ifp; 2547170530Ssam struct rt2560_softc *sc = ifp->if_softc; 2548170530Ssam 2549170530Ssam /* abort TSF synchronization */ 2550170530Ssam RAL_WRITE(sc, RT2560_CSR14, 0); 2551170530Ssam rt2560_set_bssid(sc, ifp->if_broadcastaddr); 2552170530Ssam} 2553170530Ssam 2554170530Ssamstatic void 2555170530Ssamrt2560_scan_end(struct ieee80211com *ic) 2556170530Ssam{ 2557170530Ssam struct ifnet *ifp = ic->ic_ifp; 2558170530Ssam struct rt2560_softc *sc = ifp->if_softc; 2559178354Ssam struct ieee80211vap *vap = ic->ic_scan->ss_vap; 2560170530Ssam 2561170530Ssam rt2560_enable_tsf_sync(sc); 2562170530Ssam /* XXX keep local copy */ 2563178354Ssam rt2560_set_bssid(sc, vap->iv_bss->ni_bssid); 2564170530Ssam} 2565170530Ssam 2566156321Sdamienstatic int 2567156321Sdamienrt2560_bbp_init(struct rt2560_softc *sc) 2568156321Sdamien{ 2569156321Sdamien#define N(a) (sizeof (a) / sizeof ((a)[0])) 2570156321Sdamien int i, ntries; 2571156321Sdamien 2572156321Sdamien /* wait for BBP to be ready */ 2573156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2574156321Sdamien if (rt2560_bbp_read(sc, RT2560_BBP_VERSION) != 0) 2575156321Sdamien break; 2576156321Sdamien DELAY(1); 2577156321Sdamien } 2578156321Sdamien if (ntries == 100) { 2579156321Sdamien device_printf(sc->sc_dev, "timeout waiting for BBP\n"); 2580156321Sdamien return EIO; 2581156321Sdamien } 2582156321Sdamien 2583156321Sdamien /* initialize BBP registers to default values */ 2584156321Sdamien for (i = 0; i < N(rt2560_def_bbp); i++) { 2585156321Sdamien rt2560_bbp_write(sc, rt2560_def_bbp[i].reg, 2586156321Sdamien rt2560_def_bbp[i].val); 2587156321Sdamien } 2588175938Ssephe 2589156321Sdamien /* initialize BBP registers to values stored in EEPROM */ 2590156321Sdamien for (i = 0; i < 16; i++) { 2591175938Ssephe if (sc->bbp_prom[i].reg == 0 && sc->bbp_prom[i].val == 0) 2592175938Ssephe break; 2593156321Sdamien rt2560_bbp_write(sc, sc->bbp_prom[i].reg, sc->bbp_prom[i].val); 2594156321Sdamien } 2595175938Ssephe rt2560_bbp_write(sc, 17, 0x48); /* XXX restore bbp17 */ 2596156321Sdamien 2597156321Sdamien return 0; 2598156321Sdamien#undef N 2599156321Sdamien} 2600156321Sdamien 2601156321Sdamienstatic void 2602156321Sdamienrt2560_set_txantenna(struct rt2560_softc *sc, int antenna) 2603156321Sdamien{ 2604156321Sdamien uint32_t tmp; 2605156321Sdamien uint8_t tx; 2606156321Sdamien 2607156321Sdamien tx = rt2560_bbp_read(sc, RT2560_BBP_TX) & ~RT2560_BBP_ANTMASK; 2608156321Sdamien if (antenna == 1) 2609156321Sdamien tx |= RT2560_BBP_ANTA; 2610156321Sdamien else if (antenna == 2) 2611156321Sdamien tx |= RT2560_BBP_ANTB; 2612156321Sdamien else 2613156321Sdamien tx |= RT2560_BBP_DIVERSITY; 2614156321Sdamien 2615156321Sdamien /* need to force I/Q flip for RF 2525e, 2526 and 5222 */ 2616156321Sdamien if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526 || 2617156321Sdamien sc->rf_rev == RT2560_RF_5222) 2618156321Sdamien tx |= RT2560_BBP_FLIPIQ; 2619156321Sdamien 2620156321Sdamien rt2560_bbp_write(sc, RT2560_BBP_TX, tx); 2621156321Sdamien 2622156321Sdamien /* update values for CCK and OFDM in BBPCSR1 */ 2623156321Sdamien tmp = RAL_READ(sc, RT2560_BBPCSR1) & ~0x00070007; 2624156321Sdamien tmp |= (tx & 0x7) << 16 | (tx & 0x7); 2625156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR1, tmp); 2626156321Sdamien} 2627156321Sdamien 2628156321Sdamienstatic void 2629156321Sdamienrt2560_set_rxantenna(struct rt2560_softc *sc, int antenna) 2630156321Sdamien{ 2631156321Sdamien uint8_t rx; 2632156321Sdamien 2633156321Sdamien rx = rt2560_bbp_read(sc, RT2560_BBP_RX) & ~RT2560_BBP_ANTMASK; 2634156321Sdamien if (antenna == 1) 2635156321Sdamien rx |= RT2560_BBP_ANTA; 2636156321Sdamien else if (antenna == 2) 2637156321Sdamien rx |= RT2560_BBP_ANTB; 2638156321Sdamien else 2639156321Sdamien rx |= RT2560_BBP_DIVERSITY; 2640156321Sdamien 2641156321Sdamien /* need to force no I/Q flip for RF 2525e and 2526 */ 2642156321Sdamien if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526) 2643156321Sdamien rx &= ~RT2560_BBP_FLIPIQ; 2644156321Sdamien 2645156321Sdamien rt2560_bbp_write(sc, RT2560_BBP_RX, rx); 2646156321Sdamien} 2647156321Sdamien 2648156321Sdamienstatic void 2649178354Ssamrt2560_init_locked(struct rt2560_softc *sc) 2650156321Sdamien{ 2651156321Sdamien#define N(a) (sizeof (a) / sizeof ((a)[0])) 2652178354Ssam struct ifnet *ifp = sc->sc_ifp; 2653178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2654156321Sdamien uint32_t tmp; 2655156321Sdamien int i; 2656156321Sdamien 2657178354Ssam RAL_LOCK_ASSERT(sc); 2658156975Sdamien 2659178354Ssam rt2560_stop_locked(sc); 2660170530Ssam 2661156321Sdamien /* setup tx rings */ 2662156321Sdamien tmp = RT2560_PRIO_RING_COUNT << 24 | 2663156321Sdamien RT2560_ATIM_RING_COUNT << 16 | 2664156321Sdamien RT2560_TX_RING_COUNT << 8 | 2665156321Sdamien RT2560_TX_DESC_SIZE; 2666156321Sdamien 2667156321Sdamien /* rings must be initialized in this exact order */ 2668156321Sdamien RAL_WRITE(sc, RT2560_TXCSR2, tmp); 2669156321Sdamien RAL_WRITE(sc, RT2560_TXCSR3, sc->txq.physaddr); 2670156321Sdamien RAL_WRITE(sc, RT2560_TXCSR5, sc->prioq.physaddr); 2671156321Sdamien RAL_WRITE(sc, RT2560_TXCSR4, sc->atimq.physaddr); 2672156321Sdamien RAL_WRITE(sc, RT2560_TXCSR6, sc->bcnq.physaddr); 2673156321Sdamien 2674156321Sdamien /* setup rx ring */ 2675156321Sdamien tmp = RT2560_RX_RING_COUNT << 8 | RT2560_RX_DESC_SIZE; 2676156321Sdamien 2677156321Sdamien RAL_WRITE(sc, RT2560_RXCSR1, tmp); 2678156321Sdamien RAL_WRITE(sc, RT2560_RXCSR2, sc->rxq.physaddr); 2679156321Sdamien 2680156321Sdamien /* initialize MAC registers to default values */ 2681156321Sdamien for (i = 0; i < N(rt2560_def_mac); i++) 2682156321Sdamien RAL_WRITE(sc, rt2560_def_mac[i].reg, rt2560_def_mac[i].val); 2683156321Sdamien 2684190526Ssam rt2560_set_macaddr(sc, IF_LLADDR(ifp)); 2685156321Sdamien 2686156321Sdamien /* set basic rate set (will be updated later) */ 2687156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x153); 2688156321Sdamien 2689156321Sdamien rt2560_update_slot(ifp); 2690156321Sdamien rt2560_update_plcp(sc); 2691156321Sdamien rt2560_update_led(sc, 0, 0); 2692156321Sdamien 2693156321Sdamien RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 2694156321Sdamien RAL_WRITE(sc, RT2560_CSR1, RT2560_HOST_READY); 2695156321Sdamien 2696156321Sdamien if (rt2560_bbp_init(sc) != 0) { 2697156321Sdamien rt2560_stop(sc); 2698156975Sdamien RAL_UNLOCK(sc); 2699156321Sdamien return; 2700156321Sdamien } 2701156321Sdamien 2702175938Ssephe rt2560_set_txantenna(sc, sc->tx_ant); 2703175938Ssephe rt2560_set_rxantenna(sc, sc->rx_ant); 2704175938Ssephe 2705156321Sdamien /* set default BSS channel */ 2706156321Sdamien rt2560_set_chan(sc, ic->ic_curchan); 2707156321Sdamien 2708156321Sdamien /* kick Rx */ 2709156321Sdamien tmp = RT2560_DROP_PHY_ERROR | RT2560_DROP_CRC_ERROR; 2710156321Sdamien if (ic->ic_opmode != IEEE80211_M_MONITOR) { 2711156321Sdamien tmp |= RT2560_DROP_CTL | RT2560_DROP_VERSION_ERROR; 2712156321Sdamien if (ic->ic_opmode != IEEE80211_M_HOSTAP) 2713156321Sdamien tmp |= RT2560_DROP_TODS; 2714156321Sdamien if (!(ifp->if_flags & IFF_PROMISC)) 2715156321Sdamien tmp |= RT2560_DROP_NOT_TO_ME; 2716156321Sdamien } 2717156321Sdamien RAL_WRITE(sc, RT2560_RXCSR0, tmp); 2718156321Sdamien 2719156321Sdamien /* clear old FCS and Rx FIFO errors */ 2720156321Sdamien RAL_READ(sc, RT2560_CNT0); 2721156321Sdamien RAL_READ(sc, RT2560_CNT4); 2722156321Sdamien 2723156321Sdamien /* clear any pending interrupts */ 2724156321Sdamien RAL_WRITE(sc, RT2560_CSR7, 0xffffffff); 2725156321Sdamien 2726156321Sdamien /* enable interrupts */ 2727156321Sdamien RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); 2728156321Sdamien 2729156321Sdamien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2730156321Sdamien ifp->if_drv_flags |= IFF_DRV_RUNNING; 2731156321Sdamien 2732175938Ssephe callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); 2733178354Ssam#undef N 2734178354Ssam} 2735175938Ssephe 2736178354Ssamstatic void 2737178354Ssamrt2560_init(void *priv) 2738178354Ssam{ 2739178354Ssam struct rt2560_softc *sc = priv; 2740178354Ssam struct ifnet *ifp = sc->sc_ifp; 2741178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2742156975Sdamien 2743178354Ssam RAL_LOCK(sc); 2744178354Ssam rt2560_init_locked(sc); 2745156975Sdamien RAL_UNLOCK(sc); 2746178354Ssam 2747178931Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2748178931Sthompsa ieee80211_start_all(ic); /* start all vap's */ 2749156321Sdamien} 2750156321Sdamien 2751178354Ssamstatic void 2752178354Ssamrt2560_stop_locked(struct rt2560_softc *sc) 2753156321Sdamien{ 2754178354Ssam struct ifnet *ifp = sc->sc_ifp; 2755170530Ssam volatile int *flags = &sc->sc_flags; 2756156321Sdamien 2757178354Ssam RAL_LOCK_ASSERT(sc); 2758156321Sdamien 2759178354Ssam while (*flags & RT2560_F_INPUT_RUNNING) 2760178354Ssam msleep(sc, &sc->sc_mtx, 0, "ralrunning", hz/10); 2761175938Ssephe 2762175938Ssephe callout_stop(&sc->watchdog_ch); 2763178354Ssam sc->sc_tx_timer = 0; 2764175938Ssephe 2765170530Ssam if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 2766170530Ssam ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2767156975Sdamien 2768170530Ssam /* abort Tx */ 2769170530Ssam RAL_WRITE(sc, RT2560_TXCSR0, RT2560_ABORT_TX); 2770170530Ssam 2771170530Ssam /* disable Rx */ 2772170530Ssam RAL_WRITE(sc, RT2560_RXCSR0, RT2560_DISABLE_RX); 2773156321Sdamien 2774170530Ssam /* reset ASIC (imply reset BBP) */ 2775170530Ssam RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 2776170530Ssam RAL_WRITE(sc, RT2560_CSR1, 0); 2777156321Sdamien 2778170530Ssam /* disable interrupts */ 2779170530Ssam RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 2780170530Ssam 2781170530Ssam /* reset Tx and Rx rings */ 2782170530Ssam rt2560_reset_tx_ring(sc, &sc->txq); 2783170530Ssam rt2560_reset_tx_ring(sc, &sc->atimq); 2784170530Ssam rt2560_reset_tx_ring(sc, &sc->prioq); 2785170530Ssam rt2560_reset_tx_ring(sc, &sc->bcnq); 2786170530Ssam rt2560_reset_rx_ring(sc, &sc->rxq); 2787170530Ssam } 2788175938Ssephe sc->sc_flags &= ~(RT2560_F_PRIO_OACTIVE | RT2560_F_DATA_OACTIVE); 2789178354Ssam} 2790175938Ssephe 2791178354Ssamvoid 2792178354Ssamrt2560_stop(void *arg) 2793178354Ssam{ 2794178354Ssam struct rt2560_softc *sc = arg; 2795178354Ssam 2796178354Ssam RAL_LOCK(sc); 2797178354Ssam rt2560_stop_locked(sc); 2798170530Ssam RAL_UNLOCK(sc); 2799156321Sdamien} 2800160691Ssam 2801160691Ssamstatic int 2802160691Ssamrt2560_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 2803160691Ssam const struct ieee80211_bpf_params *params) 2804160691Ssam{ 2805160691Ssam struct ieee80211com *ic = ni->ni_ic; 2806160691Ssam struct ifnet *ifp = ic->ic_ifp; 2807160691Ssam struct rt2560_softc *sc = ifp->if_softc; 2808160691Ssam 2809160691Ssam RAL_LOCK(sc); 2810160691Ssam 2811160691Ssam /* prevent management frames from being sent if we're not ready */ 2812160691Ssam if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2813160691Ssam RAL_UNLOCK(sc); 2814168860Ssephe m_freem(m); 2815168860Ssephe ieee80211_free_node(ni); 2816160691Ssam return ENETDOWN; 2817160691Ssam } 2818160691Ssam if (sc->prioq.queued >= RT2560_PRIO_RING_COUNT) { 2819160691Ssam ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2820178354Ssam sc->sc_flags |= RT2560_F_PRIO_OACTIVE; 2821160691Ssam RAL_UNLOCK(sc); 2822168860Ssephe m_freem(m); 2823168860Ssephe ieee80211_free_node(ni); 2824160691Ssam return ENOBUFS; /* XXX */ 2825160691Ssam } 2826160691Ssam 2827160691Ssam ifp->if_opackets++; 2828160691Ssam 2829160691Ssam if (params == NULL) { 2830160691Ssam /* 2831160691Ssam * Legacy path; interpret frame contents to decide 2832160691Ssam * precisely how to send the frame. 2833160691Ssam */ 2834160691Ssam if (rt2560_tx_mgt(sc, m, ni) != 0) 2835160691Ssam goto bad; 2836160691Ssam } else { 2837160691Ssam /* 2838160691Ssam * Caller supplied explicit parameters to use in 2839160691Ssam * sending the frame. 2840160691Ssam */ 2841160691Ssam if (rt2560_tx_raw(sc, m, ni, params)) 2842160691Ssam goto bad; 2843160691Ssam } 2844160691Ssam sc->sc_tx_timer = 5; 2845160691Ssam 2846160691Ssam RAL_UNLOCK(sc); 2847160691Ssam 2848160691Ssam return 0; 2849160691Ssambad: 2850160691Ssam ifp->if_oerrors++; 2851160905Ssam ieee80211_free_node(ni); 2852160691Ssam RAL_UNLOCK(sc); 2853160691Ssam return EIO; /* XXX */ 2854160691Ssam} 2855