rt2560.c revision 192468
1156321Sdamien/* $FreeBSD: head/sys/dev/ral/rt2560.c 192468 2009-05-20 20:00:40Z sam $ */ 2156321Sdamien 3156321Sdamien/*- 4156321Sdamien * Copyright (c) 2005, 2006 5156321Sdamien * Damien Bergamini <damien.bergamini@free.fr> 6156321Sdamien * 7156321Sdamien * Permission to use, copy, modify, and distribute this software for any 8156321Sdamien * purpose with or without fee is hereby granted, provided that the above 9156321Sdamien * copyright notice and this permission notice appear in all copies. 10156321Sdamien * 11156321Sdamien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12156321Sdamien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13156321Sdamien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14156321Sdamien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15156321Sdamien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16156321Sdamien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17156321Sdamien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18156321Sdamien */ 19156321Sdamien 20156321Sdamien#include <sys/cdefs.h> 21156321Sdamien__FBSDID("$FreeBSD: head/sys/dev/ral/rt2560.c 192468 2009-05-20 20:00:40Z sam $"); 22156321Sdamien 23156321Sdamien/*- 24156321Sdamien * Ralink Technology RT2560 chipset driver 25156321Sdamien * http://www.ralinktech.com/ 26156321Sdamien */ 27156321Sdamien 28156321Sdamien#include <sys/param.h> 29156321Sdamien#include <sys/sysctl.h> 30156321Sdamien#include <sys/sockio.h> 31156321Sdamien#include <sys/mbuf.h> 32156321Sdamien#include <sys/kernel.h> 33156321Sdamien#include <sys/socket.h> 34156321Sdamien#include <sys/systm.h> 35156321Sdamien#include <sys/malloc.h> 36164982Skevlo#include <sys/lock.h> 37164982Skevlo#include <sys/mutex.h> 38156321Sdamien#include <sys/module.h> 39156321Sdamien#include <sys/bus.h> 40156321Sdamien#include <sys/endian.h> 41156321Sdamien 42156321Sdamien#include <machine/bus.h> 43156321Sdamien#include <machine/resource.h> 44156321Sdamien#include <sys/rman.h> 45156321Sdamien 46156321Sdamien#include <net/bpf.h> 47156321Sdamien#include <net/if.h> 48156321Sdamien#include <net/if_arp.h> 49156321Sdamien#include <net/ethernet.h> 50156321Sdamien#include <net/if_dl.h> 51156321Sdamien#include <net/if_media.h> 52156321Sdamien#include <net/if_types.h> 53156321Sdamien 54156321Sdamien#include <net80211/ieee80211_var.h> 55156321Sdamien#include <net80211/ieee80211_radiotap.h> 56170530Ssam#include <net80211/ieee80211_regdomain.h> 57178354Ssam#include <net80211/ieee80211_amrr.h> 58156321Sdamien 59156321Sdamien#include <netinet/in.h> 60156321Sdamien#include <netinet/in_systm.h> 61156321Sdamien#include <netinet/in_var.h> 62156321Sdamien#include <netinet/ip.h> 63156321Sdamien#include <netinet/if_ether.h> 64156321Sdamien 65156327Ssilby#include <dev/ral/rt2560reg.h> 66156327Ssilby#include <dev/ral/rt2560var.h> 67156321Sdamien 68170530Ssam#define RT2560_RSSI(sc, rssi) \ 69170530Ssam ((rssi) > (RT2560_NOISE_FLOOR + (sc)->rssi_corr) ? \ 70170530Ssam ((rssi) - RT2560_NOISE_FLOOR - (sc)->rssi_corr) : 0) 71170530Ssam 72178354Ssam#define RAL_DEBUG 73156321Sdamien#ifdef RAL_DEBUG 74178354Ssam#define DPRINTF(sc, fmt, ...) do { \ 75178354Ssam if (sc->sc_debug > 0) \ 76178354Ssam printf(fmt, __VA_ARGS__); \ 77178354Ssam} while (0) 78178354Ssam#define DPRINTFN(sc, n, fmt, ...) do { \ 79178354Ssam if (sc->sc_debug >= (n)) \ 80178354Ssam printf(fmt, __VA_ARGS__); \ 81178354Ssam} while (0) 82156321Sdamien#else 83178354Ssam#define DPRINTF(sc, fmt, ...) 84178354Ssam#define DPRINTFN(sc, n, fmt, ...) 85156321Sdamien#endif 86156321Sdamien 87178354Ssamstatic struct ieee80211vap *rt2560_vap_create(struct ieee80211com *, 88178354Ssam const char name[IFNAMSIZ], int unit, int opmode, 89178354Ssam int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], 90178354Ssam const uint8_t mac[IEEE80211_ADDR_LEN]); 91178354Ssamstatic void rt2560_vap_delete(struct ieee80211vap *); 92156321Sdamienstatic void rt2560_dma_map_addr(void *, bus_dma_segment_t *, int, 93156321Sdamien int); 94156321Sdamienstatic int rt2560_alloc_tx_ring(struct rt2560_softc *, 95156321Sdamien struct rt2560_tx_ring *, int); 96156321Sdamienstatic void rt2560_reset_tx_ring(struct rt2560_softc *, 97156321Sdamien struct rt2560_tx_ring *); 98156321Sdamienstatic void rt2560_free_tx_ring(struct rt2560_softc *, 99156321Sdamien struct rt2560_tx_ring *); 100156321Sdamienstatic int rt2560_alloc_rx_ring(struct rt2560_softc *, 101156321Sdamien struct rt2560_rx_ring *, int); 102156321Sdamienstatic void rt2560_reset_rx_ring(struct rt2560_softc *, 103156321Sdamien struct rt2560_rx_ring *); 104156321Sdamienstatic void rt2560_free_rx_ring(struct rt2560_softc *, 105156321Sdamien struct rt2560_rx_ring *); 106179643Ssamstatic struct ieee80211_node *rt2560_node_alloc(struct ieee80211vap *, 107179643Ssam const uint8_t [IEEE80211_ADDR_LEN]); 108178354Ssamstatic void rt2560_newassoc(struct ieee80211_node *, int); 109178354Ssamstatic int rt2560_newstate(struct ieee80211vap *, 110156321Sdamien enum ieee80211_state, int); 111156321Sdamienstatic uint16_t rt2560_eeprom_read(struct rt2560_softc *, uint8_t); 112156321Sdamienstatic void rt2560_encryption_intr(struct rt2560_softc *); 113156321Sdamienstatic void rt2560_tx_intr(struct rt2560_softc *); 114156321Sdamienstatic void rt2560_prio_intr(struct rt2560_softc *); 115156321Sdamienstatic void rt2560_decryption_intr(struct rt2560_softc *); 116156321Sdamienstatic void rt2560_rx_intr(struct rt2560_softc *); 117178354Ssamstatic void rt2560_beacon_update(struct ieee80211vap *, int item); 118156321Sdamienstatic void rt2560_beacon_expire(struct rt2560_softc *); 119156321Sdamienstatic void rt2560_wakeup_expire(struct rt2560_softc *); 120170530Ssamstatic void rt2560_scan_start(struct ieee80211com *); 121170530Ssamstatic void rt2560_scan_end(struct ieee80211com *); 122170530Ssamstatic void rt2560_set_channel(struct ieee80211com *); 123156321Sdamienstatic void rt2560_setup_tx_desc(struct rt2560_softc *, 124156321Sdamien struct rt2560_tx_desc *, uint32_t, int, int, int, 125156321Sdamien bus_addr_t); 126156321Sdamienstatic int rt2560_tx_bcn(struct rt2560_softc *, struct mbuf *, 127156321Sdamien struct ieee80211_node *); 128156321Sdamienstatic int rt2560_tx_mgt(struct rt2560_softc *, struct mbuf *, 129156321Sdamien struct ieee80211_node *); 130156321Sdamienstatic int rt2560_tx_data(struct rt2560_softc *, struct mbuf *, 131156321Sdamien struct ieee80211_node *); 132178354Ssamstatic void rt2560_start_locked(struct ifnet *); 133156321Sdamienstatic void rt2560_start(struct ifnet *); 134165352Sbmsstatic void rt2560_watchdog(void *); 135156321Sdamienstatic int rt2560_ioctl(struct ifnet *, u_long, caddr_t); 136156321Sdamienstatic void rt2560_bbp_write(struct rt2560_softc *, uint8_t, 137156321Sdamien uint8_t); 138156321Sdamienstatic uint8_t rt2560_bbp_read(struct rt2560_softc *, uint8_t); 139156321Sdamienstatic void rt2560_rf_write(struct rt2560_softc *, uint8_t, 140156321Sdamien uint32_t); 141156321Sdamienstatic void rt2560_set_chan(struct rt2560_softc *, 142156321Sdamien struct ieee80211_channel *); 143156321Sdamien#if 0 144156321Sdamienstatic void rt2560_disable_rf_tune(struct rt2560_softc *); 145156321Sdamien#endif 146156321Sdamienstatic void rt2560_enable_tsf_sync(struct rt2560_softc *); 147192468Ssamstatic void rt2560_enable_tsf(struct rt2560_softc *); 148156321Sdamienstatic void rt2560_update_plcp(struct rt2560_softc *); 149156321Sdamienstatic void rt2560_update_slot(struct ifnet *); 150156321Sdamienstatic void rt2560_set_basicrates(struct rt2560_softc *); 151156321Sdamienstatic void rt2560_update_led(struct rt2560_softc *, int, int); 152170530Ssamstatic void rt2560_set_bssid(struct rt2560_softc *, const uint8_t *); 153156321Sdamienstatic void rt2560_set_macaddr(struct rt2560_softc *, uint8_t *); 154156321Sdamienstatic void rt2560_get_macaddr(struct rt2560_softc *, uint8_t *); 155178354Ssamstatic void rt2560_update_promisc(struct ifnet *); 156156321Sdamienstatic const char *rt2560_get_rf(int); 157175938Ssephestatic void rt2560_read_config(struct rt2560_softc *); 158156321Sdamienstatic int rt2560_bbp_init(struct rt2560_softc *); 159156321Sdamienstatic void rt2560_set_txantenna(struct rt2560_softc *, int); 160156321Sdamienstatic void rt2560_set_rxantenna(struct rt2560_softc *, int); 161178354Ssamstatic void rt2560_init_locked(struct rt2560_softc *); 162156321Sdamienstatic void rt2560_init(void *); 163178354Ssamstatic void rt2560_stop_locked(struct rt2560_softc *); 164160691Ssamstatic int rt2560_raw_xmit(struct ieee80211_node *, struct mbuf *, 165160691Ssam const struct ieee80211_bpf_params *); 166156321Sdamien 167156321Sdamienstatic const struct { 168156321Sdamien uint32_t reg; 169156321Sdamien uint32_t val; 170156321Sdamien} rt2560_def_mac[] = { 171156321Sdamien RT2560_DEF_MAC 172156321Sdamien}; 173156321Sdamien 174156321Sdamienstatic const struct { 175156321Sdamien uint8_t reg; 176156321Sdamien uint8_t val; 177156321Sdamien} rt2560_def_bbp[] = { 178156321Sdamien RT2560_DEF_BBP 179156321Sdamien}; 180156321Sdamien 181156321Sdamienstatic const uint32_t rt2560_rf2522_r2[] = RT2560_RF2522_R2; 182156321Sdamienstatic const uint32_t rt2560_rf2523_r2[] = RT2560_RF2523_R2; 183156321Sdamienstatic const uint32_t rt2560_rf2524_r2[] = RT2560_RF2524_R2; 184156321Sdamienstatic const uint32_t rt2560_rf2525_r2[] = RT2560_RF2525_R2; 185156321Sdamienstatic const uint32_t rt2560_rf2525_hi_r2[] = RT2560_RF2525_HI_R2; 186156321Sdamienstatic const uint32_t rt2560_rf2525e_r2[] = RT2560_RF2525E_R2; 187156321Sdamienstatic const uint32_t rt2560_rf2526_r2[] = RT2560_RF2526_R2; 188156321Sdamienstatic const uint32_t rt2560_rf2526_hi_r2[] = RT2560_RF2526_HI_R2; 189156321Sdamien 190156321Sdamienstatic const struct { 191156321Sdamien uint8_t chan; 192156321Sdamien uint32_t r1, r2, r4; 193156321Sdamien} rt2560_rf5222[] = { 194156321Sdamien RT2560_RF5222 195156321Sdamien}; 196156321Sdamien 197156321Sdamienint 198156321Sdamienrt2560_attach(device_t dev, int id) 199156321Sdamien{ 200156321Sdamien struct rt2560_softc *sc = device_get_softc(dev); 201178354Ssam struct ieee80211com *ic; 202156321Sdamien struct ifnet *ifp; 203178354Ssam int error; 204178354Ssam uint8_t bands; 205190526Ssam uint8_t macaddr[IEEE80211_ADDR_LEN]; 206156321Sdamien 207156321Sdamien sc->sc_dev = dev; 208156321Sdamien 209156321Sdamien mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 210156321Sdamien MTX_DEF | MTX_RECURSE); 211156321Sdamien 212165352Sbms callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0); 213156321Sdamien 214156321Sdamien /* retrieve RT2560 rev. no */ 215156321Sdamien sc->asic_rev = RAL_READ(sc, RT2560_CSR0); 216156321Sdamien 217156321Sdamien /* retrieve RF rev. no and various other things from EEPROM */ 218175938Ssephe rt2560_read_config(sc); 219156321Sdamien 220156321Sdamien device_printf(dev, "MAC/BBP RT2560 (rev 0x%02x), RF %s\n", 221156321Sdamien sc->asic_rev, rt2560_get_rf(sc->rf_rev)); 222156321Sdamien 223156321Sdamien /* 224156321Sdamien * Allocate Tx and Rx rings. 225156321Sdamien */ 226156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->txq, RT2560_TX_RING_COUNT); 227156321Sdamien if (error != 0) { 228156321Sdamien device_printf(sc->sc_dev, "could not allocate Tx ring\n"); 229156321Sdamien goto fail1; 230156321Sdamien } 231156321Sdamien 232156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->atimq, RT2560_ATIM_RING_COUNT); 233156321Sdamien if (error != 0) { 234156321Sdamien device_printf(sc->sc_dev, "could not allocate ATIM ring\n"); 235156321Sdamien goto fail2; 236156321Sdamien } 237156321Sdamien 238156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->prioq, RT2560_PRIO_RING_COUNT); 239156321Sdamien if (error != 0) { 240156321Sdamien device_printf(sc->sc_dev, "could not allocate Prio ring\n"); 241156321Sdamien goto fail3; 242156321Sdamien } 243156321Sdamien 244156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->bcnq, RT2560_BEACON_RING_COUNT); 245156321Sdamien if (error != 0) { 246156321Sdamien device_printf(sc->sc_dev, "could not allocate Beacon ring\n"); 247156321Sdamien goto fail4; 248156321Sdamien } 249156321Sdamien 250156321Sdamien error = rt2560_alloc_rx_ring(sc, &sc->rxq, RT2560_RX_RING_COUNT); 251156321Sdamien if (error != 0) { 252156321Sdamien device_printf(sc->sc_dev, "could not allocate Rx ring\n"); 253156321Sdamien goto fail5; 254156321Sdamien } 255156321Sdamien 256178354Ssam ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); 257156321Sdamien if (ifp == NULL) { 258156321Sdamien device_printf(sc->sc_dev, "can not if_alloc()\n"); 259156321Sdamien goto fail6; 260156321Sdamien } 261178354Ssam ic = ifp->if_l2com; 262156321Sdamien 263178354Ssam /* retrieve MAC address */ 264190526Ssam rt2560_get_macaddr(sc, macaddr); 265178354Ssam 266156321Sdamien ifp->if_softc = sc; 267156321Sdamien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 268156321Sdamien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 269156321Sdamien ifp->if_init = rt2560_init; 270156321Sdamien ifp->if_ioctl = rt2560_ioctl; 271156321Sdamien ifp->if_start = rt2560_start; 272156321Sdamien IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 273156321Sdamien ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 274156321Sdamien IFQ_SET_READY(&ifp->if_snd); 275156321Sdamien 276156321Sdamien ic->ic_ifp = ifp; 277178354Ssam ic->ic_opmode = IEEE80211_M_STA; 278156321Sdamien ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 279156321Sdamien 280156321Sdamien /* set device capabilities */ 281156321Sdamien ic->ic_caps = 282178957Ssam IEEE80211_C_STA /* station mode */ 283178957Ssam | IEEE80211_C_IBSS /* ibss, nee adhoc, mode */ 284178354Ssam | IEEE80211_C_HOSTAP /* hostap mode */ 285178354Ssam | IEEE80211_C_MONITOR /* monitor mode */ 286178354Ssam | IEEE80211_C_AHDEMO /* adhoc demo mode */ 287178354Ssam | IEEE80211_C_WDS /* 4-address traffic works */ 288178354Ssam | IEEE80211_C_SHPREAMBLE /* short preamble supported */ 289178354Ssam | IEEE80211_C_SHSLOT /* short slot time supported */ 290178354Ssam | IEEE80211_C_WPA /* capable of WPA1+WPA2 */ 291178354Ssam | IEEE80211_C_BGSCAN /* capable of bg scanning */ 292178354Ssam#ifdef notyet 293178354Ssam | IEEE80211_C_TXFRAG /* handle tx frags */ 294178354Ssam#endif 295178354Ssam ; 296156321Sdamien 297170530Ssam bands = 0; 298170530Ssam setbit(&bands, IEEE80211_MODE_11B); 299170530Ssam setbit(&bands, IEEE80211_MODE_11G); 300170530Ssam if (sc->rf_rev == RT2560_RF_5222) 301170530Ssam setbit(&bands, IEEE80211_MODE_11A); 302178354Ssam ieee80211_init_channels(ic, NULL, &bands); 303156321Sdamien 304190526Ssam ieee80211_ifattach(ic, macaddr); 305178354Ssam ic->ic_newassoc = rt2560_newassoc; 306178354Ssam ic->ic_raw_xmit = rt2560_raw_xmit; 307178354Ssam ic->ic_updateslot = rt2560_update_slot; 308178354Ssam ic->ic_update_promisc = rt2560_update_promisc; 309178354Ssam ic->ic_node_alloc = rt2560_node_alloc; 310170530Ssam ic->ic_scan_start = rt2560_scan_start; 311170530Ssam ic->ic_scan_end = rt2560_scan_end; 312170530Ssam ic->ic_set_channel = rt2560_set_channel; 313156321Sdamien 314178354Ssam ic->ic_vap_create = rt2560_vap_create; 315178354Ssam ic->ic_vap_delete = rt2560_vap_delete; 316156321Sdamien 317192468Ssam ieee80211_radiotap_attach(ic, 318192468Ssam &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), 319192468Ssam RT2560_TX_RADIOTAP_PRESENT, 320192468Ssam &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 321192468Ssam RT2560_RX_RADIOTAP_PRESENT); 322156321Sdamien 323156321Sdamien /* 324156321Sdamien * Add a few sysctl knobs. 325156321Sdamien */ 326178354Ssam#ifdef RAL_DEBUG 327156321Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 328156321Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 329178354Ssam "debug", CTLFLAG_RW, &sc->sc_debug, 0, "debug msgs"); 330178354Ssam#endif 331178354Ssam SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 332178354Ssam SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 333156321Sdamien "txantenna", CTLFLAG_RW, &sc->tx_ant, 0, "tx antenna (0=auto)"); 334156321Sdamien 335156321Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 336156321Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 337156321Sdamien "rxantenna", CTLFLAG_RW, &sc->rx_ant, 0, "rx antenna (0=auto)"); 338156321Sdamien 339156321Sdamien if (bootverbose) 340156321Sdamien ieee80211_announce(ic); 341156321Sdamien 342156321Sdamien return 0; 343156321Sdamien 344156321Sdamienfail6: rt2560_free_rx_ring(sc, &sc->rxq); 345156321Sdamienfail5: rt2560_free_tx_ring(sc, &sc->bcnq); 346156321Sdamienfail4: rt2560_free_tx_ring(sc, &sc->prioq); 347156321Sdamienfail3: rt2560_free_tx_ring(sc, &sc->atimq); 348156321Sdamienfail2: rt2560_free_tx_ring(sc, &sc->txq); 349156321Sdamienfail1: mtx_destroy(&sc->sc_mtx); 350156321Sdamien 351156321Sdamien return ENXIO; 352156321Sdamien} 353156321Sdamien 354156321Sdamienint 355156321Sdamienrt2560_detach(void *xsc) 356156321Sdamien{ 357156321Sdamien struct rt2560_softc *sc = xsc; 358178354Ssam struct ifnet *ifp = sc->sc_ifp; 359178354Ssam struct ieee80211com *ic = ifp->if_l2com; 360170530Ssam 361156321Sdamien rt2560_stop(sc); 362156321Sdamien 363156321Sdamien ieee80211_ifdetach(ic); 364156321Sdamien 365156321Sdamien rt2560_free_tx_ring(sc, &sc->txq); 366156321Sdamien rt2560_free_tx_ring(sc, &sc->atimq); 367156321Sdamien rt2560_free_tx_ring(sc, &sc->prioq); 368156321Sdamien rt2560_free_tx_ring(sc, &sc->bcnq); 369156321Sdamien rt2560_free_rx_ring(sc, &sc->rxq); 370156321Sdamien 371156321Sdamien if_free(ifp); 372156321Sdamien 373156321Sdamien mtx_destroy(&sc->sc_mtx); 374156321Sdamien 375156321Sdamien return 0; 376156321Sdamien} 377156321Sdamien 378178354Ssamstatic struct ieee80211vap * 379178354Ssamrt2560_vap_create(struct ieee80211com *ic, 380178354Ssam const char name[IFNAMSIZ], int unit, int opmode, int flags, 381178354Ssam const uint8_t bssid[IEEE80211_ADDR_LEN], 382178354Ssam const uint8_t mac[IEEE80211_ADDR_LEN]) 383178354Ssam{ 384178354Ssam struct ifnet *ifp = ic->ic_ifp; 385178354Ssam struct rt2560_vap *rvp; 386178354Ssam struct ieee80211vap *vap; 387178354Ssam 388178354Ssam switch (opmode) { 389178354Ssam case IEEE80211_M_STA: 390178354Ssam case IEEE80211_M_IBSS: 391178354Ssam case IEEE80211_M_AHDEMO: 392178354Ssam case IEEE80211_M_MONITOR: 393178354Ssam case IEEE80211_M_HOSTAP: 394178354Ssam if (!TAILQ_EMPTY(&ic->ic_vaps)) { 395178354Ssam if_printf(ifp, "only 1 vap supported\n"); 396178354Ssam return NULL; 397178354Ssam } 398178354Ssam if (opmode == IEEE80211_M_STA) 399178354Ssam flags |= IEEE80211_CLONE_NOBEACONS; 400178354Ssam break; 401178354Ssam case IEEE80211_M_WDS: 402178354Ssam if (TAILQ_EMPTY(&ic->ic_vaps) || 403178354Ssam ic->ic_opmode != IEEE80211_M_HOSTAP) { 404178354Ssam if_printf(ifp, "wds only supported in ap mode\n"); 405178354Ssam return NULL; 406178354Ssam } 407178354Ssam /* 408178354Ssam * Silently remove any request for a unique 409178354Ssam * bssid; WDS vap's always share the local 410178354Ssam * mac address. 411178354Ssam */ 412178354Ssam flags &= ~IEEE80211_CLONE_BSSID; 413178354Ssam break; 414178354Ssam default: 415178354Ssam if_printf(ifp, "unknown opmode %d\n", opmode); 416178354Ssam return NULL; 417178354Ssam } 418178354Ssam rvp = (struct rt2560_vap *) malloc(sizeof(struct rt2560_vap), 419178354Ssam M_80211_VAP, M_NOWAIT | M_ZERO); 420178354Ssam if (rvp == NULL) 421178354Ssam return NULL; 422178354Ssam vap = &rvp->ral_vap; 423178354Ssam ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); 424178354Ssam 425178354Ssam /* override state transition machine */ 426178354Ssam rvp->ral_newstate = vap->iv_newstate; 427178354Ssam vap->iv_newstate = rt2560_newstate; 428178354Ssam vap->iv_update_beacon = rt2560_beacon_update; 429178354Ssam 430178354Ssam ieee80211_amrr_init(&rvp->amrr, vap, 431178354Ssam IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, 432178354Ssam IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD, 433178354Ssam 500 /* ms */); 434178354Ssam 435178354Ssam /* complete setup */ 436178354Ssam ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); 437178354Ssam if (TAILQ_FIRST(&ic->ic_vaps) == vap) 438178354Ssam ic->ic_opmode = opmode; 439178354Ssam return vap; 440178354Ssam} 441178354Ssam 442178354Ssamstatic void 443178354Ssamrt2560_vap_delete(struct ieee80211vap *vap) 444178354Ssam{ 445178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 446178354Ssam 447178354Ssam ieee80211_amrr_cleanup(&rvp->amrr); 448178354Ssam ieee80211_vap_detach(vap); 449178354Ssam free(rvp, M_80211_VAP); 450178354Ssam} 451178354Ssam 452156321Sdamienvoid 453156321Sdamienrt2560_resume(void *xsc) 454156321Sdamien{ 455156321Sdamien struct rt2560_softc *sc = xsc; 456178354Ssam struct ifnet *ifp = sc->sc_ifp; 457156321Sdamien 458178354Ssam if (ifp->if_flags & IFF_UP) 459178354Ssam rt2560_init(sc); 460156321Sdamien} 461156321Sdamien 462156321Sdamienstatic void 463156321Sdamienrt2560_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 464156321Sdamien{ 465156321Sdamien if (error != 0) 466156321Sdamien return; 467156321Sdamien 468156321Sdamien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 469156321Sdamien 470156321Sdamien *(bus_addr_t *)arg = segs[0].ds_addr; 471156321Sdamien} 472156321Sdamien 473156321Sdamienstatic int 474156321Sdamienrt2560_alloc_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring, 475156321Sdamien int count) 476156321Sdamien{ 477156321Sdamien int i, error; 478156321Sdamien 479156321Sdamien ring->count = count; 480156321Sdamien ring->queued = 0; 481156321Sdamien ring->cur = ring->next = 0; 482156321Sdamien ring->cur_encrypt = ring->next_encrypt = 0; 483156321Sdamien 484171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 4, 0, 485171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 486171535Skevlo count * RT2560_TX_DESC_SIZE, 1, count * RT2560_TX_DESC_SIZE, 487171535Skevlo 0, NULL, NULL, &ring->desc_dmat); 488156321Sdamien if (error != 0) { 489156321Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 490156321Sdamien goto fail; 491156321Sdamien } 492156321Sdamien 493156321Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 494156321Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 495156321Sdamien if (error != 0) { 496156321Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 497156321Sdamien goto fail; 498156321Sdamien } 499156321Sdamien 500156321Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 501156321Sdamien count * RT2560_TX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr, 502156321Sdamien 0); 503156321Sdamien if (error != 0) { 504156321Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 505156321Sdamien goto fail; 506156321Sdamien } 507156321Sdamien 508156321Sdamien ring->data = malloc(count * sizeof (struct rt2560_tx_data), M_DEVBUF, 509156321Sdamien M_NOWAIT | M_ZERO); 510156321Sdamien if (ring->data == NULL) { 511156321Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 512156321Sdamien error = ENOMEM; 513156321Sdamien goto fail; 514156321Sdamien } 515156321Sdamien 516171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 517171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 518171535Skevlo MCLBYTES, RT2560_MAX_SCATTER, MCLBYTES, 0, NULL, NULL, 519171535Skevlo &ring->data_dmat); 520156321Sdamien if (error != 0) { 521156321Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 522156321Sdamien goto fail; 523156321Sdamien } 524156321Sdamien 525156321Sdamien for (i = 0; i < count; i++) { 526156321Sdamien error = bus_dmamap_create(ring->data_dmat, 0, 527156321Sdamien &ring->data[i].map); 528156321Sdamien if (error != 0) { 529156321Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 530156321Sdamien goto fail; 531156321Sdamien } 532156321Sdamien } 533156321Sdamien 534156321Sdamien return 0; 535156321Sdamien 536156321Sdamienfail: rt2560_free_tx_ring(sc, ring); 537156321Sdamien return error; 538156321Sdamien} 539156321Sdamien 540156321Sdamienstatic void 541156321Sdamienrt2560_reset_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) 542156321Sdamien{ 543156321Sdamien struct rt2560_tx_desc *desc; 544156321Sdamien struct rt2560_tx_data *data; 545156321Sdamien int i; 546156321Sdamien 547156321Sdamien for (i = 0; i < ring->count; i++) { 548156321Sdamien desc = &ring->desc[i]; 549156321Sdamien data = &ring->data[i]; 550156321Sdamien 551156321Sdamien if (data->m != NULL) { 552156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 553156321Sdamien BUS_DMASYNC_POSTWRITE); 554156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 555156321Sdamien m_freem(data->m); 556156321Sdamien data->m = NULL; 557156321Sdamien } 558156321Sdamien 559156321Sdamien if (data->ni != NULL) { 560156321Sdamien ieee80211_free_node(data->ni); 561156321Sdamien data->ni = NULL; 562156321Sdamien } 563156321Sdamien 564156321Sdamien desc->flags = 0; 565156321Sdamien } 566156321Sdamien 567156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 568156321Sdamien 569156321Sdamien ring->queued = 0; 570156321Sdamien ring->cur = ring->next = 0; 571156321Sdamien ring->cur_encrypt = ring->next_encrypt = 0; 572156321Sdamien} 573156321Sdamien 574156321Sdamienstatic void 575156321Sdamienrt2560_free_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) 576156321Sdamien{ 577156321Sdamien struct rt2560_tx_data *data; 578156321Sdamien int i; 579156321Sdamien 580156321Sdamien if (ring->desc != NULL) { 581156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 582156321Sdamien BUS_DMASYNC_POSTWRITE); 583156321Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 584156321Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 585156321Sdamien } 586156321Sdamien 587156321Sdamien if (ring->desc_dmat != NULL) 588156321Sdamien bus_dma_tag_destroy(ring->desc_dmat); 589156321Sdamien 590156321Sdamien if (ring->data != NULL) { 591156321Sdamien for (i = 0; i < ring->count; i++) { 592156321Sdamien data = &ring->data[i]; 593156321Sdamien 594156321Sdamien if (data->m != NULL) { 595156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 596156321Sdamien BUS_DMASYNC_POSTWRITE); 597156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 598156321Sdamien m_freem(data->m); 599156321Sdamien } 600156321Sdamien 601156321Sdamien if (data->ni != NULL) 602156321Sdamien ieee80211_free_node(data->ni); 603156321Sdamien 604156321Sdamien if (data->map != NULL) 605156321Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 606156321Sdamien } 607156321Sdamien 608156321Sdamien free(ring->data, M_DEVBUF); 609156321Sdamien } 610156321Sdamien 611156321Sdamien if (ring->data_dmat != NULL) 612156321Sdamien bus_dma_tag_destroy(ring->data_dmat); 613156321Sdamien} 614156321Sdamien 615156321Sdamienstatic int 616156321Sdamienrt2560_alloc_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring, 617156321Sdamien int count) 618156321Sdamien{ 619156321Sdamien struct rt2560_rx_desc *desc; 620156321Sdamien struct rt2560_rx_data *data; 621156321Sdamien bus_addr_t physaddr; 622156321Sdamien int i, error; 623156321Sdamien 624156321Sdamien ring->count = count; 625156321Sdamien ring->cur = ring->next = 0; 626156321Sdamien ring->cur_decrypt = 0; 627156321Sdamien 628171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 4, 0, 629171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 630171535Skevlo count * RT2560_RX_DESC_SIZE, 1, count * RT2560_RX_DESC_SIZE, 631171535Skevlo 0, NULL, NULL, &ring->desc_dmat); 632156321Sdamien if (error != 0) { 633156321Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 634156321Sdamien goto fail; 635156321Sdamien } 636156321Sdamien 637156321Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 638156321Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 639156321Sdamien if (error != 0) { 640156321Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 641156321Sdamien goto fail; 642156321Sdamien } 643156321Sdamien 644156321Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 645156321Sdamien count * RT2560_RX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr, 646156321Sdamien 0); 647156321Sdamien if (error != 0) { 648156321Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 649156321Sdamien goto fail; 650156321Sdamien } 651156321Sdamien 652156321Sdamien ring->data = malloc(count * sizeof (struct rt2560_rx_data), M_DEVBUF, 653156321Sdamien M_NOWAIT | M_ZERO); 654156321Sdamien if (ring->data == NULL) { 655156321Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 656156321Sdamien error = ENOMEM; 657156321Sdamien goto fail; 658156321Sdamien } 659156321Sdamien 660156321Sdamien /* 661156321Sdamien * Pre-allocate Rx buffers and populate Rx ring. 662156321Sdamien */ 663171535Skevlo error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 664171535Skevlo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 665171535Skevlo 1, MCLBYTES, 0, NULL, NULL, &ring->data_dmat); 666156321Sdamien if (error != 0) { 667156321Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 668156321Sdamien goto fail; 669156321Sdamien } 670156321Sdamien 671156321Sdamien for (i = 0; i < count; i++) { 672156321Sdamien desc = &sc->rxq.desc[i]; 673156321Sdamien data = &sc->rxq.data[i]; 674156321Sdamien 675156321Sdamien error = bus_dmamap_create(ring->data_dmat, 0, &data->map); 676156321Sdamien if (error != 0) { 677156321Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 678156321Sdamien goto fail; 679156321Sdamien } 680156321Sdamien 681156321Sdamien data->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 682156321Sdamien if (data->m == NULL) { 683156321Sdamien device_printf(sc->sc_dev, 684156321Sdamien "could not allocate rx mbuf\n"); 685156321Sdamien error = ENOMEM; 686156321Sdamien goto fail; 687156321Sdamien } 688156321Sdamien 689156321Sdamien error = bus_dmamap_load(ring->data_dmat, data->map, 690156321Sdamien mtod(data->m, void *), MCLBYTES, rt2560_dma_map_addr, 691156321Sdamien &physaddr, 0); 692156321Sdamien if (error != 0) { 693156321Sdamien device_printf(sc->sc_dev, 694156321Sdamien "could not load rx buf DMA map"); 695156321Sdamien goto fail; 696156321Sdamien } 697156321Sdamien 698156321Sdamien desc->flags = htole32(RT2560_RX_BUSY); 699156321Sdamien desc->physaddr = htole32(physaddr); 700156321Sdamien } 701156321Sdamien 702156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 703156321Sdamien 704156321Sdamien return 0; 705156321Sdamien 706156321Sdamienfail: rt2560_free_rx_ring(sc, ring); 707156321Sdamien return error; 708156321Sdamien} 709156321Sdamien 710156321Sdamienstatic void 711156321Sdamienrt2560_reset_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) 712156321Sdamien{ 713156321Sdamien int i; 714156321Sdamien 715156321Sdamien for (i = 0; i < ring->count; i++) { 716156321Sdamien ring->desc[i].flags = htole32(RT2560_RX_BUSY); 717156321Sdamien ring->data[i].drop = 0; 718156321Sdamien } 719156321Sdamien 720156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 721156321Sdamien 722156321Sdamien ring->cur = ring->next = 0; 723156321Sdamien ring->cur_decrypt = 0; 724156321Sdamien} 725156321Sdamien 726156321Sdamienstatic void 727156321Sdamienrt2560_free_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) 728156321Sdamien{ 729156321Sdamien struct rt2560_rx_data *data; 730156321Sdamien int i; 731156321Sdamien 732156321Sdamien if (ring->desc != NULL) { 733156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 734156321Sdamien BUS_DMASYNC_POSTWRITE); 735156321Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 736156321Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 737156321Sdamien } 738156321Sdamien 739156321Sdamien if (ring->desc_dmat != NULL) 740156321Sdamien bus_dma_tag_destroy(ring->desc_dmat); 741156321Sdamien 742156321Sdamien if (ring->data != NULL) { 743156321Sdamien for (i = 0; i < ring->count; i++) { 744156321Sdamien data = &ring->data[i]; 745156321Sdamien 746156321Sdamien if (data->m != NULL) { 747156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 748156321Sdamien BUS_DMASYNC_POSTREAD); 749156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 750156321Sdamien m_freem(data->m); 751156321Sdamien } 752156321Sdamien 753156321Sdamien if (data->map != NULL) 754156321Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 755156321Sdamien } 756156321Sdamien 757156321Sdamien free(ring->data, M_DEVBUF); 758156321Sdamien } 759156321Sdamien 760156321Sdamien if (ring->data_dmat != NULL) 761156321Sdamien bus_dma_tag_destroy(ring->data_dmat); 762156321Sdamien} 763156321Sdamien 764156321Sdamienstatic struct ieee80211_node * 765179643Ssamrt2560_node_alloc(struct ieee80211vap *vap, 766179643Ssam const uint8_t mac[IEEE80211_ADDR_LEN]) 767156321Sdamien{ 768156321Sdamien struct rt2560_node *rn; 769156321Sdamien 770156321Sdamien rn = malloc(sizeof (struct rt2560_node), M_80211_NODE, 771156321Sdamien M_NOWAIT | M_ZERO); 772156321Sdamien 773156321Sdamien return (rn != NULL) ? &rn->ni : NULL; 774156321Sdamien} 775156321Sdamien 776156321Sdamienstatic void 777178354Ssamrt2560_newassoc(struct ieee80211_node *ni, int isnew) 778156321Sdamien{ 779178354Ssam struct ieee80211vap *vap = ni->ni_vap; 780156321Sdamien 781178354Ssam ieee80211_amrr_node_init(&RT2560_VAP(vap)->amrr, 782178354Ssam &RT2560_NODE(ni)->amrr, ni); 783156321Sdamien} 784156321Sdamien 785156321Sdamienstatic int 786178354Ssamrt2560_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 787156321Sdamien{ 788178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 789178354Ssam struct ifnet *ifp = vap->iv_ic->ic_ifp; 790178354Ssam struct rt2560_softc *sc = ifp->if_softc; 791178354Ssam int error; 792156321Sdamien 793178354Ssam if (nstate == IEEE80211_S_INIT && vap->iv_state == IEEE80211_S_RUN) { 794178354Ssam /* abort TSF synchronization */ 795178354Ssam RAL_WRITE(sc, RT2560_CSR14, 0); 796156321Sdamien 797178354Ssam /* turn association led off */ 798178354Ssam rt2560_update_led(sc, 0, 0); 799178354Ssam } 800156321Sdamien 801178354Ssam error = rvp->ral_newstate(vap, nstate, arg); 802156321Sdamien 803178354Ssam if (error == 0 && nstate == IEEE80211_S_RUN) { 804178354Ssam struct ieee80211_node *ni = vap->iv_bss; 805178354Ssam struct mbuf *m; 806156321Sdamien 807178354Ssam if (vap->iv_opmode != IEEE80211_M_MONITOR) { 808156321Sdamien rt2560_update_plcp(sc); 809156321Sdamien rt2560_set_basicrates(sc); 810156321Sdamien rt2560_set_bssid(sc, ni->ni_bssid); 811156321Sdamien } 812156321Sdamien 813178354Ssam if (vap->iv_opmode == IEEE80211_M_HOSTAP || 814178354Ssam vap->iv_opmode == IEEE80211_M_IBSS) { 815178354Ssam m = ieee80211_beacon_alloc(ni, &rvp->ral_bo); 816156321Sdamien if (m == NULL) { 817178354Ssam if_printf(ifp, "could not allocate beacon\n"); 818178354Ssam return ENOBUFS; 819156321Sdamien } 820156321Sdamien ieee80211_ref_node(ni); 821156321Sdamien error = rt2560_tx_bcn(sc, m, ni); 822156321Sdamien if (error != 0) 823178354Ssam return error; 824156321Sdamien } 825156321Sdamien 826156321Sdamien /* turn assocation led on */ 827156321Sdamien rt2560_update_led(sc, 1, 0); 828156321Sdamien 829184345Ssam if (vap->iv_opmode != IEEE80211_M_MONITOR) 830156321Sdamien rt2560_enable_tsf_sync(sc); 831192468Ssam else 832192468Ssam rt2560_enable_tsf(sc); 833156321Sdamien } 834178354Ssam return error; 835156321Sdamien} 836156321Sdamien 837156321Sdamien/* 838156321Sdamien * Read 16 bits at address 'addr' from the serial EEPROM (either 93C46 or 839156321Sdamien * 93C66). 840156321Sdamien */ 841156321Sdamienstatic uint16_t 842156321Sdamienrt2560_eeprom_read(struct rt2560_softc *sc, uint8_t addr) 843156321Sdamien{ 844156321Sdamien uint32_t tmp; 845156321Sdamien uint16_t val; 846156321Sdamien int n; 847156321Sdamien 848156321Sdamien /* clock C once before the first command */ 849156321Sdamien RT2560_EEPROM_CTL(sc, 0); 850156321Sdamien 851156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 852156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 853156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 854156321Sdamien 855156321Sdamien /* write start bit (1) */ 856156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D); 857156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C); 858156321Sdamien 859156321Sdamien /* write READ opcode (10) */ 860156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D); 861156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C); 862156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 863156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 864156321Sdamien 865156321Sdamien /* write address (A5-A0 or A7-A0) */ 866156321Sdamien n = (RAL_READ(sc, RT2560_CSR21) & RT2560_93C46) ? 5 : 7; 867156321Sdamien for (; n >= 0; n--) { 868156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | 869156321Sdamien (((addr >> n) & 1) << RT2560_SHIFT_D)); 870156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | 871156321Sdamien (((addr >> n) & 1) << RT2560_SHIFT_D) | RT2560_C); 872156321Sdamien } 873156321Sdamien 874156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 875156321Sdamien 876156321Sdamien /* read data Q15-Q0 */ 877156321Sdamien val = 0; 878156321Sdamien for (n = 15; n >= 0; n--) { 879156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 880156321Sdamien tmp = RAL_READ(sc, RT2560_CSR21); 881156321Sdamien val |= ((tmp & RT2560_Q) >> RT2560_SHIFT_Q) << n; 882156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 883156321Sdamien } 884156321Sdamien 885156321Sdamien RT2560_EEPROM_CTL(sc, 0); 886156321Sdamien 887156321Sdamien /* clear Chip Select and clock C */ 888156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 889156321Sdamien RT2560_EEPROM_CTL(sc, 0); 890156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_C); 891156321Sdamien 892156321Sdamien return val; 893156321Sdamien} 894156321Sdamien 895156321Sdamien/* 896156321Sdamien * Some frames were processed by the hardware cipher engine and are ready for 897156321Sdamien * transmission. 898156321Sdamien */ 899156321Sdamienstatic void 900156321Sdamienrt2560_encryption_intr(struct rt2560_softc *sc) 901156321Sdamien{ 902156321Sdamien struct rt2560_tx_desc *desc; 903156321Sdamien int hw; 904156321Sdamien 905156321Sdamien /* retrieve last descriptor index processed by cipher engine */ 906156321Sdamien hw = RAL_READ(sc, RT2560_SECCSR1) - sc->txq.physaddr; 907156321Sdamien hw /= RT2560_TX_DESC_SIZE; 908156321Sdamien 909156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 910156321Sdamien BUS_DMASYNC_POSTREAD); 911156321Sdamien 912175938Ssephe while (sc->txq.next_encrypt != hw) { 913175938Ssephe if (sc->txq.next_encrypt == sc->txq.cur_encrypt) { 914175938Ssephe printf("hw encrypt %d, cur_encrypt %d\n", hw, 915175938Ssephe sc->txq.cur_encrypt); 916175938Ssephe break; 917175938Ssephe } 918175938Ssephe 919156321Sdamien desc = &sc->txq.desc[sc->txq.next_encrypt]; 920156321Sdamien 921156321Sdamien if ((le32toh(desc->flags) & RT2560_TX_BUSY) || 922156321Sdamien (le32toh(desc->flags) & RT2560_TX_CIPHER_BUSY)) 923156321Sdamien break; 924156321Sdamien 925156321Sdamien /* for TKIP, swap eiv field to fix a bug in ASIC */ 926156321Sdamien if ((le32toh(desc->flags) & RT2560_TX_CIPHER_MASK) == 927156321Sdamien RT2560_TX_CIPHER_TKIP) 928156321Sdamien desc->eiv = bswap32(desc->eiv); 929156321Sdamien 930156321Sdamien /* mark the frame ready for transmission */ 931175938Ssephe desc->flags |= htole32(RT2560_TX_VALID); 932175938Ssephe desc->flags |= htole32(RT2560_TX_BUSY); 933156321Sdamien 934178354Ssam DPRINTFN(sc, 15, "encryption done idx=%u\n", 935178354Ssam sc->txq.next_encrypt); 936156321Sdamien 937156321Sdamien sc->txq.next_encrypt = 938156321Sdamien (sc->txq.next_encrypt + 1) % RT2560_TX_RING_COUNT; 939156321Sdamien } 940156321Sdamien 941156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 942156321Sdamien BUS_DMASYNC_PREWRITE); 943156321Sdamien 944156321Sdamien /* kick Tx */ 945156321Sdamien RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_TX); 946156321Sdamien} 947156321Sdamien 948156321Sdamienstatic void 949156321Sdamienrt2560_tx_intr(struct rt2560_softc *sc) 950156321Sdamien{ 951178354Ssam struct ifnet *ifp = sc->sc_ifp; 952156321Sdamien struct rt2560_tx_desc *desc; 953156321Sdamien struct rt2560_tx_data *data; 954156321Sdamien struct rt2560_node *rn; 955178354Ssam struct mbuf *m; 956178354Ssam uint32_t flags; 957178354Ssam int retrycnt; 958156321Sdamien 959156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 960156321Sdamien BUS_DMASYNC_POSTREAD); 961156321Sdamien 962156321Sdamien for (;;) { 963156321Sdamien desc = &sc->txq.desc[sc->txq.next]; 964156321Sdamien data = &sc->txq.data[sc->txq.next]; 965156321Sdamien 966178354Ssam flags = le32toh(desc->flags); 967178354Ssam if ((flags & RT2560_TX_BUSY) || 968178354Ssam (flags & RT2560_TX_CIPHER_BUSY) || 969178354Ssam !(flags & RT2560_TX_VALID)) 970156321Sdamien break; 971156321Sdamien 972156321Sdamien rn = (struct rt2560_node *)data->ni; 973178354Ssam m = data->m; 974156321Sdamien 975178354Ssam switch (flags & RT2560_TX_RESULT_MASK) { 976156321Sdamien case RT2560_TX_SUCCESS: 977178354Ssam DPRINTFN(sc, 10, "%s\n", "data frame sent successfully"); 978178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 979178354Ssam ieee80211_amrr_tx_complete(&rn->amrr, 980178354Ssam IEEE80211_AMRR_SUCCESS, 0); 981156321Sdamien ifp->if_opackets++; 982156321Sdamien break; 983156321Sdamien 984156321Sdamien case RT2560_TX_SUCCESS_RETRY: 985178354Ssam retrycnt = RT2560_TX_RETRYCNT(flags); 986178354Ssam 987178354Ssam DPRINTFN(sc, 9, "data frame sent after %u retries\n", 988178354Ssam retrycnt); 989178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 990178354Ssam ieee80211_amrr_tx_complete(&rn->amrr, 991178354Ssam IEEE80211_AMRR_SUCCESS, retrycnt); 992156321Sdamien ifp->if_opackets++; 993156321Sdamien break; 994156321Sdamien 995156321Sdamien case RT2560_TX_FAIL_RETRY: 996178354Ssam retrycnt = RT2560_TX_RETRYCNT(flags); 997178354Ssam 998178354Ssam DPRINTFN(sc, 9, "data frame failed after %d retries\n", 999178354Ssam retrycnt); 1000178354Ssam if (data->rix != IEEE80211_FIXED_RATE_NONE) 1001178354Ssam ieee80211_amrr_tx_complete(&rn->amrr, 1002178354Ssam IEEE80211_AMRR_FAILURE, retrycnt); 1003156321Sdamien ifp->if_oerrors++; 1004156321Sdamien break; 1005156321Sdamien 1006156321Sdamien case RT2560_TX_FAIL_INVALID: 1007156321Sdamien case RT2560_TX_FAIL_OTHER: 1008156321Sdamien default: 1009156321Sdamien device_printf(sc->sc_dev, "sending data frame failed " 1010178354Ssam "0x%08x\n", flags); 1011156321Sdamien ifp->if_oerrors++; 1012156321Sdamien } 1013156321Sdamien 1014156321Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, 1015156321Sdamien BUS_DMASYNC_POSTWRITE); 1016156321Sdamien bus_dmamap_unload(sc->txq.data_dmat, data->map); 1017178354Ssam m_freem(m); 1018156321Sdamien data->m = NULL; 1019156321Sdamien ieee80211_free_node(data->ni); 1020156321Sdamien data->ni = NULL; 1021156321Sdamien 1022156321Sdamien /* descriptor is no longer valid */ 1023156321Sdamien desc->flags &= ~htole32(RT2560_TX_VALID); 1024156321Sdamien 1025178354Ssam DPRINTFN(sc, 15, "tx done idx=%u\n", sc->txq.next); 1026156321Sdamien 1027156321Sdamien sc->txq.queued--; 1028156321Sdamien sc->txq.next = (sc->txq.next + 1) % RT2560_TX_RING_COUNT; 1029156321Sdamien } 1030156321Sdamien 1031156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 1032156321Sdamien BUS_DMASYNC_PREWRITE); 1033156321Sdamien 1034175938Ssephe if (sc->prioq.queued == 0 && sc->txq.queued == 0) 1035175938Ssephe sc->sc_tx_timer = 0; 1036175938Ssephe 1037175938Ssephe if (sc->txq.queued < RT2560_TX_RING_COUNT - 1) { 1038175938Ssephe sc->sc_flags &= ~RT2560_F_DATA_OACTIVE; 1039175938Ssephe if ((sc->sc_flags & 1040175938Ssephe (RT2560_F_DATA_OACTIVE | RT2560_F_PRIO_OACTIVE)) == 0) 1041175938Ssephe ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1042178354Ssam rt2560_start_locked(ifp); 1043175938Ssephe } 1044156321Sdamien} 1045156321Sdamien 1046156321Sdamienstatic void 1047156321Sdamienrt2560_prio_intr(struct rt2560_softc *sc) 1048156321Sdamien{ 1049178354Ssam struct ifnet *ifp = sc->sc_ifp; 1050156321Sdamien struct rt2560_tx_desc *desc; 1051156321Sdamien struct rt2560_tx_data *data; 1052170530Ssam struct ieee80211_node *ni; 1053170530Ssam struct mbuf *m; 1054170530Ssam int flags; 1055156321Sdamien 1056156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1057156321Sdamien BUS_DMASYNC_POSTREAD); 1058156321Sdamien 1059156321Sdamien for (;;) { 1060156321Sdamien desc = &sc->prioq.desc[sc->prioq.next]; 1061156321Sdamien data = &sc->prioq.data[sc->prioq.next]; 1062156321Sdamien 1063170530Ssam flags = le32toh(desc->flags); 1064170530Ssam if ((flags & RT2560_TX_BUSY) || (flags & RT2560_TX_VALID) == 0) 1065156321Sdamien break; 1066156321Sdamien 1067170530Ssam switch (flags & RT2560_TX_RESULT_MASK) { 1068156321Sdamien case RT2560_TX_SUCCESS: 1069178354Ssam DPRINTFN(sc, 10, "%s\n", "mgt frame sent successfully"); 1070156321Sdamien break; 1071156321Sdamien 1072156321Sdamien case RT2560_TX_SUCCESS_RETRY: 1073178354Ssam DPRINTFN(sc, 9, "mgt frame sent after %u retries\n", 1074178354Ssam (flags >> 5) & 0x7); 1075156321Sdamien break; 1076156321Sdamien 1077156321Sdamien case RT2560_TX_FAIL_RETRY: 1078178354Ssam DPRINTFN(sc, 9, "%s\n", 1079178354Ssam "sending mgt frame failed (too much retries)"); 1080156321Sdamien break; 1081156321Sdamien 1082156321Sdamien case RT2560_TX_FAIL_INVALID: 1083156321Sdamien case RT2560_TX_FAIL_OTHER: 1084156321Sdamien default: 1085156321Sdamien device_printf(sc->sc_dev, "sending mgt frame failed " 1086170530Ssam "0x%08x\n", flags); 1087170530Ssam break; 1088156321Sdamien } 1089156321Sdamien 1090156321Sdamien bus_dmamap_sync(sc->prioq.data_dmat, data->map, 1091156321Sdamien BUS_DMASYNC_POSTWRITE); 1092156321Sdamien bus_dmamap_unload(sc->prioq.data_dmat, data->map); 1093170530Ssam 1094170530Ssam m = data->m; 1095156321Sdamien data->m = NULL; 1096170530Ssam ni = data->ni; 1097156321Sdamien data->ni = NULL; 1098156321Sdamien 1099156321Sdamien /* descriptor is no longer valid */ 1100156321Sdamien desc->flags &= ~htole32(RT2560_TX_VALID); 1101156321Sdamien 1102178354Ssam DPRINTFN(sc, 15, "prio done idx=%u\n", sc->prioq.next); 1103156321Sdamien 1104156321Sdamien sc->prioq.queued--; 1105156321Sdamien sc->prioq.next = (sc->prioq.next + 1) % RT2560_PRIO_RING_COUNT; 1106170530Ssam 1107170530Ssam if (m->m_flags & M_TXCB) 1108170530Ssam ieee80211_process_callback(ni, m, 1109170530Ssam (flags & RT2560_TX_RESULT_MASK) &~ 1110170530Ssam (RT2560_TX_SUCCESS | RT2560_TX_SUCCESS_RETRY)); 1111170530Ssam m_freem(m); 1112170530Ssam ieee80211_free_node(ni); 1113156321Sdamien } 1114156321Sdamien 1115156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1116156321Sdamien BUS_DMASYNC_PREWRITE); 1117156321Sdamien 1118175938Ssephe if (sc->prioq.queued == 0 && sc->txq.queued == 0) 1119175938Ssephe sc->sc_tx_timer = 0; 1120175938Ssephe 1121175938Ssephe if (sc->prioq.queued < RT2560_PRIO_RING_COUNT) { 1122175938Ssephe sc->sc_flags &= ~RT2560_F_PRIO_OACTIVE; 1123175938Ssephe if ((sc->sc_flags & 1124175938Ssephe (RT2560_F_DATA_OACTIVE | RT2560_F_PRIO_OACTIVE)) == 0) 1125175938Ssephe ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1126178354Ssam rt2560_start_locked(ifp); 1127175938Ssephe } 1128156321Sdamien} 1129156321Sdamien 1130156321Sdamien/* 1131156321Sdamien * Some frames were processed by the hardware cipher engine and are ready for 1132178354Ssam * handoff to the IEEE802.11 layer. 1133156321Sdamien */ 1134156321Sdamienstatic void 1135156321Sdamienrt2560_decryption_intr(struct rt2560_softc *sc) 1136156321Sdamien{ 1137178354Ssam struct ifnet *ifp = sc->sc_ifp; 1138178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1139156321Sdamien struct rt2560_rx_desc *desc; 1140156321Sdamien struct rt2560_rx_data *data; 1141156321Sdamien bus_addr_t physaddr; 1142156321Sdamien struct ieee80211_frame *wh; 1143156321Sdamien struct ieee80211_node *ni; 1144156321Sdamien struct mbuf *mnew, *m; 1145156321Sdamien int hw, error; 1146192468Ssam int8_t rssi, nf; 1147156321Sdamien 1148156321Sdamien /* retrieve last decriptor index processed by cipher engine */ 1149156321Sdamien hw = RAL_READ(sc, RT2560_SECCSR0) - sc->rxq.physaddr; 1150156321Sdamien hw /= RT2560_RX_DESC_SIZE; 1151156321Sdamien 1152156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1153156321Sdamien BUS_DMASYNC_POSTREAD); 1154156321Sdamien 1155156321Sdamien for (; sc->rxq.cur_decrypt != hw;) { 1156156321Sdamien desc = &sc->rxq.desc[sc->rxq.cur_decrypt]; 1157156321Sdamien data = &sc->rxq.data[sc->rxq.cur_decrypt]; 1158156321Sdamien 1159156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_BUSY) || 1160156321Sdamien (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY)) 1161156321Sdamien break; 1162156321Sdamien 1163156321Sdamien if (data->drop) { 1164156321Sdamien ifp->if_ierrors++; 1165156321Sdamien goto skip; 1166156321Sdamien } 1167156321Sdamien 1168156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_CIPHER_MASK) != 0 && 1169156321Sdamien (le32toh(desc->flags) & RT2560_RX_ICV_ERROR)) { 1170156321Sdamien ifp->if_ierrors++; 1171156321Sdamien goto skip; 1172156321Sdamien } 1173156321Sdamien 1174156321Sdamien /* 1175156321Sdamien * Try to allocate a new mbuf for this ring element and load it 1176156321Sdamien * before processing the current mbuf. If the ring element 1177156321Sdamien * cannot be loaded, drop the received packet and reuse the old 1178156321Sdamien * mbuf. In the unlikely case that the old mbuf can't be 1179156321Sdamien * reloaded either, explicitly panic. 1180156321Sdamien */ 1181156321Sdamien mnew = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1182156321Sdamien if (mnew == NULL) { 1183156321Sdamien ifp->if_ierrors++; 1184156321Sdamien goto skip; 1185156321Sdamien } 1186156321Sdamien 1187156321Sdamien bus_dmamap_sync(sc->rxq.data_dmat, data->map, 1188156321Sdamien BUS_DMASYNC_POSTREAD); 1189156321Sdamien bus_dmamap_unload(sc->rxq.data_dmat, data->map); 1190156321Sdamien 1191156321Sdamien error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 1192156321Sdamien mtod(mnew, void *), MCLBYTES, rt2560_dma_map_addr, 1193156321Sdamien &physaddr, 0); 1194156321Sdamien if (error != 0) { 1195156321Sdamien m_freem(mnew); 1196156321Sdamien 1197156321Sdamien /* try to reload the old mbuf */ 1198156321Sdamien error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 1199156321Sdamien mtod(data->m, void *), MCLBYTES, 1200156321Sdamien rt2560_dma_map_addr, &physaddr, 0); 1201156321Sdamien if (error != 0) { 1202156321Sdamien /* very unlikely that it will fail... */ 1203156321Sdamien panic("%s: could not load old rx mbuf", 1204156321Sdamien device_get_name(sc->sc_dev)); 1205156321Sdamien } 1206156321Sdamien ifp->if_ierrors++; 1207156321Sdamien goto skip; 1208156321Sdamien } 1209156321Sdamien 1210156321Sdamien /* 1211156321Sdamien * New mbuf successfully loaded, update Rx ring and continue 1212156321Sdamien * processing. 1213156321Sdamien */ 1214156321Sdamien m = data->m; 1215156321Sdamien data->m = mnew; 1216156321Sdamien desc->physaddr = htole32(physaddr); 1217156321Sdamien 1218156321Sdamien /* finalize mbuf */ 1219156321Sdamien m->m_pkthdr.rcvif = ifp; 1220156321Sdamien m->m_pkthdr.len = m->m_len = 1221156321Sdamien (le32toh(desc->flags) >> 16) & 0xfff; 1222156321Sdamien 1223192468Ssam rssi = RT2560_RSSI(sc, desc->rssi); 1224192468Ssam nf = RT2560_NOISE_FLOOR; 1225192468Ssam if (ieee80211_radiotap_active(ic)) { 1226156321Sdamien struct rt2560_rx_radiotap_header *tap = &sc->sc_rxtap; 1227156321Sdamien uint32_t tsf_lo, tsf_hi; 1228156321Sdamien 1229156321Sdamien /* get timestamp (low and high 32 bits) */ 1230156321Sdamien tsf_hi = RAL_READ(sc, RT2560_CSR17); 1231156321Sdamien tsf_lo = RAL_READ(sc, RT2560_CSR16); 1232156321Sdamien 1233156321Sdamien tap->wr_tsf = 1234156321Sdamien htole64(((uint64_t)tsf_hi << 32) | tsf_lo); 1235156321Sdamien tap->wr_flags = 0; 1236178354Ssam tap->wr_rate = ieee80211_plcp2rate(desc->rate, 1237178958Ssam (desc->flags & htole32(RT2560_RX_OFDM)) ? 1238178958Ssam IEEE80211_T_OFDM : IEEE80211_T_CCK); 1239156321Sdamien tap->wr_antenna = sc->rx_ant; 1240192468Ssam tap->wr_antsignal = nf + rssi; 1241192468Ssam tap->wr_antnoise = nf; 1242156321Sdamien } 1243156321Sdamien 1244175938Ssephe sc->sc_flags |= RT2560_F_INPUT_RUNNING; 1245170530Ssam RAL_UNLOCK(sc); 1246156321Sdamien wh = mtod(m, struct ieee80211_frame *); 1247156321Sdamien ni = ieee80211_find_rxnode(ic, 1248156321Sdamien (struct ieee80211_frame_min *)wh); 1249178354Ssam if (ni != NULL) { 1250192468Ssam (void) ieee80211_input(ni, m, rssi, nf); 1251178354Ssam ieee80211_free_node(ni); 1252178354Ssam } else 1253192468Ssam (void) ieee80211_input_all(ic, m, rssi, nf); 1254156321Sdamien 1255170530Ssam RAL_LOCK(sc); 1256175938Ssephe sc->sc_flags &= ~RT2560_F_INPUT_RUNNING; 1257156321Sdamienskip: desc->flags = htole32(RT2560_RX_BUSY); 1258156321Sdamien 1259178354Ssam DPRINTFN(sc, 15, "decryption done idx=%u\n", sc->rxq.cur_decrypt); 1260156321Sdamien 1261156321Sdamien sc->rxq.cur_decrypt = 1262156321Sdamien (sc->rxq.cur_decrypt + 1) % RT2560_RX_RING_COUNT; 1263156321Sdamien } 1264156321Sdamien 1265156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1266156321Sdamien BUS_DMASYNC_PREWRITE); 1267156321Sdamien} 1268156321Sdamien 1269156321Sdamien/* 1270156321Sdamien * Some frames were received. Pass them to the hardware cipher engine before 1271156321Sdamien * sending them to the 802.11 layer. 1272156321Sdamien */ 1273156321Sdamienstatic void 1274156321Sdamienrt2560_rx_intr(struct rt2560_softc *sc) 1275156321Sdamien{ 1276156321Sdamien struct rt2560_rx_desc *desc; 1277156321Sdamien struct rt2560_rx_data *data; 1278156321Sdamien 1279156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1280156321Sdamien BUS_DMASYNC_POSTREAD); 1281156321Sdamien 1282156321Sdamien for (;;) { 1283156321Sdamien desc = &sc->rxq.desc[sc->rxq.cur]; 1284156321Sdamien data = &sc->rxq.data[sc->rxq.cur]; 1285156321Sdamien 1286156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_BUSY) || 1287156321Sdamien (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY)) 1288156321Sdamien break; 1289156321Sdamien 1290156321Sdamien data->drop = 0; 1291156321Sdamien 1292156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_PHY_ERROR) || 1293156321Sdamien (le32toh(desc->flags) & RT2560_RX_CRC_ERROR)) { 1294156321Sdamien /* 1295156321Sdamien * This should not happen since we did not request 1296156321Sdamien * to receive those frames when we filled RXCSR0. 1297156321Sdamien */ 1298178354Ssam DPRINTFN(sc, 5, "PHY or CRC error flags 0x%08x\n", 1299178354Ssam le32toh(desc->flags)); 1300156321Sdamien data->drop = 1; 1301156321Sdamien } 1302156321Sdamien 1303156321Sdamien if (((le32toh(desc->flags) >> 16) & 0xfff) > MCLBYTES) { 1304178354Ssam DPRINTFN(sc, 5, "%s\n", "bad length"); 1305156321Sdamien data->drop = 1; 1306156321Sdamien } 1307156321Sdamien 1308156321Sdamien /* mark the frame for decryption */ 1309156321Sdamien desc->flags |= htole32(RT2560_RX_CIPHER_BUSY); 1310156321Sdamien 1311178354Ssam DPRINTFN(sc, 15, "rx done idx=%u\n", sc->rxq.cur); 1312156321Sdamien 1313156321Sdamien sc->rxq.cur = (sc->rxq.cur + 1) % RT2560_RX_RING_COUNT; 1314156321Sdamien } 1315156321Sdamien 1316156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1317156321Sdamien BUS_DMASYNC_PREWRITE); 1318156321Sdamien 1319156321Sdamien /* kick decrypt */ 1320156321Sdamien RAL_WRITE(sc, RT2560_SECCSR0, RT2560_KICK_DECRYPT); 1321156321Sdamien} 1322156321Sdamien 1323172211Ssamstatic void 1324178354Ssamrt2560_beacon_update(struct ieee80211vap *vap, int item) 1325172211Ssam{ 1326178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 1327178354Ssam struct ieee80211_beacon_offsets *bo = &rvp->ral_bo; 1328172211Ssam 1329172211Ssam setbit(bo->bo_flags, item); 1330172211Ssam} 1331172211Ssam 1332156321Sdamien/* 1333156321Sdamien * This function is called periodically in IBSS mode when a new beacon must be 1334156321Sdamien * sent out. 1335156321Sdamien */ 1336156321Sdamienstatic void 1337156321Sdamienrt2560_beacon_expire(struct rt2560_softc *sc) 1338156321Sdamien{ 1339178354Ssam struct ifnet *ifp = sc->sc_ifp; 1340178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1341178354Ssam struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 1342178354Ssam struct rt2560_vap *rvp = RT2560_VAP(vap); 1343156321Sdamien struct rt2560_tx_data *data; 1344156321Sdamien 1345156321Sdamien if (ic->ic_opmode != IEEE80211_M_IBSS && 1346156321Sdamien ic->ic_opmode != IEEE80211_M_HOSTAP) 1347170530Ssam return; 1348156321Sdamien 1349156321Sdamien data = &sc->bcnq.data[sc->bcnq.next]; 1350170530Ssam /* 1351170530Ssam * Don't send beacon if bsschan isn't set 1352170530Ssam */ 1353170530Ssam if (data->ni == NULL) 1354170530Ssam return; 1355156321Sdamien 1356156321Sdamien bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_POSTWRITE); 1357156321Sdamien bus_dmamap_unload(sc->bcnq.data_dmat, data->map); 1358156321Sdamien 1359178354Ssam /* XXX 1 =>'s mcast frames which means all PS sta's will wakeup! */ 1360178354Ssam ieee80211_beacon_update(data->ni, &rvp->ral_bo, data->m, 1); 1361156321Sdamien 1362156321Sdamien rt2560_tx_bcn(sc, data->m, data->ni); 1363156321Sdamien 1364178354Ssam DPRINTFN(sc, 15, "%s", "beacon expired\n"); 1365156321Sdamien 1366156321Sdamien sc->bcnq.next = (sc->bcnq.next + 1) % RT2560_BEACON_RING_COUNT; 1367156321Sdamien} 1368156321Sdamien 1369156321Sdamien/* ARGSUSED */ 1370156321Sdamienstatic void 1371156321Sdamienrt2560_wakeup_expire(struct rt2560_softc *sc) 1372156321Sdamien{ 1373178354Ssam DPRINTFN(sc, 2, "%s", "wakeup expired\n"); 1374156321Sdamien} 1375156321Sdamien 1376156321Sdamienvoid 1377156321Sdamienrt2560_intr(void *arg) 1378156321Sdamien{ 1379156321Sdamien struct rt2560_softc *sc = arg; 1380156975Sdamien struct ifnet *ifp = sc->sc_ifp; 1381156321Sdamien uint32_t r; 1382156321Sdamien 1383156321Sdamien RAL_LOCK(sc); 1384156321Sdamien 1385156321Sdamien /* disable interrupts */ 1386156321Sdamien RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 1387156321Sdamien 1388156975Sdamien /* don't re-enable interrupts if we're shutting down */ 1389156975Sdamien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1390156975Sdamien RAL_UNLOCK(sc); 1391156975Sdamien return; 1392156975Sdamien } 1393156975Sdamien 1394156321Sdamien r = RAL_READ(sc, RT2560_CSR7); 1395156321Sdamien RAL_WRITE(sc, RT2560_CSR7, r); 1396156321Sdamien 1397156321Sdamien if (r & RT2560_BEACON_EXPIRE) 1398156321Sdamien rt2560_beacon_expire(sc); 1399156321Sdamien 1400156321Sdamien if (r & RT2560_WAKEUP_EXPIRE) 1401156321Sdamien rt2560_wakeup_expire(sc); 1402156321Sdamien 1403156321Sdamien if (r & RT2560_ENCRYPTION_DONE) 1404156321Sdamien rt2560_encryption_intr(sc); 1405156321Sdamien 1406156321Sdamien if (r & RT2560_TX_DONE) 1407156321Sdamien rt2560_tx_intr(sc); 1408156321Sdamien 1409156321Sdamien if (r & RT2560_PRIO_DONE) 1410156321Sdamien rt2560_prio_intr(sc); 1411156321Sdamien 1412156321Sdamien if (r & RT2560_DECRYPTION_DONE) 1413156321Sdamien rt2560_decryption_intr(sc); 1414156321Sdamien 1415175938Ssephe if (r & RT2560_RX_DONE) { 1416156321Sdamien rt2560_rx_intr(sc); 1417175938Ssephe rt2560_encryption_intr(sc); 1418175938Ssephe } 1419156321Sdamien 1420156321Sdamien /* re-enable interrupts */ 1421156321Sdamien RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); 1422156321Sdamien 1423156321Sdamien RAL_UNLOCK(sc); 1424156321Sdamien} 1425156321Sdamien 1426156321Sdamien#define RAL_SIFS 10 /* us */ 1427156321Sdamien 1428156321Sdamien#define RT2560_TXRX_TURNAROUND 10 /* us */ 1429156321Sdamien 1430178958Ssamstatic uint8_t 1431178958Ssamrt2560_plcp_signal(int rate) 1432178958Ssam{ 1433178958Ssam switch (rate) { 1434178958Ssam /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ 1435178958Ssam case 12: return 0xb; 1436178958Ssam case 18: return 0xf; 1437178958Ssam case 24: return 0xa; 1438178958Ssam case 36: return 0xe; 1439178958Ssam case 48: return 0x9; 1440178958Ssam case 72: return 0xd; 1441178958Ssam case 96: return 0x8; 1442178958Ssam case 108: return 0xc; 1443178958Ssam 1444178958Ssam /* CCK rates (NB: not IEEE std, device-specific) */ 1445178958Ssam case 2: return 0x0; 1446178958Ssam case 4: return 0x1; 1447178958Ssam case 11: return 0x2; 1448178958Ssam case 22: return 0x3; 1449178958Ssam } 1450178958Ssam return 0xff; /* XXX unsupported/unknown rate */ 1451178958Ssam} 1452178958Ssam 1453156321Sdamienstatic void 1454156321Sdamienrt2560_setup_tx_desc(struct rt2560_softc *sc, struct rt2560_tx_desc *desc, 1455156321Sdamien uint32_t flags, int len, int rate, int encrypt, bus_addr_t physaddr) 1456156321Sdamien{ 1457178354Ssam struct ifnet *ifp = sc->sc_ifp; 1458178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1459156321Sdamien uint16_t plcp_length; 1460156321Sdamien int remainder; 1461156321Sdamien 1462156321Sdamien desc->flags = htole32(flags); 1463156321Sdamien desc->flags |= htole32(len << 16); 1464156321Sdamien 1465156321Sdamien desc->physaddr = htole32(physaddr); 1466156321Sdamien desc->wme = htole16( 1467156321Sdamien RT2560_AIFSN(2) | 1468156321Sdamien RT2560_LOGCWMIN(3) | 1469156321Sdamien RT2560_LOGCWMAX(8)); 1470156321Sdamien 1471156321Sdamien /* setup PLCP fields */ 1472178958Ssam desc->plcp_signal = rt2560_plcp_signal(rate); 1473156321Sdamien desc->plcp_service = 4; 1474156321Sdamien 1475156321Sdamien len += IEEE80211_CRC_LEN; 1476190532Ssam if (ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) { 1477156321Sdamien desc->flags |= htole32(RT2560_TX_OFDM); 1478156321Sdamien 1479156321Sdamien plcp_length = len & 0xfff; 1480156321Sdamien desc->plcp_length_hi = plcp_length >> 6; 1481156321Sdamien desc->plcp_length_lo = plcp_length & 0x3f; 1482156321Sdamien } else { 1483156321Sdamien plcp_length = (16 * len + rate - 1) / rate; 1484156321Sdamien if (rate == 22) { 1485156321Sdamien remainder = (16 * len) % 22; 1486156321Sdamien if (remainder != 0 && remainder < 7) 1487156321Sdamien desc->plcp_service |= RT2560_PLCP_LENGEXT; 1488156321Sdamien } 1489156321Sdamien desc->plcp_length_hi = plcp_length >> 8; 1490156321Sdamien desc->plcp_length_lo = plcp_length & 0xff; 1491156321Sdamien 1492156321Sdamien if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 1493156321Sdamien desc->plcp_signal |= 0x08; 1494156321Sdamien } 1495175938Ssephe 1496175938Ssephe if (!encrypt) 1497175938Ssephe desc->flags |= htole32(RT2560_TX_VALID); 1498175938Ssephe desc->flags |= encrypt ? htole32(RT2560_TX_CIPHER_BUSY) 1499175938Ssephe : htole32(RT2560_TX_BUSY); 1500156321Sdamien} 1501156321Sdamien 1502156321Sdamienstatic int 1503156321Sdamienrt2560_tx_bcn(struct rt2560_softc *sc, struct mbuf *m0, 1504156321Sdamien struct ieee80211_node *ni) 1505156321Sdamien{ 1506178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1507156321Sdamien struct rt2560_tx_desc *desc; 1508156321Sdamien struct rt2560_tx_data *data; 1509156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1510156321Sdamien int nsegs, rate, error; 1511156321Sdamien 1512156321Sdamien desc = &sc->bcnq.desc[sc->bcnq.cur]; 1513156321Sdamien data = &sc->bcnq.data[sc->bcnq.cur]; 1514156321Sdamien 1515178354Ssam /* XXX maybe a separate beacon rate? */ 1516178354Ssam rate = vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)].mgmtrate; 1517156321Sdamien 1518156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->bcnq.data_dmat, data->map, m0, 1519156321Sdamien segs, &nsegs, BUS_DMA_NOWAIT); 1520156321Sdamien if (error != 0) { 1521156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1522156321Sdamien error); 1523156321Sdamien m_freem(m0); 1524156321Sdamien return error; 1525156321Sdamien } 1526156321Sdamien 1527192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 1528156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1529156321Sdamien 1530156321Sdamien tap->wt_flags = 0; 1531156321Sdamien tap->wt_rate = rate; 1532156321Sdamien tap->wt_antenna = sc->tx_ant; 1533156321Sdamien 1534192468Ssam ieee80211_radiotap_tx(vap, m0); 1535156321Sdamien } 1536156321Sdamien 1537156321Sdamien data->m = m0; 1538156321Sdamien data->ni = ni; 1539156321Sdamien 1540156321Sdamien rt2560_setup_tx_desc(sc, desc, RT2560_TX_IFS_NEWBACKOFF | 1541156321Sdamien RT2560_TX_TIMESTAMP, m0->m_pkthdr.len, rate, 0, segs->ds_addr); 1542156321Sdamien 1543178354Ssam DPRINTFN(sc, 10, "sending beacon frame len=%u idx=%u rate=%u\n", 1544178354Ssam m0->m_pkthdr.len, sc->bcnq.cur, rate); 1545156321Sdamien 1546156321Sdamien bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1547156321Sdamien bus_dmamap_sync(sc->bcnq.desc_dmat, sc->bcnq.desc_map, 1548156321Sdamien BUS_DMASYNC_PREWRITE); 1549156321Sdamien 1550156321Sdamien sc->bcnq.cur = (sc->bcnq.cur + 1) % RT2560_BEACON_RING_COUNT; 1551156321Sdamien 1552156321Sdamien return 0; 1553156321Sdamien} 1554156321Sdamien 1555156321Sdamienstatic int 1556156321Sdamienrt2560_tx_mgt(struct rt2560_softc *sc, struct mbuf *m0, 1557156321Sdamien struct ieee80211_node *ni) 1558156321Sdamien{ 1559178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1560178354Ssam struct ieee80211com *ic = ni->ni_ic; 1561156321Sdamien struct rt2560_tx_desc *desc; 1562156321Sdamien struct rt2560_tx_data *data; 1563156321Sdamien struct ieee80211_frame *wh; 1564173386Skevlo struct ieee80211_key *k; 1565156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1566156321Sdamien uint16_t dur; 1567156321Sdamien uint32_t flags = 0; 1568156321Sdamien int nsegs, rate, error; 1569156321Sdamien 1570156321Sdamien desc = &sc->prioq.desc[sc->prioq.cur]; 1571156321Sdamien data = &sc->prioq.data[sc->prioq.cur]; 1572156321Sdamien 1573178354Ssam rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate; 1574156321Sdamien 1575173386Skevlo wh = mtod(m0, struct ieee80211_frame *); 1576173386Skevlo 1577173386Skevlo if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1578178354Ssam k = ieee80211_crypto_encap(ni, m0); 1579173386Skevlo if (k == NULL) { 1580173386Skevlo m_freem(m0); 1581173386Skevlo return ENOBUFS; 1582173386Skevlo } 1583173386Skevlo } 1584173386Skevlo 1585156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, 1586156321Sdamien segs, &nsegs, 0); 1587156321Sdamien if (error != 0) { 1588156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1589156321Sdamien error); 1590156321Sdamien m_freem(m0); 1591156321Sdamien return error; 1592156321Sdamien } 1593156321Sdamien 1594192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 1595156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1596156321Sdamien 1597156321Sdamien tap->wt_flags = 0; 1598156321Sdamien tap->wt_rate = rate; 1599156321Sdamien tap->wt_antenna = sc->tx_ant; 1600156321Sdamien 1601192468Ssam ieee80211_radiotap_tx(vap, m0); 1602156321Sdamien } 1603156321Sdamien 1604156321Sdamien data->m = m0; 1605156321Sdamien data->ni = ni; 1606178354Ssam /* management frames are not taken into account for amrr */ 1607178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1608156321Sdamien 1609156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1610156321Sdamien 1611156321Sdamien if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1612156321Sdamien flags |= RT2560_TX_ACK; 1613156321Sdamien 1614190532Ssam dur = ieee80211_ack_duration(ic->ic_rt, 1615178354Ssam rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); 1616156321Sdamien *(uint16_t *)wh->i_dur = htole16(dur); 1617156321Sdamien 1618156321Sdamien /* tell hardware to add timestamp for probe responses */ 1619156321Sdamien if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 1620156321Sdamien IEEE80211_FC0_TYPE_MGT && 1621156321Sdamien (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 1622156321Sdamien IEEE80211_FC0_SUBTYPE_PROBE_RESP) 1623156321Sdamien flags |= RT2560_TX_TIMESTAMP; 1624156321Sdamien } 1625156321Sdamien 1626156321Sdamien rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 0, 1627156321Sdamien segs->ds_addr); 1628156321Sdamien 1629156321Sdamien bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1630156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1631156321Sdamien BUS_DMASYNC_PREWRITE); 1632156321Sdamien 1633178354Ssam DPRINTFN(sc, 10, "sending mgt frame len=%u idx=%u rate=%u\n", 1634178354Ssam m0->m_pkthdr.len, sc->prioq.cur, rate); 1635156321Sdamien 1636156321Sdamien /* kick prio */ 1637156321Sdamien sc->prioq.queued++; 1638156321Sdamien sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; 1639156321Sdamien RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); 1640156321Sdamien 1641156321Sdamien return 0; 1642156321Sdamien} 1643156321Sdamien 1644160691Ssamstatic int 1645178354Ssamrt2560_sendprot(struct rt2560_softc *sc, 1646178354Ssam const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) 1647178354Ssam{ 1648178354Ssam struct ieee80211com *ic = ni->ni_ic; 1649178354Ssam const struct ieee80211_frame *wh; 1650178354Ssam struct rt2560_tx_desc *desc; 1651178354Ssam struct rt2560_tx_data *data; 1652178354Ssam struct mbuf *mprot; 1653178354Ssam int protrate, ackrate, pktlen, flags, isshort, error; 1654178354Ssam uint16_t dur; 1655178354Ssam bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1656178354Ssam int nsegs; 1657178354Ssam 1658178354Ssam KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, 1659178354Ssam ("protection %d", prot)); 1660178354Ssam 1661178354Ssam wh = mtod(m, const struct ieee80211_frame *); 1662178354Ssam pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; 1663178354Ssam 1664190532Ssam protrate = ieee80211_ctl_rate(ic->ic_rt, rate); 1665190532Ssam ackrate = ieee80211_ack_rate(ic->ic_rt, rate); 1666178354Ssam 1667178354Ssam isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; 1668190532Ssam dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort) 1669190532Ssam + ieee80211_ack_duration(ic->ic_rt, rate, isshort); 1670178354Ssam flags = RT2560_TX_MORE_FRAG; 1671178354Ssam if (prot == IEEE80211_PROT_RTSCTS) { 1672178354Ssam /* NB: CTS is the same size as an ACK */ 1673190532Ssam dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); 1674178354Ssam flags |= RT2560_TX_ACK; 1675178354Ssam mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); 1676178354Ssam } else { 1677178354Ssam mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); 1678178354Ssam } 1679178354Ssam if (mprot == NULL) { 1680178354Ssam /* XXX stat + msg */ 1681178354Ssam return ENOBUFS; 1682178354Ssam } 1683178354Ssam 1684178354Ssam desc = &sc->txq.desc[sc->txq.cur_encrypt]; 1685178354Ssam data = &sc->txq.data[sc->txq.cur_encrypt]; 1686178354Ssam 1687178354Ssam error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, 1688178354Ssam mprot, segs, &nsegs, 0); 1689178354Ssam if (error != 0) { 1690178354Ssam device_printf(sc->sc_dev, 1691178354Ssam "could not map mbuf (error %d)\n", error); 1692178354Ssam m_freem(mprot); 1693178354Ssam return error; 1694178354Ssam } 1695178354Ssam 1696178354Ssam data->m = mprot; 1697178354Ssam data->ni = ieee80211_ref_node(ni); 1698178354Ssam /* ctl frames are not taken into account for amrr */ 1699178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1700178354Ssam 1701178354Ssam rt2560_setup_tx_desc(sc, desc, flags, mprot->m_pkthdr.len, protrate, 1, 1702178354Ssam segs->ds_addr); 1703178354Ssam 1704178354Ssam bus_dmamap_sync(sc->txq.data_dmat, data->map, 1705178354Ssam BUS_DMASYNC_PREWRITE); 1706178354Ssam 1707178354Ssam sc->txq.queued++; 1708178354Ssam sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; 1709178354Ssam 1710178354Ssam return 0; 1711178354Ssam} 1712178354Ssam 1713178354Ssamstatic int 1714160691Ssamrt2560_tx_raw(struct rt2560_softc *sc, struct mbuf *m0, 1715160691Ssam struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) 1716160691Ssam{ 1717192468Ssam struct ieee80211vap *vap = ni->ni_vap; 1718160691Ssam struct rt2560_tx_desc *desc; 1719160691Ssam struct rt2560_tx_data *data; 1720160691Ssam bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1721160691Ssam uint32_t flags; 1722160691Ssam int nsegs, rate, error; 1723160691Ssam 1724160691Ssam desc = &sc->prioq.desc[sc->prioq.cur]; 1725160691Ssam data = &sc->prioq.data[sc->prioq.cur]; 1726160691Ssam 1727160691Ssam rate = params->ibp_rate0 & IEEE80211_RATE_VAL; 1728160691Ssam /* XXX validate */ 1729168860Ssephe if (rate == 0) { 1730178354Ssam /* XXX fall back to mcast/mgmt rate? */ 1731168860Ssephe m_freem(m0); 1732160691Ssam return EINVAL; 1733168860Ssephe } 1734160691Ssam 1735178354Ssam flags = 0; 1736178354Ssam if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) 1737178354Ssam flags |= RT2560_TX_ACK; 1738178354Ssam if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { 1739178354Ssam error = rt2560_sendprot(sc, m0, ni, 1740178354Ssam params->ibp_flags & IEEE80211_BPF_RTS ? 1741178354Ssam IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, 1742178354Ssam rate); 1743178354Ssam if (error) { 1744178354Ssam m_freem(m0); 1745178354Ssam return error; 1746178354Ssam } 1747178354Ssam flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; 1748178354Ssam } 1749178354Ssam 1750160691Ssam error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, 1751160691Ssam segs, &nsegs, 0); 1752160691Ssam if (error != 0) { 1753160691Ssam device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1754160691Ssam error); 1755160691Ssam m_freem(m0); 1756160691Ssam return error; 1757160691Ssam } 1758160691Ssam 1759192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 1760160691Ssam struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1761160691Ssam 1762160691Ssam tap->wt_flags = 0; 1763160691Ssam tap->wt_rate = rate; 1764160691Ssam tap->wt_antenna = sc->tx_ant; 1765160691Ssam 1766192468Ssam ieee80211_radiotap_tx(ni->ni_vap, m0); 1767160691Ssam } 1768160691Ssam 1769160691Ssam data->m = m0; 1770160691Ssam data->ni = ni; 1771160691Ssam 1772160691Ssam /* XXX need to setup descriptor ourself */ 1773160691Ssam rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, 1774160691Ssam rate, (params->ibp_flags & IEEE80211_BPF_CRYPTO) != 0, 1775160691Ssam segs->ds_addr); 1776160691Ssam 1777160691Ssam bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1778160691Ssam bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1779160691Ssam BUS_DMASYNC_PREWRITE); 1780160691Ssam 1781178354Ssam DPRINTFN(sc, 10, "sending raw frame len=%u idx=%u rate=%u\n", 1782178354Ssam m0->m_pkthdr.len, sc->prioq.cur, rate); 1783160691Ssam 1784160691Ssam /* kick prio */ 1785160691Ssam sc->prioq.queued++; 1786160691Ssam sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; 1787160691Ssam RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); 1788160691Ssam 1789160691Ssam return 0; 1790160691Ssam} 1791160691Ssam 1792156321Sdamienstatic int 1793156321Sdamienrt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0, 1794156321Sdamien struct ieee80211_node *ni) 1795156321Sdamien{ 1796178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1797178354Ssam struct ieee80211com *ic = ni->ni_ic; 1798156321Sdamien struct rt2560_tx_desc *desc; 1799156321Sdamien struct rt2560_tx_data *data; 1800156321Sdamien struct ieee80211_frame *wh; 1801178354Ssam const struct ieee80211_txparam *tp; 1802156321Sdamien struct ieee80211_key *k; 1803156321Sdamien struct mbuf *mnew; 1804156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1805156321Sdamien uint16_t dur; 1806178354Ssam uint32_t flags; 1807156321Sdamien int nsegs, rate, error; 1808156321Sdamien 1809156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1810156321Sdamien 1811178354Ssam tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; 1812178354Ssam if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1813178354Ssam rate = tp->mcastrate; 1814178354Ssam } else if (m0->m_flags & M_EAPOL) { 1815178354Ssam rate = tp->mgmtrate; 1816178354Ssam } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 1817178354Ssam rate = tp->ucastrate; 1818156321Sdamien } else { 1819178354Ssam (void) ieee80211_amrr_choose(ni, &RT2560_NODE(ni)->amrr); 1820178354Ssam rate = ni->ni_txrate; 1821156321Sdamien } 1822156321Sdamien 1823156321Sdamien if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1824178354Ssam k = ieee80211_crypto_encap(ni, m0); 1825156321Sdamien if (k == NULL) { 1826156321Sdamien m_freem(m0); 1827156321Sdamien return ENOBUFS; 1828156321Sdamien } 1829156321Sdamien 1830156321Sdamien /* packet header may have moved, reset our local pointer */ 1831156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1832156321Sdamien } 1833156321Sdamien 1834178354Ssam flags = 0; 1835178354Ssam if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1836178354Ssam int prot = IEEE80211_PROT_NONE; 1837178354Ssam if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) 1838178354Ssam prot = IEEE80211_PROT_RTSCTS; 1839178354Ssam else if ((ic->ic_flags & IEEE80211_F_USEPROT) && 1840190532Ssam ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) 1841178354Ssam prot = ic->ic_protmode; 1842178354Ssam if (prot != IEEE80211_PROT_NONE) { 1843178354Ssam error = rt2560_sendprot(sc, m0, ni, prot, rate); 1844178354Ssam if (error) { 1845178354Ssam m_freem(m0); 1846178354Ssam return error; 1847178354Ssam } 1848178354Ssam flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; 1849156321Sdamien } 1850156321Sdamien } 1851156321Sdamien 1852156321Sdamien data = &sc->txq.data[sc->txq.cur_encrypt]; 1853156321Sdamien desc = &sc->txq.desc[sc->txq.cur_encrypt]; 1854156321Sdamien 1855156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, m0, 1856156321Sdamien segs, &nsegs, 0); 1857156321Sdamien if (error != 0 && error != EFBIG) { 1858156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1859156321Sdamien error); 1860156321Sdamien m_freem(m0); 1861156321Sdamien return error; 1862156321Sdamien } 1863156321Sdamien if (error != 0) { 1864156321Sdamien mnew = m_defrag(m0, M_DONTWAIT); 1865156321Sdamien if (mnew == NULL) { 1866156321Sdamien device_printf(sc->sc_dev, 1867156321Sdamien "could not defragment mbuf\n"); 1868156321Sdamien m_freem(m0); 1869156321Sdamien return ENOBUFS; 1870156321Sdamien } 1871156321Sdamien m0 = mnew; 1872156321Sdamien 1873156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, 1874156321Sdamien m0, segs, &nsegs, 0); 1875156321Sdamien if (error != 0) { 1876156321Sdamien device_printf(sc->sc_dev, 1877156321Sdamien "could not map mbuf (error %d)\n", error); 1878156321Sdamien m_freem(m0); 1879156321Sdamien return error; 1880156321Sdamien } 1881156321Sdamien 1882156321Sdamien /* packet header may have moved, reset our local pointer */ 1883156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1884156321Sdamien } 1885156321Sdamien 1886192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 1887156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1888156321Sdamien 1889156321Sdamien tap->wt_flags = 0; 1890156321Sdamien tap->wt_rate = rate; 1891156321Sdamien tap->wt_antenna = sc->tx_ant; 1892156321Sdamien 1893192468Ssam ieee80211_radiotap_tx(vap, m0); 1894156321Sdamien } 1895156321Sdamien 1896156321Sdamien data->m = m0; 1897156321Sdamien data->ni = ni; 1898156321Sdamien 1899156321Sdamien /* remember link conditions for rate adaptation algorithm */ 1900178354Ssam if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) { 1901178354Ssam data->rix = ni->ni_txrate; 1902178354Ssam /* XXX probably need last rssi value and not avg */ 1903178354Ssam data->rssi = ic->ic_node_getrssi(ni); 1904156321Sdamien } else 1905178354Ssam data->rix = IEEE80211_FIXED_RATE_NONE; 1906156321Sdamien 1907156321Sdamien if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1908156321Sdamien flags |= RT2560_TX_ACK; 1909156321Sdamien 1910190532Ssam dur = ieee80211_ack_duration(ic->ic_rt, 1911178354Ssam rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); 1912156321Sdamien *(uint16_t *)wh->i_dur = htole16(dur); 1913156321Sdamien } 1914156321Sdamien 1915156321Sdamien rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 1, 1916156321Sdamien segs->ds_addr); 1917156321Sdamien 1918156321Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1919156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 1920156321Sdamien BUS_DMASYNC_PREWRITE); 1921156321Sdamien 1922178354Ssam DPRINTFN(sc, 10, "sending data frame len=%u idx=%u rate=%u\n", 1923178354Ssam m0->m_pkthdr.len, sc->txq.cur_encrypt, rate); 1924156321Sdamien 1925156321Sdamien /* kick encrypt */ 1926156321Sdamien sc->txq.queued++; 1927156321Sdamien sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; 1928156321Sdamien RAL_WRITE(sc, RT2560_SECCSR1, RT2560_KICK_ENCRYPT); 1929156321Sdamien 1930156321Sdamien return 0; 1931156321Sdamien} 1932156321Sdamien 1933156321Sdamienstatic void 1934178354Ssamrt2560_start_locked(struct ifnet *ifp) 1935156321Sdamien{ 1936156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 1937178354Ssam struct mbuf *m; 1938156321Sdamien struct ieee80211_node *ni; 1939156321Sdamien 1940178354Ssam RAL_LOCK_ASSERT(sc); 1941156321Sdamien 1942156321Sdamien for (;;) { 1943178354Ssam IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 1944178354Ssam if (m == NULL) 1945178354Ssam break; 1946178354Ssam if (sc->txq.queued >= RT2560_TX_RING_COUNT - 1) { 1947178354Ssam IFQ_DRV_PREPEND(&ifp->if_snd, m); 1948178354Ssam ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1949178354Ssam sc->sc_flags |= RT2560_F_DATA_OACTIVE; 1950178354Ssam break; 1951178354Ssam } 1952178354Ssam ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; 1953178354Ssam if (rt2560_tx_data(sc, m, ni) != 0) { 1954178354Ssam ieee80211_free_node(ni); 1955178354Ssam ifp->if_oerrors++; 1956178354Ssam break; 1957156321Sdamien } 1958156321Sdamien 1959156321Sdamien sc->sc_tx_timer = 5; 1960156321Sdamien } 1961178354Ssam} 1962156321Sdamien 1963178354Ssamstatic void 1964178354Ssamrt2560_start(struct ifnet *ifp) 1965178354Ssam{ 1966178354Ssam struct rt2560_softc *sc = ifp->if_softc; 1967178354Ssam 1968178354Ssam RAL_LOCK(sc); 1969178354Ssam rt2560_start_locked(ifp); 1970156321Sdamien RAL_UNLOCK(sc); 1971156321Sdamien} 1972156321Sdamien 1973156321Sdamienstatic void 1974165352Sbmsrt2560_watchdog(void *arg) 1975156321Sdamien{ 1976167470Ssam struct rt2560_softc *sc = arg; 1977175938Ssephe struct ifnet *ifp = sc->sc_ifp; 1978156321Sdamien 1979178354Ssam RAL_LOCK_ASSERT(sc); 1980178354Ssam 1981178354Ssam KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, ("not running")); 1982178354Ssam 1983178354Ssam if (sc->sc_invalid) /* card ejected */ 1984175938Ssephe return; 1985175938Ssephe 1986175938Ssephe rt2560_encryption_intr(sc); 1987175938Ssephe rt2560_tx_intr(sc); 1988175938Ssephe 1989178354Ssam if (sc->sc_tx_timer > 0 && --sc->sc_tx_timer == 0) { 1990178354Ssam if_printf(ifp, "device timeout\n"); 1991178354Ssam rt2560_init_locked(sc); 1992178354Ssam ifp->if_oerrors++; 1993178354Ssam /* NB: callout is reset in rt2560_init() */ 1994178354Ssam return; 1995156321Sdamien } 1996175938Ssephe callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); 1997156321Sdamien} 1998156321Sdamien 1999156321Sdamienstatic int 2000156321Sdamienrt2560_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 2001156321Sdamien{ 2002156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 2003178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2004178354Ssam struct ifreq *ifr = (struct ifreq *) data; 2005178354Ssam int error = 0, startall = 0; 2006156321Sdamien 2007156321Sdamien switch (cmd) { 2008156321Sdamien case SIOCSIFFLAGS: 2009178704Sthompsa RAL_LOCK(sc); 2010156321Sdamien if (ifp->if_flags & IFF_UP) { 2011178354Ssam if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 2012178354Ssam rt2560_init_locked(sc); 2013178354Ssam startall = 1; 2014178354Ssam } else 2015178354Ssam rt2560_update_promisc(ifp); 2016156321Sdamien } else { 2017156321Sdamien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2018178354Ssam rt2560_stop_locked(sc); 2019156321Sdamien } 2020178704Sthompsa RAL_UNLOCK(sc); 2021178704Sthompsa if (startall) 2022178704Sthompsa ieee80211_start_all(ic); 2023156321Sdamien break; 2024178354Ssam case SIOCGIFMEDIA: 2025178354Ssam error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); 2026178354Ssam break; 2027178704Sthompsa case SIOCGIFADDR: 2028178354Ssam error = ether_ioctl(ifp, cmd, data); 2029178354Ssam break; 2030178704Sthompsa default: 2031178704Sthompsa error = EINVAL; 2032178704Sthompsa break; 2033156321Sdamien } 2034156321Sdamien return error; 2035156321Sdamien} 2036156321Sdamien 2037156321Sdamienstatic void 2038156321Sdamienrt2560_bbp_write(struct rt2560_softc *sc, uint8_t reg, uint8_t val) 2039156321Sdamien{ 2040156321Sdamien uint32_t tmp; 2041156321Sdamien int ntries; 2042156321Sdamien 2043156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2044156321Sdamien if (!(RAL_READ(sc, RT2560_BBPCSR) & RT2560_BBP_BUSY)) 2045156321Sdamien break; 2046156321Sdamien DELAY(1); 2047156321Sdamien } 2048156321Sdamien if (ntries == 100) { 2049156321Sdamien device_printf(sc->sc_dev, "could not write to BBP\n"); 2050156321Sdamien return; 2051156321Sdamien } 2052156321Sdamien 2053156321Sdamien tmp = RT2560_BBP_WRITE | RT2560_BBP_BUSY | reg << 8 | val; 2054156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR, tmp); 2055156321Sdamien 2056178354Ssam DPRINTFN(sc, 15, "BBP R%u <- 0x%02x\n", reg, val); 2057156321Sdamien} 2058156321Sdamien 2059156321Sdamienstatic uint8_t 2060156321Sdamienrt2560_bbp_read(struct rt2560_softc *sc, uint8_t reg) 2061156321Sdamien{ 2062156321Sdamien uint32_t val; 2063156321Sdamien int ntries; 2064156321Sdamien 2065175938Ssephe for (ntries = 0; ntries < 100; ntries++) { 2066175938Ssephe if (!(RAL_READ(sc, RT2560_BBPCSR) & RT2560_BBP_BUSY)) 2067175938Ssephe break; 2068175938Ssephe DELAY(1); 2069175938Ssephe } 2070175938Ssephe if (ntries == 100) { 2071175938Ssephe device_printf(sc->sc_dev, "could not read from BBP\n"); 2072175938Ssephe return 0; 2073175938Ssephe } 2074175938Ssephe 2075156321Sdamien val = RT2560_BBP_BUSY | reg << 8; 2076156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR, val); 2077156321Sdamien 2078156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2079156321Sdamien val = RAL_READ(sc, RT2560_BBPCSR); 2080156321Sdamien if (!(val & RT2560_BBP_BUSY)) 2081156321Sdamien return val & 0xff; 2082156321Sdamien DELAY(1); 2083156321Sdamien } 2084156321Sdamien 2085156321Sdamien device_printf(sc->sc_dev, "could not read from BBP\n"); 2086156321Sdamien return 0; 2087156321Sdamien} 2088156321Sdamien 2089156321Sdamienstatic void 2090156321Sdamienrt2560_rf_write(struct rt2560_softc *sc, uint8_t reg, uint32_t val) 2091156321Sdamien{ 2092156321Sdamien uint32_t tmp; 2093156321Sdamien int ntries; 2094156321Sdamien 2095156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2096156321Sdamien if (!(RAL_READ(sc, RT2560_RFCSR) & RT2560_RF_BUSY)) 2097156321Sdamien break; 2098156321Sdamien DELAY(1); 2099156321Sdamien } 2100156321Sdamien if (ntries == 100) { 2101156321Sdamien device_printf(sc->sc_dev, "could not write to RF\n"); 2102156321Sdamien return; 2103156321Sdamien } 2104156321Sdamien 2105156321Sdamien tmp = RT2560_RF_BUSY | RT2560_RF_20BIT | (val & 0xfffff) << 2 | 2106156321Sdamien (reg & 0x3); 2107156321Sdamien RAL_WRITE(sc, RT2560_RFCSR, tmp); 2108156321Sdamien 2109156321Sdamien /* remember last written value in sc */ 2110156321Sdamien sc->rf_regs[reg] = val; 2111156321Sdamien 2112178354Ssam DPRINTFN(sc, 15, "RF R[%u] <- 0x%05x\n", reg & 0x3, val & 0xfffff); 2113156321Sdamien} 2114156321Sdamien 2115156321Sdamienstatic void 2116156321Sdamienrt2560_set_chan(struct rt2560_softc *sc, struct ieee80211_channel *c) 2117156321Sdamien{ 2118178354Ssam struct ifnet *ifp = sc->sc_ifp; 2119178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2120156321Sdamien uint8_t power, tmp; 2121156321Sdamien u_int i, chan; 2122156321Sdamien 2123156321Sdamien chan = ieee80211_chan2ieee(ic, c); 2124178354Ssam KASSERT(chan != 0 && chan != IEEE80211_CHAN_ANY, ("chan 0x%x", chan)); 2125156321Sdamien 2126156321Sdamien if (IEEE80211_IS_CHAN_2GHZ(c)) 2127156321Sdamien power = min(sc->txpow[chan - 1], 31); 2128156321Sdamien else 2129156321Sdamien power = 31; 2130156321Sdamien 2131156321Sdamien /* adjust txpower using ifconfig settings */ 2132156321Sdamien power -= (100 - ic->ic_txpowlimit) / 8; 2133156321Sdamien 2134178354Ssam DPRINTFN(sc, 2, "setting channel to %u, txpower to %u\n", chan, power); 2135156321Sdamien 2136156321Sdamien switch (sc->rf_rev) { 2137156321Sdamien case RT2560_RF_2522: 2138156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x00814); 2139156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2522_r2[chan - 1]); 2140156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2141156321Sdamien break; 2142156321Sdamien 2143156321Sdamien case RT2560_RF_2523: 2144156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08804); 2145156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2523_r2[chan - 1]); 2146156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x38044); 2147156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2148156321Sdamien break; 2149156321Sdamien 2150156321Sdamien case RT2560_RF_2524: 2151156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x0c808); 2152156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2524_r2[chan - 1]); 2153156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2154156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2155156321Sdamien break; 2156156321Sdamien 2157156321Sdamien case RT2560_RF_2525: 2158156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2159156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_hi_r2[chan - 1]); 2160156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2161156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2162156321Sdamien 2163156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2164156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_r2[chan - 1]); 2165156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2166156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2167156321Sdamien break; 2168156321Sdamien 2169156321Sdamien case RT2560_RF_2525E: 2170156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2171156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525e_r2[chan - 1]); 2172156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2173156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00286 : 0x00282); 2174156321Sdamien break; 2175156321Sdamien 2176156321Sdamien case RT2560_RF_2526: 2177156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_hi_r2[chan - 1]); 2178156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); 2179156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08804); 2180156321Sdamien 2181156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_r2[chan - 1]); 2182156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2183156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); 2184156321Sdamien break; 2185156321Sdamien 2186156321Sdamien /* dual-band RF */ 2187156321Sdamien case RT2560_RF_5222: 2188156321Sdamien for (i = 0; rt2560_rf5222[i].chan != chan; i++); 2189156321Sdamien 2190156321Sdamien rt2560_rf_write(sc, RAL_RF1, rt2560_rf5222[i].r1); 2191156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf5222[i].r2); 2192156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2193156321Sdamien rt2560_rf_write(sc, RAL_RF4, rt2560_rf5222[i].r4); 2194156321Sdamien break; 2195170530Ssam default: 2196170530Ssam printf("unknown ral rev=%d\n", sc->rf_rev); 2197156321Sdamien } 2198156321Sdamien 2199178354Ssam /* XXX */ 2200178354Ssam if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { 2201156321Sdamien /* set Japan filter bit for channel 14 */ 2202156321Sdamien tmp = rt2560_bbp_read(sc, 70); 2203156321Sdamien 2204156321Sdamien tmp &= ~RT2560_JAPAN_FILTER; 2205156321Sdamien if (chan == 14) 2206156321Sdamien tmp |= RT2560_JAPAN_FILTER; 2207156321Sdamien 2208156321Sdamien rt2560_bbp_write(sc, 70, tmp); 2209156321Sdamien 2210156321Sdamien /* clear CRC errors */ 2211156321Sdamien RAL_READ(sc, RT2560_CNT0); 2212156321Sdamien } 2213156321Sdamien} 2214156321Sdamien 2215170530Ssamstatic void 2216170530Ssamrt2560_set_channel(struct ieee80211com *ic) 2217170530Ssam{ 2218170530Ssam struct ifnet *ifp = ic->ic_ifp; 2219170530Ssam struct rt2560_softc *sc = ifp->if_softc; 2220170530Ssam 2221170530Ssam RAL_LOCK(sc); 2222170530Ssam rt2560_set_chan(sc, ic->ic_curchan); 2223170530Ssam RAL_UNLOCK(sc); 2224170530Ssam 2225170530Ssam} 2226170530Ssam 2227156321Sdamien#if 0 2228156321Sdamien/* 2229156321Sdamien * Disable RF auto-tuning. 2230156321Sdamien */ 2231156321Sdamienstatic void 2232156321Sdamienrt2560_disable_rf_tune(struct rt2560_softc *sc) 2233156321Sdamien{ 2234156321Sdamien uint32_t tmp; 2235156321Sdamien 2236156321Sdamien if (sc->rf_rev != RT2560_RF_2523) { 2237156321Sdamien tmp = sc->rf_regs[RAL_RF1] & ~RAL_RF1_AUTOTUNE; 2238156321Sdamien rt2560_rf_write(sc, RAL_RF1, tmp); 2239156321Sdamien } 2240156321Sdamien 2241156321Sdamien tmp = sc->rf_regs[RAL_RF3] & ~RAL_RF3_AUTOTUNE; 2242156321Sdamien rt2560_rf_write(sc, RAL_RF3, tmp); 2243156321Sdamien 2244178354Ssam DPRINTFN(sc, 2, "%s", "disabling RF autotune\n"); 2245156321Sdamien} 2246156321Sdamien#endif 2247156321Sdamien 2248156321Sdamien/* 2249156321Sdamien * Refer to IEEE Std 802.11-1999 pp. 123 for more information on TSF 2250156321Sdamien * synchronization. 2251156321Sdamien */ 2252156321Sdamienstatic void 2253156321Sdamienrt2560_enable_tsf_sync(struct rt2560_softc *sc) 2254156321Sdamien{ 2255178354Ssam struct ifnet *ifp = sc->sc_ifp; 2256178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2257178354Ssam struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2258156321Sdamien uint16_t logcwmin, preload; 2259156321Sdamien uint32_t tmp; 2260156321Sdamien 2261156321Sdamien /* first, disable TSF synchronization */ 2262156321Sdamien RAL_WRITE(sc, RT2560_CSR14, 0); 2263156321Sdamien 2264178354Ssam tmp = 16 * vap->iv_bss->ni_intval; 2265156321Sdamien RAL_WRITE(sc, RT2560_CSR12, tmp); 2266156321Sdamien 2267156321Sdamien RAL_WRITE(sc, RT2560_CSR13, 0); 2268156321Sdamien 2269156321Sdamien logcwmin = 5; 2270178354Ssam preload = (vap->iv_opmode == IEEE80211_M_STA) ? 384 : 1024; 2271156321Sdamien tmp = logcwmin << 16 | preload; 2272156321Sdamien RAL_WRITE(sc, RT2560_BCNOCSR, tmp); 2273156321Sdamien 2274156321Sdamien /* finally, enable TSF synchronization */ 2275156321Sdamien tmp = RT2560_ENABLE_TSF | RT2560_ENABLE_TBCN; 2276156321Sdamien if (ic->ic_opmode == IEEE80211_M_STA) 2277156321Sdamien tmp |= RT2560_ENABLE_TSF_SYNC(1); 2278156321Sdamien else 2279156321Sdamien tmp |= RT2560_ENABLE_TSF_SYNC(2) | 2280156321Sdamien RT2560_ENABLE_BEACON_GENERATOR; 2281156321Sdamien RAL_WRITE(sc, RT2560_CSR14, tmp); 2282156321Sdamien 2283178354Ssam DPRINTF(sc, "%s", "enabling TSF synchronization\n"); 2284156321Sdamien} 2285156321Sdamien 2286156321Sdamienstatic void 2287192468Ssamrt2560_enable_tsf(struct rt2560_softc *sc) 2288192468Ssam{ 2289192468Ssam RAL_WRITE(sc, RT2560_CSR14, 0); 2290192468Ssam RAL_WRITE(sc, RT2560_CSR14, 2291192468Ssam RT2560_ENABLE_TSF_SYNC(2) | RT2560_ENABLE_TSF); 2292192468Ssam} 2293192468Ssam 2294192468Ssamstatic void 2295156321Sdamienrt2560_update_plcp(struct rt2560_softc *sc) 2296156321Sdamien{ 2297178354Ssam struct ifnet *ifp = sc->sc_ifp; 2298178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2299156321Sdamien 2300156321Sdamien /* no short preamble for 1Mbps */ 2301156321Sdamien RAL_WRITE(sc, RT2560_PLCP1MCSR, 0x00700400); 2302156321Sdamien 2303156321Sdamien if (!(ic->ic_flags & IEEE80211_F_SHPREAMBLE)) { 2304156321Sdamien /* values taken from the reference driver */ 2305156321Sdamien RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380401); 2306156321Sdamien RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x00150402); 2307156321Sdamien RAL_WRITE(sc, RT2560_PLCP11MCSR, 0x000b8403); 2308156321Sdamien } else { 2309156321Sdamien /* same values as above or'ed 0x8 */ 2310156321Sdamien RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380409); 2311156321Sdamien RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x0015040a); 2312156321Sdamien RAL_WRITE(sc, RT2560_PLCP11MCSR, 0x000b840b); 2313156321Sdamien } 2314156321Sdamien 2315178354Ssam DPRINTF(sc, "updating PLCP for %s preamble\n", 2316178354Ssam (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? "short" : "long"); 2317156321Sdamien} 2318156321Sdamien 2319156321Sdamien/* 2320156321Sdamien * This function can be called by ieee80211_set_shortslottime(). Refer to 2321156321Sdamien * IEEE Std 802.11-1999 pp. 85 to know how these values are computed. 2322156321Sdamien */ 2323156321Sdamienstatic void 2324156321Sdamienrt2560_update_slot(struct ifnet *ifp) 2325156321Sdamien{ 2326156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 2327178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2328156321Sdamien uint8_t slottime; 2329156321Sdamien uint16_t tx_sifs, tx_pifs, tx_difs, eifs; 2330156321Sdamien uint32_t tmp; 2331156321Sdamien 2332175938Ssephe#ifndef FORCE_SLOTTIME 2333156321Sdamien slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; 2334175938Ssephe#else 2335175938Ssephe /* 2336175938Ssephe * Setting slot time according to "short slot time" capability 2337175938Ssephe * in beacon/probe_resp seems to cause problem to acknowledge 2338175938Ssephe * certain AP's data frames transimitted at CCK/DS rates: the 2339175938Ssephe * problematic AP keeps retransmitting data frames, probably 2340175938Ssephe * because MAC level acks are not received by hardware. 2341175938Ssephe * So we cheat a little bit here by claiming we are capable of 2342175938Ssephe * "short slot time" but setting hardware slot time to the normal 2343175938Ssephe * slot time. ral(4) does not seem to have trouble to receive 2344175938Ssephe * frames transmitted using short slot time even if hardware 2345175938Ssephe * slot time is set to normal slot time. If we didn't use this 2346175938Ssephe * trick, we would have to claim that short slot time is not 2347175938Ssephe * supported; this would give relative poor RX performance 2348175938Ssephe * (-1Mb~-2Mb lower) and the _whole_ BSS would stop using short 2349175938Ssephe * slot time. 2350175938Ssephe */ 2351175938Ssephe slottime = 20; 2352175938Ssephe#endif 2353156321Sdamien 2354156321Sdamien /* update the MAC slot boundaries */ 2355156321Sdamien tx_sifs = RAL_SIFS - RT2560_TXRX_TURNAROUND; 2356156321Sdamien tx_pifs = tx_sifs + slottime; 2357156321Sdamien tx_difs = tx_sifs + 2 * slottime; 2358156321Sdamien eifs = (ic->ic_curmode == IEEE80211_MODE_11B) ? 364 : 60; 2359156321Sdamien 2360156321Sdamien tmp = RAL_READ(sc, RT2560_CSR11); 2361156321Sdamien tmp = (tmp & ~0x1f00) | slottime << 8; 2362156321Sdamien RAL_WRITE(sc, RT2560_CSR11, tmp); 2363156321Sdamien 2364156321Sdamien tmp = tx_pifs << 16 | tx_sifs; 2365156321Sdamien RAL_WRITE(sc, RT2560_CSR18, tmp); 2366156321Sdamien 2367156321Sdamien tmp = eifs << 16 | tx_difs; 2368156321Sdamien RAL_WRITE(sc, RT2560_CSR19, tmp); 2369156321Sdamien 2370178354Ssam DPRINTF(sc, "setting slottime to %uus\n", slottime); 2371156321Sdamien} 2372156321Sdamien 2373156321Sdamienstatic void 2374156321Sdamienrt2560_set_basicrates(struct rt2560_softc *sc) 2375156321Sdamien{ 2376178354Ssam struct ifnet *ifp = sc->sc_ifp; 2377178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2378156321Sdamien 2379156321Sdamien /* update basic rate set */ 2380156321Sdamien if (ic->ic_curmode == IEEE80211_MODE_11B) { 2381156321Sdamien /* 11b basic rates: 1, 2Mbps */ 2382156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x3); 2383156321Sdamien } else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) { 2384156321Sdamien /* 11a basic rates: 6, 12, 24Mbps */ 2385156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x150); 2386156321Sdamien } else { 2387156321Sdamien /* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */ 2388156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x15f); 2389156321Sdamien } 2390156321Sdamien} 2391156321Sdamien 2392156321Sdamienstatic void 2393156321Sdamienrt2560_update_led(struct rt2560_softc *sc, int led1, int led2) 2394156321Sdamien{ 2395156321Sdamien uint32_t tmp; 2396156321Sdamien 2397156321Sdamien /* set ON period to 70ms and OFF period to 30ms */ 2398156321Sdamien tmp = led1 << 16 | led2 << 17 | 70 << 8 | 30; 2399156321Sdamien RAL_WRITE(sc, RT2560_LEDCSR, tmp); 2400156321Sdamien} 2401156321Sdamien 2402156321Sdamienstatic void 2403170530Ssamrt2560_set_bssid(struct rt2560_softc *sc, const uint8_t *bssid) 2404156321Sdamien{ 2405156321Sdamien uint32_t tmp; 2406156321Sdamien 2407156321Sdamien tmp = bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24; 2408156321Sdamien RAL_WRITE(sc, RT2560_CSR5, tmp); 2409156321Sdamien 2410156321Sdamien tmp = bssid[4] | bssid[5] << 8; 2411156321Sdamien RAL_WRITE(sc, RT2560_CSR6, tmp); 2412156321Sdamien 2413178354Ssam DPRINTF(sc, "setting BSSID to %6D\n", bssid, ":"); 2414156321Sdamien} 2415156321Sdamien 2416156321Sdamienstatic void 2417156321Sdamienrt2560_set_macaddr(struct rt2560_softc *sc, uint8_t *addr) 2418156321Sdamien{ 2419156321Sdamien uint32_t tmp; 2420156321Sdamien 2421156321Sdamien tmp = addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24; 2422156321Sdamien RAL_WRITE(sc, RT2560_CSR3, tmp); 2423156321Sdamien 2424156321Sdamien tmp = addr[4] | addr[5] << 8; 2425156321Sdamien RAL_WRITE(sc, RT2560_CSR4, tmp); 2426156321Sdamien 2427178354Ssam DPRINTF(sc, "setting MAC address to %6D\n", addr, ":"); 2428156321Sdamien} 2429156321Sdamien 2430156321Sdamienstatic void 2431156321Sdamienrt2560_get_macaddr(struct rt2560_softc *sc, uint8_t *addr) 2432156321Sdamien{ 2433156321Sdamien uint32_t tmp; 2434156321Sdamien 2435156321Sdamien tmp = RAL_READ(sc, RT2560_CSR3); 2436156321Sdamien addr[0] = tmp & 0xff; 2437156321Sdamien addr[1] = (tmp >> 8) & 0xff; 2438156321Sdamien addr[2] = (tmp >> 16) & 0xff; 2439156321Sdamien addr[3] = (tmp >> 24); 2440156321Sdamien 2441156321Sdamien tmp = RAL_READ(sc, RT2560_CSR4); 2442156321Sdamien addr[4] = tmp & 0xff; 2443156321Sdamien addr[5] = (tmp >> 8) & 0xff; 2444156321Sdamien} 2445156321Sdamien 2446156321Sdamienstatic void 2447178354Ssamrt2560_update_promisc(struct ifnet *ifp) 2448156321Sdamien{ 2449178354Ssam struct rt2560_softc *sc = ifp->if_softc; 2450156321Sdamien uint32_t tmp; 2451156321Sdamien 2452156321Sdamien tmp = RAL_READ(sc, RT2560_RXCSR0); 2453156321Sdamien 2454156321Sdamien tmp &= ~RT2560_DROP_NOT_TO_ME; 2455156321Sdamien if (!(ifp->if_flags & IFF_PROMISC)) 2456156321Sdamien tmp |= RT2560_DROP_NOT_TO_ME; 2457156321Sdamien 2458156321Sdamien RAL_WRITE(sc, RT2560_RXCSR0, tmp); 2459156321Sdamien 2460178354Ssam DPRINTF(sc, "%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ? 2461178354Ssam "entering" : "leaving"); 2462156321Sdamien} 2463156321Sdamien 2464156321Sdamienstatic const char * 2465156321Sdamienrt2560_get_rf(int rev) 2466156321Sdamien{ 2467156321Sdamien switch (rev) { 2468156321Sdamien case RT2560_RF_2522: return "RT2522"; 2469156321Sdamien case RT2560_RF_2523: return "RT2523"; 2470156321Sdamien case RT2560_RF_2524: return "RT2524"; 2471156321Sdamien case RT2560_RF_2525: return "RT2525"; 2472156321Sdamien case RT2560_RF_2525E: return "RT2525e"; 2473156321Sdamien case RT2560_RF_2526: return "RT2526"; 2474156321Sdamien case RT2560_RF_5222: return "RT5222"; 2475156321Sdamien default: return "unknown"; 2476156321Sdamien } 2477156321Sdamien} 2478156321Sdamien 2479156321Sdamienstatic void 2480175938Ssephert2560_read_config(struct rt2560_softc *sc) 2481156321Sdamien{ 2482156321Sdamien uint16_t val; 2483156321Sdamien int i; 2484156321Sdamien 2485156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_CONFIG0); 2486156321Sdamien sc->rf_rev = (val >> 11) & 0x7; 2487156321Sdamien sc->hw_radio = (val >> 10) & 0x1; 2488156321Sdamien sc->led_mode = (val >> 6) & 0x7; 2489156321Sdamien sc->rx_ant = (val >> 4) & 0x3; 2490156321Sdamien sc->tx_ant = (val >> 2) & 0x3; 2491156321Sdamien sc->nb_ant = val & 0x3; 2492156321Sdamien 2493156321Sdamien /* read default values for BBP registers */ 2494156321Sdamien for (i = 0; i < 16; i++) { 2495156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_BBP_BASE + i); 2496175938Ssephe if (val == 0 || val == 0xffff) 2497175938Ssephe continue; 2498175938Ssephe 2499156321Sdamien sc->bbp_prom[i].reg = val >> 8; 2500156321Sdamien sc->bbp_prom[i].val = val & 0xff; 2501156321Sdamien } 2502156321Sdamien 2503156321Sdamien /* read Tx power for all b/g channels */ 2504156321Sdamien for (i = 0; i < 14 / 2; i++) { 2505156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_TXPOWER + i); 2506175938Ssephe sc->txpow[i * 2] = val & 0xff; 2507175938Ssephe sc->txpow[i * 2 + 1] = val >> 8; 2508156321Sdamien } 2509175938Ssephe for (i = 0; i < 14; ++i) { 2510175938Ssephe if (sc->txpow[i] > 31) 2511175938Ssephe sc->txpow[i] = 24; 2512175938Ssephe } 2513170530Ssam 2514170530Ssam val = rt2560_eeprom_read(sc, RT2560_EEPROM_CALIBRATE); 2515170530Ssam if ((val & 0xff) == 0xff) 2516170530Ssam sc->rssi_corr = RT2560_DEFAULT_RSSI_CORR; 2517170530Ssam else 2518170530Ssam sc->rssi_corr = val & 0xff; 2519178354Ssam DPRINTF(sc, "rssi correction %d, calibrate 0x%02x\n", 2520178354Ssam sc->rssi_corr, val); 2521156321Sdamien} 2522156321Sdamien 2523170530Ssam 2524170530Ssamstatic void 2525170530Ssamrt2560_scan_start(struct ieee80211com *ic) 2526170530Ssam{ 2527170530Ssam struct ifnet *ifp = ic->ic_ifp; 2528170530Ssam struct rt2560_softc *sc = ifp->if_softc; 2529170530Ssam 2530170530Ssam /* abort TSF synchronization */ 2531170530Ssam RAL_WRITE(sc, RT2560_CSR14, 0); 2532170530Ssam rt2560_set_bssid(sc, ifp->if_broadcastaddr); 2533170530Ssam} 2534170530Ssam 2535170530Ssamstatic void 2536170530Ssamrt2560_scan_end(struct ieee80211com *ic) 2537170530Ssam{ 2538170530Ssam struct ifnet *ifp = ic->ic_ifp; 2539170530Ssam struct rt2560_softc *sc = ifp->if_softc; 2540178354Ssam struct ieee80211vap *vap = ic->ic_scan->ss_vap; 2541170530Ssam 2542170530Ssam rt2560_enable_tsf_sync(sc); 2543170530Ssam /* XXX keep local copy */ 2544178354Ssam rt2560_set_bssid(sc, vap->iv_bss->ni_bssid); 2545170530Ssam} 2546170530Ssam 2547156321Sdamienstatic int 2548156321Sdamienrt2560_bbp_init(struct rt2560_softc *sc) 2549156321Sdamien{ 2550156321Sdamien#define N(a) (sizeof (a) / sizeof ((a)[0])) 2551156321Sdamien int i, ntries; 2552156321Sdamien 2553156321Sdamien /* wait for BBP to be ready */ 2554156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2555156321Sdamien if (rt2560_bbp_read(sc, RT2560_BBP_VERSION) != 0) 2556156321Sdamien break; 2557156321Sdamien DELAY(1); 2558156321Sdamien } 2559156321Sdamien if (ntries == 100) { 2560156321Sdamien device_printf(sc->sc_dev, "timeout waiting for BBP\n"); 2561156321Sdamien return EIO; 2562156321Sdamien } 2563156321Sdamien 2564156321Sdamien /* initialize BBP registers to default values */ 2565156321Sdamien for (i = 0; i < N(rt2560_def_bbp); i++) { 2566156321Sdamien rt2560_bbp_write(sc, rt2560_def_bbp[i].reg, 2567156321Sdamien rt2560_def_bbp[i].val); 2568156321Sdamien } 2569175938Ssephe 2570156321Sdamien /* initialize BBP registers to values stored in EEPROM */ 2571156321Sdamien for (i = 0; i < 16; i++) { 2572175938Ssephe if (sc->bbp_prom[i].reg == 0 && sc->bbp_prom[i].val == 0) 2573175938Ssephe break; 2574156321Sdamien rt2560_bbp_write(sc, sc->bbp_prom[i].reg, sc->bbp_prom[i].val); 2575156321Sdamien } 2576175938Ssephe rt2560_bbp_write(sc, 17, 0x48); /* XXX restore bbp17 */ 2577156321Sdamien 2578156321Sdamien return 0; 2579156321Sdamien#undef N 2580156321Sdamien} 2581156321Sdamien 2582156321Sdamienstatic void 2583156321Sdamienrt2560_set_txantenna(struct rt2560_softc *sc, int antenna) 2584156321Sdamien{ 2585156321Sdamien uint32_t tmp; 2586156321Sdamien uint8_t tx; 2587156321Sdamien 2588156321Sdamien tx = rt2560_bbp_read(sc, RT2560_BBP_TX) & ~RT2560_BBP_ANTMASK; 2589156321Sdamien if (antenna == 1) 2590156321Sdamien tx |= RT2560_BBP_ANTA; 2591156321Sdamien else if (antenna == 2) 2592156321Sdamien tx |= RT2560_BBP_ANTB; 2593156321Sdamien else 2594156321Sdamien tx |= RT2560_BBP_DIVERSITY; 2595156321Sdamien 2596156321Sdamien /* need to force I/Q flip for RF 2525e, 2526 and 5222 */ 2597156321Sdamien if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526 || 2598156321Sdamien sc->rf_rev == RT2560_RF_5222) 2599156321Sdamien tx |= RT2560_BBP_FLIPIQ; 2600156321Sdamien 2601156321Sdamien rt2560_bbp_write(sc, RT2560_BBP_TX, tx); 2602156321Sdamien 2603156321Sdamien /* update values for CCK and OFDM in BBPCSR1 */ 2604156321Sdamien tmp = RAL_READ(sc, RT2560_BBPCSR1) & ~0x00070007; 2605156321Sdamien tmp |= (tx & 0x7) << 16 | (tx & 0x7); 2606156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR1, tmp); 2607156321Sdamien} 2608156321Sdamien 2609156321Sdamienstatic void 2610156321Sdamienrt2560_set_rxantenna(struct rt2560_softc *sc, int antenna) 2611156321Sdamien{ 2612156321Sdamien uint8_t rx; 2613156321Sdamien 2614156321Sdamien rx = rt2560_bbp_read(sc, RT2560_BBP_RX) & ~RT2560_BBP_ANTMASK; 2615156321Sdamien if (antenna == 1) 2616156321Sdamien rx |= RT2560_BBP_ANTA; 2617156321Sdamien else if (antenna == 2) 2618156321Sdamien rx |= RT2560_BBP_ANTB; 2619156321Sdamien else 2620156321Sdamien rx |= RT2560_BBP_DIVERSITY; 2621156321Sdamien 2622156321Sdamien /* need to force no I/Q flip for RF 2525e and 2526 */ 2623156321Sdamien if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526) 2624156321Sdamien rx &= ~RT2560_BBP_FLIPIQ; 2625156321Sdamien 2626156321Sdamien rt2560_bbp_write(sc, RT2560_BBP_RX, rx); 2627156321Sdamien} 2628156321Sdamien 2629156321Sdamienstatic void 2630178354Ssamrt2560_init_locked(struct rt2560_softc *sc) 2631156321Sdamien{ 2632156321Sdamien#define N(a) (sizeof (a) / sizeof ((a)[0])) 2633178354Ssam struct ifnet *ifp = sc->sc_ifp; 2634178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2635156321Sdamien uint32_t tmp; 2636156321Sdamien int i; 2637156321Sdamien 2638178354Ssam RAL_LOCK_ASSERT(sc); 2639156975Sdamien 2640178354Ssam rt2560_stop_locked(sc); 2641170530Ssam 2642156321Sdamien /* setup tx rings */ 2643156321Sdamien tmp = RT2560_PRIO_RING_COUNT << 24 | 2644156321Sdamien RT2560_ATIM_RING_COUNT << 16 | 2645156321Sdamien RT2560_TX_RING_COUNT << 8 | 2646156321Sdamien RT2560_TX_DESC_SIZE; 2647156321Sdamien 2648156321Sdamien /* rings must be initialized in this exact order */ 2649156321Sdamien RAL_WRITE(sc, RT2560_TXCSR2, tmp); 2650156321Sdamien RAL_WRITE(sc, RT2560_TXCSR3, sc->txq.physaddr); 2651156321Sdamien RAL_WRITE(sc, RT2560_TXCSR5, sc->prioq.physaddr); 2652156321Sdamien RAL_WRITE(sc, RT2560_TXCSR4, sc->atimq.physaddr); 2653156321Sdamien RAL_WRITE(sc, RT2560_TXCSR6, sc->bcnq.physaddr); 2654156321Sdamien 2655156321Sdamien /* setup rx ring */ 2656156321Sdamien tmp = RT2560_RX_RING_COUNT << 8 | RT2560_RX_DESC_SIZE; 2657156321Sdamien 2658156321Sdamien RAL_WRITE(sc, RT2560_RXCSR1, tmp); 2659156321Sdamien RAL_WRITE(sc, RT2560_RXCSR2, sc->rxq.physaddr); 2660156321Sdamien 2661156321Sdamien /* initialize MAC registers to default values */ 2662156321Sdamien for (i = 0; i < N(rt2560_def_mac); i++) 2663156321Sdamien RAL_WRITE(sc, rt2560_def_mac[i].reg, rt2560_def_mac[i].val); 2664156321Sdamien 2665190526Ssam rt2560_set_macaddr(sc, IF_LLADDR(ifp)); 2666156321Sdamien 2667156321Sdamien /* set basic rate set (will be updated later) */ 2668156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x153); 2669156321Sdamien 2670156321Sdamien rt2560_update_slot(ifp); 2671156321Sdamien rt2560_update_plcp(sc); 2672156321Sdamien rt2560_update_led(sc, 0, 0); 2673156321Sdamien 2674156321Sdamien RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 2675156321Sdamien RAL_WRITE(sc, RT2560_CSR1, RT2560_HOST_READY); 2676156321Sdamien 2677156321Sdamien if (rt2560_bbp_init(sc) != 0) { 2678156321Sdamien rt2560_stop(sc); 2679156975Sdamien RAL_UNLOCK(sc); 2680156321Sdamien return; 2681156321Sdamien } 2682156321Sdamien 2683175938Ssephe rt2560_set_txantenna(sc, sc->tx_ant); 2684175938Ssephe rt2560_set_rxantenna(sc, sc->rx_ant); 2685175938Ssephe 2686156321Sdamien /* set default BSS channel */ 2687156321Sdamien rt2560_set_chan(sc, ic->ic_curchan); 2688156321Sdamien 2689156321Sdamien /* kick Rx */ 2690156321Sdamien tmp = RT2560_DROP_PHY_ERROR | RT2560_DROP_CRC_ERROR; 2691156321Sdamien if (ic->ic_opmode != IEEE80211_M_MONITOR) { 2692156321Sdamien tmp |= RT2560_DROP_CTL | RT2560_DROP_VERSION_ERROR; 2693156321Sdamien if (ic->ic_opmode != IEEE80211_M_HOSTAP) 2694156321Sdamien tmp |= RT2560_DROP_TODS; 2695156321Sdamien if (!(ifp->if_flags & IFF_PROMISC)) 2696156321Sdamien tmp |= RT2560_DROP_NOT_TO_ME; 2697156321Sdamien } 2698156321Sdamien RAL_WRITE(sc, RT2560_RXCSR0, tmp); 2699156321Sdamien 2700156321Sdamien /* clear old FCS and Rx FIFO errors */ 2701156321Sdamien RAL_READ(sc, RT2560_CNT0); 2702156321Sdamien RAL_READ(sc, RT2560_CNT4); 2703156321Sdamien 2704156321Sdamien /* clear any pending interrupts */ 2705156321Sdamien RAL_WRITE(sc, RT2560_CSR7, 0xffffffff); 2706156321Sdamien 2707156321Sdamien /* enable interrupts */ 2708156321Sdamien RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); 2709156321Sdamien 2710156321Sdamien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2711156321Sdamien ifp->if_drv_flags |= IFF_DRV_RUNNING; 2712156321Sdamien 2713175938Ssephe callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); 2714178354Ssam#undef N 2715178354Ssam} 2716175938Ssephe 2717178354Ssamstatic void 2718178354Ssamrt2560_init(void *priv) 2719178354Ssam{ 2720178354Ssam struct rt2560_softc *sc = priv; 2721178354Ssam struct ifnet *ifp = sc->sc_ifp; 2722178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2723156975Sdamien 2724178354Ssam RAL_LOCK(sc); 2725178354Ssam rt2560_init_locked(sc); 2726156975Sdamien RAL_UNLOCK(sc); 2727178354Ssam 2728178931Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2729178931Sthompsa ieee80211_start_all(ic); /* start all vap's */ 2730156321Sdamien} 2731156321Sdamien 2732178354Ssamstatic void 2733178354Ssamrt2560_stop_locked(struct rt2560_softc *sc) 2734156321Sdamien{ 2735178354Ssam struct ifnet *ifp = sc->sc_ifp; 2736170530Ssam volatile int *flags = &sc->sc_flags; 2737156321Sdamien 2738178354Ssam RAL_LOCK_ASSERT(sc); 2739156321Sdamien 2740178354Ssam while (*flags & RT2560_F_INPUT_RUNNING) 2741178354Ssam msleep(sc, &sc->sc_mtx, 0, "ralrunning", hz/10); 2742175938Ssephe 2743175938Ssephe callout_stop(&sc->watchdog_ch); 2744178354Ssam sc->sc_tx_timer = 0; 2745175938Ssephe 2746170530Ssam if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 2747170530Ssam ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2748156975Sdamien 2749170530Ssam /* abort Tx */ 2750170530Ssam RAL_WRITE(sc, RT2560_TXCSR0, RT2560_ABORT_TX); 2751170530Ssam 2752170530Ssam /* disable Rx */ 2753170530Ssam RAL_WRITE(sc, RT2560_RXCSR0, RT2560_DISABLE_RX); 2754156321Sdamien 2755170530Ssam /* reset ASIC (imply reset BBP) */ 2756170530Ssam RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 2757170530Ssam RAL_WRITE(sc, RT2560_CSR1, 0); 2758156321Sdamien 2759170530Ssam /* disable interrupts */ 2760170530Ssam RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 2761170530Ssam 2762170530Ssam /* reset Tx and Rx rings */ 2763170530Ssam rt2560_reset_tx_ring(sc, &sc->txq); 2764170530Ssam rt2560_reset_tx_ring(sc, &sc->atimq); 2765170530Ssam rt2560_reset_tx_ring(sc, &sc->prioq); 2766170530Ssam rt2560_reset_tx_ring(sc, &sc->bcnq); 2767170530Ssam rt2560_reset_rx_ring(sc, &sc->rxq); 2768170530Ssam } 2769175938Ssephe sc->sc_flags &= ~(RT2560_F_PRIO_OACTIVE | RT2560_F_DATA_OACTIVE); 2770178354Ssam} 2771175938Ssephe 2772178354Ssamvoid 2773178354Ssamrt2560_stop(void *arg) 2774178354Ssam{ 2775178354Ssam struct rt2560_softc *sc = arg; 2776178354Ssam 2777178354Ssam RAL_LOCK(sc); 2778178354Ssam rt2560_stop_locked(sc); 2779170530Ssam RAL_UNLOCK(sc); 2780156321Sdamien} 2781160691Ssam 2782160691Ssamstatic int 2783160691Ssamrt2560_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 2784160691Ssam const struct ieee80211_bpf_params *params) 2785160691Ssam{ 2786160691Ssam struct ieee80211com *ic = ni->ni_ic; 2787160691Ssam struct ifnet *ifp = ic->ic_ifp; 2788160691Ssam struct rt2560_softc *sc = ifp->if_softc; 2789160691Ssam 2790160691Ssam RAL_LOCK(sc); 2791160691Ssam 2792160691Ssam /* prevent management frames from being sent if we're not ready */ 2793160691Ssam if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2794160691Ssam RAL_UNLOCK(sc); 2795168860Ssephe m_freem(m); 2796168860Ssephe ieee80211_free_node(ni); 2797160691Ssam return ENETDOWN; 2798160691Ssam } 2799160691Ssam if (sc->prioq.queued >= RT2560_PRIO_RING_COUNT) { 2800160691Ssam ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2801178354Ssam sc->sc_flags |= RT2560_F_PRIO_OACTIVE; 2802160691Ssam RAL_UNLOCK(sc); 2803168860Ssephe m_freem(m); 2804168860Ssephe ieee80211_free_node(ni); 2805160691Ssam return ENOBUFS; /* XXX */ 2806160691Ssam } 2807160691Ssam 2808160691Ssam ifp->if_opackets++; 2809160691Ssam 2810160691Ssam if (params == NULL) { 2811160691Ssam /* 2812160691Ssam * Legacy path; interpret frame contents to decide 2813160691Ssam * precisely how to send the frame. 2814160691Ssam */ 2815160691Ssam if (rt2560_tx_mgt(sc, m, ni) != 0) 2816160691Ssam goto bad; 2817160691Ssam } else { 2818160691Ssam /* 2819160691Ssam * Caller supplied explicit parameters to use in 2820160691Ssam * sending the frame. 2821160691Ssam */ 2822160691Ssam if (rt2560_tx_raw(sc, m, ni, params)) 2823160691Ssam goto bad; 2824160691Ssam } 2825160691Ssam sc->sc_tx_timer = 5; 2826160691Ssam 2827160691Ssam RAL_UNLOCK(sc); 2828160691Ssam 2829160691Ssam return 0; 2830160691Ssambad: 2831160691Ssam ifp->if_oerrors++; 2832160905Ssam ieee80211_free_node(ni); 2833160691Ssam RAL_UNLOCK(sc); 2834160691Ssam return EIO; /* XXX */ 2835160691Ssam} 2836