1156321Sdamien/* $FreeBSD$ */ 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$"); 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> 57206358Srpaulo#include <net80211/ieee80211_ratectl.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 *, 88234753Sdim const char [IFNAMSIZ], int, enum ieee80211_opmode, 89234753Sdim int, const uint8_t [IEEE80211_ADDR_LEN], 90234753Sdim const uint8_t [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 *); 106178354Ssamstatic int rt2560_newstate(struct ieee80211vap *, 107156321Sdamien enum ieee80211_state, int); 108156321Sdamienstatic uint16_t rt2560_eeprom_read(struct rt2560_softc *, uint8_t); 109156321Sdamienstatic void rt2560_encryption_intr(struct rt2560_softc *); 110156321Sdamienstatic void rt2560_tx_intr(struct rt2560_softc *); 111156321Sdamienstatic void rt2560_prio_intr(struct rt2560_softc *); 112156321Sdamienstatic void rt2560_decryption_intr(struct rt2560_softc *); 113156321Sdamienstatic void rt2560_rx_intr(struct rt2560_softc *); 114178354Ssamstatic void rt2560_beacon_update(struct ieee80211vap *, int item); 115156321Sdamienstatic void rt2560_beacon_expire(struct rt2560_softc *); 116156321Sdamienstatic void rt2560_wakeup_expire(struct rt2560_softc *); 117170530Ssamstatic void rt2560_scan_start(struct ieee80211com *); 118170530Ssamstatic void rt2560_scan_end(struct ieee80211com *); 119170530Ssamstatic void rt2560_set_channel(struct ieee80211com *); 120156321Sdamienstatic void rt2560_setup_tx_desc(struct rt2560_softc *, 121156321Sdamien struct rt2560_tx_desc *, uint32_t, int, int, int, 122156321Sdamien bus_addr_t); 123156321Sdamienstatic int rt2560_tx_bcn(struct rt2560_softc *, struct mbuf *, 124156321Sdamien struct ieee80211_node *); 125156321Sdamienstatic int rt2560_tx_mgt(struct rt2560_softc *, struct mbuf *, 126156321Sdamien struct ieee80211_node *); 127156321Sdamienstatic int rt2560_tx_data(struct rt2560_softc *, struct mbuf *, 128156321Sdamien struct ieee80211_node *); 129178354Ssamstatic void rt2560_start_locked(struct ifnet *); 130156321Sdamienstatic void rt2560_start(struct ifnet *); 131165352Sbmsstatic void rt2560_watchdog(void *); 132156321Sdamienstatic int rt2560_ioctl(struct ifnet *, u_long, caddr_t); 133156321Sdamienstatic void rt2560_bbp_write(struct rt2560_softc *, uint8_t, 134156321Sdamien uint8_t); 135156321Sdamienstatic uint8_t rt2560_bbp_read(struct rt2560_softc *, uint8_t); 136156321Sdamienstatic void rt2560_rf_write(struct rt2560_softc *, uint8_t, 137156321Sdamien uint32_t); 138156321Sdamienstatic void rt2560_set_chan(struct rt2560_softc *, 139156321Sdamien struct ieee80211_channel *); 140156321Sdamien#if 0 141156321Sdamienstatic void rt2560_disable_rf_tune(struct rt2560_softc *); 142156321Sdamien#endif 143156321Sdamienstatic void rt2560_enable_tsf_sync(struct rt2560_softc *); 144192468Ssamstatic void rt2560_enable_tsf(struct rt2560_softc *); 145156321Sdamienstatic void rt2560_update_plcp(struct rt2560_softc *); 146156321Sdamienstatic void rt2560_update_slot(struct ifnet *); 147220502Sbschmidtstatic void rt2560_set_basicrates(struct rt2560_softc *, 148220502Sbschmidt const struct ieee80211_rateset *); 149156321Sdamienstatic void rt2560_update_led(struct rt2560_softc *, int, int); 150170530Ssamstatic void rt2560_set_bssid(struct rt2560_softc *, const uint8_t *); 151156321Sdamienstatic void rt2560_set_macaddr(struct rt2560_softc *, uint8_t *); 152156321Sdamienstatic void rt2560_get_macaddr(struct rt2560_softc *, uint8_t *); 153178354Ssamstatic void rt2560_update_promisc(struct ifnet *); 154156321Sdamienstatic const char *rt2560_get_rf(int); 155175938Ssephestatic void rt2560_read_config(struct rt2560_softc *); 156156321Sdamienstatic int rt2560_bbp_init(struct rt2560_softc *); 157156321Sdamienstatic void rt2560_set_txantenna(struct rt2560_softc *, int); 158156321Sdamienstatic void rt2560_set_rxantenna(struct rt2560_softc *, int); 159178354Ssamstatic void rt2560_init_locked(struct rt2560_softc *); 160156321Sdamienstatic void rt2560_init(void *); 161178354Ssamstatic void rt2560_stop_locked(struct rt2560_softc *); 162160691Ssamstatic int rt2560_raw_xmit(struct ieee80211_node *, struct mbuf *, 163160691Ssam const struct ieee80211_bpf_params *); 164156321Sdamien 165156321Sdamienstatic const struct { 166156321Sdamien uint32_t reg; 167156321Sdamien uint32_t val; 168156321Sdamien} rt2560_def_mac[] = { 169156321Sdamien RT2560_DEF_MAC 170156321Sdamien}; 171156321Sdamien 172156321Sdamienstatic const struct { 173156321Sdamien uint8_t reg; 174156321Sdamien uint8_t val; 175156321Sdamien} rt2560_def_bbp[] = { 176156321Sdamien RT2560_DEF_BBP 177156321Sdamien}; 178156321Sdamien 179156321Sdamienstatic const uint32_t rt2560_rf2522_r2[] = RT2560_RF2522_R2; 180156321Sdamienstatic const uint32_t rt2560_rf2523_r2[] = RT2560_RF2523_R2; 181156321Sdamienstatic const uint32_t rt2560_rf2524_r2[] = RT2560_RF2524_R2; 182156321Sdamienstatic const uint32_t rt2560_rf2525_r2[] = RT2560_RF2525_R2; 183156321Sdamienstatic const uint32_t rt2560_rf2525_hi_r2[] = RT2560_RF2525_HI_R2; 184156321Sdamienstatic const uint32_t rt2560_rf2525e_r2[] = RT2560_RF2525E_R2; 185156321Sdamienstatic const uint32_t rt2560_rf2526_r2[] = RT2560_RF2526_R2; 186156321Sdamienstatic const uint32_t rt2560_rf2526_hi_r2[] = RT2560_RF2526_HI_R2; 187156321Sdamien 188156321Sdamienstatic const struct { 189156321Sdamien uint8_t chan; 190156321Sdamien uint32_t r1, r2, r4; 191156321Sdamien} rt2560_rf5222[] = { 192156321Sdamien RT2560_RF5222 193156321Sdamien}; 194156321Sdamien 195156321Sdamienint 196156321Sdamienrt2560_attach(device_t dev, int id) 197156321Sdamien{ 198156321Sdamien struct rt2560_softc *sc = device_get_softc(dev); 199178354Ssam struct ieee80211com *ic; 200156321Sdamien struct ifnet *ifp; 201178354Ssam int error; 202178354Ssam uint8_t bands; 203190526Ssam uint8_t macaddr[IEEE80211_ADDR_LEN]; 204156321Sdamien 205156321Sdamien sc->sc_dev = dev; 206156321Sdamien 207156321Sdamien mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 208156321Sdamien MTX_DEF | MTX_RECURSE); 209156321Sdamien 210165352Sbms callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0); 211156321Sdamien 212156321Sdamien /* retrieve RT2560 rev. no */ 213156321Sdamien sc->asic_rev = RAL_READ(sc, RT2560_CSR0); 214156321Sdamien 215156321Sdamien /* retrieve RF rev. no and various other things from EEPROM */ 216175938Ssephe rt2560_read_config(sc); 217156321Sdamien 218156321Sdamien device_printf(dev, "MAC/BBP RT2560 (rev 0x%02x), RF %s\n", 219156321Sdamien sc->asic_rev, rt2560_get_rf(sc->rf_rev)); 220156321Sdamien 221156321Sdamien /* 222156321Sdamien * Allocate Tx and Rx rings. 223156321Sdamien */ 224156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->txq, RT2560_TX_RING_COUNT); 225156321Sdamien if (error != 0) { 226156321Sdamien device_printf(sc->sc_dev, "could not allocate Tx ring\n"); 227156321Sdamien goto fail1; 228156321Sdamien } 229156321Sdamien 230156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->atimq, RT2560_ATIM_RING_COUNT); 231156321Sdamien if (error != 0) { 232156321Sdamien device_printf(sc->sc_dev, "could not allocate ATIM ring\n"); 233156321Sdamien goto fail2; 234156321Sdamien } 235156321Sdamien 236156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->prioq, RT2560_PRIO_RING_COUNT); 237156321Sdamien if (error != 0) { 238156321Sdamien device_printf(sc->sc_dev, "could not allocate Prio ring\n"); 239156321Sdamien goto fail3; 240156321Sdamien } 241156321Sdamien 242156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->bcnq, RT2560_BEACON_RING_COUNT); 243156321Sdamien if (error != 0) { 244156321Sdamien device_printf(sc->sc_dev, "could not allocate Beacon ring\n"); 245156321Sdamien goto fail4; 246156321Sdamien } 247156321Sdamien 248156321Sdamien error = rt2560_alloc_rx_ring(sc, &sc->rxq, RT2560_RX_RING_COUNT); 249156321Sdamien if (error != 0) { 250156321Sdamien device_printf(sc->sc_dev, "could not allocate Rx ring\n"); 251156321Sdamien goto fail5; 252156321Sdamien } 253156321Sdamien 254178354Ssam ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); 255156321Sdamien if (ifp == NULL) { 256156321Sdamien device_printf(sc->sc_dev, "can not if_alloc()\n"); 257156321Sdamien goto fail6; 258156321Sdamien } 259178354Ssam ic = ifp->if_l2com; 260156321Sdamien 261178354Ssam /* retrieve MAC address */ 262190526Ssam rt2560_get_macaddr(sc, macaddr); 263178354Ssam 264156321Sdamien ifp->if_softc = sc; 265156321Sdamien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 266156321Sdamien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 267156321Sdamien ifp->if_init = rt2560_init; 268156321Sdamien ifp->if_ioctl = rt2560_ioctl; 269156321Sdamien ifp->if_start = rt2560_start; 270207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 271207554Ssobomax ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 272156321Sdamien IFQ_SET_READY(&ifp->if_snd); 273156321Sdamien 274156321Sdamien ic->ic_ifp = ifp; 275178354Ssam ic->ic_opmode = IEEE80211_M_STA; 276156321Sdamien ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 277156321Sdamien 278156321Sdamien /* set device capabilities */ 279156321Sdamien ic->ic_caps = 280178957Ssam IEEE80211_C_STA /* station mode */ 281178957Ssam | IEEE80211_C_IBSS /* ibss, nee adhoc, mode */ 282178354Ssam | IEEE80211_C_HOSTAP /* hostap mode */ 283178354Ssam | IEEE80211_C_MONITOR /* monitor mode */ 284178354Ssam | IEEE80211_C_AHDEMO /* adhoc demo mode */ 285178354Ssam | IEEE80211_C_WDS /* 4-address traffic works */ 286195618Srpaulo | IEEE80211_C_MBSS /* mesh point link mode */ 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_raw_xmit = rt2560_raw_xmit; 305178354Ssam ic->ic_updateslot = rt2560_update_slot; 306178354Ssam ic->ic_update_promisc = rt2560_update_promisc; 307170530Ssam ic->ic_scan_start = rt2560_scan_start; 308170530Ssam ic->ic_scan_end = rt2560_scan_end; 309170530Ssam ic->ic_set_channel = rt2560_set_channel; 310156321Sdamien 311178354Ssam ic->ic_vap_create = rt2560_vap_create; 312178354Ssam ic->ic_vap_delete = rt2560_vap_delete; 313156321Sdamien 314192468Ssam ieee80211_radiotap_attach(ic, 315192468Ssam &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), 316192468Ssam RT2560_TX_RADIOTAP_PRESENT, 317192468Ssam &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 318192468Ssam RT2560_RX_RADIOTAP_PRESENT); 319156321Sdamien 320156321Sdamien /* 321156321Sdamien * Add a few sysctl knobs. 322156321Sdamien */ 323178354Ssam#ifdef RAL_DEBUG 324156321Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 325156321Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 326178354Ssam "debug", CTLFLAG_RW, &sc->sc_debug, 0, "debug msgs"); 327178354Ssam#endif 328178354Ssam SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 329178354Ssam SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 330156321Sdamien "txantenna", CTLFLAG_RW, &sc->tx_ant, 0, "tx antenna (0=auto)"); 331156321Sdamien 332156321Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 333156321Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 334156321Sdamien "rxantenna", CTLFLAG_RW, &sc->rx_ant, 0, "rx antenna (0=auto)"); 335156321Sdamien 336156321Sdamien if (bootverbose) 337156321Sdamien ieee80211_announce(ic); 338156321Sdamien 339156321Sdamien return 0; 340156321Sdamien 341156321Sdamienfail6: rt2560_free_rx_ring(sc, &sc->rxq); 342156321Sdamienfail5: rt2560_free_tx_ring(sc, &sc->bcnq); 343156321Sdamienfail4: rt2560_free_tx_ring(sc, &sc->prioq); 344156321Sdamienfail3: rt2560_free_tx_ring(sc, &sc->atimq); 345156321Sdamienfail2: rt2560_free_tx_ring(sc, &sc->txq); 346156321Sdamienfail1: mtx_destroy(&sc->sc_mtx); 347156321Sdamien 348156321Sdamien return ENXIO; 349156321Sdamien} 350156321Sdamien 351156321Sdamienint 352156321Sdamienrt2560_detach(void *xsc) 353156321Sdamien{ 354156321Sdamien struct rt2560_softc *sc = xsc; 355178354Ssam struct ifnet *ifp = sc->sc_ifp; 356178354Ssam struct ieee80211com *ic = ifp->if_l2com; 357170530Ssam 358156321Sdamien rt2560_stop(sc); 359156321Sdamien 360156321Sdamien ieee80211_ifdetach(ic); 361156321Sdamien 362156321Sdamien rt2560_free_tx_ring(sc, &sc->txq); 363156321Sdamien rt2560_free_tx_ring(sc, &sc->atimq); 364156321Sdamien rt2560_free_tx_ring(sc, &sc->prioq); 365156321Sdamien rt2560_free_tx_ring(sc, &sc->bcnq); 366156321Sdamien rt2560_free_rx_ring(sc, &sc->rxq); 367156321Sdamien 368156321Sdamien if_free(ifp); 369156321Sdamien 370156321Sdamien mtx_destroy(&sc->sc_mtx); 371156321Sdamien 372156321Sdamien return 0; 373156321Sdamien} 374156321Sdamien 375178354Ssamstatic struct ieee80211vap * 376234753Sdimrt2560_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, 377234753Sdim enum ieee80211_opmode opmode, int flags, 378234753Sdim const uint8_t bssid[IEEE80211_ADDR_LEN], 379234753Sdim const uint8_t mac[IEEE80211_ADDR_LEN]) 380178354Ssam{ 381178354Ssam struct ifnet *ifp = ic->ic_ifp; 382178354Ssam struct rt2560_vap *rvp; 383178354Ssam struct ieee80211vap *vap; 384178354Ssam 385178354Ssam switch (opmode) { 386178354Ssam case IEEE80211_M_STA: 387178354Ssam case IEEE80211_M_IBSS: 388178354Ssam case IEEE80211_M_AHDEMO: 389178354Ssam case IEEE80211_M_MONITOR: 390178354Ssam case IEEE80211_M_HOSTAP: 391195618Srpaulo case IEEE80211_M_MBSS: 392195618Srpaulo /* XXXRP: TBD */ 393178354Ssam if (!TAILQ_EMPTY(&ic->ic_vaps)) { 394178354Ssam if_printf(ifp, "only 1 vap supported\n"); 395178354Ssam return NULL; 396178354Ssam } 397178354Ssam if (opmode == IEEE80211_M_STA) 398178354Ssam flags |= IEEE80211_CLONE_NOBEACONS; 399178354Ssam break; 400178354Ssam case IEEE80211_M_WDS: 401178354Ssam if (TAILQ_EMPTY(&ic->ic_vaps) || 402178354Ssam ic->ic_opmode != IEEE80211_M_HOSTAP) { 403178354Ssam if_printf(ifp, "wds only supported in ap mode\n"); 404178354Ssam return NULL; 405178354Ssam } 406178354Ssam /* 407178354Ssam * Silently remove any request for a unique 408178354Ssam * bssid; WDS vap's always share the local 409178354Ssam * mac address. 410178354Ssam */ 411178354Ssam flags &= ~IEEE80211_CLONE_BSSID; 412178354Ssam break; 413178354Ssam default: 414178354Ssam if_printf(ifp, "unknown opmode %d\n", opmode); 415178354Ssam return NULL; 416178354Ssam } 417178354Ssam rvp = (struct rt2560_vap *) malloc(sizeof(struct rt2560_vap), 418178354Ssam M_80211_VAP, M_NOWAIT | M_ZERO); 419178354Ssam if (rvp == NULL) 420178354Ssam return NULL; 421178354Ssam vap = &rvp->ral_vap; 422178354Ssam ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); 423178354Ssam 424178354Ssam /* override state transition machine */ 425178354Ssam rvp->ral_newstate = vap->iv_newstate; 426178354Ssam vap->iv_newstate = rt2560_newstate; 427178354Ssam vap->iv_update_beacon = rt2560_beacon_update; 428178354Ssam 429206358Srpaulo ieee80211_ratectl_init(vap); 430178354Ssam /* complete setup */ 431178354Ssam ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); 432178354Ssam if (TAILQ_FIRST(&ic->ic_vaps) == vap) 433178354Ssam ic->ic_opmode = opmode; 434178354Ssam return vap; 435178354Ssam} 436178354Ssam 437178354Ssamstatic void 438178354Ssamrt2560_vap_delete(struct ieee80211vap *vap) 439178354Ssam{ 440178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 441178354Ssam 442206358Srpaulo ieee80211_ratectl_deinit(vap); 443178354Ssam ieee80211_vap_detach(vap); 444178354Ssam free(rvp, M_80211_VAP); 445178354Ssam} 446178354Ssam 447156321Sdamienvoid 448156321Sdamienrt2560_resume(void *xsc) 449156321Sdamien{ 450156321Sdamien struct rt2560_softc *sc = xsc; 451178354Ssam struct ifnet *ifp = sc->sc_ifp; 452156321Sdamien 453178354Ssam if (ifp->if_flags & IFF_UP) 454178354Ssam rt2560_init(sc); 455156321Sdamien} 456156321Sdamien 457156321Sdamienstatic void 458156321Sdamienrt2560_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 459156321Sdamien{ 460156321Sdamien if (error != 0) 461156321Sdamien return; 462156321Sdamien 463156321Sdamien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 464156321Sdamien 465156321Sdamien *(bus_addr_t *)arg = segs[0].ds_addr; 466156321Sdamien} 467156321Sdamien 468156321Sdamienstatic int 469156321Sdamienrt2560_alloc_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring, 470156321Sdamien int count) 471156321Sdamien{ 472156321Sdamien int i, error; 473156321Sdamien 474156321Sdamien ring->count = count; 475156321Sdamien ring->queued = 0; 476156321Sdamien ring->cur = ring->next = 0; 477156321Sdamien ring->cur_encrypt = ring->next_encrypt = 0; 478156321Sdamien 479171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 4, 0, 480171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 481171535Skevlo count * RT2560_TX_DESC_SIZE, 1, count * RT2560_TX_DESC_SIZE, 482171535Skevlo 0, NULL, NULL, &ring->desc_dmat); 483156321Sdamien if (error != 0) { 484156321Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 485156321Sdamien goto fail; 486156321Sdamien } 487156321Sdamien 488156321Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 489156321Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 490156321Sdamien if (error != 0) { 491156321Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 492156321Sdamien goto fail; 493156321Sdamien } 494156321Sdamien 495156321Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 496156321Sdamien count * RT2560_TX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr, 497156321Sdamien 0); 498156321Sdamien if (error != 0) { 499156321Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 500156321Sdamien goto fail; 501156321Sdamien } 502156321Sdamien 503156321Sdamien ring->data = malloc(count * sizeof (struct rt2560_tx_data), M_DEVBUF, 504156321Sdamien M_NOWAIT | M_ZERO); 505156321Sdamien if (ring->data == NULL) { 506156321Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 507156321Sdamien error = ENOMEM; 508156321Sdamien goto fail; 509156321Sdamien } 510156321Sdamien 511171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 512171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 513171535Skevlo MCLBYTES, RT2560_MAX_SCATTER, MCLBYTES, 0, NULL, NULL, 514171535Skevlo &ring->data_dmat); 515156321Sdamien if (error != 0) { 516156321Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 517156321Sdamien goto fail; 518156321Sdamien } 519156321Sdamien 520156321Sdamien for (i = 0; i < count; i++) { 521156321Sdamien error = bus_dmamap_create(ring->data_dmat, 0, 522156321Sdamien &ring->data[i].map); 523156321Sdamien if (error != 0) { 524156321Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 525156321Sdamien goto fail; 526156321Sdamien } 527156321Sdamien } 528156321Sdamien 529156321Sdamien return 0; 530156321Sdamien 531156321Sdamienfail: rt2560_free_tx_ring(sc, ring); 532156321Sdamien return error; 533156321Sdamien} 534156321Sdamien 535156321Sdamienstatic void 536156321Sdamienrt2560_reset_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) 537156321Sdamien{ 538156321Sdamien struct rt2560_tx_desc *desc; 539156321Sdamien struct rt2560_tx_data *data; 540156321Sdamien int i; 541156321Sdamien 542156321Sdamien for (i = 0; i < ring->count; i++) { 543156321Sdamien desc = &ring->desc[i]; 544156321Sdamien data = &ring->data[i]; 545156321Sdamien 546156321Sdamien if (data->m != NULL) { 547156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 548156321Sdamien BUS_DMASYNC_POSTWRITE); 549156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 550156321Sdamien m_freem(data->m); 551156321Sdamien data->m = NULL; 552156321Sdamien } 553156321Sdamien 554156321Sdamien if (data->ni != NULL) { 555156321Sdamien ieee80211_free_node(data->ni); 556156321Sdamien data->ni = NULL; 557156321Sdamien } 558156321Sdamien 559156321Sdamien desc->flags = 0; 560156321Sdamien } 561156321Sdamien 562156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 563156321Sdamien 564156321Sdamien ring->queued = 0; 565156321Sdamien ring->cur = ring->next = 0; 566156321Sdamien ring->cur_encrypt = ring->next_encrypt = 0; 567156321Sdamien} 568156321Sdamien 569156321Sdamienstatic void 570156321Sdamienrt2560_free_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) 571156321Sdamien{ 572156321Sdamien struct rt2560_tx_data *data; 573156321Sdamien int i; 574156321Sdamien 575156321Sdamien if (ring->desc != NULL) { 576156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 577156321Sdamien BUS_DMASYNC_POSTWRITE); 578156321Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 579156321Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 580156321Sdamien } 581156321Sdamien 582156321Sdamien if (ring->desc_dmat != NULL) 583156321Sdamien bus_dma_tag_destroy(ring->desc_dmat); 584156321Sdamien 585156321Sdamien if (ring->data != NULL) { 586156321Sdamien for (i = 0; i < ring->count; i++) { 587156321Sdamien data = &ring->data[i]; 588156321Sdamien 589156321Sdamien if (data->m != NULL) { 590156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 591156321Sdamien BUS_DMASYNC_POSTWRITE); 592156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 593156321Sdamien m_freem(data->m); 594156321Sdamien } 595156321Sdamien 596156321Sdamien if (data->ni != NULL) 597156321Sdamien ieee80211_free_node(data->ni); 598156321Sdamien 599156321Sdamien if (data->map != NULL) 600156321Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 601156321Sdamien } 602156321Sdamien 603156321Sdamien free(ring->data, M_DEVBUF); 604156321Sdamien } 605156321Sdamien 606156321Sdamien if (ring->data_dmat != NULL) 607156321Sdamien bus_dma_tag_destroy(ring->data_dmat); 608156321Sdamien} 609156321Sdamien 610156321Sdamienstatic int 611156321Sdamienrt2560_alloc_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring, 612156321Sdamien int count) 613156321Sdamien{ 614156321Sdamien struct rt2560_rx_desc *desc; 615156321Sdamien struct rt2560_rx_data *data; 616156321Sdamien bus_addr_t physaddr; 617156321Sdamien int i, error; 618156321Sdamien 619156321Sdamien ring->count = count; 620156321Sdamien ring->cur = ring->next = 0; 621156321Sdamien ring->cur_decrypt = 0; 622156321Sdamien 623171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 4, 0, 624171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 625171535Skevlo count * RT2560_RX_DESC_SIZE, 1, count * RT2560_RX_DESC_SIZE, 626171535Skevlo 0, NULL, NULL, &ring->desc_dmat); 627156321Sdamien if (error != 0) { 628156321Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 629156321Sdamien goto fail; 630156321Sdamien } 631156321Sdamien 632156321Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 633156321Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 634156321Sdamien if (error != 0) { 635156321Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 636156321Sdamien goto fail; 637156321Sdamien } 638156321Sdamien 639156321Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 640156321Sdamien count * RT2560_RX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr, 641156321Sdamien 0); 642156321Sdamien if (error != 0) { 643156321Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 644156321Sdamien goto fail; 645156321Sdamien } 646156321Sdamien 647156321Sdamien ring->data = malloc(count * sizeof (struct rt2560_rx_data), M_DEVBUF, 648156321Sdamien M_NOWAIT | M_ZERO); 649156321Sdamien if (ring->data == NULL) { 650156321Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 651156321Sdamien error = ENOMEM; 652156321Sdamien goto fail; 653156321Sdamien } 654156321Sdamien 655156321Sdamien /* 656156321Sdamien * Pre-allocate Rx buffers and populate Rx ring. 657156321Sdamien */ 658171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 659171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 660171535Skevlo 1, MCLBYTES, 0, NULL, NULL, &ring->data_dmat); 661156321Sdamien if (error != 0) { 662156321Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 663156321Sdamien goto fail; 664156321Sdamien } 665156321Sdamien 666156321Sdamien for (i = 0; i < count; i++) { 667156321Sdamien desc = &sc->rxq.desc[i]; 668156321Sdamien data = &sc->rxq.data[i]; 669156321Sdamien 670156321Sdamien error = bus_dmamap_create(ring->data_dmat, 0, &data->map); 671156321Sdamien if (error != 0) { 672156321Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 673156321Sdamien goto fail; 674156321Sdamien } 675156321Sdamien 676248078Smarius data->m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 677156321Sdamien if (data->m == NULL) { 678156321Sdamien device_printf(sc->sc_dev, 679156321Sdamien "could not allocate rx mbuf\n"); 680156321Sdamien error = ENOMEM; 681156321Sdamien goto fail; 682156321Sdamien } 683156321Sdamien 684156321Sdamien error = bus_dmamap_load(ring->data_dmat, data->map, 685156321Sdamien mtod(data->m, void *), MCLBYTES, rt2560_dma_map_addr, 686156321Sdamien &physaddr, 0); 687156321Sdamien if (error != 0) { 688156321Sdamien device_printf(sc->sc_dev, 689156321Sdamien "could not load rx buf DMA map"); 690156321Sdamien goto fail; 691156321Sdamien } 692156321Sdamien 693156321Sdamien desc->flags = htole32(RT2560_RX_BUSY); 694156321Sdamien desc->physaddr = htole32(physaddr); 695156321Sdamien } 696156321Sdamien 697156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 698156321Sdamien 699156321Sdamien return 0; 700156321Sdamien 701156321Sdamienfail: rt2560_free_rx_ring(sc, ring); 702156321Sdamien return error; 703156321Sdamien} 704156321Sdamien 705156321Sdamienstatic void 706156321Sdamienrt2560_reset_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) 707156321Sdamien{ 708156321Sdamien int i; 709156321Sdamien 710156321Sdamien for (i = 0; i < ring->count; i++) { 711156321Sdamien ring->desc[i].flags = htole32(RT2560_RX_BUSY); 712156321Sdamien ring->data[i].drop = 0; 713156321Sdamien } 714156321Sdamien 715156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 716156321Sdamien 717156321Sdamien ring->cur = ring->next = 0; 718156321Sdamien ring->cur_decrypt = 0; 719156321Sdamien} 720156321Sdamien 721156321Sdamienstatic void 722156321Sdamienrt2560_free_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) 723156321Sdamien{ 724156321Sdamien struct rt2560_rx_data *data; 725156321Sdamien int i; 726156321Sdamien 727156321Sdamien if (ring->desc != NULL) { 728156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 729156321Sdamien BUS_DMASYNC_POSTWRITE); 730156321Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 731156321Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 732156321Sdamien } 733156321Sdamien 734156321Sdamien if (ring->desc_dmat != NULL) 735156321Sdamien bus_dma_tag_destroy(ring->desc_dmat); 736156321Sdamien 737156321Sdamien if (ring->data != NULL) { 738156321Sdamien for (i = 0; i < ring->count; i++) { 739156321Sdamien data = &ring->data[i]; 740156321Sdamien 741156321Sdamien if (data->m != NULL) { 742156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 743156321Sdamien BUS_DMASYNC_POSTREAD); 744156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 745156321Sdamien m_freem(data->m); 746156321Sdamien } 747156321Sdamien 748156321Sdamien if (data->map != NULL) 749156321Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 750156321Sdamien } 751156321Sdamien 752156321Sdamien free(ring->data, M_DEVBUF); 753156321Sdamien } 754156321Sdamien 755156321Sdamien if (ring->data_dmat != NULL) 756156321Sdamien bus_dma_tag_destroy(ring->data_dmat); 757156321Sdamien} 758156321Sdamien 759156321Sdamienstatic int 760178354Ssamrt2560_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 761156321Sdamien{ 762178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 763178354Ssam struct ifnet *ifp = vap->iv_ic->ic_ifp; 764178354Ssam struct rt2560_softc *sc = ifp->if_softc; 765178354Ssam int error; 766156321Sdamien 767178354Ssam if (nstate == IEEE80211_S_INIT && vap->iv_state == IEEE80211_S_RUN) { 768178354Ssam /* abort TSF synchronization */ 769178354Ssam RAL_WRITE(sc, RT2560_CSR14, 0); 770156321Sdamien 771178354Ssam /* turn association led off */ 772178354Ssam rt2560_update_led(sc, 0, 0); 773178354Ssam } 774156321Sdamien 775178354Ssam error = rvp->ral_newstate(vap, nstate, arg); 776156321Sdamien 777178354Ssam if (error == 0 && nstate == IEEE80211_S_RUN) { 778178354Ssam struct ieee80211_node *ni = vap->iv_bss; 779178354Ssam struct mbuf *m; 780156321Sdamien 781178354Ssam if (vap->iv_opmode != IEEE80211_M_MONITOR) { 782156321Sdamien rt2560_update_plcp(sc); 783220502Sbschmidt rt2560_set_basicrates(sc, &ni->ni_rates); 784156321Sdamien rt2560_set_bssid(sc, ni->ni_bssid); 785156321Sdamien } 786156321Sdamien 787178354Ssam if (vap->iv_opmode == IEEE80211_M_HOSTAP || 788195618Srpaulo vap->iv_opmode == IEEE80211_M_IBSS || 789195618Srpaulo vap->iv_opmode == IEEE80211_M_MBSS) { 790178354Ssam m = ieee80211_beacon_alloc(ni, &rvp->ral_bo); 791156321Sdamien if (m == NULL) { 792178354Ssam if_printf(ifp, "could not allocate beacon\n"); 793178354Ssam return ENOBUFS; 794156321Sdamien } 795156321Sdamien ieee80211_ref_node(ni); 796156321Sdamien error = rt2560_tx_bcn(sc, m, ni); 797156321Sdamien if (error != 0) 798178354Ssam return error; 799156321Sdamien } 800156321Sdamien 801156321Sdamien /* turn assocation led on */ 802156321Sdamien rt2560_update_led(sc, 1, 0); 803156321Sdamien 804184345Ssam if (vap->iv_opmode != IEEE80211_M_MONITOR) 805156321Sdamien rt2560_enable_tsf_sync(sc); 806192468Ssam else 807192468Ssam rt2560_enable_tsf(sc); 808156321Sdamien } 809178354Ssam return error; 810156321Sdamien} 811156321Sdamien 812156321Sdamien/* 813156321Sdamien * Read 16 bits at address 'addr' from the serial EEPROM (either 93C46 or 814156321Sdamien * 93C66). 815156321Sdamien */ 816156321Sdamienstatic uint16_t 817156321Sdamienrt2560_eeprom_read(struct rt2560_softc *sc, uint8_t addr) 818156321Sdamien{ 819156321Sdamien uint32_t tmp; 820156321Sdamien uint16_t val; 821156321Sdamien int n; 822156321Sdamien 823156321Sdamien /* clock C once before the first command */ 824156321Sdamien RT2560_EEPROM_CTL(sc, 0); 825156321Sdamien 826156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 827156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 828156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 829156321Sdamien 830156321Sdamien /* write start bit (1) */ 831156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D); 832156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C); 833156321Sdamien 834156321Sdamien /* write READ opcode (10) */ 835156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D); 836156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C); 837156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 838156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 839156321Sdamien 840156321Sdamien /* write address (A5-A0 or A7-A0) */ 841156321Sdamien n = (RAL_READ(sc, RT2560_CSR21) & RT2560_93C46) ? 5 : 7; 842156321Sdamien for (; n >= 0; n--) { 843156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | 844156321Sdamien (((addr >> n) & 1) << RT2560_SHIFT_D)); 845156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | 846156321Sdamien (((addr >> n) & 1) << RT2560_SHIFT_D) | RT2560_C); 847156321Sdamien } 848156321Sdamien 849156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 850156321Sdamien 851156321Sdamien /* read data Q15-Q0 */ 852156321Sdamien val = 0; 853156321Sdamien for (n = 15; n >= 0; n--) { 854156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 855156321Sdamien tmp = RAL_READ(sc, RT2560_CSR21); 856156321Sdamien val |= ((tmp & RT2560_Q) >> RT2560_SHIFT_Q) << n; 857156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 858156321Sdamien } 859156321Sdamien 860156321Sdamien RT2560_EEPROM_CTL(sc, 0); 861156321Sdamien 862156321Sdamien /* clear Chip Select and clock C */ 863156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 864156321Sdamien RT2560_EEPROM_CTL(sc, 0); 865156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_C); 866156321Sdamien 867156321Sdamien return val; 868156321Sdamien} 869156321Sdamien 870156321Sdamien/* 871156321Sdamien * Some frames were processed by the hardware cipher engine and are ready for 872156321Sdamien * transmission. 873156321Sdamien */ 874156321Sdamienstatic void 875156321Sdamienrt2560_encryption_intr(struct rt2560_softc *sc) 876156321Sdamien{ 877156321Sdamien struct rt2560_tx_desc *desc; 878156321Sdamien int hw; 879156321Sdamien 880156321Sdamien /* retrieve last descriptor index processed by cipher engine */ 881156321Sdamien hw = RAL_READ(sc, RT2560_SECCSR1) - sc->txq.physaddr; 882156321Sdamien hw /= RT2560_TX_DESC_SIZE; 883156321Sdamien 884156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 885156321Sdamien BUS_DMASYNC_POSTREAD); 886156321Sdamien 887175938Ssephe while (sc->txq.next_encrypt != hw) { 888175938Ssephe if (sc->txq.next_encrypt == sc->txq.cur_encrypt) { 889175938Ssephe printf("hw encrypt %d, cur_encrypt %d\n", hw, 890175938Ssephe sc->txq.cur_encrypt); 891175938Ssephe break; 892175938Ssephe } 893175938Ssephe 894156321Sdamien desc = &sc->txq.desc[sc->txq.next_encrypt]; 895156321Sdamien 896156321Sdamien if ((le32toh(desc->flags) & RT2560_TX_BUSY) || 897156321Sdamien (le32toh(desc->flags) & RT2560_TX_CIPHER_BUSY)) 898156321Sdamien break; 899156321Sdamien 900156321Sdamien /* for TKIP, swap eiv field to fix a bug in ASIC */ 901156321Sdamien if ((le32toh(desc->flags) & RT2560_TX_CIPHER_MASK) == 902156321Sdamien RT2560_TX_CIPHER_TKIP) 903156321Sdamien desc->eiv = bswap32(desc->eiv); 904156321Sdamien 905156321Sdamien /* mark the frame ready for transmission */ 906175938Ssephe desc->flags |= htole32(RT2560_TX_VALID); 907175938Ssephe desc->flags |= htole32(RT2560_TX_BUSY); 908156321Sdamien 909178354Ssam DPRINTFN(sc, 15, "encryption done idx=%u\n", 910178354Ssam sc->txq.next_encrypt); 911156321Sdamien 912156321Sdamien sc->txq.next_encrypt = 913156321Sdamien (sc->txq.next_encrypt + 1) % RT2560_TX_RING_COUNT; 914156321Sdamien } 915156321Sdamien 916156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 917156321Sdamien BUS_DMASYNC_PREWRITE); 918156321Sdamien 919156321Sdamien /* kick Tx */ 920156321Sdamien RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_TX); 921156321Sdamien} 922156321Sdamien 923156321Sdamienstatic void 924156321Sdamienrt2560_tx_intr(struct rt2560_softc *sc) 925156321Sdamien{ 926178354Ssam struct ifnet *ifp = sc->sc_ifp; 927156321Sdamien struct rt2560_tx_desc *desc; 928156321Sdamien struct rt2560_tx_data *data; 929178354Ssam struct mbuf *m; 930178354Ssam uint32_t flags; 931178354Ssam int retrycnt; 932206358Srpaulo struct ieee80211vap *vap; 933206358Srpaulo struct ieee80211_node *ni; 934156321Sdamien 935156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 936156321Sdamien BUS_DMASYNC_POSTREAD); 937156321Sdamien 938156321Sdamien for (;;) { 939156321Sdamien desc = &sc->txq.desc[sc->txq.next]; 940156321Sdamien data = &sc->txq.data[sc->txq.next]; 941156321Sdamien 942178354Ssam flags = le32toh(desc->flags); 943178354Ssam if ((flags & RT2560_TX_BUSY) || 944178354Ssam (flags & RT2560_TX_CIPHER_BUSY) || 945178354Ssam !(flags & RT2560_TX_VALID)) 946156321Sdamien break; 947156321Sdamien 948178354Ssam m = data->m; 949206358Srpaulo ni = data->ni; 950206358Srpaulo vap = ni->ni_vap; 951156321Sdamien 952178354Ssam switch (flags & RT2560_TX_RESULT_MASK) { 953156321Sdamien case RT2560_TX_SUCCESS: 954206358Srpaulo retrycnt = 0; 955206358Srpaulo 956178354Ssam DPRINTFN(sc, 10, "%s\n", "data frame sent successfully"); 957178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 958206358Srpaulo ieee80211_ratectl_tx_complete(vap, ni, 959206358Srpaulo IEEE80211_RATECTL_TX_SUCCESS, 960206358Srpaulo &retrycnt, NULL); 961156321Sdamien ifp->if_opackets++; 962156321Sdamien break; 963156321Sdamien 964156321Sdamien case RT2560_TX_SUCCESS_RETRY: 965178354Ssam retrycnt = RT2560_TX_RETRYCNT(flags); 966178354Ssam 967178354Ssam DPRINTFN(sc, 9, "data frame sent after %u retries\n", 968178354Ssam retrycnt); 969178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 970206358Srpaulo ieee80211_ratectl_tx_complete(vap, ni, 971206358Srpaulo IEEE80211_RATECTL_TX_SUCCESS, 972206358Srpaulo &retrycnt, NULL); 973156321Sdamien ifp->if_opackets++; 974156321Sdamien break; 975156321Sdamien 976156321Sdamien case RT2560_TX_FAIL_RETRY: 977178354Ssam retrycnt = RT2560_TX_RETRYCNT(flags); 978178354Ssam 979178354Ssam DPRINTFN(sc, 9, "data frame failed after %d retries\n", 980178354Ssam retrycnt); 981178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 982206358Srpaulo ieee80211_ratectl_tx_complete(vap, ni, 983206358Srpaulo IEEE80211_RATECTL_TX_FAILURE, 984206358Srpaulo &retrycnt, NULL); 985156321Sdamien ifp->if_oerrors++; 986156321Sdamien break; 987156321Sdamien 988156321Sdamien case RT2560_TX_FAIL_INVALID: 989156321Sdamien case RT2560_TX_FAIL_OTHER: 990156321Sdamien default: 991156321Sdamien device_printf(sc->sc_dev, "sending data frame failed " 992178354Ssam "0x%08x\n", flags); 993156321Sdamien ifp->if_oerrors++; 994156321Sdamien } 995156321Sdamien 996156321Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, 997156321Sdamien BUS_DMASYNC_POSTWRITE); 998156321Sdamien bus_dmamap_unload(sc->txq.data_dmat, data->map); 999178354Ssam m_freem(m); 1000156321Sdamien data->m = NULL; 1001156321Sdamien ieee80211_free_node(data->ni); 1002156321Sdamien data->ni = NULL; 1003156321Sdamien 1004156321Sdamien /* descriptor is no longer valid */ 1005156321Sdamien desc->flags &= ~htole32(RT2560_TX_VALID); 1006156321Sdamien 1007178354Ssam DPRINTFN(sc, 15, "tx done idx=%u\n", sc->txq.next); 1008156321Sdamien 1009156321Sdamien sc->txq.queued--; 1010156321Sdamien sc->txq.next = (sc->txq.next + 1) % RT2560_TX_RING_COUNT; 1011156321Sdamien } 1012156321Sdamien 1013156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 1014156321Sdamien BUS_DMASYNC_PREWRITE); 1015156321Sdamien 1016175938Ssephe if (sc->prioq.queued == 0 && sc->txq.queued == 0) 1017175938Ssephe sc->sc_tx_timer = 0; 1018175938Ssephe 1019175938Ssephe if (sc->txq.queued < RT2560_TX_RING_COUNT - 1) { 1020175938Ssephe sc->sc_flags &= ~RT2560_F_DATA_OACTIVE; 1021175938Ssephe if ((sc->sc_flags & 1022175938Ssephe (RT2560_F_DATA_OACTIVE | RT2560_F_PRIO_OACTIVE)) == 0) 1023175938Ssephe ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1024178354Ssam rt2560_start_locked(ifp); 1025175938Ssephe } 1026156321Sdamien} 1027156321Sdamien 1028156321Sdamienstatic void 1029156321Sdamienrt2560_prio_intr(struct rt2560_softc *sc) 1030156321Sdamien{ 1031178354Ssam struct ifnet *ifp = sc->sc_ifp; 1032156321Sdamien struct rt2560_tx_desc *desc; 1033156321Sdamien struct rt2560_tx_data *data; 1034170530Ssam struct ieee80211_node *ni; 1035170530Ssam struct mbuf *m; 1036170530Ssam int flags; 1037156321Sdamien 1038156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1039156321Sdamien BUS_DMASYNC_POSTREAD); 1040156321Sdamien 1041156321Sdamien for (;;) { 1042156321Sdamien desc = &sc->prioq.desc[sc->prioq.next]; 1043156321Sdamien data = &sc->prioq.data[sc->prioq.next]; 1044156321Sdamien 1045170530Ssam flags = le32toh(desc->flags); 1046170530Ssam if ((flags & RT2560_TX_BUSY) || (flags & RT2560_TX_VALID) == 0) 1047156321Sdamien break; 1048156321Sdamien 1049170530Ssam switch (flags & RT2560_TX_RESULT_MASK) { 1050156321Sdamien case RT2560_TX_SUCCESS: 1051178354Ssam DPRINTFN(sc, 10, "%s\n", "mgt frame sent successfully"); 1052156321Sdamien break; 1053156321Sdamien 1054156321Sdamien case RT2560_TX_SUCCESS_RETRY: 1055178354Ssam DPRINTFN(sc, 9, "mgt frame sent after %u retries\n", 1056178354Ssam (flags >> 5) & 0x7); 1057156321Sdamien break; 1058156321Sdamien 1059156321Sdamien case RT2560_TX_FAIL_RETRY: 1060178354Ssam DPRINTFN(sc, 9, "%s\n", 1061178354Ssam "sending mgt frame failed (too much retries)"); 1062156321Sdamien break; 1063156321Sdamien 1064156321Sdamien case RT2560_TX_FAIL_INVALID: 1065156321Sdamien case RT2560_TX_FAIL_OTHER: 1066156321Sdamien default: 1067156321Sdamien device_printf(sc->sc_dev, "sending mgt frame failed " 1068170530Ssam "0x%08x\n", flags); 1069170530Ssam break; 1070156321Sdamien } 1071156321Sdamien 1072156321Sdamien bus_dmamap_sync(sc->prioq.data_dmat, data->map, 1073156321Sdamien BUS_DMASYNC_POSTWRITE); 1074156321Sdamien bus_dmamap_unload(sc->prioq.data_dmat, data->map); 1075170530Ssam 1076170530Ssam m = data->m; 1077156321Sdamien data->m = NULL; 1078170530Ssam ni = data->ni; 1079156321Sdamien data->ni = NULL; 1080156321Sdamien 1081156321Sdamien /* descriptor is no longer valid */ 1082156321Sdamien desc->flags &= ~htole32(RT2560_TX_VALID); 1083156321Sdamien 1084178354Ssam DPRINTFN(sc, 15, "prio done idx=%u\n", sc->prioq.next); 1085156321Sdamien 1086156321Sdamien sc->prioq.queued--; 1087156321Sdamien sc->prioq.next = (sc->prioq.next + 1) % RT2560_PRIO_RING_COUNT; 1088170530Ssam 1089170530Ssam if (m->m_flags & M_TXCB) 1090170530Ssam ieee80211_process_callback(ni, m, 1091170530Ssam (flags & RT2560_TX_RESULT_MASK) &~ 1092170530Ssam (RT2560_TX_SUCCESS | RT2560_TX_SUCCESS_RETRY)); 1093170530Ssam m_freem(m); 1094170530Ssam ieee80211_free_node(ni); 1095156321Sdamien } 1096156321Sdamien 1097156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1098156321Sdamien BUS_DMASYNC_PREWRITE); 1099156321Sdamien 1100175938Ssephe if (sc->prioq.queued == 0 && sc->txq.queued == 0) 1101175938Ssephe sc->sc_tx_timer = 0; 1102175938Ssephe 1103175938Ssephe if (sc->prioq.queued < RT2560_PRIO_RING_COUNT) { 1104175938Ssephe sc->sc_flags &= ~RT2560_F_PRIO_OACTIVE; 1105175938Ssephe if ((sc->sc_flags & 1106175938Ssephe (RT2560_F_DATA_OACTIVE | RT2560_F_PRIO_OACTIVE)) == 0) 1107175938Ssephe ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1108178354Ssam rt2560_start_locked(ifp); 1109175938Ssephe } 1110156321Sdamien} 1111156321Sdamien 1112156321Sdamien/* 1113156321Sdamien * Some frames were processed by the hardware cipher engine and are ready for 1114178354Ssam * handoff to the IEEE802.11 layer. 1115156321Sdamien */ 1116156321Sdamienstatic void 1117156321Sdamienrt2560_decryption_intr(struct rt2560_softc *sc) 1118156321Sdamien{ 1119178354Ssam struct ifnet *ifp = sc->sc_ifp; 1120178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1121156321Sdamien struct rt2560_rx_desc *desc; 1122156321Sdamien struct rt2560_rx_data *data; 1123156321Sdamien bus_addr_t physaddr; 1124156321Sdamien struct ieee80211_frame *wh; 1125156321Sdamien struct ieee80211_node *ni; 1126156321Sdamien struct mbuf *mnew, *m; 1127156321Sdamien int hw, error; 1128192468Ssam int8_t rssi, nf; 1129156321Sdamien 1130156321Sdamien /* retrieve last decriptor index processed by cipher engine */ 1131156321Sdamien hw = RAL_READ(sc, RT2560_SECCSR0) - sc->rxq.physaddr; 1132156321Sdamien hw /= RT2560_RX_DESC_SIZE; 1133156321Sdamien 1134156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1135156321Sdamien BUS_DMASYNC_POSTREAD); 1136156321Sdamien 1137156321Sdamien for (; sc->rxq.cur_decrypt != hw;) { 1138156321Sdamien desc = &sc->rxq.desc[sc->rxq.cur_decrypt]; 1139156321Sdamien data = &sc->rxq.data[sc->rxq.cur_decrypt]; 1140156321Sdamien 1141156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_BUSY) || 1142156321Sdamien (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY)) 1143156321Sdamien break; 1144156321Sdamien 1145156321Sdamien if (data->drop) { 1146156321Sdamien ifp->if_ierrors++; 1147156321Sdamien goto skip; 1148156321Sdamien } 1149156321Sdamien 1150156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_CIPHER_MASK) != 0 && 1151156321Sdamien (le32toh(desc->flags) & RT2560_RX_ICV_ERROR)) { 1152156321Sdamien ifp->if_ierrors++; 1153156321Sdamien goto skip; 1154156321Sdamien } 1155156321Sdamien 1156156321Sdamien /* 1157156321Sdamien * Try to allocate a new mbuf for this ring element and load it 1158156321Sdamien * before processing the current mbuf. If the ring element 1159156321Sdamien * cannot be loaded, drop the received packet and reuse the old 1160156321Sdamien * mbuf. In the unlikely case that the old mbuf can't be 1161156321Sdamien * reloaded either, explicitly panic. 1162156321Sdamien */ 1163248078Smarius mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1164156321Sdamien if (mnew == NULL) { 1165156321Sdamien ifp->if_ierrors++; 1166156321Sdamien goto skip; 1167156321Sdamien } 1168156321Sdamien 1169156321Sdamien bus_dmamap_sync(sc->rxq.data_dmat, data->map, 1170156321Sdamien BUS_DMASYNC_POSTREAD); 1171156321Sdamien bus_dmamap_unload(sc->rxq.data_dmat, data->map); 1172156321Sdamien 1173156321Sdamien error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 1174156321Sdamien mtod(mnew, void *), MCLBYTES, rt2560_dma_map_addr, 1175156321Sdamien &physaddr, 0); 1176156321Sdamien if (error != 0) { 1177156321Sdamien m_freem(mnew); 1178156321Sdamien 1179156321Sdamien /* try to reload the old mbuf */ 1180156321Sdamien error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 1181156321Sdamien mtod(data->m, void *), MCLBYTES, 1182156321Sdamien rt2560_dma_map_addr, &physaddr, 0); 1183156321Sdamien if (error != 0) { 1184156321Sdamien /* very unlikely that it will fail... */ 1185156321Sdamien panic("%s: could not load old rx mbuf", 1186156321Sdamien device_get_name(sc->sc_dev)); 1187156321Sdamien } 1188156321Sdamien ifp->if_ierrors++; 1189156321Sdamien goto skip; 1190156321Sdamien } 1191156321Sdamien 1192156321Sdamien /* 1193156321Sdamien * New mbuf successfully loaded, update Rx ring and continue 1194156321Sdamien * processing. 1195156321Sdamien */ 1196156321Sdamien m = data->m; 1197156321Sdamien data->m = mnew; 1198156321Sdamien desc->physaddr = htole32(physaddr); 1199156321Sdamien 1200156321Sdamien /* finalize mbuf */ 1201156321Sdamien m->m_pkthdr.rcvif = ifp; 1202156321Sdamien m->m_pkthdr.len = m->m_len = 1203156321Sdamien (le32toh(desc->flags) >> 16) & 0xfff; 1204156321Sdamien 1205192468Ssam rssi = RT2560_RSSI(sc, desc->rssi); 1206192468Ssam nf = RT2560_NOISE_FLOOR; 1207192468Ssam if (ieee80211_radiotap_active(ic)) { 1208156321Sdamien struct rt2560_rx_radiotap_header *tap = &sc->sc_rxtap; 1209156321Sdamien uint32_t tsf_lo, tsf_hi; 1210156321Sdamien 1211156321Sdamien /* get timestamp (low and high 32 bits) */ 1212156321Sdamien tsf_hi = RAL_READ(sc, RT2560_CSR17); 1213156321Sdamien tsf_lo = RAL_READ(sc, RT2560_CSR16); 1214156321Sdamien 1215156321Sdamien tap->wr_tsf = 1216156321Sdamien htole64(((uint64_t)tsf_hi << 32) | tsf_lo); 1217156321Sdamien tap->wr_flags = 0; 1218178354Ssam tap->wr_rate = ieee80211_plcp2rate(desc->rate, 1219178958Ssam (desc->flags & htole32(RT2560_RX_OFDM)) ? 1220178958Ssam IEEE80211_T_OFDM : IEEE80211_T_CCK); 1221156321Sdamien tap->wr_antenna = sc->rx_ant; 1222192468Ssam tap->wr_antsignal = nf + rssi; 1223192468Ssam tap->wr_antnoise = nf; 1224156321Sdamien } 1225156321Sdamien 1226175938Ssephe sc->sc_flags |= RT2560_F_INPUT_RUNNING; 1227170530Ssam RAL_UNLOCK(sc); 1228156321Sdamien wh = mtod(m, struct ieee80211_frame *); 1229156321Sdamien ni = ieee80211_find_rxnode(ic, 1230156321Sdamien (struct ieee80211_frame_min *)wh); 1231178354Ssam if (ni != NULL) { 1232192468Ssam (void) ieee80211_input(ni, m, rssi, nf); 1233178354Ssam ieee80211_free_node(ni); 1234178354Ssam } else 1235192468Ssam (void) ieee80211_input_all(ic, m, rssi, nf); 1236156321Sdamien 1237170530Ssam RAL_LOCK(sc); 1238175938Ssephe sc->sc_flags &= ~RT2560_F_INPUT_RUNNING; 1239156321Sdamienskip: desc->flags = htole32(RT2560_RX_BUSY); 1240156321Sdamien 1241178354Ssam DPRINTFN(sc, 15, "decryption done idx=%u\n", sc->rxq.cur_decrypt); 1242156321Sdamien 1243156321Sdamien sc->rxq.cur_decrypt = 1244156321Sdamien (sc->rxq.cur_decrypt + 1) % RT2560_RX_RING_COUNT; 1245156321Sdamien } 1246156321Sdamien 1247156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1248156321Sdamien BUS_DMASYNC_PREWRITE); 1249156321Sdamien} 1250156321Sdamien 1251156321Sdamien/* 1252156321Sdamien * Some frames were received. Pass them to the hardware cipher engine before 1253156321Sdamien * sending them to the 802.11 layer. 1254156321Sdamien */ 1255156321Sdamienstatic void 1256156321Sdamienrt2560_rx_intr(struct rt2560_softc *sc) 1257156321Sdamien{ 1258156321Sdamien struct rt2560_rx_desc *desc; 1259156321Sdamien struct rt2560_rx_data *data; 1260156321Sdamien 1261156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1262156321Sdamien BUS_DMASYNC_POSTREAD); 1263156321Sdamien 1264156321Sdamien for (;;) { 1265156321Sdamien desc = &sc->rxq.desc[sc->rxq.cur]; 1266156321Sdamien data = &sc->rxq.data[sc->rxq.cur]; 1267156321Sdamien 1268156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_BUSY) || 1269156321Sdamien (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY)) 1270156321Sdamien break; 1271156321Sdamien 1272156321Sdamien data->drop = 0; 1273156321Sdamien 1274156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_PHY_ERROR) || 1275156321Sdamien (le32toh(desc->flags) & RT2560_RX_CRC_ERROR)) { 1276156321Sdamien /* 1277156321Sdamien * This should not happen since we did not request 1278156321Sdamien * to receive those frames when we filled RXCSR0. 1279156321Sdamien */ 1280178354Ssam DPRINTFN(sc, 5, "PHY or CRC error flags 0x%08x\n", 1281178354Ssam le32toh(desc->flags)); 1282156321Sdamien data->drop = 1; 1283156321Sdamien } 1284156321Sdamien 1285156321Sdamien if (((le32toh(desc->flags) >> 16) & 0xfff) > MCLBYTES) { 1286178354Ssam DPRINTFN(sc, 5, "%s\n", "bad length"); 1287156321Sdamien data->drop = 1; 1288156321Sdamien } 1289156321Sdamien 1290156321Sdamien /* mark the frame for decryption */ 1291156321Sdamien desc->flags |= htole32(RT2560_RX_CIPHER_BUSY); 1292156321Sdamien 1293178354Ssam DPRINTFN(sc, 15, "rx done idx=%u\n", sc->rxq.cur); 1294156321Sdamien 1295156321Sdamien sc->rxq.cur = (sc->rxq.cur + 1) % RT2560_RX_RING_COUNT; 1296156321Sdamien } 1297156321Sdamien 1298156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1299156321Sdamien BUS_DMASYNC_PREWRITE); 1300156321Sdamien 1301156321Sdamien /* kick decrypt */ 1302156321Sdamien RAL_WRITE(sc, RT2560_SECCSR0, RT2560_KICK_DECRYPT); 1303156321Sdamien} 1304156321Sdamien 1305172211Ssamstatic void 1306178354Ssamrt2560_beacon_update(struct ieee80211vap *vap, int item) 1307172211Ssam{ 1308178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 1309178354Ssam struct ieee80211_beacon_offsets *bo = &rvp->ral_bo; 1310172211Ssam 1311172211Ssam setbit(bo->bo_flags, item); 1312172211Ssam} 1313172211Ssam 1314156321Sdamien/* 1315156321Sdamien * This function is called periodically in IBSS mode when a new beacon must be 1316156321Sdamien * sent out. 1317156321Sdamien */ 1318156321Sdamienstatic void 1319156321Sdamienrt2560_beacon_expire(struct rt2560_softc *sc) 1320156321Sdamien{ 1321178354Ssam struct ifnet *ifp = sc->sc_ifp; 1322178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1323178354Ssam struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 1324178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 1325156321Sdamien struct rt2560_tx_data *data; 1326156321Sdamien 1327156321Sdamien if (ic->ic_opmode != IEEE80211_M_IBSS && 1328195618Srpaulo ic->ic_opmode != IEEE80211_M_HOSTAP && 1329195618Srpaulo ic->ic_opmode != IEEE80211_M_MBSS) 1330170530Ssam return; 1331156321Sdamien 1332156321Sdamien data = &sc->bcnq.data[sc->bcnq.next]; 1333170530Ssam /* 1334170530Ssam * Don't send beacon if bsschan isn't set 1335170530Ssam */ 1336170530Ssam if (data->ni == NULL) 1337170530Ssam return; 1338156321Sdamien 1339156321Sdamien bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_POSTWRITE); 1340156321Sdamien bus_dmamap_unload(sc->bcnq.data_dmat, data->map); 1341156321Sdamien 1342178354Ssam /* XXX 1 =>'s mcast frames which means all PS sta's will wakeup! */ 1343178354Ssam ieee80211_beacon_update(data->ni, &rvp->ral_bo, data->m, 1); 1344156321Sdamien 1345156321Sdamien rt2560_tx_bcn(sc, data->m, data->ni); 1346156321Sdamien 1347178354Ssam DPRINTFN(sc, 15, "%s", "beacon expired\n"); 1348156321Sdamien 1349156321Sdamien sc->bcnq.next = (sc->bcnq.next + 1) % RT2560_BEACON_RING_COUNT; 1350156321Sdamien} 1351156321Sdamien 1352156321Sdamien/* ARGSUSED */ 1353156321Sdamienstatic void 1354156321Sdamienrt2560_wakeup_expire(struct rt2560_softc *sc) 1355156321Sdamien{ 1356178354Ssam DPRINTFN(sc, 2, "%s", "wakeup expired\n"); 1357156321Sdamien} 1358156321Sdamien 1359156321Sdamienvoid 1360156321Sdamienrt2560_intr(void *arg) 1361156321Sdamien{ 1362156321Sdamien struct rt2560_softc *sc = arg; 1363156975Sdamien struct ifnet *ifp = sc->sc_ifp; 1364156321Sdamien uint32_t r; 1365156321Sdamien 1366156321Sdamien RAL_LOCK(sc); 1367156321Sdamien 1368156321Sdamien /* disable interrupts */ 1369156321Sdamien RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 1370156321Sdamien 1371156975Sdamien /* don't re-enable interrupts if we're shutting down */ 1372156975Sdamien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1373156975Sdamien RAL_UNLOCK(sc); 1374156975Sdamien return; 1375156975Sdamien } 1376156975Sdamien 1377156321Sdamien r = RAL_READ(sc, RT2560_CSR7); 1378156321Sdamien RAL_WRITE(sc, RT2560_CSR7, r); 1379156321Sdamien 1380156321Sdamien if (r & RT2560_BEACON_EXPIRE) 1381156321Sdamien rt2560_beacon_expire(sc); 1382156321Sdamien 1383156321Sdamien if (r & RT2560_WAKEUP_EXPIRE) 1384156321Sdamien rt2560_wakeup_expire(sc); 1385156321Sdamien 1386156321Sdamien if (r & RT2560_ENCRYPTION_DONE) 1387156321Sdamien rt2560_encryption_intr(sc); 1388156321Sdamien 1389156321Sdamien if (r & RT2560_TX_DONE) 1390156321Sdamien rt2560_tx_intr(sc); 1391156321Sdamien 1392156321Sdamien if (r & RT2560_PRIO_DONE) 1393156321Sdamien rt2560_prio_intr(sc); 1394156321Sdamien 1395156321Sdamien if (r & RT2560_DECRYPTION_DONE) 1396156321Sdamien rt2560_decryption_intr(sc); 1397156321Sdamien 1398175938Ssephe if (r & RT2560_RX_DONE) { 1399156321Sdamien rt2560_rx_intr(sc); 1400175938Ssephe rt2560_encryption_intr(sc); 1401175938Ssephe } 1402156321Sdamien 1403156321Sdamien /* re-enable interrupts */ 1404156321Sdamien RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); 1405156321Sdamien 1406156321Sdamien RAL_UNLOCK(sc); 1407156321Sdamien} 1408156321Sdamien 1409156321Sdamien#define RAL_SIFS 10 /* us */ 1410156321Sdamien 1411156321Sdamien#define RT2560_TXRX_TURNAROUND 10 /* us */ 1412156321Sdamien 1413178958Ssamstatic uint8_t 1414178958Ssamrt2560_plcp_signal(int rate) 1415178958Ssam{ 1416178958Ssam switch (rate) { 1417178958Ssam /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ 1418178958Ssam case 12: return 0xb; 1419178958Ssam case 18: return 0xf; 1420178958Ssam case 24: return 0xa; 1421178958Ssam case 36: return 0xe; 1422178958Ssam case 48: return 0x9; 1423178958Ssam case 72: return 0xd; 1424178958Ssam case 96: return 0x8; 1425178958Ssam case 108: return 0xc; 1426178958Ssam 1427178958Ssam /* CCK rates (NB: not IEEE std, device-specific) */ 1428178958Ssam case 2: return 0x0; 1429178958Ssam case 4: return 0x1; 1430178958Ssam case 11: return 0x2; 1431178958Ssam case 22: return 0x3; 1432178958Ssam } 1433178958Ssam return 0xff; /* XXX unsupported/unknown rate */ 1434178958Ssam} 1435178958Ssam 1436156321Sdamienstatic void 1437156321Sdamienrt2560_setup_tx_desc(struct rt2560_softc *sc, struct rt2560_tx_desc *desc, 1438156321Sdamien uint32_t flags, int len, int rate, int encrypt, bus_addr_t physaddr) 1439156321Sdamien{ 1440178354Ssam struct ifnet *ifp = sc->sc_ifp; 1441178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1442156321Sdamien uint16_t plcp_length; 1443156321Sdamien int remainder; 1444156321Sdamien 1445156321Sdamien desc->flags = htole32(flags); 1446156321Sdamien desc->flags |= htole32(len << 16); 1447156321Sdamien 1448156321Sdamien desc->physaddr = htole32(physaddr); 1449156321Sdamien desc->wme = htole16( 1450156321Sdamien RT2560_AIFSN(2) | 1451156321Sdamien RT2560_LOGCWMIN(3) | 1452156321Sdamien RT2560_LOGCWMAX(8)); 1453156321Sdamien 1454156321Sdamien /* setup PLCP fields */ 1455178958Ssam desc->plcp_signal = rt2560_plcp_signal(rate); 1456156321Sdamien desc->plcp_service = 4; 1457156321Sdamien 1458156321Sdamien len += IEEE80211_CRC_LEN; 1459190532Ssam if (ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) { 1460156321Sdamien desc->flags |= htole32(RT2560_TX_OFDM); 1461156321Sdamien 1462156321Sdamien plcp_length = len & 0xfff; 1463156321Sdamien desc->plcp_length_hi = plcp_length >> 6; 1464156321Sdamien desc->plcp_length_lo = plcp_length & 0x3f; 1465156321Sdamien } else { 1466156321Sdamien plcp_length = (16 * len + rate - 1) / rate; 1467156321Sdamien if (rate == 22) { 1468156321Sdamien remainder = (16 * len) % 22; 1469156321Sdamien if (remainder != 0 && remainder < 7) 1470156321Sdamien desc->plcp_service |= RT2560_PLCP_LENGEXT; 1471156321Sdamien } 1472156321Sdamien desc->plcp_length_hi = plcp_length >> 8; 1473156321Sdamien desc->plcp_length_lo = plcp_length & 0xff; 1474156321Sdamien 1475156321Sdamien if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 1476156321Sdamien desc->plcp_signal |= 0x08; 1477156321Sdamien } 1478175938Ssephe 1479175938Ssephe if (!encrypt) 1480175938Ssephe desc->flags |= htole32(RT2560_TX_VALID); 1481175938Ssephe desc->flags |= encrypt ? htole32(RT2560_TX_CIPHER_BUSY) 1482175938Ssephe : htole32(RT2560_TX_BUSY); 1483156321Sdamien} 1484156321Sdamien 1485156321Sdamienstatic int 1486156321Sdamienrt2560_tx_bcn(struct rt2560_softc *sc, struct mbuf *m0, 1487156321Sdamien struct ieee80211_node *ni) 1488156321Sdamien{ 1489178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1490156321Sdamien struct rt2560_tx_desc *desc; 1491156321Sdamien struct rt2560_tx_data *data; 1492156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1493156321Sdamien int nsegs, rate, error; 1494156321Sdamien 1495156321Sdamien desc = &sc->bcnq.desc[sc->bcnq.cur]; 1496156321Sdamien data = &sc->bcnq.data[sc->bcnq.cur]; 1497156321Sdamien 1498178354Ssam /* XXX maybe a separate beacon rate? */ 1499178354Ssam rate = vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)].mgmtrate; 1500156321Sdamien 1501156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->bcnq.data_dmat, data->map, m0, 1502156321Sdamien segs, &nsegs, BUS_DMA_NOWAIT); 1503156321Sdamien if (error != 0) { 1504156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1505156321Sdamien error); 1506156321Sdamien m_freem(m0); 1507156321Sdamien return error; 1508156321Sdamien } 1509156321Sdamien 1510192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 1511156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1512156321Sdamien 1513156321Sdamien tap->wt_flags = 0; 1514156321Sdamien tap->wt_rate = rate; 1515156321Sdamien tap->wt_antenna = sc->tx_ant; 1516156321Sdamien 1517192468Ssam ieee80211_radiotap_tx(vap, m0); 1518156321Sdamien } 1519156321Sdamien 1520156321Sdamien data->m = m0; 1521156321Sdamien data->ni = ni; 1522156321Sdamien 1523156321Sdamien rt2560_setup_tx_desc(sc, desc, RT2560_TX_IFS_NEWBACKOFF | 1524156321Sdamien RT2560_TX_TIMESTAMP, m0->m_pkthdr.len, rate, 0, segs->ds_addr); 1525156321Sdamien 1526178354Ssam DPRINTFN(sc, 10, "sending beacon frame len=%u idx=%u rate=%u\n", 1527178354Ssam m0->m_pkthdr.len, sc->bcnq.cur, rate); 1528156321Sdamien 1529156321Sdamien bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1530156321Sdamien bus_dmamap_sync(sc->bcnq.desc_dmat, sc->bcnq.desc_map, 1531156321Sdamien BUS_DMASYNC_PREWRITE); 1532156321Sdamien 1533156321Sdamien sc->bcnq.cur = (sc->bcnq.cur + 1) % RT2560_BEACON_RING_COUNT; 1534156321Sdamien 1535156321Sdamien return 0; 1536156321Sdamien} 1537156321Sdamien 1538156321Sdamienstatic int 1539156321Sdamienrt2560_tx_mgt(struct rt2560_softc *sc, struct mbuf *m0, 1540156321Sdamien struct ieee80211_node *ni) 1541156321Sdamien{ 1542178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1543178354Ssam struct ieee80211com *ic = ni->ni_ic; 1544156321Sdamien struct rt2560_tx_desc *desc; 1545156321Sdamien struct rt2560_tx_data *data; 1546156321Sdamien struct ieee80211_frame *wh; 1547173386Skevlo struct ieee80211_key *k; 1548156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1549156321Sdamien uint16_t dur; 1550156321Sdamien uint32_t flags = 0; 1551156321Sdamien int nsegs, rate, error; 1552156321Sdamien 1553156321Sdamien desc = &sc->prioq.desc[sc->prioq.cur]; 1554156321Sdamien data = &sc->prioq.data[sc->prioq.cur]; 1555156321Sdamien 1556178354Ssam rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate; 1557156321Sdamien 1558173386Skevlo wh = mtod(m0, struct ieee80211_frame *); 1559173386Skevlo 1560173386Skevlo if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1561178354Ssam k = ieee80211_crypto_encap(ni, m0); 1562173386Skevlo if (k == NULL) { 1563173386Skevlo m_freem(m0); 1564173386Skevlo return ENOBUFS; 1565173386Skevlo } 1566173386Skevlo } 1567173386Skevlo 1568156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, 1569156321Sdamien segs, &nsegs, 0); 1570156321Sdamien if (error != 0) { 1571156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1572156321Sdamien error); 1573156321Sdamien m_freem(m0); 1574156321Sdamien return error; 1575156321Sdamien } 1576156321Sdamien 1577192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 1578156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1579156321Sdamien 1580156321Sdamien tap->wt_flags = 0; 1581156321Sdamien tap->wt_rate = rate; 1582156321Sdamien tap->wt_antenna = sc->tx_ant; 1583156321Sdamien 1584192468Ssam ieee80211_radiotap_tx(vap, m0); 1585156321Sdamien } 1586156321Sdamien 1587156321Sdamien data->m = m0; 1588156321Sdamien data->ni = ni; 1589178354Ssam /* management frames are not taken into account for amrr */ 1590178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1591156321Sdamien 1592156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1593156321Sdamien 1594156321Sdamien if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1595156321Sdamien flags |= RT2560_TX_ACK; 1596156321Sdamien 1597190532Ssam dur = ieee80211_ack_duration(ic->ic_rt, 1598178354Ssam rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); 1599156321Sdamien *(uint16_t *)wh->i_dur = htole16(dur); 1600156321Sdamien 1601156321Sdamien /* tell hardware to add timestamp for probe responses */ 1602156321Sdamien if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 1603156321Sdamien IEEE80211_FC0_TYPE_MGT && 1604156321Sdamien (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 1605156321Sdamien IEEE80211_FC0_SUBTYPE_PROBE_RESP) 1606156321Sdamien flags |= RT2560_TX_TIMESTAMP; 1607156321Sdamien } 1608156321Sdamien 1609156321Sdamien rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 0, 1610156321Sdamien segs->ds_addr); 1611156321Sdamien 1612156321Sdamien bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1613156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1614156321Sdamien BUS_DMASYNC_PREWRITE); 1615156321Sdamien 1616178354Ssam DPRINTFN(sc, 10, "sending mgt frame len=%u idx=%u rate=%u\n", 1617178354Ssam m0->m_pkthdr.len, sc->prioq.cur, rate); 1618156321Sdamien 1619156321Sdamien /* kick prio */ 1620156321Sdamien sc->prioq.queued++; 1621156321Sdamien sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; 1622156321Sdamien RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); 1623156321Sdamien 1624156321Sdamien return 0; 1625156321Sdamien} 1626156321Sdamien 1627160691Ssamstatic int 1628178354Ssamrt2560_sendprot(struct rt2560_softc *sc, 1629178354Ssam const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) 1630178354Ssam{ 1631178354Ssam struct ieee80211com *ic = ni->ni_ic; 1632178354Ssam const struct ieee80211_frame *wh; 1633178354Ssam struct rt2560_tx_desc *desc; 1634178354Ssam struct rt2560_tx_data *data; 1635178354Ssam struct mbuf *mprot; 1636178354Ssam int protrate, ackrate, pktlen, flags, isshort, error; 1637178354Ssam uint16_t dur; 1638178354Ssam bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1639178354Ssam int nsegs; 1640178354Ssam 1641178354Ssam KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, 1642178354Ssam ("protection %d", prot)); 1643178354Ssam 1644178354Ssam wh = mtod(m, const struct ieee80211_frame *); 1645178354Ssam pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; 1646178354Ssam 1647190532Ssam protrate = ieee80211_ctl_rate(ic->ic_rt, rate); 1648190532Ssam ackrate = ieee80211_ack_rate(ic->ic_rt, rate); 1649178354Ssam 1650178354Ssam isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; 1651190532Ssam dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort) 1652190532Ssam + ieee80211_ack_duration(ic->ic_rt, rate, isshort); 1653178354Ssam flags = RT2560_TX_MORE_FRAG; 1654178354Ssam if (prot == IEEE80211_PROT_RTSCTS) { 1655178354Ssam /* NB: CTS is the same size as an ACK */ 1656190532Ssam dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); 1657178354Ssam flags |= RT2560_TX_ACK; 1658178354Ssam mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); 1659178354Ssam } else { 1660178354Ssam mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); 1661178354Ssam } 1662178354Ssam if (mprot == NULL) { 1663178354Ssam /* XXX stat + msg */ 1664178354Ssam return ENOBUFS; 1665178354Ssam } 1666178354Ssam 1667178354Ssam desc = &sc->txq.desc[sc->txq.cur_encrypt]; 1668178354Ssam data = &sc->txq.data[sc->txq.cur_encrypt]; 1669178354Ssam 1670178354Ssam error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, 1671178354Ssam mprot, segs, &nsegs, 0); 1672178354Ssam if (error != 0) { 1673178354Ssam device_printf(sc->sc_dev, 1674178354Ssam "could not map mbuf (error %d)\n", error); 1675178354Ssam m_freem(mprot); 1676178354Ssam return error; 1677178354Ssam } 1678178354Ssam 1679178354Ssam data->m = mprot; 1680178354Ssam data->ni = ieee80211_ref_node(ni); 1681178354Ssam /* ctl frames are not taken into account for amrr */ 1682178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1683178354Ssam 1684178354Ssam rt2560_setup_tx_desc(sc, desc, flags, mprot->m_pkthdr.len, protrate, 1, 1685178354Ssam segs->ds_addr); 1686178354Ssam 1687178354Ssam bus_dmamap_sync(sc->txq.data_dmat, data->map, 1688178354Ssam BUS_DMASYNC_PREWRITE); 1689178354Ssam 1690178354Ssam sc->txq.queued++; 1691178354Ssam sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; 1692178354Ssam 1693178354Ssam return 0; 1694178354Ssam} 1695178354Ssam 1696178354Ssamstatic int 1697160691Ssamrt2560_tx_raw(struct rt2560_softc *sc, struct mbuf *m0, 1698160691Ssam struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) 1699160691Ssam{ 1700192468Ssam struct ieee80211vap *vap = ni->ni_vap; 1701193073Ssam struct ieee80211com *ic = ni->ni_ic; 1702160691Ssam struct rt2560_tx_desc *desc; 1703160691Ssam struct rt2560_tx_data *data; 1704160691Ssam bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1705160691Ssam uint32_t flags; 1706160691Ssam int nsegs, rate, error; 1707160691Ssam 1708160691Ssam desc = &sc->prioq.desc[sc->prioq.cur]; 1709160691Ssam data = &sc->prioq.data[sc->prioq.cur]; 1710160691Ssam 1711193073Ssam rate = params->ibp_rate0; 1712193073Ssam if (!ieee80211_isratevalid(ic->ic_rt, rate)) { 1713178354Ssam /* XXX fall back to mcast/mgmt rate? */ 1714168860Ssephe m_freem(m0); 1715160691Ssam return EINVAL; 1716168860Ssephe } 1717160691Ssam 1718178354Ssam flags = 0; 1719178354Ssam if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) 1720178354Ssam flags |= RT2560_TX_ACK; 1721178354Ssam if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { 1722178354Ssam error = rt2560_sendprot(sc, m0, ni, 1723178354Ssam params->ibp_flags & IEEE80211_BPF_RTS ? 1724178354Ssam IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, 1725178354Ssam rate); 1726178354Ssam if (error) { 1727178354Ssam m_freem(m0); 1728178354Ssam return error; 1729178354Ssam } 1730178354Ssam flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; 1731178354Ssam } 1732178354Ssam 1733160691Ssam error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, 1734160691Ssam segs, &nsegs, 0); 1735160691Ssam if (error != 0) { 1736160691Ssam device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1737160691Ssam error); 1738160691Ssam m_freem(m0); 1739160691Ssam return error; 1740160691Ssam } 1741160691Ssam 1742192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 1743160691Ssam struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1744160691Ssam 1745160691Ssam tap->wt_flags = 0; 1746160691Ssam tap->wt_rate = rate; 1747160691Ssam tap->wt_antenna = sc->tx_ant; 1748160691Ssam 1749192468Ssam ieee80211_radiotap_tx(ni->ni_vap, m0); 1750160691Ssam } 1751160691Ssam 1752160691Ssam data->m = m0; 1753160691Ssam data->ni = ni; 1754160691Ssam 1755160691Ssam /* XXX need to setup descriptor ourself */ 1756160691Ssam rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, 1757160691Ssam rate, (params->ibp_flags & IEEE80211_BPF_CRYPTO) != 0, 1758160691Ssam segs->ds_addr); 1759160691Ssam 1760160691Ssam bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1761160691Ssam bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1762160691Ssam BUS_DMASYNC_PREWRITE); 1763160691Ssam 1764178354Ssam DPRINTFN(sc, 10, "sending raw frame len=%u idx=%u rate=%u\n", 1765178354Ssam m0->m_pkthdr.len, sc->prioq.cur, rate); 1766160691Ssam 1767160691Ssam /* kick prio */ 1768160691Ssam sc->prioq.queued++; 1769160691Ssam sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; 1770160691Ssam RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); 1771160691Ssam 1772160691Ssam return 0; 1773160691Ssam} 1774160691Ssam 1775156321Sdamienstatic int 1776156321Sdamienrt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0, 1777156321Sdamien struct ieee80211_node *ni) 1778156321Sdamien{ 1779178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1780178354Ssam struct ieee80211com *ic = ni->ni_ic; 1781156321Sdamien struct rt2560_tx_desc *desc; 1782156321Sdamien struct rt2560_tx_data *data; 1783156321Sdamien struct ieee80211_frame *wh; 1784178354Ssam const struct ieee80211_txparam *tp; 1785156321Sdamien struct ieee80211_key *k; 1786156321Sdamien struct mbuf *mnew; 1787156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1788156321Sdamien uint16_t dur; 1789178354Ssam uint32_t flags; 1790156321Sdamien int nsegs, rate, error; 1791156321Sdamien 1792156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1793156321Sdamien 1794178354Ssam tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; 1795178354Ssam if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1796178354Ssam rate = tp->mcastrate; 1797178354Ssam } else if (m0->m_flags & M_EAPOL) { 1798178354Ssam rate = tp->mgmtrate; 1799178354Ssam } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 1800178354Ssam rate = tp->ucastrate; 1801156321Sdamien } else { 1802206358Srpaulo (void) ieee80211_ratectl_rate(ni, NULL, 0); 1803178354Ssam rate = ni->ni_txrate; 1804156321Sdamien } 1805156321Sdamien 1806156321Sdamien if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1807178354Ssam k = ieee80211_crypto_encap(ni, m0); 1808156321Sdamien if (k == NULL) { 1809156321Sdamien m_freem(m0); 1810156321Sdamien return ENOBUFS; 1811156321Sdamien } 1812156321Sdamien 1813156321Sdamien /* packet header may have moved, reset our local pointer */ 1814156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1815156321Sdamien } 1816156321Sdamien 1817178354Ssam flags = 0; 1818178354Ssam if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1819178354Ssam int prot = IEEE80211_PROT_NONE; 1820178354Ssam if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) 1821178354Ssam prot = IEEE80211_PROT_RTSCTS; 1822178354Ssam else if ((ic->ic_flags & IEEE80211_F_USEPROT) && 1823190532Ssam ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) 1824178354Ssam prot = ic->ic_protmode; 1825178354Ssam if (prot != IEEE80211_PROT_NONE) { 1826178354Ssam error = rt2560_sendprot(sc, m0, ni, prot, rate); 1827178354Ssam if (error) { 1828178354Ssam m_freem(m0); 1829178354Ssam return error; 1830178354Ssam } 1831178354Ssam flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; 1832156321Sdamien } 1833156321Sdamien } 1834156321Sdamien 1835156321Sdamien data = &sc->txq.data[sc->txq.cur_encrypt]; 1836156321Sdamien desc = &sc->txq.desc[sc->txq.cur_encrypt]; 1837156321Sdamien 1838156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, m0, 1839156321Sdamien segs, &nsegs, 0); 1840156321Sdamien if (error != 0 && error != EFBIG) { 1841156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1842156321Sdamien error); 1843156321Sdamien m_freem(m0); 1844156321Sdamien return error; 1845156321Sdamien } 1846156321Sdamien if (error != 0) { 1847248078Smarius mnew = m_defrag(m0, M_NOWAIT); 1848156321Sdamien if (mnew == NULL) { 1849156321Sdamien device_printf(sc->sc_dev, 1850156321Sdamien "could not defragment mbuf\n"); 1851156321Sdamien m_freem(m0); 1852156321Sdamien return ENOBUFS; 1853156321Sdamien } 1854156321Sdamien m0 = mnew; 1855156321Sdamien 1856156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, 1857156321Sdamien m0, segs, &nsegs, 0); 1858156321Sdamien if (error != 0) { 1859156321Sdamien device_printf(sc->sc_dev, 1860156321Sdamien "could not map mbuf (error %d)\n", error); 1861156321Sdamien m_freem(m0); 1862156321Sdamien return error; 1863156321Sdamien } 1864156321Sdamien 1865156321Sdamien /* packet header may have moved, reset our local pointer */ 1866156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1867156321Sdamien } 1868156321Sdamien 1869192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 1870156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1871156321Sdamien 1872156321Sdamien tap->wt_flags = 0; 1873156321Sdamien tap->wt_rate = rate; 1874156321Sdamien tap->wt_antenna = sc->tx_ant; 1875156321Sdamien 1876192468Ssam ieee80211_radiotap_tx(vap, m0); 1877156321Sdamien } 1878156321Sdamien 1879156321Sdamien data->m = m0; 1880156321Sdamien data->ni = ni; 1881156321Sdamien 1882156321Sdamien /* remember link conditions for rate adaptation algorithm */ 1883178354Ssam if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) { 1884178354Ssam data->rix = ni->ni_txrate; 1885178354Ssam /* XXX probably need last rssi value and not avg */ 1886178354Ssam data->rssi = ic->ic_node_getrssi(ni); 1887156321Sdamien } else 1888178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1889156321Sdamien 1890156321Sdamien if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1891156321Sdamien flags |= RT2560_TX_ACK; 1892156321Sdamien 1893190532Ssam dur = ieee80211_ack_duration(ic->ic_rt, 1894178354Ssam rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); 1895156321Sdamien *(uint16_t *)wh->i_dur = htole16(dur); 1896156321Sdamien } 1897156321Sdamien 1898156321Sdamien rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 1, 1899156321Sdamien segs->ds_addr); 1900156321Sdamien 1901156321Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1902156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 1903156321Sdamien BUS_DMASYNC_PREWRITE); 1904156321Sdamien 1905178354Ssam DPRINTFN(sc, 10, "sending data frame len=%u idx=%u rate=%u\n", 1906178354Ssam m0->m_pkthdr.len, sc->txq.cur_encrypt, rate); 1907156321Sdamien 1908156321Sdamien /* kick encrypt */ 1909156321Sdamien sc->txq.queued++; 1910156321Sdamien sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; 1911156321Sdamien RAL_WRITE(sc, RT2560_SECCSR1, RT2560_KICK_ENCRYPT); 1912156321Sdamien 1913156321Sdamien return 0; 1914156321Sdamien} 1915156321Sdamien 1916156321Sdamienstatic void 1917178354Ssamrt2560_start_locked(struct ifnet *ifp) 1918156321Sdamien{ 1919156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 1920178354Ssam struct mbuf *m; 1921156321Sdamien struct ieee80211_node *ni; 1922156321Sdamien 1923178354Ssam RAL_LOCK_ASSERT(sc); 1924156321Sdamien 1925156321Sdamien for (;;) { 1926178354Ssam IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 1927178354Ssam if (m == NULL) 1928178354Ssam break; 1929178354Ssam if (sc->txq.queued >= RT2560_TX_RING_COUNT - 1) { 1930178354Ssam IFQ_DRV_PREPEND(&ifp->if_snd, m); 1931178354Ssam ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1932178354Ssam sc->sc_flags |= RT2560_F_DATA_OACTIVE; 1933178354Ssam break; 1934178354Ssam } 1935178354Ssam ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; 1936178354Ssam if (rt2560_tx_data(sc, m, ni) != 0) { 1937178354Ssam ieee80211_free_node(ni); 1938178354Ssam ifp->if_oerrors++; 1939178354Ssam break; 1940156321Sdamien } 1941156321Sdamien 1942156321Sdamien sc->sc_tx_timer = 5; 1943156321Sdamien } 1944178354Ssam} 1945156321Sdamien 1946178354Ssamstatic void 1947178354Ssamrt2560_start(struct ifnet *ifp) 1948178354Ssam{ 1949178354Ssam struct rt2560_softc *sc = ifp->if_softc; 1950178354Ssam 1951178354Ssam RAL_LOCK(sc); 1952178354Ssam rt2560_start_locked(ifp); 1953156321Sdamien RAL_UNLOCK(sc); 1954156321Sdamien} 1955156321Sdamien 1956156321Sdamienstatic void 1957165352Sbmsrt2560_watchdog(void *arg) 1958156321Sdamien{ 1959167470Ssam struct rt2560_softc *sc = arg; 1960175938Ssephe struct ifnet *ifp = sc->sc_ifp; 1961156321Sdamien 1962178354Ssam RAL_LOCK_ASSERT(sc); 1963178354Ssam 1964178354Ssam KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, ("not running")); 1965178354Ssam 1966178354Ssam if (sc->sc_invalid) /* card ejected */ 1967175938Ssephe return; 1968175938Ssephe 1969175938Ssephe rt2560_encryption_intr(sc); 1970175938Ssephe rt2560_tx_intr(sc); 1971175938Ssephe 1972178354Ssam if (sc->sc_tx_timer > 0 && --sc->sc_tx_timer == 0) { 1973178354Ssam if_printf(ifp, "device timeout\n"); 1974178354Ssam rt2560_init_locked(sc); 1975178354Ssam ifp->if_oerrors++; 1976178354Ssam /* NB: callout is reset in rt2560_init() */ 1977178354Ssam return; 1978156321Sdamien } 1979175938Ssephe callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); 1980156321Sdamien} 1981156321Sdamien 1982156321Sdamienstatic int 1983156321Sdamienrt2560_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1984156321Sdamien{ 1985156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 1986178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1987178354Ssam struct ifreq *ifr = (struct ifreq *) data; 1988178354Ssam int error = 0, startall = 0; 1989156321Sdamien 1990156321Sdamien switch (cmd) { 1991156321Sdamien case SIOCSIFFLAGS: 1992178704Sthompsa RAL_LOCK(sc); 1993156321Sdamien if (ifp->if_flags & IFF_UP) { 1994178354Ssam if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1995178354Ssam rt2560_init_locked(sc); 1996178354Ssam startall = 1; 1997178354Ssam } else 1998178354Ssam rt2560_update_promisc(ifp); 1999156321Sdamien } else { 2000156321Sdamien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2001178354Ssam rt2560_stop_locked(sc); 2002156321Sdamien } 2003178704Sthompsa RAL_UNLOCK(sc); 2004178704Sthompsa if (startall) 2005178704Sthompsa ieee80211_start_all(ic); 2006156321Sdamien break; 2007178354Ssam case SIOCGIFMEDIA: 2008178354Ssam error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); 2009178354Ssam break; 2010178704Sthompsa case SIOCGIFADDR: 2011178354Ssam error = ether_ioctl(ifp, cmd, data); 2012178354Ssam break; 2013178704Sthompsa default: 2014178704Sthompsa error = EINVAL; 2015178704Sthompsa break; 2016156321Sdamien } 2017156321Sdamien return error; 2018156321Sdamien} 2019156321Sdamien 2020156321Sdamienstatic void 2021156321Sdamienrt2560_bbp_write(struct rt2560_softc *sc, uint8_t reg, uint8_t val) 2022156321Sdamien{ 2023156321Sdamien uint32_t tmp; 2024156321Sdamien int ntries; 2025156321Sdamien 2026156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2027156321Sdamien if (!(RAL_READ(sc, RT2560_BBPCSR) & RT2560_BBP_BUSY)) 2028156321Sdamien break; 2029156321Sdamien DELAY(1); 2030156321Sdamien } 2031156321Sdamien if (ntries == 100) { 2032156321Sdamien device_printf(sc->sc_dev, "could not write to BBP\n"); 2033156321Sdamien return; 2034156321Sdamien } 2035156321Sdamien 2036156321Sdamien tmp = RT2560_BBP_WRITE | RT2560_BBP_BUSY | reg << 8 | val; 2037156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR, tmp); 2038156321Sdamien 2039178354Ssam DPRINTFN(sc, 15, "BBP R%u <- 0x%02x\n", reg, val); 2040156321Sdamien} 2041156321Sdamien 2042156321Sdamienstatic uint8_t 2043156321Sdamienrt2560_bbp_read(struct rt2560_softc *sc, uint8_t reg) 2044156321Sdamien{ 2045156321Sdamien uint32_t val; 2046156321Sdamien int ntries; 2047156321Sdamien 2048175938Ssephe for (ntries = 0; ntries < 100; ntries++) { 2049175938Ssephe if (!(RAL_READ(sc, RT2560_BBPCSR) & RT2560_BBP_BUSY)) 2050175938Ssephe break; 2051175938Ssephe DELAY(1); 2052175938Ssephe } 2053175938Ssephe if (ntries == 100) { 2054175938Ssephe device_printf(sc->sc_dev, "could not read from BBP\n"); 2055175938Ssephe return 0; 2056175938Ssephe } 2057175938Ssephe 2058156321Sdamien val = RT2560_BBP_BUSY | reg << 8; 2059156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR, val); 2060156321Sdamien 2061156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2062156321Sdamien val = RAL_READ(sc, RT2560_BBPCSR); 2063156321Sdamien if (!(val & RT2560_BBP_BUSY)) 2064156321Sdamien return val & 0xff; 2065156321Sdamien DELAY(1); 2066156321Sdamien } 2067156321Sdamien 2068156321Sdamien device_printf(sc->sc_dev, "could not read from BBP\n"); 2069156321Sdamien return 0; 2070156321Sdamien} 2071156321Sdamien 2072156321Sdamienstatic void 2073156321Sdamienrt2560_rf_write(struct rt2560_softc *sc, uint8_t reg, uint32_t val) 2074156321Sdamien{ 2075156321Sdamien uint32_t tmp; 2076156321Sdamien int ntries; 2077156321Sdamien 2078156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2079156321Sdamien if (!(RAL_READ(sc, RT2560_RFCSR) & RT2560_RF_BUSY)) 2080156321Sdamien break; 2081156321Sdamien DELAY(1); 2082156321Sdamien } 2083156321Sdamien if (ntries == 100) { 2084156321Sdamien device_printf(sc->sc_dev, "could not write to RF\n"); 2085156321Sdamien return; 2086156321Sdamien } 2087156321Sdamien 2088156321Sdamien tmp = RT2560_RF_BUSY | RT2560_RF_20BIT | (val & 0xfffff) << 2 | 2089156321Sdamien (reg & 0x3); 2090156321Sdamien RAL_WRITE(sc, RT2560_RFCSR, tmp); 2091156321Sdamien 2092156321Sdamien /* remember last written value in sc */ 2093156321Sdamien sc->rf_regs[reg] = val; 2094156321Sdamien 2095178354Ssam DPRINTFN(sc, 15, "RF R[%u] <- 0x%05x\n", reg & 0x3, val & 0xfffff); 2096156321Sdamien} 2097156321Sdamien 2098156321Sdamienstatic void 2099156321Sdamienrt2560_set_chan(struct rt2560_softc *sc, struct ieee80211_channel *c) 2100156321Sdamien{ 2101178354Ssam struct ifnet *ifp = sc->sc_ifp; 2102178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2103156321Sdamien uint8_t power, tmp; 2104156321Sdamien u_int i, chan; 2105156321Sdamien 2106156321Sdamien chan = ieee80211_chan2ieee(ic, c); 2107178354Ssam KASSERT(chan != 0 && chan != IEEE80211_CHAN_ANY, ("chan 0x%x", chan)); 2108156321Sdamien 2109156321Sdamien if (IEEE80211_IS_CHAN_2GHZ(c)) 2110156321Sdamien power = min(sc->txpow[chan - 1], 31); 2111156321Sdamien else 2112156321Sdamien power = 31; 2113156321Sdamien 2114156321Sdamien /* adjust txpower using ifconfig settings */ 2115156321Sdamien power -= (100 - ic->ic_txpowlimit) / 8; 2116156321Sdamien 2117178354Ssam DPRINTFN(sc, 2, "setting channel to %u, txpower to %u\n", chan, power); 2118156321Sdamien 2119156321Sdamien switch (sc->rf_rev) { 2120156321Sdamien case RT2560_RF_2522: 2121156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x00814); 2122156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2522_r2[chan - 1]); 2123156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2124156321Sdamien break; 2125156321Sdamien 2126156321Sdamien case RT2560_RF_2523: 2127156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08804); 2128156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2523_r2[chan - 1]); 2129156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x38044); 2130156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2131156321Sdamien break; 2132156321Sdamien 2133156321Sdamien case RT2560_RF_2524: 2134156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x0c808); 2135156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2524_r2[chan - 1]); 2136156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2137156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2138156321Sdamien break; 2139156321Sdamien 2140156321Sdamien case RT2560_RF_2525: 2141156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2142156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_hi_r2[chan - 1]); 2143156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2144156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2145156321Sdamien 2146156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2147156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_r2[chan - 1]); 2148156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2149156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2150156321Sdamien break; 2151156321Sdamien 2152156321Sdamien case RT2560_RF_2525E: 2153156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2154156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525e_r2[chan - 1]); 2155156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2156156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00286 : 0x00282); 2157156321Sdamien break; 2158156321Sdamien 2159156321Sdamien case RT2560_RF_2526: 2160156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_hi_r2[chan - 1]); 2161156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); 2162156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08804); 2163156321Sdamien 2164156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_r2[chan - 1]); 2165156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2166156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); 2167156321Sdamien break; 2168156321Sdamien 2169156321Sdamien /* dual-band RF */ 2170156321Sdamien case RT2560_RF_5222: 2171156321Sdamien for (i = 0; rt2560_rf5222[i].chan != chan; i++); 2172156321Sdamien 2173156321Sdamien rt2560_rf_write(sc, RAL_RF1, rt2560_rf5222[i].r1); 2174156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf5222[i].r2); 2175156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2176156321Sdamien rt2560_rf_write(sc, RAL_RF4, rt2560_rf5222[i].r4); 2177156321Sdamien break; 2178170530Ssam default: 2179170530Ssam printf("unknown ral rev=%d\n", sc->rf_rev); 2180156321Sdamien } 2181156321Sdamien 2182178354Ssam /* XXX */ 2183178354Ssam if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { 2184156321Sdamien /* set Japan filter bit for channel 14 */ 2185156321Sdamien tmp = rt2560_bbp_read(sc, 70); 2186156321Sdamien 2187156321Sdamien tmp &= ~RT2560_JAPAN_FILTER; 2188156321Sdamien if (chan == 14) 2189156321Sdamien tmp |= RT2560_JAPAN_FILTER; 2190156321Sdamien 2191156321Sdamien rt2560_bbp_write(sc, 70, tmp); 2192156321Sdamien 2193156321Sdamien /* clear CRC errors */ 2194156321Sdamien RAL_READ(sc, RT2560_CNT0); 2195156321Sdamien } 2196156321Sdamien} 2197156321Sdamien 2198170530Ssamstatic void 2199170530Ssamrt2560_set_channel(struct ieee80211com *ic) 2200170530Ssam{ 2201170530Ssam struct ifnet *ifp = ic->ic_ifp; 2202170530Ssam struct rt2560_softc *sc = ifp->if_softc; 2203170530Ssam 2204170530Ssam RAL_LOCK(sc); 2205170530Ssam rt2560_set_chan(sc, ic->ic_curchan); 2206170530Ssam RAL_UNLOCK(sc); 2207170530Ssam 2208170530Ssam} 2209170530Ssam 2210156321Sdamien#if 0 2211156321Sdamien/* 2212156321Sdamien * Disable RF auto-tuning. 2213156321Sdamien */ 2214156321Sdamienstatic void 2215156321Sdamienrt2560_disable_rf_tune(struct rt2560_softc *sc) 2216156321Sdamien{ 2217156321Sdamien uint32_t tmp; 2218156321Sdamien 2219156321Sdamien if (sc->rf_rev != RT2560_RF_2523) { 2220156321Sdamien tmp = sc->rf_regs[RAL_RF1] & ~RAL_RF1_AUTOTUNE; 2221156321Sdamien rt2560_rf_write(sc, RAL_RF1, tmp); 2222156321Sdamien } 2223156321Sdamien 2224156321Sdamien tmp = sc->rf_regs[RAL_RF3] & ~RAL_RF3_AUTOTUNE; 2225156321Sdamien rt2560_rf_write(sc, RAL_RF3, tmp); 2226156321Sdamien 2227178354Ssam DPRINTFN(sc, 2, "%s", "disabling RF autotune\n"); 2228156321Sdamien} 2229156321Sdamien#endif 2230156321Sdamien 2231156321Sdamien/* 2232156321Sdamien * Refer to IEEE Std 802.11-1999 pp. 123 for more information on TSF 2233156321Sdamien * synchronization. 2234156321Sdamien */ 2235156321Sdamienstatic void 2236156321Sdamienrt2560_enable_tsf_sync(struct rt2560_softc *sc) 2237156321Sdamien{ 2238178354Ssam struct ifnet *ifp = sc->sc_ifp; 2239178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2240178354Ssam struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2241156321Sdamien uint16_t logcwmin, preload; 2242156321Sdamien uint32_t tmp; 2243156321Sdamien 2244156321Sdamien /* first, disable TSF synchronization */ 2245156321Sdamien RAL_WRITE(sc, RT2560_CSR14, 0); 2246156321Sdamien 2247178354Ssam tmp = 16 * vap->iv_bss->ni_intval; 2248156321Sdamien RAL_WRITE(sc, RT2560_CSR12, tmp); 2249156321Sdamien 2250156321Sdamien RAL_WRITE(sc, RT2560_CSR13, 0); 2251156321Sdamien 2252156321Sdamien logcwmin = 5; 2253178354Ssam preload = (vap->iv_opmode == IEEE80211_M_STA) ? 384 : 1024; 2254156321Sdamien tmp = logcwmin << 16 | preload; 2255156321Sdamien RAL_WRITE(sc, RT2560_BCNOCSR, tmp); 2256156321Sdamien 2257156321Sdamien /* finally, enable TSF synchronization */ 2258156321Sdamien tmp = RT2560_ENABLE_TSF | RT2560_ENABLE_TBCN; 2259156321Sdamien if (ic->ic_opmode == IEEE80211_M_STA) 2260156321Sdamien tmp |= RT2560_ENABLE_TSF_SYNC(1); 2261156321Sdamien else 2262156321Sdamien tmp |= RT2560_ENABLE_TSF_SYNC(2) | 2263156321Sdamien RT2560_ENABLE_BEACON_GENERATOR; 2264156321Sdamien RAL_WRITE(sc, RT2560_CSR14, tmp); 2265156321Sdamien 2266178354Ssam DPRINTF(sc, "%s", "enabling TSF synchronization\n"); 2267156321Sdamien} 2268156321Sdamien 2269156321Sdamienstatic void 2270192468Ssamrt2560_enable_tsf(struct rt2560_softc *sc) 2271192468Ssam{ 2272192468Ssam RAL_WRITE(sc, RT2560_CSR14, 0); 2273192468Ssam RAL_WRITE(sc, RT2560_CSR14, 2274192468Ssam RT2560_ENABLE_TSF_SYNC(2) | RT2560_ENABLE_TSF); 2275192468Ssam} 2276192468Ssam 2277192468Ssamstatic void 2278156321Sdamienrt2560_update_plcp(struct rt2560_softc *sc) 2279156321Sdamien{ 2280178354Ssam struct ifnet *ifp = sc->sc_ifp; 2281178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2282156321Sdamien 2283156321Sdamien /* no short preamble for 1Mbps */ 2284156321Sdamien RAL_WRITE(sc, RT2560_PLCP1MCSR, 0x00700400); 2285156321Sdamien 2286156321Sdamien if (!(ic->ic_flags & IEEE80211_F_SHPREAMBLE)) { 2287156321Sdamien /* values taken from the reference driver */ 2288156321Sdamien RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380401); 2289156321Sdamien RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x00150402); 2290156321Sdamien RAL_WRITE(sc, RT2560_PLCP11MCSR, 0x000b8403); 2291156321Sdamien } else { 2292156321Sdamien /* same values as above or'ed 0x8 */ 2293156321Sdamien RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380409); 2294156321Sdamien RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x0015040a); 2295156321Sdamien RAL_WRITE(sc, RT2560_PLCP11MCSR, 0x000b840b); 2296156321Sdamien } 2297156321Sdamien 2298178354Ssam DPRINTF(sc, "updating PLCP for %s preamble\n", 2299178354Ssam (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? "short" : "long"); 2300156321Sdamien} 2301156321Sdamien 2302156321Sdamien/* 2303156321Sdamien * This function can be called by ieee80211_set_shortslottime(). Refer to 2304156321Sdamien * IEEE Std 802.11-1999 pp. 85 to know how these values are computed. 2305156321Sdamien */ 2306156321Sdamienstatic void 2307156321Sdamienrt2560_update_slot(struct ifnet *ifp) 2308156321Sdamien{ 2309156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 2310178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2311156321Sdamien uint8_t slottime; 2312156321Sdamien uint16_t tx_sifs, tx_pifs, tx_difs, eifs; 2313156321Sdamien uint32_t tmp; 2314156321Sdamien 2315175938Ssephe#ifndef FORCE_SLOTTIME 2316156321Sdamien slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; 2317175938Ssephe#else 2318175938Ssephe /* 2319175938Ssephe * Setting slot time according to "short slot time" capability 2320175938Ssephe * in beacon/probe_resp seems to cause problem to acknowledge 2321175938Ssephe * certain AP's data frames transimitted at CCK/DS rates: the 2322175938Ssephe * problematic AP keeps retransmitting data frames, probably 2323175938Ssephe * because MAC level acks are not received by hardware. 2324175938Ssephe * So we cheat a little bit here by claiming we are capable of 2325175938Ssephe * "short slot time" but setting hardware slot time to the normal 2326175938Ssephe * slot time. ral(4) does not seem to have trouble to receive 2327175938Ssephe * frames transmitted using short slot time even if hardware 2328175938Ssephe * slot time is set to normal slot time. If we didn't use this 2329175938Ssephe * trick, we would have to claim that short slot time is not 2330175938Ssephe * supported; this would give relative poor RX performance 2331175938Ssephe * (-1Mb~-2Mb lower) and the _whole_ BSS would stop using short 2332175938Ssephe * slot time. 2333175938Ssephe */ 2334175938Ssephe slottime = 20; 2335175938Ssephe#endif 2336156321Sdamien 2337156321Sdamien /* update the MAC slot boundaries */ 2338156321Sdamien tx_sifs = RAL_SIFS - RT2560_TXRX_TURNAROUND; 2339156321Sdamien tx_pifs = tx_sifs + slottime; 2340156321Sdamien tx_difs = tx_sifs + 2 * slottime; 2341156321Sdamien eifs = (ic->ic_curmode == IEEE80211_MODE_11B) ? 364 : 60; 2342156321Sdamien 2343156321Sdamien tmp = RAL_READ(sc, RT2560_CSR11); 2344156321Sdamien tmp = (tmp & ~0x1f00) | slottime << 8; 2345156321Sdamien RAL_WRITE(sc, RT2560_CSR11, tmp); 2346156321Sdamien 2347156321Sdamien tmp = tx_pifs << 16 | tx_sifs; 2348156321Sdamien RAL_WRITE(sc, RT2560_CSR18, tmp); 2349156321Sdamien 2350156321Sdamien tmp = eifs << 16 | tx_difs; 2351156321Sdamien RAL_WRITE(sc, RT2560_CSR19, tmp); 2352156321Sdamien 2353178354Ssam DPRINTF(sc, "setting slottime to %uus\n", slottime); 2354156321Sdamien} 2355156321Sdamien 2356156321Sdamienstatic void 2357220502Sbschmidtrt2560_set_basicrates(struct rt2560_softc *sc, 2358220502Sbschmidt const struct ieee80211_rateset *rs) 2359156321Sdamien{ 2360220502Sbschmidt#define RV(r) ((r) & IEEE80211_RATE_VAL) 2361178354Ssam struct ifnet *ifp = sc->sc_ifp; 2362178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2363220502Sbschmidt uint32_t mask = 0; 2364220502Sbschmidt uint8_t rate; 2365220502Sbschmidt int i; 2366156321Sdamien 2367220502Sbschmidt for (i = 0; i < rs->rs_nrates; i++) { 2368220502Sbschmidt rate = rs->rs_rates[i]; 2369220502Sbschmidt 2370220502Sbschmidt if (!(rate & IEEE80211_RATE_BASIC)) 2371220502Sbschmidt continue; 2372220502Sbschmidt 2373220502Sbschmidt mask |= 1 << ic->ic_rt->rateCodeToIndex[RV(rate)]; 2374156321Sdamien } 2375220502Sbschmidt 2376220502Sbschmidt RAL_WRITE(sc, RT2560_ARSP_PLCP_1, mask); 2377220502Sbschmidt 2378220502Sbschmidt DPRINTF(sc, "Setting basic rate mask to 0x%x\n", mask); 2379220502Sbschmidt#undef RV 2380156321Sdamien} 2381156321Sdamien 2382156321Sdamienstatic void 2383156321Sdamienrt2560_update_led(struct rt2560_softc *sc, int led1, int led2) 2384156321Sdamien{ 2385156321Sdamien uint32_t tmp; 2386156321Sdamien 2387156321Sdamien /* set ON period to 70ms and OFF period to 30ms */ 2388156321Sdamien tmp = led1 << 16 | led2 << 17 | 70 << 8 | 30; 2389156321Sdamien RAL_WRITE(sc, RT2560_LEDCSR, tmp); 2390156321Sdamien} 2391156321Sdamien 2392156321Sdamienstatic void 2393170530Ssamrt2560_set_bssid(struct rt2560_softc *sc, const uint8_t *bssid) 2394156321Sdamien{ 2395156321Sdamien uint32_t tmp; 2396156321Sdamien 2397156321Sdamien tmp = bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24; 2398156321Sdamien RAL_WRITE(sc, RT2560_CSR5, tmp); 2399156321Sdamien 2400156321Sdamien tmp = bssid[4] | bssid[5] << 8; 2401156321Sdamien RAL_WRITE(sc, RT2560_CSR6, tmp); 2402156321Sdamien 2403178354Ssam DPRINTF(sc, "setting BSSID to %6D\n", bssid, ":"); 2404156321Sdamien} 2405156321Sdamien 2406156321Sdamienstatic void 2407156321Sdamienrt2560_set_macaddr(struct rt2560_softc *sc, uint8_t *addr) 2408156321Sdamien{ 2409156321Sdamien uint32_t tmp; 2410156321Sdamien 2411156321Sdamien tmp = addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24; 2412156321Sdamien RAL_WRITE(sc, RT2560_CSR3, tmp); 2413156321Sdamien 2414156321Sdamien tmp = addr[4] | addr[5] << 8; 2415156321Sdamien RAL_WRITE(sc, RT2560_CSR4, tmp); 2416156321Sdamien 2417178354Ssam DPRINTF(sc, "setting MAC address to %6D\n", addr, ":"); 2418156321Sdamien} 2419156321Sdamien 2420156321Sdamienstatic void 2421156321Sdamienrt2560_get_macaddr(struct rt2560_softc *sc, uint8_t *addr) 2422156321Sdamien{ 2423156321Sdamien uint32_t tmp; 2424156321Sdamien 2425156321Sdamien tmp = RAL_READ(sc, RT2560_CSR3); 2426156321Sdamien addr[0] = tmp & 0xff; 2427156321Sdamien addr[1] = (tmp >> 8) & 0xff; 2428156321Sdamien addr[2] = (tmp >> 16) & 0xff; 2429156321Sdamien addr[3] = (tmp >> 24); 2430156321Sdamien 2431156321Sdamien tmp = RAL_READ(sc, RT2560_CSR4); 2432156321Sdamien addr[4] = tmp & 0xff; 2433156321Sdamien addr[5] = (tmp >> 8) & 0xff; 2434156321Sdamien} 2435156321Sdamien 2436156321Sdamienstatic void 2437178354Ssamrt2560_update_promisc(struct ifnet *ifp) 2438156321Sdamien{ 2439178354Ssam struct rt2560_softc *sc = ifp->if_softc; 2440156321Sdamien uint32_t tmp; 2441156321Sdamien 2442156321Sdamien tmp = RAL_READ(sc, RT2560_RXCSR0); 2443156321Sdamien 2444156321Sdamien tmp &= ~RT2560_DROP_NOT_TO_ME; 2445156321Sdamien if (!(ifp->if_flags & IFF_PROMISC)) 2446156321Sdamien tmp |= RT2560_DROP_NOT_TO_ME; 2447156321Sdamien 2448156321Sdamien RAL_WRITE(sc, RT2560_RXCSR0, tmp); 2449156321Sdamien 2450178354Ssam DPRINTF(sc, "%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ? 2451178354Ssam "entering" : "leaving"); 2452156321Sdamien} 2453156321Sdamien 2454156321Sdamienstatic const char * 2455156321Sdamienrt2560_get_rf(int rev) 2456156321Sdamien{ 2457156321Sdamien switch (rev) { 2458156321Sdamien case RT2560_RF_2522: return "RT2522"; 2459156321Sdamien case RT2560_RF_2523: return "RT2523"; 2460156321Sdamien case RT2560_RF_2524: return "RT2524"; 2461156321Sdamien case RT2560_RF_2525: return "RT2525"; 2462156321Sdamien case RT2560_RF_2525E: return "RT2525e"; 2463156321Sdamien case RT2560_RF_2526: return "RT2526"; 2464156321Sdamien case RT2560_RF_5222: return "RT5222"; 2465156321Sdamien default: return "unknown"; 2466156321Sdamien } 2467156321Sdamien} 2468156321Sdamien 2469156321Sdamienstatic void 2470175938Ssephert2560_read_config(struct rt2560_softc *sc) 2471156321Sdamien{ 2472156321Sdamien uint16_t val; 2473156321Sdamien int i; 2474156321Sdamien 2475156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_CONFIG0); 2476156321Sdamien sc->rf_rev = (val >> 11) & 0x7; 2477156321Sdamien sc->hw_radio = (val >> 10) & 0x1; 2478156321Sdamien sc->led_mode = (val >> 6) & 0x7; 2479156321Sdamien sc->rx_ant = (val >> 4) & 0x3; 2480156321Sdamien sc->tx_ant = (val >> 2) & 0x3; 2481156321Sdamien sc->nb_ant = val & 0x3; 2482156321Sdamien 2483156321Sdamien /* read default values for BBP registers */ 2484156321Sdamien for (i = 0; i < 16; i++) { 2485156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_BBP_BASE + i); 2486175938Ssephe if (val == 0 || val == 0xffff) 2487175938Ssephe continue; 2488175938Ssephe 2489156321Sdamien sc->bbp_prom[i].reg = val >> 8; 2490156321Sdamien sc->bbp_prom[i].val = val & 0xff; 2491156321Sdamien } 2492156321Sdamien 2493156321Sdamien /* read Tx power for all b/g channels */ 2494156321Sdamien for (i = 0; i < 14 / 2; i++) { 2495156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_TXPOWER + i); 2496175938Ssephe sc->txpow[i * 2] = val & 0xff; 2497175938Ssephe sc->txpow[i * 2 + 1] = val >> 8; 2498156321Sdamien } 2499175938Ssephe for (i = 0; i < 14; ++i) { 2500175938Ssephe if (sc->txpow[i] > 31) 2501175938Ssephe sc->txpow[i] = 24; 2502175938Ssephe } 2503170530Ssam 2504170530Ssam val = rt2560_eeprom_read(sc, RT2560_EEPROM_CALIBRATE); 2505170530Ssam if ((val & 0xff) == 0xff) 2506170530Ssam sc->rssi_corr = RT2560_DEFAULT_RSSI_CORR; 2507170530Ssam else 2508170530Ssam sc->rssi_corr = val & 0xff; 2509178354Ssam DPRINTF(sc, "rssi correction %d, calibrate 0x%02x\n", 2510178354Ssam sc->rssi_corr, val); 2511156321Sdamien} 2512156321Sdamien 2513170530Ssam 2514170530Ssamstatic void 2515170530Ssamrt2560_scan_start(struct ieee80211com *ic) 2516170530Ssam{ 2517170530Ssam struct ifnet *ifp = ic->ic_ifp; 2518170530Ssam struct rt2560_softc *sc = ifp->if_softc; 2519170530Ssam 2520170530Ssam /* abort TSF synchronization */ 2521170530Ssam RAL_WRITE(sc, RT2560_CSR14, 0); 2522170530Ssam rt2560_set_bssid(sc, ifp->if_broadcastaddr); 2523170530Ssam} 2524170530Ssam 2525170530Ssamstatic void 2526170530Ssamrt2560_scan_end(struct ieee80211com *ic) 2527170530Ssam{ 2528170530Ssam struct ifnet *ifp = ic->ic_ifp; 2529170530Ssam struct rt2560_softc *sc = ifp->if_softc; 2530178354Ssam struct ieee80211vap *vap = ic->ic_scan->ss_vap; 2531170530Ssam 2532170530Ssam rt2560_enable_tsf_sync(sc); 2533170530Ssam /* XXX keep local copy */ 2534178354Ssam rt2560_set_bssid(sc, vap->iv_bss->ni_bssid); 2535170530Ssam} 2536170530Ssam 2537156321Sdamienstatic int 2538156321Sdamienrt2560_bbp_init(struct rt2560_softc *sc) 2539156321Sdamien{ 2540156321Sdamien#define N(a) (sizeof (a) / sizeof ((a)[0])) 2541156321Sdamien int i, ntries; 2542156321Sdamien 2543156321Sdamien /* wait for BBP to be ready */ 2544156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2545156321Sdamien if (rt2560_bbp_read(sc, RT2560_BBP_VERSION) != 0) 2546156321Sdamien break; 2547156321Sdamien DELAY(1); 2548156321Sdamien } 2549156321Sdamien if (ntries == 100) { 2550156321Sdamien device_printf(sc->sc_dev, "timeout waiting for BBP\n"); 2551156321Sdamien return EIO; 2552156321Sdamien } 2553156321Sdamien 2554156321Sdamien /* initialize BBP registers to default values */ 2555156321Sdamien for (i = 0; i < N(rt2560_def_bbp); i++) { 2556156321Sdamien rt2560_bbp_write(sc, rt2560_def_bbp[i].reg, 2557156321Sdamien rt2560_def_bbp[i].val); 2558156321Sdamien } 2559175938Ssephe 2560156321Sdamien /* initialize BBP registers to values stored in EEPROM */ 2561156321Sdamien for (i = 0; i < 16; i++) { 2562175938Ssephe if (sc->bbp_prom[i].reg == 0 && sc->bbp_prom[i].val == 0) 2563175938Ssephe break; 2564156321Sdamien rt2560_bbp_write(sc, sc->bbp_prom[i].reg, sc->bbp_prom[i].val); 2565156321Sdamien } 2566175938Ssephe rt2560_bbp_write(sc, 17, 0x48); /* XXX restore bbp17 */ 2567156321Sdamien 2568156321Sdamien return 0; 2569156321Sdamien#undef N 2570156321Sdamien} 2571156321Sdamien 2572156321Sdamienstatic void 2573156321Sdamienrt2560_set_txantenna(struct rt2560_softc *sc, int antenna) 2574156321Sdamien{ 2575156321Sdamien uint32_t tmp; 2576156321Sdamien uint8_t tx; 2577156321Sdamien 2578156321Sdamien tx = rt2560_bbp_read(sc, RT2560_BBP_TX) & ~RT2560_BBP_ANTMASK; 2579156321Sdamien if (antenna == 1) 2580156321Sdamien tx |= RT2560_BBP_ANTA; 2581156321Sdamien else if (antenna == 2) 2582156321Sdamien tx |= RT2560_BBP_ANTB; 2583156321Sdamien else 2584156321Sdamien tx |= RT2560_BBP_DIVERSITY; 2585156321Sdamien 2586156321Sdamien /* need to force I/Q flip for RF 2525e, 2526 and 5222 */ 2587156321Sdamien if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526 || 2588156321Sdamien sc->rf_rev == RT2560_RF_5222) 2589156321Sdamien tx |= RT2560_BBP_FLIPIQ; 2590156321Sdamien 2591156321Sdamien rt2560_bbp_write(sc, RT2560_BBP_TX, tx); 2592156321Sdamien 2593156321Sdamien /* update values for CCK and OFDM in BBPCSR1 */ 2594156321Sdamien tmp = RAL_READ(sc, RT2560_BBPCSR1) & ~0x00070007; 2595156321Sdamien tmp |= (tx & 0x7) << 16 | (tx & 0x7); 2596156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR1, tmp); 2597156321Sdamien} 2598156321Sdamien 2599156321Sdamienstatic void 2600156321Sdamienrt2560_set_rxantenna(struct rt2560_softc *sc, int antenna) 2601156321Sdamien{ 2602156321Sdamien uint8_t rx; 2603156321Sdamien 2604156321Sdamien rx = rt2560_bbp_read(sc, RT2560_BBP_RX) & ~RT2560_BBP_ANTMASK; 2605156321Sdamien if (antenna == 1) 2606156321Sdamien rx |= RT2560_BBP_ANTA; 2607156321Sdamien else if (antenna == 2) 2608156321Sdamien rx |= RT2560_BBP_ANTB; 2609156321Sdamien else 2610156321Sdamien rx |= RT2560_BBP_DIVERSITY; 2611156321Sdamien 2612156321Sdamien /* need to force no I/Q flip for RF 2525e and 2526 */ 2613156321Sdamien if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526) 2614156321Sdamien rx &= ~RT2560_BBP_FLIPIQ; 2615156321Sdamien 2616156321Sdamien rt2560_bbp_write(sc, RT2560_BBP_RX, rx); 2617156321Sdamien} 2618156321Sdamien 2619156321Sdamienstatic void 2620178354Ssamrt2560_init_locked(struct rt2560_softc *sc) 2621156321Sdamien{ 2622156321Sdamien#define N(a) (sizeof (a) / sizeof ((a)[0])) 2623178354Ssam struct ifnet *ifp = sc->sc_ifp; 2624178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2625156321Sdamien uint32_t tmp; 2626156321Sdamien int i; 2627156321Sdamien 2628178354Ssam RAL_LOCK_ASSERT(sc); 2629156975Sdamien 2630178354Ssam rt2560_stop_locked(sc); 2631170530Ssam 2632156321Sdamien /* setup tx rings */ 2633156321Sdamien tmp = RT2560_PRIO_RING_COUNT << 24 | 2634156321Sdamien RT2560_ATIM_RING_COUNT << 16 | 2635156321Sdamien RT2560_TX_RING_COUNT << 8 | 2636156321Sdamien RT2560_TX_DESC_SIZE; 2637156321Sdamien 2638156321Sdamien /* rings must be initialized in this exact order */ 2639156321Sdamien RAL_WRITE(sc, RT2560_TXCSR2, tmp); 2640156321Sdamien RAL_WRITE(sc, RT2560_TXCSR3, sc->txq.physaddr); 2641156321Sdamien RAL_WRITE(sc, RT2560_TXCSR5, sc->prioq.physaddr); 2642156321Sdamien RAL_WRITE(sc, RT2560_TXCSR4, sc->atimq.physaddr); 2643156321Sdamien RAL_WRITE(sc, RT2560_TXCSR6, sc->bcnq.physaddr); 2644156321Sdamien 2645156321Sdamien /* setup rx ring */ 2646156321Sdamien tmp = RT2560_RX_RING_COUNT << 8 | RT2560_RX_DESC_SIZE; 2647156321Sdamien 2648156321Sdamien RAL_WRITE(sc, RT2560_RXCSR1, tmp); 2649156321Sdamien RAL_WRITE(sc, RT2560_RXCSR2, sc->rxq.physaddr); 2650156321Sdamien 2651156321Sdamien /* initialize MAC registers to default values */ 2652156321Sdamien for (i = 0; i < N(rt2560_def_mac); i++) 2653156321Sdamien RAL_WRITE(sc, rt2560_def_mac[i].reg, rt2560_def_mac[i].val); 2654156321Sdamien 2655190526Ssam rt2560_set_macaddr(sc, IF_LLADDR(ifp)); 2656156321Sdamien 2657156321Sdamien /* set basic rate set (will be updated later) */ 2658156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x153); 2659156321Sdamien 2660156321Sdamien rt2560_update_slot(ifp); 2661156321Sdamien rt2560_update_plcp(sc); 2662156321Sdamien rt2560_update_led(sc, 0, 0); 2663156321Sdamien 2664156321Sdamien RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 2665156321Sdamien RAL_WRITE(sc, RT2560_CSR1, RT2560_HOST_READY); 2666156321Sdamien 2667156321Sdamien if (rt2560_bbp_init(sc) != 0) { 2668213268Sjhb rt2560_stop_locked(sc); 2669156321Sdamien return; 2670156321Sdamien } 2671156321Sdamien 2672175938Ssephe rt2560_set_txantenna(sc, sc->tx_ant); 2673175938Ssephe rt2560_set_rxantenna(sc, sc->rx_ant); 2674175938Ssephe 2675156321Sdamien /* set default BSS channel */ 2676156321Sdamien rt2560_set_chan(sc, ic->ic_curchan); 2677156321Sdamien 2678156321Sdamien /* kick Rx */ 2679156321Sdamien tmp = RT2560_DROP_PHY_ERROR | RT2560_DROP_CRC_ERROR; 2680156321Sdamien if (ic->ic_opmode != IEEE80211_M_MONITOR) { 2681156321Sdamien tmp |= RT2560_DROP_CTL | RT2560_DROP_VERSION_ERROR; 2682195618Srpaulo if (ic->ic_opmode != IEEE80211_M_HOSTAP && 2683195618Srpaulo ic->ic_opmode != IEEE80211_M_MBSS) 2684156321Sdamien tmp |= RT2560_DROP_TODS; 2685156321Sdamien if (!(ifp->if_flags & IFF_PROMISC)) 2686156321Sdamien tmp |= RT2560_DROP_NOT_TO_ME; 2687156321Sdamien } 2688156321Sdamien RAL_WRITE(sc, RT2560_RXCSR0, tmp); 2689156321Sdamien 2690156321Sdamien /* clear old FCS and Rx FIFO errors */ 2691156321Sdamien RAL_READ(sc, RT2560_CNT0); 2692156321Sdamien RAL_READ(sc, RT2560_CNT4); 2693156321Sdamien 2694156321Sdamien /* clear any pending interrupts */ 2695156321Sdamien RAL_WRITE(sc, RT2560_CSR7, 0xffffffff); 2696156321Sdamien 2697156321Sdamien /* enable interrupts */ 2698156321Sdamien RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); 2699156321Sdamien 2700156321Sdamien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2701156321Sdamien ifp->if_drv_flags |= IFF_DRV_RUNNING; 2702156321Sdamien 2703175938Ssephe callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); 2704178354Ssam#undef N 2705178354Ssam} 2706175938Ssephe 2707178354Ssamstatic void 2708178354Ssamrt2560_init(void *priv) 2709178354Ssam{ 2710178354Ssam struct rt2560_softc *sc = priv; 2711178354Ssam struct ifnet *ifp = sc->sc_ifp; 2712178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2713156975Sdamien 2714178354Ssam RAL_LOCK(sc); 2715178354Ssam rt2560_init_locked(sc); 2716156975Sdamien RAL_UNLOCK(sc); 2717178354Ssam 2718178931Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2719178931Sthompsa ieee80211_start_all(ic); /* start all vap's */ 2720156321Sdamien} 2721156321Sdamien 2722178354Ssamstatic void 2723178354Ssamrt2560_stop_locked(struct rt2560_softc *sc) 2724156321Sdamien{ 2725178354Ssam struct ifnet *ifp = sc->sc_ifp; 2726170530Ssam volatile int *flags = &sc->sc_flags; 2727156321Sdamien 2728178354Ssam RAL_LOCK_ASSERT(sc); 2729156321Sdamien 2730178354Ssam while (*flags & RT2560_F_INPUT_RUNNING) 2731178354Ssam msleep(sc, &sc->sc_mtx, 0, "ralrunning", hz/10); 2732175938Ssephe 2733175938Ssephe callout_stop(&sc->watchdog_ch); 2734178354Ssam sc->sc_tx_timer = 0; 2735175938Ssephe 2736170530Ssam if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 2737170530Ssam ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2738156975Sdamien 2739170530Ssam /* abort Tx */ 2740170530Ssam RAL_WRITE(sc, RT2560_TXCSR0, RT2560_ABORT_TX); 2741170530Ssam 2742170530Ssam /* disable Rx */ 2743170530Ssam RAL_WRITE(sc, RT2560_RXCSR0, RT2560_DISABLE_RX); 2744156321Sdamien 2745170530Ssam /* reset ASIC (imply reset BBP) */ 2746170530Ssam RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 2747170530Ssam RAL_WRITE(sc, RT2560_CSR1, 0); 2748156321Sdamien 2749170530Ssam /* disable interrupts */ 2750170530Ssam RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 2751170530Ssam 2752170530Ssam /* reset Tx and Rx rings */ 2753170530Ssam rt2560_reset_tx_ring(sc, &sc->txq); 2754170530Ssam rt2560_reset_tx_ring(sc, &sc->atimq); 2755170530Ssam rt2560_reset_tx_ring(sc, &sc->prioq); 2756170530Ssam rt2560_reset_tx_ring(sc, &sc->bcnq); 2757170530Ssam rt2560_reset_rx_ring(sc, &sc->rxq); 2758170530Ssam } 2759175938Ssephe sc->sc_flags &= ~(RT2560_F_PRIO_OACTIVE | RT2560_F_DATA_OACTIVE); 2760178354Ssam} 2761175938Ssephe 2762178354Ssamvoid 2763178354Ssamrt2560_stop(void *arg) 2764178354Ssam{ 2765178354Ssam struct rt2560_softc *sc = arg; 2766178354Ssam 2767178354Ssam RAL_LOCK(sc); 2768178354Ssam rt2560_stop_locked(sc); 2769170530Ssam RAL_UNLOCK(sc); 2770156321Sdamien} 2771160691Ssam 2772160691Ssamstatic int 2773160691Ssamrt2560_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 2774160691Ssam const struct ieee80211_bpf_params *params) 2775160691Ssam{ 2776160691Ssam struct ieee80211com *ic = ni->ni_ic; 2777160691Ssam struct ifnet *ifp = ic->ic_ifp; 2778160691Ssam struct rt2560_softc *sc = ifp->if_softc; 2779160691Ssam 2780160691Ssam RAL_LOCK(sc); 2781160691Ssam 2782160691Ssam /* prevent management frames from being sent if we're not ready */ 2783160691Ssam if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2784160691Ssam RAL_UNLOCK(sc); 2785168860Ssephe m_freem(m); 2786168860Ssephe ieee80211_free_node(ni); 2787160691Ssam return ENETDOWN; 2788160691Ssam } 2789160691Ssam if (sc->prioq.queued >= RT2560_PRIO_RING_COUNT) { 2790160691Ssam ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2791178354Ssam sc->sc_flags |= RT2560_F_PRIO_OACTIVE; 2792160691Ssam RAL_UNLOCK(sc); 2793168860Ssephe m_freem(m); 2794168860Ssephe ieee80211_free_node(ni); 2795160691Ssam return ENOBUFS; /* XXX */ 2796160691Ssam } 2797160691Ssam 2798160691Ssam ifp->if_opackets++; 2799160691Ssam 2800160691Ssam if (params == NULL) { 2801160691Ssam /* 2802160691Ssam * Legacy path; interpret frame contents to decide 2803160691Ssam * precisely how to send the frame. 2804160691Ssam */ 2805160691Ssam if (rt2560_tx_mgt(sc, m, ni) != 0) 2806160691Ssam goto bad; 2807160691Ssam } else { 2808160691Ssam /* 2809160691Ssam * Caller supplied explicit parameters to use in 2810160691Ssam * sending the frame. 2811160691Ssam */ 2812160691Ssam if (rt2560_tx_raw(sc, m, ni, params)) 2813160691Ssam goto bad; 2814160691Ssam } 2815160691Ssam sc->sc_tx_timer = 5; 2816160691Ssam 2817160691Ssam RAL_UNLOCK(sc); 2818160691Ssam 2819160691Ssam return 0; 2820160691Ssambad: 2821160691Ssam ifp->if_oerrors++; 2822160905Ssam ieee80211_free_node(ni); 2823160691Ssam RAL_UNLOCK(sc); 2824160691Ssam return EIO; /* XXX */ 2825160691Ssam} 2826