rt2560.c revision 160905
1156321Sdamien/* $FreeBSD: head/sys/dev/ral/rt2560.c 160905 2006-08-02 04:54:14Z 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 160905 2006-08-02 04:54:14Z 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> 36156321Sdamien#include <sys/module.h> 37156321Sdamien#include <sys/bus.h> 38156321Sdamien#include <sys/endian.h> 39156321Sdamien 40156321Sdamien#include <machine/bus.h> 41156321Sdamien#include <machine/resource.h> 42156321Sdamien#include <sys/rman.h> 43156321Sdamien 44156321Sdamien#include <net/bpf.h> 45156321Sdamien#include <net/if.h> 46156321Sdamien#include <net/if_arp.h> 47156321Sdamien#include <net/ethernet.h> 48156321Sdamien#include <net/if_dl.h> 49156321Sdamien#include <net/if_media.h> 50156321Sdamien#include <net/if_types.h> 51156321Sdamien 52156321Sdamien#include <net80211/ieee80211_var.h> 53156321Sdamien#include <net80211/ieee80211_radiotap.h> 54156321Sdamien 55156321Sdamien#include <netinet/in.h> 56156321Sdamien#include <netinet/in_systm.h> 57156321Sdamien#include <netinet/in_var.h> 58156321Sdamien#include <netinet/ip.h> 59156321Sdamien#include <netinet/if_ether.h> 60156321Sdamien 61156327Ssilby#include <dev/ral/if_ralrate.h> 62156327Ssilby#include <dev/ral/rt2560reg.h> 63156327Ssilby#include <dev/ral/rt2560var.h> 64156321Sdamien 65156321Sdamien#ifdef RAL_DEBUG 66156321Sdamien#define DPRINTF(x) do { if (ral_debug > 0) printf x; } while (0) 67156321Sdamien#define DPRINTFN(n, x) do { if (ral_debug >= (n)) printf x; } while (0) 68156321Sdamienextern int ral_debug; 69156321Sdamien#else 70156321Sdamien#define DPRINTF(x) 71156321Sdamien#define DPRINTFN(n, x) 72156321Sdamien#endif 73156321Sdamien 74156321Sdamienstatic void rt2560_dma_map_addr(void *, bus_dma_segment_t *, int, 75156321Sdamien int); 76156321Sdamienstatic int rt2560_alloc_tx_ring(struct rt2560_softc *, 77156321Sdamien struct rt2560_tx_ring *, int); 78156321Sdamienstatic void rt2560_reset_tx_ring(struct rt2560_softc *, 79156321Sdamien struct rt2560_tx_ring *); 80156321Sdamienstatic void rt2560_free_tx_ring(struct rt2560_softc *, 81156321Sdamien struct rt2560_tx_ring *); 82156321Sdamienstatic int rt2560_alloc_rx_ring(struct rt2560_softc *, 83156321Sdamien struct rt2560_rx_ring *, int); 84156321Sdamienstatic void rt2560_reset_rx_ring(struct rt2560_softc *, 85156321Sdamien struct rt2560_rx_ring *); 86156321Sdamienstatic void rt2560_free_rx_ring(struct rt2560_softc *, 87156321Sdamien struct rt2560_rx_ring *); 88156321Sdamienstatic struct ieee80211_node *rt2560_node_alloc( 89156321Sdamien struct ieee80211_node_table *); 90156321Sdamienstatic int rt2560_media_change(struct ifnet *); 91156321Sdamienstatic void rt2560_next_scan(void *); 92156321Sdamienstatic void rt2560_iter_func(void *, struct ieee80211_node *); 93156321Sdamienstatic void rt2560_update_rssadapt(void *); 94156321Sdamienstatic int rt2560_newstate(struct ieee80211com *, 95156321Sdamien enum ieee80211_state, int); 96156321Sdamienstatic uint16_t rt2560_eeprom_read(struct rt2560_softc *, uint8_t); 97156321Sdamienstatic void rt2560_encryption_intr(struct rt2560_softc *); 98156321Sdamienstatic void rt2560_tx_intr(struct rt2560_softc *); 99156321Sdamienstatic void rt2560_prio_intr(struct rt2560_softc *); 100156321Sdamienstatic void rt2560_decryption_intr(struct rt2560_softc *); 101156321Sdamienstatic void rt2560_rx_intr(struct rt2560_softc *); 102156321Sdamienstatic void rt2560_beacon_expire(struct rt2560_softc *); 103156321Sdamienstatic void rt2560_wakeup_expire(struct rt2560_softc *); 104156321Sdamienstatic uint8_t rt2560_rxrate(struct rt2560_rx_desc *); 105156321Sdamienstatic int rt2560_ack_rate(struct ieee80211com *, int); 106156321Sdamienstatic uint16_t rt2560_txtime(int, int, uint32_t); 107156321Sdamienstatic uint8_t rt2560_plcp_signal(int); 108156321Sdamienstatic void rt2560_setup_tx_desc(struct rt2560_softc *, 109156321Sdamien struct rt2560_tx_desc *, uint32_t, int, int, int, 110156321Sdamien bus_addr_t); 111156321Sdamienstatic int rt2560_tx_bcn(struct rt2560_softc *, struct mbuf *, 112156321Sdamien struct ieee80211_node *); 113156321Sdamienstatic int rt2560_tx_mgt(struct rt2560_softc *, struct mbuf *, 114156321Sdamien struct ieee80211_node *); 115156321Sdamienstatic struct mbuf *rt2560_get_rts(struct rt2560_softc *, 116156321Sdamien struct ieee80211_frame *, uint16_t); 117156321Sdamienstatic int rt2560_tx_data(struct rt2560_softc *, struct mbuf *, 118156321Sdamien struct ieee80211_node *); 119156321Sdamienstatic void rt2560_start(struct ifnet *); 120156321Sdamienstatic void rt2560_watchdog(struct ifnet *); 121156321Sdamienstatic int rt2560_reset(struct ifnet *); 122156321Sdamienstatic int rt2560_ioctl(struct ifnet *, u_long, caddr_t); 123156321Sdamienstatic void rt2560_bbp_write(struct rt2560_softc *, uint8_t, 124156321Sdamien uint8_t); 125156321Sdamienstatic uint8_t rt2560_bbp_read(struct rt2560_softc *, uint8_t); 126156321Sdamienstatic void rt2560_rf_write(struct rt2560_softc *, uint8_t, 127156321Sdamien uint32_t); 128156321Sdamienstatic void rt2560_set_chan(struct rt2560_softc *, 129156321Sdamien struct ieee80211_channel *); 130156321Sdamien#if 0 131156321Sdamienstatic void rt2560_disable_rf_tune(struct rt2560_softc *); 132156321Sdamien#endif 133156321Sdamienstatic void rt2560_enable_tsf_sync(struct rt2560_softc *); 134156321Sdamienstatic void rt2560_update_plcp(struct rt2560_softc *); 135156321Sdamienstatic void rt2560_update_slot(struct ifnet *); 136156321Sdamienstatic void rt2560_set_basicrates(struct rt2560_softc *); 137156321Sdamienstatic void rt2560_update_led(struct rt2560_softc *, int, int); 138156321Sdamienstatic void rt2560_set_bssid(struct rt2560_softc *, uint8_t *); 139156321Sdamienstatic void rt2560_set_macaddr(struct rt2560_softc *, uint8_t *); 140156321Sdamienstatic void rt2560_get_macaddr(struct rt2560_softc *, uint8_t *); 141156321Sdamienstatic void rt2560_update_promisc(struct rt2560_softc *); 142156321Sdamienstatic const char *rt2560_get_rf(int); 143156321Sdamienstatic void rt2560_read_eeprom(struct rt2560_softc *); 144156321Sdamienstatic int rt2560_bbp_init(struct rt2560_softc *); 145156321Sdamienstatic void rt2560_set_txantenna(struct rt2560_softc *, int); 146156321Sdamienstatic void rt2560_set_rxantenna(struct rt2560_softc *, int); 147156321Sdamienstatic void rt2560_init(void *); 148156321Sdamienstatic void rt2560_stop(void *); 149160691Ssamstatic int rt2560_raw_xmit(struct ieee80211_node *, struct mbuf *, 150160691Ssam const struct ieee80211_bpf_params *); 151156321Sdamien 152156321Sdamien/* 153156321Sdamien * Supported rates for 802.11a/b/g modes (in 500Kbps unit). 154156321Sdamien */ 155156321Sdamienstatic const struct ieee80211_rateset rt2560_rateset_11a = 156156321Sdamien { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } }; 157156321Sdamien 158156321Sdamienstatic const struct ieee80211_rateset rt2560_rateset_11b = 159156321Sdamien { 4, { 2, 4, 11, 22 } }; 160156321Sdamien 161156321Sdamienstatic const struct ieee80211_rateset rt2560_rateset_11g = 162156321Sdamien { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } }; 163156321Sdamien 164156321Sdamienstatic const struct { 165156321Sdamien uint32_t reg; 166156321Sdamien uint32_t val; 167156321Sdamien} rt2560_def_mac[] = { 168156321Sdamien RT2560_DEF_MAC 169156321Sdamien}; 170156321Sdamien 171156321Sdamienstatic const struct { 172156321Sdamien uint8_t reg; 173156321Sdamien uint8_t val; 174156321Sdamien} rt2560_def_bbp[] = { 175156321Sdamien RT2560_DEF_BBP 176156321Sdamien}; 177156321Sdamien 178156321Sdamienstatic const uint32_t rt2560_rf2522_r2[] = RT2560_RF2522_R2; 179156321Sdamienstatic const uint32_t rt2560_rf2523_r2[] = RT2560_RF2523_R2; 180156321Sdamienstatic const uint32_t rt2560_rf2524_r2[] = RT2560_RF2524_R2; 181156321Sdamienstatic const uint32_t rt2560_rf2525_r2[] = RT2560_RF2525_R2; 182156321Sdamienstatic const uint32_t rt2560_rf2525_hi_r2[] = RT2560_RF2525_HI_R2; 183156321Sdamienstatic const uint32_t rt2560_rf2525e_r2[] = RT2560_RF2525E_R2; 184156321Sdamienstatic const uint32_t rt2560_rf2526_r2[] = RT2560_RF2526_R2; 185156321Sdamienstatic const uint32_t rt2560_rf2526_hi_r2[] = RT2560_RF2526_HI_R2; 186156321Sdamien 187156321Sdamienstatic const struct { 188156321Sdamien uint8_t chan; 189156321Sdamien uint32_t r1, r2, r4; 190156321Sdamien} rt2560_rf5222[] = { 191156321Sdamien RT2560_RF5222 192156321Sdamien}; 193156321Sdamien 194156321Sdamienint 195156321Sdamienrt2560_attach(device_t dev, int id) 196156321Sdamien{ 197156321Sdamien struct rt2560_softc *sc = device_get_softc(dev); 198156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 199156321Sdamien struct ifnet *ifp; 200156321Sdamien int error, i; 201156321Sdamien 202156321Sdamien sc->sc_dev = dev; 203156321Sdamien 204156321Sdamien mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 205156321Sdamien MTX_DEF | MTX_RECURSE); 206156321Sdamien 207156321Sdamien callout_init(&sc->scan_ch, debug_mpsafenet ? CALLOUT_MPSAFE : 0); 208156321Sdamien callout_init(&sc->rssadapt_ch, CALLOUT_MPSAFE); 209156321Sdamien 210156321Sdamien /* retrieve RT2560 rev. no */ 211156321Sdamien sc->asic_rev = RAL_READ(sc, RT2560_CSR0); 212156321Sdamien 213156321Sdamien /* retrieve MAC address */ 214156321Sdamien rt2560_get_macaddr(sc, ic->ic_myaddr); 215156321Sdamien 216156321Sdamien /* retrieve RF rev. no and various other things from EEPROM */ 217156321Sdamien rt2560_read_eeprom(sc); 218156321Sdamien 219156321Sdamien device_printf(dev, "MAC/BBP RT2560 (rev 0x%02x), RF %s\n", 220156321Sdamien sc->asic_rev, rt2560_get_rf(sc->rf_rev)); 221156321Sdamien 222156321Sdamien /* 223156321Sdamien * Allocate Tx and Rx rings. 224156321Sdamien */ 225156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->txq, RT2560_TX_RING_COUNT); 226156321Sdamien if (error != 0) { 227156321Sdamien device_printf(sc->sc_dev, "could not allocate Tx ring\n"); 228156321Sdamien goto fail1; 229156321Sdamien } 230156321Sdamien 231156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->atimq, RT2560_ATIM_RING_COUNT); 232156321Sdamien if (error != 0) { 233156321Sdamien device_printf(sc->sc_dev, "could not allocate ATIM ring\n"); 234156321Sdamien goto fail2; 235156321Sdamien } 236156321Sdamien 237156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->prioq, RT2560_PRIO_RING_COUNT); 238156321Sdamien if (error != 0) { 239156321Sdamien device_printf(sc->sc_dev, "could not allocate Prio ring\n"); 240156321Sdamien goto fail3; 241156321Sdamien } 242156321Sdamien 243156321Sdamien error = rt2560_alloc_tx_ring(sc, &sc->bcnq, RT2560_BEACON_RING_COUNT); 244156321Sdamien if (error != 0) { 245156321Sdamien device_printf(sc->sc_dev, "could not allocate Beacon ring\n"); 246156321Sdamien goto fail4; 247156321Sdamien } 248156321Sdamien 249156321Sdamien error = rt2560_alloc_rx_ring(sc, &sc->rxq, RT2560_RX_RING_COUNT); 250156321Sdamien if (error != 0) { 251156321Sdamien device_printf(sc->sc_dev, "could not allocate Rx ring\n"); 252156321Sdamien goto fail5; 253156321Sdamien } 254156321Sdamien 255156321Sdamien ifp = sc->sc_ifp = if_alloc(IFT_ETHER); 256156321Sdamien if (ifp == NULL) { 257156321Sdamien device_printf(sc->sc_dev, "can not if_alloc()\n"); 258156321Sdamien goto fail6; 259156321Sdamien } 260156321Sdamien 261156321Sdamien ifp->if_softc = sc; 262156321Sdamien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 263156321Sdamien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 264156321Sdamien ifp->if_init = rt2560_init; 265156321Sdamien ifp->if_ioctl = rt2560_ioctl; 266156321Sdamien ifp->if_start = rt2560_start; 267156321Sdamien ifp->if_watchdog = rt2560_watchdog; 268156321Sdamien IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 269156321Sdamien ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 270156321Sdamien IFQ_SET_READY(&ifp->if_snd); 271156321Sdamien 272156321Sdamien ic->ic_ifp = ifp; 273156321Sdamien ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 274156321Sdamien ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 275156321Sdamien ic->ic_state = IEEE80211_S_INIT; 276156321Sdamien 277156321Sdamien /* set device capabilities */ 278156321Sdamien ic->ic_caps = 279156321Sdamien IEEE80211_C_IBSS | /* IBSS mode supported */ 280156321Sdamien IEEE80211_C_MONITOR | /* monitor mode supported */ 281156321Sdamien IEEE80211_C_HOSTAP | /* HostAp mode supported */ 282156321Sdamien IEEE80211_C_TXPMGT | /* tx power management */ 283156321Sdamien IEEE80211_C_SHPREAMBLE | /* short preamble supported */ 284156321Sdamien IEEE80211_C_SHSLOT | /* short slot time supported */ 285156321Sdamien IEEE80211_C_WPA; /* 802.11i */ 286156321Sdamien 287156321Sdamien if (sc->rf_rev == RT2560_RF_5222) { 288156321Sdamien /* set supported .11a rates */ 289156321Sdamien ic->ic_sup_rates[IEEE80211_MODE_11A] = rt2560_rateset_11a; 290156321Sdamien 291156321Sdamien /* set supported .11a channels */ 292156321Sdamien for (i = 36; i <= 64; i += 4) { 293156321Sdamien ic->ic_channels[i].ic_freq = 294156321Sdamien ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); 295156321Sdamien ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A; 296156321Sdamien } 297156321Sdamien for (i = 100; i <= 140; i += 4) { 298156321Sdamien ic->ic_channels[i].ic_freq = 299156321Sdamien ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); 300156321Sdamien ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A; 301156321Sdamien } 302156321Sdamien for (i = 149; i <= 161; i += 4) { 303156321Sdamien ic->ic_channels[i].ic_freq = 304156321Sdamien ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); 305156321Sdamien ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A; 306156321Sdamien } 307156321Sdamien } 308156321Sdamien 309156321Sdamien /* set supported .11b and .11g rates */ 310156321Sdamien ic->ic_sup_rates[IEEE80211_MODE_11B] = rt2560_rateset_11b; 311156321Sdamien ic->ic_sup_rates[IEEE80211_MODE_11G] = rt2560_rateset_11g; 312156321Sdamien 313156321Sdamien /* set supported .11b and .11g channels (1 through 14) */ 314156321Sdamien for (i = 1; i <= 14; i++) { 315156321Sdamien ic->ic_channels[i].ic_freq = 316156321Sdamien ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); 317156321Sdamien ic->ic_channels[i].ic_flags = 318156321Sdamien IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | 319156321Sdamien IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; 320156321Sdamien } 321156321Sdamien 322156321Sdamien ieee80211_ifattach(ic); 323156321Sdamien ic->ic_node_alloc = rt2560_node_alloc; 324156321Sdamien ic->ic_updateslot = rt2560_update_slot; 325156321Sdamien ic->ic_reset = rt2560_reset; 326156321Sdamien /* enable s/w bmiss handling in sta mode */ 327156321Sdamien ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; 328156321Sdamien 329156321Sdamien /* override state transition machine */ 330156321Sdamien sc->sc_newstate = ic->ic_newstate; 331156321Sdamien ic->ic_newstate = rt2560_newstate; 332160691Ssam ic->ic_raw_xmit = rt2560_raw_xmit; 333156321Sdamien ieee80211_media_init(ic, rt2560_media_change, ieee80211_media_status); 334156321Sdamien 335156321Sdamien bpfattach2(ifp, DLT_IEEE802_11_RADIO, 336156321Sdamien sizeof (struct ieee80211_frame) + 64, &sc->sc_drvbpf); 337156321Sdamien 338156321Sdamien sc->sc_rxtap_len = sizeof sc->sc_rxtapu; 339156321Sdamien sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); 340156321Sdamien sc->sc_rxtap.wr_ihdr.it_present = htole32(RT2560_RX_RADIOTAP_PRESENT); 341156321Sdamien 342156321Sdamien sc->sc_txtap_len = sizeof sc->sc_txtapu; 343156321Sdamien sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); 344156321Sdamien sc->sc_txtap.wt_ihdr.it_present = htole32(RT2560_TX_RADIOTAP_PRESENT); 345156321Sdamien 346156321Sdamien /* 347156321Sdamien * Add a few sysctl knobs. 348156321Sdamien */ 349156321Sdamien sc->dwelltime = 200; 350156321Sdamien 351156321Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 352156321Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 353156321Sdamien "txantenna", CTLFLAG_RW, &sc->tx_ant, 0, "tx antenna (0=auto)"); 354156321Sdamien 355156321Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 356156321Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 357156321Sdamien "rxantenna", CTLFLAG_RW, &sc->rx_ant, 0, "rx antenna (0=auto)"); 358156321Sdamien 359156321Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 360156321Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "dwell", 361156321Sdamien CTLFLAG_RW, &sc->dwelltime, 0, 362156321Sdamien "channel dwell time (ms) for AP/station scanning"); 363156321Sdamien 364156321Sdamien if (bootverbose) 365156321Sdamien ieee80211_announce(ic); 366156321Sdamien 367156321Sdamien return 0; 368156321Sdamien 369156321Sdamienfail6: rt2560_free_rx_ring(sc, &sc->rxq); 370156321Sdamienfail5: rt2560_free_tx_ring(sc, &sc->bcnq); 371156321Sdamienfail4: rt2560_free_tx_ring(sc, &sc->prioq); 372156321Sdamienfail3: rt2560_free_tx_ring(sc, &sc->atimq); 373156321Sdamienfail2: rt2560_free_tx_ring(sc, &sc->txq); 374156321Sdamienfail1: mtx_destroy(&sc->sc_mtx); 375156321Sdamien 376156321Sdamien return ENXIO; 377156321Sdamien} 378156321Sdamien 379156321Sdamienint 380156321Sdamienrt2560_detach(void *xsc) 381156321Sdamien{ 382156321Sdamien struct rt2560_softc *sc = xsc; 383156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 384156321Sdamien struct ifnet *ifp = ic->ic_ifp; 385156321Sdamien 386156321Sdamien rt2560_stop(sc); 387156321Sdamien callout_stop(&sc->scan_ch); 388156321Sdamien callout_stop(&sc->rssadapt_ch); 389156321Sdamien 390156321Sdamien bpfdetach(ifp); 391156321Sdamien ieee80211_ifdetach(ic); 392156321Sdamien 393156321Sdamien rt2560_free_tx_ring(sc, &sc->txq); 394156321Sdamien rt2560_free_tx_ring(sc, &sc->atimq); 395156321Sdamien rt2560_free_tx_ring(sc, &sc->prioq); 396156321Sdamien rt2560_free_tx_ring(sc, &sc->bcnq); 397156321Sdamien rt2560_free_rx_ring(sc, &sc->rxq); 398156321Sdamien 399156321Sdamien if_free(ifp); 400156321Sdamien 401156321Sdamien mtx_destroy(&sc->sc_mtx); 402156321Sdamien 403156321Sdamien return 0; 404156321Sdamien} 405156321Sdamien 406156321Sdamienvoid 407156321Sdamienrt2560_shutdown(void *xsc) 408156321Sdamien{ 409156321Sdamien struct rt2560_softc *sc = xsc; 410156321Sdamien 411156321Sdamien rt2560_stop(sc); 412156321Sdamien} 413156321Sdamien 414156321Sdamienvoid 415156321Sdamienrt2560_suspend(void *xsc) 416156321Sdamien{ 417156321Sdamien struct rt2560_softc *sc = xsc; 418156321Sdamien 419156321Sdamien rt2560_stop(sc); 420156321Sdamien} 421156321Sdamien 422156321Sdamienvoid 423156321Sdamienrt2560_resume(void *xsc) 424156321Sdamien{ 425156321Sdamien struct rt2560_softc *sc = xsc; 426156321Sdamien struct ifnet *ifp = sc->sc_ic.ic_ifp; 427156321Sdamien 428156321Sdamien if (ifp->if_flags & IFF_UP) { 429156321Sdamien ifp->if_init(ifp->if_softc); 430156321Sdamien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 431156321Sdamien ifp->if_start(ifp); 432156321Sdamien } 433156321Sdamien} 434156321Sdamien 435156321Sdamienstatic void 436156321Sdamienrt2560_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 437156321Sdamien{ 438156321Sdamien if (error != 0) 439156321Sdamien return; 440156321Sdamien 441156321Sdamien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 442156321Sdamien 443156321Sdamien *(bus_addr_t *)arg = segs[0].ds_addr; 444156321Sdamien} 445156321Sdamien 446156321Sdamienstatic int 447156321Sdamienrt2560_alloc_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring, 448156321Sdamien int count) 449156321Sdamien{ 450156321Sdamien int i, error; 451156321Sdamien 452156321Sdamien ring->count = count; 453156321Sdamien ring->queued = 0; 454156321Sdamien ring->cur = ring->next = 0; 455156321Sdamien ring->cur_encrypt = ring->next_encrypt = 0; 456156321Sdamien 457156321Sdamien error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT, 458156321Sdamien BUS_SPACE_MAXADDR, NULL, NULL, count * RT2560_TX_DESC_SIZE, 1, 459156321Sdamien count * RT2560_TX_DESC_SIZE, 0, NULL, NULL, &ring->desc_dmat); 460156321Sdamien if (error != 0) { 461156321Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 462156321Sdamien goto fail; 463156321Sdamien } 464156321Sdamien 465156321Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 466156321Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 467156321Sdamien if (error != 0) { 468156321Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 469156321Sdamien goto fail; 470156321Sdamien } 471156321Sdamien 472156321Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 473156321Sdamien count * RT2560_TX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr, 474156321Sdamien 0); 475156321Sdamien if (error != 0) { 476156321Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 477156321Sdamien goto fail; 478156321Sdamien } 479156321Sdamien 480156321Sdamien ring->data = malloc(count * sizeof (struct rt2560_tx_data), M_DEVBUF, 481156321Sdamien M_NOWAIT | M_ZERO); 482156321Sdamien if (ring->data == NULL) { 483156321Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 484156321Sdamien error = ENOMEM; 485156321Sdamien goto fail; 486156321Sdamien } 487156321Sdamien 488156321Sdamien error = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, 489156321Sdamien BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, RT2560_MAX_SCATTER, 490156321Sdamien MCLBYTES, 0, NULL, NULL, &ring->data_dmat); 491156321Sdamien if (error != 0) { 492156321Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 493156321Sdamien goto fail; 494156321Sdamien } 495156321Sdamien 496156321Sdamien for (i = 0; i < count; i++) { 497156321Sdamien error = bus_dmamap_create(ring->data_dmat, 0, 498156321Sdamien &ring->data[i].map); 499156321Sdamien if (error != 0) { 500156321Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 501156321Sdamien goto fail; 502156321Sdamien } 503156321Sdamien } 504156321Sdamien 505156321Sdamien return 0; 506156321Sdamien 507156321Sdamienfail: rt2560_free_tx_ring(sc, ring); 508156321Sdamien return error; 509156321Sdamien} 510156321Sdamien 511156321Sdamienstatic void 512156321Sdamienrt2560_reset_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) 513156321Sdamien{ 514156321Sdamien struct rt2560_tx_desc *desc; 515156321Sdamien struct rt2560_tx_data *data; 516156321Sdamien int i; 517156321Sdamien 518156321Sdamien for (i = 0; i < ring->count; i++) { 519156321Sdamien desc = &ring->desc[i]; 520156321Sdamien data = &ring->data[i]; 521156321Sdamien 522156321Sdamien if (data->m != NULL) { 523156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 524156321Sdamien BUS_DMASYNC_POSTWRITE); 525156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 526156321Sdamien m_freem(data->m); 527156321Sdamien data->m = NULL; 528156321Sdamien } 529156321Sdamien 530156321Sdamien if (data->ni != NULL) { 531156321Sdamien ieee80211_free_node(data->ni); 532156321Sdamien data->ni = NULL; 533156321Sdamien } 534156321Sdamien 535156321Sdamien desc->flags = 0; 536156321Sdamien } 537156321Sdamien 538156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 539156321Sdamien 540156321Sdamien ring->queued = 0; 541156321Sdamien ring->cur = ring->next = 0; 542156321Sdamien ring->cur_encrypt = ring->next_encrypt = 0; 543156321Sdamien} 544156321Sdamien 545156321Sdamienstatic void 546156321Sdamienrt2560_free_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) 547156321Sdamien{ 548156321Sdamien struct rt2560_tx_data *data; 549156321Sdamien int i; 550156321Sdamien 551156321Sdamien if (ring->desc != NULL) { 552156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 553156321Sdamien BUS_DMASYNC_POSTWRITE); 554156321Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 555156321Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 556156321Sdamien } 557156321Sdamien 558156321Sdamien if (ring->desc_dmat != NULL) 559156321Sdamien bus_dma_tag_destroy(ring->desc_dmat); 560156321Sdamien 561156321Sdamien if (ring->data != NULL) { 562156321Sdamien for (i = 0; i < ring->count; i++) { 563156321Sdamien data = &ring->data[i]; 564156321Sdamien 565156321Sdamien if (data->m != NULL) { 566156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 567156321Sdamien BUS_DMASYNC_POSTWRITE); 568156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 569156321Sdamien m_freem(data->m); 570156321Sdamien } 571156321Sdamien 572156321Sdamien if (data->ni != NULL) 573156321Sdamien ieee80211_free_node(data->ni); 574156321Sdamien 575156321Sdamien if (data->map != NULL) 576156321Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 577156321Sdamien } 578156321Sdamien 579156321Sdamien free(ring->data, M_DEVBUF); 580156321Sdamien } 581156321Sdamien 582156321Sdamien if (ring->data_dmat != NULL) 583156321Sdamien bus_dma_tag_destroy(ring->data_dmat); 584156321Sdamien} 585156321Sdamien 586156321Sdamienstatic int 587156321Sdamienrt2560_alloc_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring, 588156321Sdamien int count) 589156321Sdamien{ 590156321Sdamien struct rt2560_rx_desc *desc; 591156321Sdamien struct rt2560_rx_data *data; 592156321Sdamien bus_addr_t physaddr; 593156321Sdamien int i, error; 594156321Sdamien 595156321Sdamien ring->count = count; 596156321Sdamien ring->cur = ring->next = 0; 597156321Sdamien ring->cur_decrypt = 0; 598156321Sdamien 599156321Sdamien error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT, 600156321Sdamien BUS_SPACE_MAXADDR, NULL, NULL, count * RT2560_RX_DESC_SIZE, 1, 601156321Sdamien count * RT2560_RX_DESC_SIZE, 0, NULL, NULL, &ring->desc_dmat); 602156321Sdamien if (error != 0) { 603156321Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 604156321Sdamien goto fail; 605156321Sdamien } 606156321Sdamien 607156321Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 608156321Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 609156321Sdamien if (error != 0) { 610156321Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 611156321Sdamien goto fail; 612156321Sdamien } 613156321Sdamien 614156321Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 615156321Sdamien count * RT2560_RX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr, 616156321Sdamien 0); 617156321Sdamien if (error != 0) { 618156321Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 619156321Sdamien goto fail; 620156321Sdamien } 621156321Sdamien 622156321Sdamien ring->data = malloc(count * sizeof (struct rt2560_rx_data), M_DEVBUF, 623156321Sdamien M_NOWAIT | M_ZERO); 624156321Sdamien if (ring->data == NULL) { 625156321Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 626156321Sdamien error = ENOMEM; 627156321Sdamien goto fail; 628156321Sdamien } 629156321Sdamien 630156321Sdamien /* 631156321Sdamien * Pre-allocate Rx buffers and populate Rx ring. 632156321Sdamien */ 633156321Sdamien error = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, 634156321Sdamien BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, MCLBYTES, 0, NULL, 635156321Sdamien NULL, &ring->data_dmat); 636156321Sdamien if (error != 0) { 637156321Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 638156321Sdamien goto fail; 639156321Sdamien } 640156321Sdamien 641156321Sdamien for (i = 0; i < count; i++) { 642156321Sdamien desc = &sc->rxq.desc[i]; 643156321Sdamien data = &sc->rxq.data[i]; 644156321Sdamien 645156321Sdamien error = bus_dmamap_create(ring->data_dmat, 0, &data->map); 646156321Sdamien if (error != 0) { 647156321Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 648156321Sdamien goto fail; 649156321Sdamien } 650156321Sdamien 651156321Sdamien data->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 652156321Sdamien if (data->m == NULL) { 653156321Sdamien device_printf(sc->sc_dev, 654156321Sdamien "could not allocate rx mbuf\n"); 655156321Sdamien error = ENOMEM; 656156321Sdamien goto fail; 657156321Sdamien } 658156321Sdamien 659156321Sdamien error = bus_dmamap_load(ring->data_dmat, data->map, 660156321Sdamien mtod(data->m, void *), MCLBYTES, rt2560_dma_map_addr, 661156321Sdamien &physaddr, 0); 662156321Sdamien if (error != 0) { 663156321Sdamien device_printf(sc->sc_dev, 664156321Sdamien "could not load rx buf DMA map"); 665156321Sdamien goto fail; 666156321Sdamien } 667156321Sdamien 668156321Sdamien desc->flags = htole32(RT2560_RX_BUSY); 669156321Sdamien desc->physaddr = htole32(physaddr); 670156321Sdamien } 671156321Sdamien 672156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 673156321Sdamien 674156321Sdamien return 0; 675156321Sdamien 676156321Sdamienfail: rt2560_free_rx_ring(sc, ring); 677156321Sdamien return error; 678156321Sdamien} 679156321Sdamien 680156321Sdamienstatic void 681156321Sdamienrt2560_reset_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) 682156321Sdamien{ 683156321Sdamien int i; 684156321Sdamien 685156321Sdamien for (i = 0; i < ring->count; i++) { 686156321Sdamien ring->desc[i].flags = htole32(RT2560_RX_BUSY); 687156321Sdamien ring->data[i].drop = 0; 688156321Sdamien } 689156321Sdamien 690156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 691156321Sdamien 692156321Sdamien ring->cur = ring->next = 0; 693156321Sdamien ring->cur_decrypt = 0; 694156321Sdamien} 695156321Sdamien 696156321Sdamienstatic void 697156321Sdamienrt2560_free_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) 698156321Sdamien{ 699156321Sdamien struct rt2560_rx_data *data; 700156321Sdamien int i; 701156321Sdamien 702156321Sdamien if (ring->desc != NULL) { 703156321Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 704156321Sdamien BUS_DMASYNC_POSTWRITE); 705156321Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 706156321Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 707156321Sdamien } 708156321Sdamien 709156321Sdamien if (ring->desc_dmat != NULL) 710156321Sdamien bus_dma_tag_destroy(ring->desc_dmat); 711156321Sdamien 712156321Sdamien if (ring->data != NULL) { 713156321Sdamien for (i = 0; i < ring->count; i++) { 714156321Sdamien data = &ring->data[i]; 715156321Sdamien 716156321Sdamien if (data->m != NULL) { 717156321Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 718156321Sdamien BUS_DMASYNC_POSTREAD); 719156321Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 720156321Sdamien m_freem(data->m); 721156321Sdamien } 722156321Sdamien 723156321Sdamien if (data->map != NULL) 724156321Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 725156321Sdamien } 726156321Sdamien 727156321Sdamien free(ring->data, M_DEVBUF); 728156321Sdamien } 729156321Sdamien 730156321Sdamien if (ring->data_dmat != NULL) 731156321Sdamien bus_dma_tag_destroy(ring->data_dmat); 732156321Sdamien} 733156321Sdamien 734156321Sdamienstatic struct ieee80211_node * 735156321Sdamienrt2560_node_alloc(struct ieee80211_node_table *nt) 736156321Sdamien{ 737156321Sdamien struct rt2560_node *rn; 738156321Sdamien 739156321Sdamien rn = malloc(sizeof (struct rt2560_node), M_80211_NODE, 740156321Sdamien M_NOWAIT | M_ZERO); 741156321Sdamien 742156321Sdamien return (rn != NULL) ? &rn->ni : NULL; 743156321Sdamien} 744156321Sdamien 745156321Sdamienstatic int 746156321Sdamienrt2560_media_change(struct ifnet *ifp) 747156321Sdamien{ 748156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 749156321Sdamien int error; 750156321Sdamien 751156321Sdamien error = ieee80211_media_change(ifp); 752156321Sdamien if (error != ENETRESET) 753156321Sdamien return error; 754156321Sdamien 755156321Sdamien if ((ifp->if_flags & IFF_UP) && 756156321Sdamien (ifp->if_drv_flags & IFF_DRV_RUNNING)) 757156321Sdamien rt2560_init(sc); 758156321Sdamien 759156321Sdamien return 0; 760156321Sdamien} 761156321Sdamien 762156321Sdamien/* 763156321Sdamien * This function is called periodically (every 200ms) during scanning to 764156321Sdamien * switch from one channel to another. 765156321Sdamien */ 766156321Sdamienstatic void 767156321Sdamienrt2560_next_scan(void *arg) 768156321Sdamien{ 769156321Sdamien struct rt2560_softc *sc = arg; 770156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 771156321Sdamien 772156321Sdamien if (ic->ic_state == IEEE80211_S_SCAN) 773156321Sdamien ieee80211_next_scan(ic); 774156321Sdamien} 775156321Sdamien 776156321Sdamien/* 777156321Sdamien * This function is called for each node present in the node station table. 778156321Sdamien */ 779156321Sdamienstatic void 780156321Sdamienrt2560_iter_func(void *arg, struct ieee80211_node *ni) 781156321Sdamien{ 782156321Sdamien struct rt2560_node *rn = (struct rt2560_node *)ni; 783156321Sdamien 784156321Sdamien ral_rssadapt_updatestats(&rn->rssadapt); 785156321Sdamien} 786156321Sdamien 787156321Sdamien/* 788156321Sdamien * This function is called periodically (every 100ms) in RUN state to update 789156321Sdamien * the rate adaptation statistics. 790156321Sdamien */ 791156321Sdamienstatic void 792156321Sdamienrt2560_update_rssadapt(void *arg) 793156321Sdamien{ 794156321Sdamien struct rt2560_softc *sc = arg; 795156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 796156321Sdamien 797156321Sdamien RAL_LOCK(sc); 798156321Sdamien 799156321Sdamien ieee80211_iterate_nodes(&ic->ic_sta, rt2560_iter_func, arg); 800156321Sdamien callout_reset(&sc->rssadapt_ch, hz / 10, rt2560_update_rssadapt, sc); 801156321Sdamien 802156321Sdamien RAL_UNLOCK(sc); 803156321Sdamien} 804156321Sdamien 805156321Sdamienstatic int 806156321Sdamienrt2560_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 807156321Sdamien{ 808156321Sdamien struct rt2560_softc *sc = ic->ic_ifp->if_softc; 809156321Sdamien enum ieee80211_state ostate; 810156321Sdamien struct ieee80211_node *ni; 811156321Sdamien struct mbuf *m; 812156321Sdamien int error = 0; 813156321Sdamien 814156321Sdamien ostate = ic->ic_state; 815156321Sdamien callout_stop(&sc->scan_ch); 816156321Sdamien 817156321Sdamien switch (nstate) { 818156321Sdamien case IEEE80211_S_INIT: 819156321Sdamien callout_stop(&sc->rssadapt_ch); 820156321Sdamien 821156321Sdamien if (ostate == IEEE80211_S_RUN) { 822156321Sdamien /* abort TSF synchronization */ 823156321Sdamien RAL_WRITE(sc, RT2560_CSR14, 0); 824156321Sdamien 825156321Sdamien /* turn association led off */ 826156321Sdamien rt2560_update_led(sc, 0, 0); 827156321Sdamien } 828156321Sdamien break; 829156321Sdamien 830156321Sdamien case IEEE80211_S_SCAN: 831156321Sdamien rt2560_set_chan(sc, ic->ic_curchan); 832156321Sdamien callout_reset(&sc->scan_ch, (sc->dwelltime * hz) / 1000, 833156321Sdamien rt2560_next_scan, sc); 834156321Sdamien break; 835156321Sdamien 836156321Sdamien case IEEE80211_S_AUTH: 837156321Sdamien rt2560_set_chan(sc, ic->ic_curchan); 838156321Sdamien break; 839156321Sdamien 840156321Sdamien case IEEE80211_S_ASSOC: 841156321Sdamien rt2560_set_chan(sc, ic->ic_curchan); 842156321Sdamien break; 843156321Sdamien 844156321Sdamien case IEEE80211_S_RUN: 845156321Sdamien rt2560_set_chan(sc, ic->ic_curchan); 846156321Sdamien 847156321Sdamien ni = ic->ic_bss; 848156321Sdamien 849156321Sdamien if (ic->ic_opmode != IEEE80211_M_MONITOR) { 850156321Sdamien rt2560_update_plcp(sc); 851156321Sdamien rt2560_set_basicrates(sc); 852156321Sdamien rt2560_set_bssid(sc, ni->ni_bssid); 853156321Sdamien } 854156321Sdamien 855156321Sdamien if (ic->ic_opmode == IEEE80211_M_HOSTAP || 856156321Sdamien ic->ic_opmode == IEEE80211_M_IBSS) { 857156321Sdamien m = ieee80211_beacon_alloc(ic, ni, &sc->sc_bo); 858156321Sdamien if (m == NULL) { 859156321Sdamien device_printf(sc->sc_dev, 860156321Sdamien "could not allocate beacon\n"); 861156321Sdamien error = ENOBUFS; 862156321Sdamien break; 863156321Sdamien } 864156321Sdamien 865156321Sdamien ieee80211_ref_node(ni); 866156321Sdamien error = rt2560_tx_bcn(sc, m, ni); 867156321Sdamien if (error != 0) 868156321Sdamien break; 869156321Sdamien } 870156321Sdamien 871156321Sdamien /* turn assocation led on */ 872156321Sdamien rt2560_update_led(sc, 1, 0); 873156321Sdamien 874156321Sdamien if (ic->ic_opmode != IEEE80211_M_MONITOR) { 875156321Sdamien callout_reset(&sc->rssadapt_ch, hz / 10, 876156321Sdamien rt2560_update_rssadapt, sc); 877156321Sdamien 878156321Sdamien rt2560_enable_tsf_sync(sc); 879156321Sdamien } 880156321Sdamien break; 881156321Sdamien } 882156321Sdamien 883156321Sdamien return (error != 0) ? error : sc->sc_newstate(ic, nstate, arg); 884156321Sdamien} 885156321Sdamien 886156321Sdamien/* 887156321Sdamien * Read 16 bits at address 'addr' from the serial EEPROM (either 93C46 or 888156321Sdamien * 93C66). 889156321Sdamien */ 890156321Sdamienstatic uint16_t 891156321Sdamienrt2560_eeprom_read(struct rt2560_softc *sc, uint8_t addr) 892156321Sdamien{ 893156321Sdamien uint32_t tmp; 894156321Sdamien uint16_t val; 895156321Sdamien int n; 896156321Sdamien 897156321Sdamien /* clock C once before the first command */ 898156321Sdamien RT2560_EEPROM_CTL(sc, 0); 899156321Sdamien 900156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 901156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 902156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 903156321Sdamien 904156321Sdamien /* write start bit (1) */ 905156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D); 906156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C); 907156321Sdamien 908156321Sdamien /* write READ opcode (10) */ 909156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D); 910156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C); 911156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 912156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 913156321Sdamien 914156321Sdamien /* write address (A5-A0 or A7-A0) */ 915156321Sdamien n = (RAL_READ(sc, RT2560_CSR21) & RT2560_93C46) ? 5 : 7; 916156321Sdamien for (; n >= 0; n--) { 917156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | 918156321Sdamien (((addr >> n) & 1) << RT2560_SHIFT_D)); 919156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | 920156321Sdamien (((addr >> n) & 1) << RT2560_SHIFT_D) | RT2560_C); 921156321Sdamien } 922156321Sdamien 923156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 924156321Sdamien 925156321Sdamien /* read data Q15-Q0 */ 926156321Sdamien val = 0; 927156321Sdamien for (n = 15; n >= 0; n--) { 928156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 929156321Sdamien tmp = RAL_READ(sc, RT2560_CSR21); 930156321Sdamien val |= ((tmp & RT2560_Q) >> RT2560_SHIFT_Q) << n; 931156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 932156321Sdamien } 933156321Sdamien 934156321Sdamien RT2560_EEPROM_CTL(sc, 0); 935156321Sdamien 936156321Sdamien /* clear Chip Select and clock C */ 937156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_S); 938156321Sdamien RT2560_EEPROM_CTL(sc, 0); 939156321Sdamien RT2560_EEPROM_CTL(sc, RT2560_C); 940156321Sdamien 941156321Sdamien return val; 942156321Sdamien} 943156321Sdamien 944156321Sdamien/* 945156321Sdamien * Some frames were processed by the hardware cipher engine and are ready for 946156321Sdamien * transmission. 947156321Sdamien */ 948156321Sdamienstatic void 949156321Sdamienrt2560_encryption_intr(struct rt2560_softc *sc) 950156321Sdamien{ 951156321Sdamien struct rt2560_tx_desc *desc; 952156321Sdamien int hw; 953156321Sdamien 954156321Sdamien /* retrieve last descriptor index processed by cipher engine */ 955156321Sdamien hw = RAL_READ(sc, RT2560_SECCSR1) - sc->txq.physaddr; 956156321Sdamien hw /= RT2560_TX_DESC_SIZE; 957156321Sdamien 958156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 959156321Sdamien BUS_DMASYNC_POSTREAD); 960156321Sdamien 961156321Sdamien for (; sc->txq.next_encrypt != hw;) { 962156321Sdamien desc = &sc->txq.desc[sc->txq.next_encrypt]; 963156321Sdamien 964156321Sdamien if ((le32toh(desc->flags) & RT2560_TX_BUSY) || 965156321Sdamien (le32toh(desc->flags) & RT2560_TX_CIPHER_BUSY)) 966156321Sdamien break; 967156321Sdamien 968156321Sdamien /* for TKIP, swap eiv field to fix a bug in ASIC */ 969156321Sdamien if ((le32toh(desc->flags) & RT2560_TX_CIPHER_MASK) == 970156321Sdamien RT2560_TX_CIPHER_TKIP) 971156321Sdamien desc->eiv = bswap32(desc->eiv); 972156321Sdamien 973156321Sdamien /* mark the frame ready for transmission */ 974156321Sdamien desc->flags |= htole32(RT2560_TX_BUSY | RT2560_TX_VALID); 975156321Sdamien 976156321Sdamien DPRINTFN(15, ("encryption done idx=%u\n", 977156321Sdamien sc->txq.next_encrypt)); 978156321Sdamien 979156321Sdamien sc->txq.next_encrypt = 980156321Sdamien (sc->txq.next_encrypt + 1) % RT2560_TX_RING_COUNT; 981156321Sdamien } 982156321Sdamien 983156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 984156321Sdamien BUS_DMASYNC_PREWRITE); 985156321Sdamien 986156321Sdamien /* kick Tx */ 987156321Sdamien RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_TX); 988156321Sdamien} 989156321Sdamien 990156321Sdamienstatic void 991156321Sdamienrt2560_tx_intr(struct rt2560_softc *sc) 992156321Sdamien{ 993156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 994156321Sdamien struct ifnet *ifp = ic->ic_ifp; 995156321Sdamien struct rt2560_tx_desc *desc; 996156321Sdamien struct rt2560_tx_data *data; 997156321Sdamien struct rt2560_node *rn; 998156321Sdamien 999156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 1000156321Sdamien BUS_DMASYNC_POSTREAD); 1001156321Sdamien 1002156321Sdamien for (;;) { 1003156321Sdamien desc = &sc->txq.desc[sc->txq.next]; 1004156321Sdamien data = &sc->txq.data[sc->txq.next]; 1005156321Sdamien 1006156321Sdamien if ((le32toh(desc->flags) & RT2560_TX_BUSY) || 1007156321Sdamien (le32toh(desc->flags) & RT2560_TX_CIPHER_BUSY) || 1008156321Sdamien !(le32toh(desc->flags) & RT2560_TX_VALID)) 1009156321Sdamien break; 1010156321Sdamien 1011156321Sdamien rn = (struct rt2560_node *)data->ni; 1012156321Sdamien 1013156321Sdamien switch (le32toh(desc->flags) & RT2560_TX_RESULT_MASK) { 1014156321Sdamien case RT2560_TX_SUCCESS: 1015156321Sdamien DPRINTFN(10, ("data frame sent successfully\n")); 1016156321Sdamien if (data->id.id_node != NULL) { 1017156321Sdamien ral_rssadapt_raise_rate(ic, &rn->rssadapt, 1018156321Sdamien &data->id); 1019156321Sdamien } 1020156321Sdamien ifp->if_opackets++; 1021156321Sdamien break; 1022156321Sdamien 1023156321Sdamien case RT2560_TX_SUCCESS_RETRY: 1024156321Sdamien DPRINTFN(9, ("data frame sent after %u retries\n", 1025156321Sdamien (le32toh(desc->flags) >> 5) & 0x7)); 1026156321Sdamien ifp->if_opackets++; 1027156321Sdamien break; 1028156321Sdamien 1029156321Sdamien case RT2560_TX_FAIL_RETRY: 1030156321Sdamien DPRINTFN(9, ("sending data frame failed (too much " 1031156321Sdamien "retries)\n")); 1032156321Sdamien if (data->id.id_node != NULL) { 1033156321Sdamien ral_rssadapt_lower_rate(ic, data->ni, 1034156321Sdamien &rn->rssadapt, &data->id); 1035156321Sdamien } 1036156321Sdamien ifp->if_oerrors++; 1037156321Sdamien break; 1038156321Sdamien 1039156321Sdamien case RT2560_TX_FAIL_INVALID: 1040156321Sdamien case RT2560_TX_FAIL_OTHER: 1041156321Sdamien default: 1042156321Sdamien device_printf(sc->sc_dev, "sending data frame failed " 1043156321Sdamien "0x%08x\n", le32toh(desc->flags)); 1044156321Sdamien ifp->if_oerrors++; 1045156321Sdamien } 1046156321Sdamien 1047156321Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, 1048156321Sdamien BUS_DMASYNC_POSTWRITE); 1049156321Sdamien bus_dmamap_unload(sc->txq.data_dmat, data->map); 1050156321Sdamien m_freem(data->m); 1051156321Sdamien data->m = NULL; 1052156321Sdamien ieee80211_free_node(data->ni); 1053156321Sdamien data->ni = NULL; 1054156321Sdamien 1055156321Sdamien /* descriptor is no longer valid */ 1056156321Sdamien desc->flags &= ~htole32(RT2560_TX_VALID); 1057156321Sdamien 1058156321Sdamien DPRINTFN(15, ("tx done idx=%u\n", sc->txq.next)); 1059156321Sdamien 1060156321Sdamien sc->txq.queued--; 1061156321Sdamien sc->txq.next = (sc->txq.next + 1) % RT2560_TX_RING_COUNT; 1062156321Sdamien } 1063156321Sdamien 1064156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 1065156321Sdamien BUS_DMASYNC_PREWRITE); 1066156321Sdamien 1067156321Sdamien sc->sc_tx_timer = 0; 1068156321Sdamien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1069156321Sdamien rt2560_start(ifp); 1070156321Sdamien} 1071156321Sdamien 1072156321Sdamienstatic void 1073156321Sdamienrt2560_prio_intr(struct rt2560_softc *sc) 1074156321Sdamien{ 1075156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 1076156321Sdamien struct ifnet *ifp = ic->ic_ifp; 1077156321Sdamien struct rt2560_tx_desc *desc; 1078156321Sdamien struct rt2560_tx_data *data; 1079156321Sdamien 1080156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1081156321Sdamien BUS_DMASYNC_POSTREAD); 1082156321Sdamien 1083156321Sdamien for (;;) { 1084156321Sdamien desc = &sc->prioq.desc[sc->prioq.next]; 1085156321Sdamien data = &sc->prioq.data[sc->prioq.next]; 1086156321Sdamien 1087156321Sdamien if ((le32toh(desc->flags) & RT2560_TX_BUSY) || 1088156321Sdamien !(le32toh(desc->flags) & RT2560_TX_VALID)) 1089156321Sdamien break; 1090156321Sdamien 1091156321Sdamien switch (le32toh(desc->flags) & RT2560_TX_RESULT_MASK) { 1092156321Sdamien case RT2560_TX_SUCCESS: 1093156321Sdamien DPRINTFN(10, ("mgt frame sent successfully\n")); 1094156321Sdamien break; 1095156321Sdamien 1096156321Sdamien case RT2560_TX_SUCCESS_RETRY: 1097156321Sdamien DPRINTFN(9, ("mgt frame sent after %u retries\n", 1098156321Sdamien (le32toh(desc->flags) >> 5) & 0x7)); 1099156321Sdamien break; 1100156321Sdamien 1101156321Sdamien case RT2560_TX_FAIL_RETRY: 1102156321Sdamien DPRINTFN(9, ("sending mgt frame failed (too much " 1103156321Sdamien "retries)\n")); 1104156321Sdamien break; 1105156321Sdamien 1106156321Sdamien case RT2560_TX_FAIL_INVALID: 1107156321Sdamien case RT2560_TX_FAIL_OTHER: 1108156321Sdamien default: 1109156321Sdamien device_printf(sc->sc_dev, "sending mgt frame failed " 1110156321Sdamien "0x%08x\n", le32toh(desc->flags)); 1111156321Sdamien } 1112156321Sdamien 1113156321Sdamien bus_dmamap_sync(sc->prioq.data_dmat, data->map, 1114156321Sdamien BUS_DMASYNC_POSTWRITE); 1115156321Sdamien bus_dmamap_unload(sc->prioq.data_dmat, data->map); 1116156321Sdamien m_freem(data->m); 1117156321Sdamien data->m = NULL; 1118156321Sdamien ieee80211_free_node(data->ni); 1119156321Sdamien data->ni = NULL; 1120156321Sdamien 1121156321Sdamien /* descriptor is no longer valid */ 1122156321Sdamien desc->flags &= ~htole32(RT2560_TX_VALID); 1123156321Sdamien 1124156321Sdamien DPRINTFN(15, ("prio done idx=%u\n", sc->prioq.next)); 1125156321Sdamien 1126156321Sdamien sc->prioq.queued--; 1127156321Sdamien sc->prioq.next = (sc->prioq.next + 1) % RT2560_PRIO_RING_COUNT; 1128156321Sdamien } 1129156321Sdamien 1130156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1131156321Sdamien BUS_DMASYNC_PREWRITE); 1132156321Sdamien 1133156321Sdamien sc->sc_tx_timer = 0; 1134156321Sdamien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1135156321Sdamien rt2560_start(ifp); 1136156321Sdamien} 1137156321Sdamien 1138156321Sdamien/* 1139156321Sdamien * Some frames were processed by the hardware cipher engine and are ready for 1140156321Sdamien * transmission to the IEEE802.11 layer. 1141156321Sdamien */ 1142156321Sdamienstatic void 1143156321Sdamienrt2560_decryption_intr(struct rt2560_softc *sc) 1144156321Sdamien{ 1145156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 1146156321Sdamien struct ifnet *ifp = ic->ic_ifp; 1147156321Sdamien struct rt2560_rx_desc *desc; 1148156321Sdamien struct rt2560_rx_data *data; 1149156321Sdamien bus_addr_t physaddr; 1150156321Sdamien struct ieee80211_frame *wh; 1151156321Sdamien struct ieee80211_node *ni; 1152156321Sdamien struct rt2560_node *rn; 1153156321Sdamien struct mbuf *mnew, *m; 1154156321Sdamien int hw, error; 1155156321Sdamien 1156156321Sdamien /* retrieve last decriptor index processed by cipher engine */ 1157156321Sdamien hw = RAL_READ(sc, RT2560_SECCSR0) - sc->rxq.physaddr; 1158156321Sdamien hw /= RT2560_RX_DESC_SIZE; 1159156321Sdamien 1160156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1161156321Sdamien BUS_DMASYNC_POSTREAD); 1162156321Sdamien 1163156321Sdamien for (; sc->rxq.cur_decrypt != hw;) { 1164156321Sdamien desc = &sc->rxq.desc[sc->rxq.cur_decrypt]; 1165156321Sdamien data = &sc->rxq.data[sc->rxq.cur_decrypt]; 1166156321Sdamien 1167156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_BUSY) || 1168156321Sdamien (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY)) 1169156321Sdamien break; 1170156321Sdamien 1171156321Sdamien if (data->drop) { 1172156321Sdamien ifp->if_ierrors++; 1173156321Sdamien goto skip; 1174156321Sdamien } 1175156321Sdamien 1176156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_CIPHER_MASK) != 0 && 1177156321Sdamien (le32toh(desc->flags) & RT2560_RX_ICV_ERROR)) { 1178156321Sdamien ifp->if_ierrors++; 1179156321Sdamien goto skip; 1180156321Sdamien } 1181156321Sdamien 1182156321Sdamien /* 1183156321Sdamien * Try to allocate a new mbuf for this ring element and load it 1184156321Sdamien * before processing the current mbuf. If the ring element 1185156321Sdamien * cannot be loaded, drop the received packet and reuse the old 1186156321Sdamien * mbuf. In the unlikely case that the old mbuf can't be 1187156321Sdamien * reloaded either, explicitly panic. 1188156321Sdamien */ 1189156321Sdamien mnew = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1190156321Sdamien if (mnew == NULL) { 1191156321Sdamien ifp->if_ierrors++; 1192156321Sdamien goto skip; 1193156321Sdamien } 1194156321Sdamien 1195156321Sdamien bus_dmamap_sync(sc->rxq.data_dmat, data->map, 1196156321Sdamien BUS_DMASYNC_POSTREAD); 1197156321Sdamien bus_dmamap_unload(sc->rxq.data_dmat, data->map); 1198156321Sdamien 1199156321Sdamien error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 1200156321Sdamien mtod(mnew, void *), MCLBYTES, rt2560_dma_map_addr, 1201156321Sdamien &physaddr, 0); 1202156321Sdamien if (error != 0) { 1203156321Sdamien m_freem(mnew); 1204156321Sdamien 1205156321Sdamien /* try to reload the old mbuf */ 1206156321Sdamien error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 1207156321Sdamien mtod(data->m, void *), MCLBYTES, 1208156321Sdamien rt2560_dma_map_addr, &physaddr, 0); 1209156321Sdamien if (error != 0) { 1210156321Sdamien /* very unlikely that it will fail... */ 1211156321Sdamien panic("%s: could not load old rx mbuf", 1212156321Sdamien device_get_name(sc->sc_dev)); 1213156321Sdamien } 1214156321Sdamien ifp->if_ierrors++; 1215156321Sdamien goto skip; 1216156321Sdamien } 1217156321Sdamien 1218156321Sdamien /* 1219156321Sdamien * New mbuf successfully loaded, update Rx ring and continue 1220156321Sdamien * processing. 1221156321Sdamien */ 1222156321Sdamien m = data->m; 1223156321Sdamien data->m = mnew; 1224156321Sdamien desc->physaddr = htole32(physaddr); 1225156321Sdamien 1226156321Sdamien /* finalize mbuf */ 1227156321Sdamien m->m_pkthdr.rcvif = ifp; 1228156321Sdamien m->m_pkthdr.len = m->m_len = 1229156321Sdamien (le32toh(desc->flags) >> 16) & 0xfff; 1230156321Sdamien 1231159180Scsjp if (bpf_peers_present(sc->sc_drvbpf)) { 1232156321Sdamien struct rt2560_rx_radiotap_header *tap = &sc->sc_rxtap; 1233156321Sdamien uint32_t tsf_lo, tsf_hi; 1234156321Sdamien 1235156321Sdamien /* get timestamp (low and high 32 bits) */ 1236156321Sdamien tsf_hi = RAL_READ(sc, RT2560_CSR17); 1237156321Sdamien tsf_lo = RAL_READ(sc, RT2560_CSR16); 1238156321Sdamien 1239156321Sdamien tap->wr_tsf = 1240156321Sdamien htole64(((uint64_t)tsf_hi << 32) | tsf_lo); 1241156321Sdamien tap->wr_flags = 0; 1242156321Sdamien tap->wr_rate = rt2560_rxrate(desc); 1243156321Sdamien tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); 1244156321Sdamien tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); 1245156321Sdamien tap->wr_antenna = sc->rx_ant; 1246156321Sdamien tap->wr_antsignal = desc->rssi; 1247156321Sdamien 1248156321Sdamien bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m); 1249156321Sdamien } 1250156321Sdamien 1251156321Sdamien wh = mtod(m, struct ieee80211_frame *); 1252156321Sdamien ni = ieee80211_find_rxnode(ic, 1253156321Sdamien (struct ieee80211_frame_min *)wh); 1254156321Sdamien 1255156321Sdamien /* send the frame to the 802.11 layer */ 1256156321Sdamien ieee80211_input(ic, m, ni, desc->rssi, 0); 1257156321Sdamien 1258156321Sdamien /* give rssi to the rate adatation algorithm */ 1259156321Sdamien rn = (struct rt2560_node *)ni; 1260156321Sdamien ral_rssadapt_input(ic, ni, &rn->rssadapt, desc->rssi); 1261156321Sdamien 1262156321Sdamien /* node is no longer needed */ 1263156321Sdamien ieee80211_free_node(ni); 1264156321Sdamien 1265156321Sdamienskip: desc->flags = htole32(RT2560_RX_BUSY); 1266156321Sdamien 1267156321Sdamien DPRINTFN(15, ("decryption done idx=%u\n", sc->rxq.cur_decrypt)); 1268156321Sdamien 1269156321Sdamien sc->rxq.cur_decrypt = 1270156321Sdamien (sc->rxq.cur_decrypt + 1) % RT2560_RX_RING_COUNT; 1271156321Sdamien } 1272156321Sdamien 1273156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1274156321Sdamien BUS_DMASYNC_PREWRITE); 1275156321Sdamien} 1276156321Sdamien 1277156321Sdamien/* 1278156321Sdamien * Some frames were received. Pass them to the hardware cipher engine before 1279156321Sdamien * sending them to the 802.11 layer. 1280156321Sdamien */ 1281156321Sdamienstatic void 1282156321Sdamienrt2560_rx_intr(struct rt2560_softc *sc) 1283156321Sdamien{ 1284156321Sdamien struct rt2560_rx_desc *desc; 1285156321Sdamien struct rt2560_rx_data *data; 1286156321Sdamien 1287156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1288156321Sdamien BUS_DMASYNC_POSTREAD); 1289156321Sdamien 1290156321Sdamien for (;;) { 1291156321Sdamien desc = &sc->rxq.desc[sc->rxq.cur]; 1292156321Sdamien data = &sc->rxq.data[sc->rxq.cur]; 1293156321Sdamien 1294156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_BUSY) || 1295156321Sdamien (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY)) 1296156321Sdamien break; 1297156321Sdamien 1298156321Sdamien data->drop = 0; 1299156321Sdamien 1300156321Sdamien if ((le32toh(desc->flags) & RT2560_RX_PHY_ERROR) || 1301156321Sdamien (le32toh(desc->flags) & RT2560_RX_CRC_ERROR)) { 1302156321Sdamien /* 1303156321Sdamien * This should not happen since we did not request 1304156321Sdamien * to receive those frames when we filled RXCSR0. 1305156321Sdamien */ 1306156321Sdamien DPRINTFN(5, ("PHY or CRC error flags 0x%08x\n", 1307156321Sdamien le32toh(desc->flags))); 1308156321Sdamien data->drop = 1; 1309156321Sdamien } 1310156321Sdamien 1311156321Sdamien if (((le32toh(desc->flags) >> 16) & 0xfff) > MCLBYTES) { 1312156321Sdamien DPRINTFN(5, ("bad length\n")); 1313156321Sdamien data->drop = 1; 1314156321Sdamien } 1315156321Sdamien 1316156321Sdamien /* mark the frame for decryption */ 1317156321Sdamien desc->flags |= htole32(RT2560_RX_CIPHER_BUSY); 1318156321Sdamien 1319156321Sdamien DPRINTFN(15, ("rx done idx=%u\n", sc->rxq.cur)); 1320156321Sdamien 1321156321Sdamien sc->rxq.cur = (sc->rxq.cur + 1) % RT2560_RX_RING_COUNT; 1322156321Sdamien } 1323156321Sdamien 1324156321Sdamien bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 1325156321Sdamien BUS_DMASYNC_PREWRITE); 1326156321Sdamien 1327156321Sdamien /* kick decrypt */ 1328156321Sdamien RAL_WRITE(sc, RT2560_SECCSR0, RT2560_KICK_DECRYPT); 1329156321Sdamien} 1330156321Sdamien 1331156321Sdamien/* 1332156321Sdamien * This function is called periodically in IBSS mode when a new beacon must be 1333156321Sdamien * sent out. 1334156321Sdamien */ 1335156321Sdamienstatic void 1336156321Sdamienrt2560_beacon_expire(struct rt2560_softc *sc) 1337156321Sdamien{ 1338156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 1339156321Sdamien struct rt2560_tx_data *data; 1340156321Sdamien 1341156321Sdamien if (ic->ic_opmode != IEEE80211_M_IBSS && 1342156321Sdamien ic->ic_opmode != IEEE80211_M_HOSTAP) 1343156321Sdamien return; 1344156321Sdamien 1345156321Sdamien data = &sc->bcnq.data[sc->bcnq.next]; 1346156321Sdamien 1347156321Sdamien bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_POSTWRITE); 1348156321Sdamien bus_dmamap_unload(sc->bcnq.data_dmat, data->map); 1349156321Sdamien 1350156321Sdamien ieee80211_beacon_update(ic, data->ni, &sc->sc_bo, data->m, 1); 1351156321Sdamien 1352159180Scsjp if (bpf_peers_present(ic->ic_rawbpf)) 1353156321Sdamien bpf_mtap(ic->ic_rawbpf, data->m); 1354156321Sdamien 1355156321Sdamien rt2560_tx_bcn(sc, data->m, data->ni); 1356156321Sdamien 1357156321Sdamien DPRINTFN(15, ("beacon expired\n")); 1358156321Sdamien 1359156321Sdamien sc->bcnq.next = (sc->bcnq.next + 1) % RT2560_BEACON_RING_COUNT; 1360156321Sdamien} 1361156321Sdamien 1362156321Sdamien/* ARGSUSED */ 1363156321Sdamienstatic void 1364156321Sdamienrt2560_wakeup_expire(struct rt2560_softc *sc) 1365156321Sdamien{ 1366156321Sdamien DPRINTFN(2, ("wakeup expired\n")); 1367156321Sdamien} 1368156321Sdamien 1369156321Sdamienvoid 1370156321Sdamienrt2560_intr(void *arg) 1371156321Sdamien{ 1372156321Sdamien struct rt2560_softc *sc = arg; 1373156975Sdamien struct ifnet *ifp = sc->sc_ifp; 1374156321Sdamien uint32_t r; 1375156321Sdamien 1376156321Sdamien RAL_LOCK(sc); 1377156321Sdamien 1378156321Sdamien /* disable interrupts */ 1379156321Sdamien RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 1380156321Sdamien 1381156975Sdamien /* don't re-enable interrupts if we're shutting down */ 1382156975Sdamien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1383156975Sdamien RAL_UNLOCK(sc); 1384156975Sdamien return; 1385156975Sdamien } 1386156975Sdamien 1387156321Sdamien r = RAL_READ(sc, RT2560_CSR7); 1388156321Sdamien RAL_WRITE(sc, RT2560_CSR7, r); 1389156321Sdamien 1390156321Sdamien if (r & RT2560_BEACON_EXPIRE) 1391156321Sdamien rt2560_beacon_expire(sc); 1392156321Sdamien 1393156321Sdamien if (r & RT2560_WAKEUP_EXPIRE) 1394156321Sdamien rt2560_wakeup_expire(sc); 1395156321Sdamien 1396156321Sdamien if (r & RT2560_ENCRYPTION_DONE) 1397156321Sdamien rt2560_encryption_intr(sc); 1398156321Sdamien 1399156321Sdamien if (r & RT2560_TX_DONE) 1400156321Sdamien rt2560_tx_intr(sc); 1401156321Sdamien 1402156321Sdamien if (r & RT2560_PRIO_DONE) 1403156321Sdamien rt2560_prio_intr(sc); 1404156321Sdamien 1405156321Sdamien if (r & RT2560_DECRYPTION_DONE) 1406156321Sdamien rt2560_decryption_intr(sc); 1407156321Sdamien 1408156321Sdamien if (r & RT2560_RX_DONE) 1409156321Sdamien rt2560_rx_intr(sc); 1410156321Sdamien 1411156321Sdamien /* re-enable interrupts */ 1412156321Sdamien RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); 1413156321Sdamien 1414156321Sdamien RAL_UNLOCK(sc); 1415156321Sdamien} 1416156321Sdamien 1417156321Sdamien/* quickly determine if a given rate is CCK or OFDM */ 1418156321Sdamien#define RAL_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) 1419156321Sdamien 1420156321Sdamien#define RAL_ACK_SIZE 14 /* 10 + 4(FCS) */ 1421156321Sdamien#define RAL_CTS_SIZE 14 /* 10 + 4(FCS) */ 1422156321Sdamien 1423156321Sdamien#define RAL_SIFS 10 /* us */ 1424156321Sdamien 1425156321Sdamien#define RT2560_TXRX_TURNAROUND 10 /* us */ 1426156321Sdamien 1427156321Sdamien/* 1428156321Sdamien * This function is only used by the Rx radiotap code. 1429156321Sdamien */ 1430156321Sdamienstatic uint8_t 1431156321Sdamienrt2560_rxrate(struct rt2560_rx_desc *desc) 1432156321Sdamien{ 1433156321Sdamien if (le32toh(desc->flags) & RT2560_RX_OFDM) { 1434156321Sdamien /* reverse function of rt2560_plcp_signal */ 1435156321Sdamien switch (desc->rate) { 1436156321Sdamien case 0xb: return 12; 1437156321Sdamien case 0xf: return 18; 1438156321Sdamien case 0xa: return 24; 1439156321Sdamien case 0xe: return 36; 1440156321Sdamien case 0x9: return 48; 1441156321Sdamien case 0xd: return 72; 1442156321Sdamien case 0x8: return 96; 1443156321Sdamien case 0xc: return 108; 1444156321Sdamien } 1445156321Sdamien } else { 1446156321Sdamien if (desc->rate == 10) 1447156321Sdamien return 2; 1448156321Sdamien if (desc->rate == 20) 1449156321Sdamien return 4; 1450156321Sdamien if (desc->rate == 55) 1451156321Sdamien return 11; 1452156321Sdamien if (desc->rate == 110) 1453156321Sdamien return 22; 1454156321Sdamien } 1455156321Sdamien return 2; /* should not get there */ 1456156321Sdamien} 1457156321Sdamien 1458156321Sdamien/* 1459156321Sdamien * Return the expected ack rate for a frame transmitted at rate `rate'. 1460156321Sdamien * XXX: this should depend on the destination node basic rate set. 1461156321Sdamien */ 1462156321Sdamienstatic int 1463156321Sdamienrt2560_ack_rate(struct ieee80211com *ic, int rate) 1464156321Sdamien{ 1465156321Sdamien switch (rate) { 1466156321Sdamien /* CCK rates */ 1467156321Sdamien case 2: 1468156321Sdamien return 2; 1469156321Sdamien case 4: 1470156321Sdamien case 11: 1471156321Sdamien case 22: 1472156321Sdamien return (ic->ic_curmode == IEEE80211_MODE_11B) ? 4 : rate; 1473156321Sdamien 1474156321Sdamien /* OFDM rates */ 1475156321Sdamien case 12: 1476156321Sdamien case 18: 1477156321Sdamien return 12; 1478156321Sdamien case 24: 1479156321Sdamien case 36: 1480156321Sdamien return 24; 1481156321Sdamien case 48: 1482156321Sdamien case 72: 1483156321Sdamien case 96: 1484156321Sdamien case 108: 1485156321Sdamien return 48; 1486156321Sdamien } 1487156321Sdamien 1488156321Sdamien /* default to 1Mbps */ 1489156321Sdamien return 2; 1490156321Sdamien} 1491156321Sdamien 1492156321Sdamien/* 1493156321Sdamien * Compute the duration (in us) needed to transmit `len' bytes at rate `rate'. 1494156321Sdamien * The function automatically determines the operating mode depending on the 1495156321Sdamien * given rate. `flags' indicates whether short preamble is in use or not. 1496156321Sdamien */ 1497156321Sdamienstatic uint16_t 1498156321Sdamienrt2560_txtime(int len, int rate, uint32_t flags) 1499156321Sdamien{ 1500156321Sdamien uint16_t txtime; 1501156321Sdamien 1502156321Sdamien if (RAL_RATE_IS_OFDM(rate)) { 1503156321Sdamien /* IEEE Std 802.11a-1999, pp. 37 */ 1504156321Sdamien txtime = (8 + 4 * len + 3 + rate - 1) / rate; 1505156321Sdamien txtime = 16 + 4 + 4 * txtime + 6; 1506156321Sdamien } else { 1507156321Sdamien /* IEEE Std 802.11b-1999, pp. 28 */ 1508156321Sdamien txtime = (16 * len + rate - 1) / rate; 1509156321Sdamien if (rate != 2 && (flags & IEEE80211_F_SHPREAMBLE)) 1510156321Sdamien txtime += 72 + 24; 1511156321Sdamien else 1512156321Sdamien txtime += 144 + 48; 1513156321Sdamien } 1514156321Sdamien 1515156321Sdamien return txtime; 1516156321Sdamien} 1517156321Sdamien 1518156321Sdamienstatic uint8_t 1519156321Sdamienrt2560_plcp_signal(int rate) 1520156321Sdamien{ 1521156321Sdamien switch (rate) { 1522156321Sdamien /* CCK rates (returned values are device-dependent) */ 1523156321Sdamien case 2: return 0x0; 1524156321Sdamien case 4: return 0x1; 1525156321Sdamien case 11: return 0x2; 1526156321Sdamien case 22: return 0x3; 1527156321Sdamien 1528156321Sdamien /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ 1529156321Sdamien case 12: return 0xb; 1530156321Sdamien case 18: return 0xf; 1531156321Sdamien case 24: return 0xa; 1532156321Sdamien case 36: return 0xe; 1533156321Sdamien case 48: return 0x9; 1534156321Sdamien case 72: return 0xd; 1535156321Sdamien case 96: return 0x8; 1536156321Sdamien case 108: return 0xc; 1537156321Sdamien 1538156321Sdamien /* unsupported rates (should not get there) */ 1539156321Sdamien default: return 0xff; 1540156321Sdamien } 1541156321Sdamien} 1542156321Sdamien 1543156321Sdamienstatic void 1544156321Sdamienrt2560_setup_tx_desc(struct rt2560_softc *sc, struct rt2560_tx_desc *desc, 1545156321Sdamien uint32_t flags, int len, int rate, int encrypt, bus_addr_t physaddr) 1546156321Sdamien{ 1547156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 1548156321Sdamien uint16_t plcp_length; 1549156321Sdamien int remainder; 1550156321Sdamien 1551156321Sdamien desc->flags = htole32(flags); 1552156321Sdamien desc->flags |= htole32(len << 16); 1553156321Sdamien desc->flags |= encrypt ? htole32(RT2560_TX_CIPHER_BUSY) : 1554156321Sdamien htole32(RT2560_TX_BUSY | RT2560_TX_VALID); 1555156321Sdamien 1556156321Sdamien desc->physaddr = htole32(physaddr); 1557156321Sdamien desc->wme = htole16( 1558156321Sdamien RT2560_AIFSN(2) | 1559156321Sdamien RT2560_LOGCWMIN(3) | 1560156321Sdamien RT2560_LOGCWMAX(8)); 1561156321Sdamien 1562156321Sdamien /* setup PLCP fields */ 1563156321Sdamien desc->plcp_signal = rt2560_plcp_signal(rate); 1564156321Sdamien desc->plcp_service = 4; 1565156321Sdamien 1566156321Sdamien len += IEEE80211_CRC_LEN; 1567156321Sdamien if (RAL_RATE_IS_OFDM(rate)) { 1568156321Sdamien desc->flags |= htole32(RT2560_TX_OFDM); 1569156321Sdamien 1570156321Sdamien plcp_length = len & 0xfff; 1571156321Sdamien desc->plcp_length_hi = plcp_length >> 6; 1572156321Sdamien desc->plcp_length_lo = plcp_length & 0x3f; 1573156321Sdamien } else { 1574156321Sdamien plcp_length = (16 * len + rate - 1) / rate; 1575156321Sdamien if (rate == 22) { 1576156321Sdamien remainder = (16 * len) % 22; 1577156321Sdamien if (remainder != 0 && remainder < 7) 1578156321Sdamien desc->plcp_service |= RT2560_PLCP_LENGEXT; 1579156321Sdamien } 1580156321Sdamien desc->plcp_length_hi = plcp_length >> 8; 1581156321Sdamien desc->plcp_length_lo = plcp_length & 0xff; 1582156321Sdamien 1583156321Sdamien if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 1584156321Sdamien desc->plcp_signal |= 0x08; 1585156321Sdamien } 1586156321Sdamien} 1587156321Sdamien 1588156321Sdamienstatic int 1589156321Sdamienrt2560_tx_bcn(struct rt2560_softc *sc, struct mbuf *m0, 1590156321Sdamien struct ieee80211_node *ni) 1591156321Sdamien{ 1592156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 1593156321Sdamien struct rt2560_tx_desc *desc; 1594156321Sdamien struct rt2560_tx_data *data; 1595156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1596156321Sdamien int nsegs, rate, error; 1597156321Sdamien 1598156321Sdamien desc = &sc->bcnq.desc[sc->bcnq.cur]; 1599156321Sdamien data = &sc->bcnq.data[sc->bcnq.cur]; 1600156321Sdamien 1601156321Sdamien rate = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? 12 : 2; 1602156321Sdamien 1603156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->bcnq.data_dmat, data->map, m0, 1604156321Sdamien segs, &nsegs, BUS_DMA_NOWAIT); 1605156321Sdamien if (error != 0) { 1606156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1607156321Sdamien error); 1608156321Sdamien m_freem(m0); 1609156321Sdamien return error; 1610156321Sdamien } 1611156321Sdamien 1612159180Scsjp if (bpf_peers_present(sc->sc_drvbpf)) { 1613156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1614156321Sdamien 1615156321Sdamien tap->wt_flags = 0; 1616156321Sdamien tap->wt_rate = rate; 1617156321Sdamien tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 1618156321Sdamien tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 1619156321Sdamien tap->wt_antenna = sc->tx_ant; 1620156321Sdamien 1621156321Sdamien bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0); 1622156321Sdamien } 1623156321Sdamien 1624156321Sdamien data->m = m0; 1625156321Sdamien data->ni = ni; 1626156321Sdamien 1627156321Sdamien rt2560_setup_tx_desc(sc, desc, RT2560_TX_IFS_NEWBACKOFF | 1628156321Sdamien RT2560_TX_TIMESTAMP, m0->m_pkthdr.len, rate, 0, segs->ds_addr); 1629156321Sdamien 1630156321Sdamien DPRINTFN(10, ("sending beacon frame len=%u idx=%u rate=%u\n", 1631156321Sdamien m0->m_pkthdr.len, sc->bcnq.cur, rate)); 1632156321Sdamien 1633156321Sdamien bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1634156321Sdamien bus_dmamap_sync(sc->bcnq.desc_dmat, sc->bcnq.desc_map, 1635156321Sdamien BUS_DMASYNC_PREWRITE); 1636156321Sdamien 1637156321Sdamien sc->bcnq.cur = (sc->bcnq.cur + 1) % RT2560_BEACON_RING_COUNT; 1638156321Sdamien 1639156321Sdamien return 0; 1640156321Sdamien} 1641156321Sdamien 1642156321Sdamienstatic int 1643156321Sdamienrt2560_tx_mgt(struct rt2560_softc *sc, struct mbuf *m0, 1644156321Sdamien struct ieee80211_node *ni) 1645156321Sdamien{ 1646156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 1647156321Sdamien struct rt2560_tx_desc *desc; 1648156321Sdamien struct rt2560_tx_data *data; 1649156321Sdamien struct ieee80211_frame *wh; 1650156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1651156321Sdamien uint16_t dur; 1652156321Sdamien uint32_t flags = 0; 1653156321Sdamien int nsegs, rate, error; 1654156321Sdamien 1655156321Sdamien desc = &sc->prioq.desc[sc->prioq.cur]; 1656156321Sdamien data = &sc->prioq.data[sc->prioq.cur]; 1657156321Sdamien 1658156321Sdamien rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2; 1659156321Sdamien 1660156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, 1661156321Sdamien segs, &nsegs, 0); 1662156321Sdamien if (error != 0) { 1663156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1664156321Sdamien error); 1665156321Sdamien m_freem(m0); 1666156321Sdamien return error; 1667156321Sdamien } 1668156321Sdamien 1669159180Scsjp if (bpf_peers_present(sc->sc_drvbpf)) { 1670156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1671156321Sdamien 1672156321Sdamien tap->wt_flags = 0; 1673156321Sdamien tap->wt_rate = rate; 1674156321Sdamien tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 1675156321Sdamien tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 1676156321Sdamien tap->wt_antenna = sc->tx_ant; 1677156321Sdamien 1678156321Sdamien bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0); 1679156321Sdamien } 1680156321Sdamien 1681156321Sdamien data->m = m0; 1682156321Sdamien data->ni = ni; 1683156321Sdamien 1684156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1685156321Sdamien 1686156321Sdamien if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1687156321Sdamien flags |= RT2560_TX_ACK; 1688156321Sdamien 1689156321Sdamien dur = rt2560_txtime(RAL_ACK_SIZE, rate, ic->ic_flags) + 1690156321Sdamien RAL_SIFS; 1691156321Sdamien *(uint16_t *)wh->i_dur = htole16(dur); 1692156321Sdamien 1693156321Sdamien /* tell hardware to add timestamp for probe responses */ 1694156321Sdamien if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 1695156321Sdamien IEEE80211_FC0_TYPE_MGT && 1696156321Sdamien (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 1697156321Sdamien IEEE80211_FC0_SUBTYPE_PROBE_RESP) 1698156321Sdamien flags |= RT2560_TX_TIMESTAMP; 1699156321Sdamien } 1700156321Sdamien 1701156321Sdamien rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 0, 1702156321Sdamien segs->ds_addr); 1703156321Sdamien 1704156321Sdamien bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1705156321Sdamien bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1706156321Sdamien BUS_DMASYNC_PREWRITE); 1707156321Sdamien 1708156321Sdamien DPRINTFN(10, ("sending mgt frame len=%u idx=%u rate=%u\n", 1709156321Sdamien m0->m_pkthdr.len, sc->prioq.cur, rate)); 1710156321Sdamien 1711156321Sdamien /* kick prio */ 1712156321Sdamien sc->prioq.queued++; 1713156321Sdamien sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; 1714156321Sdamien RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); 1715156321Sdamien 1716156321Sdamien return 0; 1717156321Sdamien} 1718156321Sdamien 1719160691Ssamstatic int 1720160691Ssamrt2560_tx_raw(struct rt2560_softc *sc, struct mbuf *m0, 1721160691Ssam struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) 1722160691Ssam{ 1723160691Ssam struct ieee80211com *ic = &sc->sc_ic; 1724160691Ssam struct rt2560_tx_desc *desc; 1725160691Ssam struct rt2560_tx_data *data; 1726160691Ssam bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1727160691Ssam uint32_t flags; 1728160691Ssam int nsegs, rate, error; 1729160691Ssam 1730160691Ssam desc = &sc->prioq.desc[sc->prioq.cur]; 1731160691Ssam data = &sc->prioq.data[sc->prioq.cur]; 1732160691Ssam 1733160691Ssam rate = params->ibp_rate0 & IEEE80211_RATE_VAL; 1734160691Ssam /* XXX validate */ 1735160691Ssam if (rate == 0) 1736160691Ssam return EINVAL; 1737160691Ssam 1738160691Ssam error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, 1739160691Ssam segs, &nsegs, 0); 1740160691Ssam if (error != 0) { 1741160691Ssam device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1742160691Ssam error); 1743160691Ssam m_freem(m0); 1744160691Ssam return error; 1745160691Ssam } 1746160691Ssam 1747160691Ssam if (bpf_peers_present(sc->sc_drvbpf)) { 1748160691Ssam struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1749160691Ssam 1750160691Ssam tap->wt_flags = 0; 1751160691Ssam tap->wt_rate = rate; 1752160691Ssam tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 1753160691Ssam tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 1754160691Ssam tap->wt_antenna = sc->tx_ant; 1755160691Ssam 1756160691Ssam bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0); 1757160691Ssam } 1758160691Ssam 1759160691Ssam data->m = m0; 1760160691Ssam data->ni = ni; 1761160691Ssam 1762160691Ssam flags = 0; 1763160691Ssam if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) 1764160691Ssam flags |= RT2560_TX_ACK; 1765160691Ssam 1766160691Ssam /* XXX need to setup descriptor ourself */ 1767160691Ssam rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, 1768160691Ssam rate, (params->ibp_flags & IEEE80211_BPF_CRYPTO) != 0, 1769160691Ssam segs->ds_addr); 1770160691Ssam 1771160691Ssam bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1772160691Ssam bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, 1773160691Ssam BUS_DMASYNC_PREWRITE); 1774160691Ssam 1775160691Ssam DPRINTFN(10, ("sending raw frame len=%u idx=%u rate=%u\n", 1776160691Ssam m0->m_pkthdr.len, sc->prioq.cur, rate)); 1777160691Ssam 1778160691Ssam /* kick prio */ 1779160691Ssam sc->prioq.queued++; 1780160691Ssam sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; 1781160691Ssam RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); 1782160691Ssam 1783160691Ssam return 0; 1784160691Ssam} 1785160691Ssam 1786156321Sdamien/* 1787156321Sdamien * Build a RTS control frame. 1788156321Sdamien */ 1789156321Sdamienstatic struct mbuf * 1790156321Sdamienrt2560_get_rts(struct rt2560_softc *sc, struct ieee80211_frame *wh, 1791156321Sdamien uint16_t dur) 1792156321Sdamien{ 1793156321Sdamien struct ieee80211_frame_rts *rts; 1794156321Sdamien struct mbuf *m; 1795156321Sdamien 1796156321Sdamien MGETHDR(m, M_DONTWAIT, MT_DATA); 1797156321Sdamien if (m == NULL) { 1798156321Sdamien sc->sc_ic.ic_stats.is_tx_nobuf++; 1799156321Sdamien device_printf(sc->sc_dev, "could not allocate RTS frame\n"); 1800156321Sdamien return NULL; 1801156321Sdamien } 1802156321Sdamien 1803156321Sdamien rts = mtod(m, struct ieee80211_frame_rts *); 1804156321Sdamien 1805156321Sdamien rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL | 1806156321Sdamien IEEE80211_FC0_SUBTYPE_RTS; 1807156321Sdamien rts->i_fc[1] = IEEE80211_FC1_DIR_NODS; 1808156321Sdamien *(uint16_t *)rts->i_dur = htole16(dur); 1809156321Sdamien IEEE80211_ADDR_COPY(rts->i_ra, wh->i_addr1); 1810156321Sdamien IEEE80211_ADDR_COPY(rts->i_ta, wh->i_addr2); 1811156321Sdamien 1812156321Sdamien m->m_pkthdr.len = m->m_len = sizeof (struct ieee80211_frame_rts); 1813156321Sdamien 1814156321Sdamien return m; 1815156321Sdamien} 1816156321Sdamien 1817156321Sdamienstatic int 1818156321Sdamienrt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0, 1819156321Sdamien struct ieee80211_node *ni) 1820156321Sdamien{ 1821156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 1822156321Sdamien struct rt2560_tx_desc *desc; 1823156321Sdamien struct rt2560_tx_data *data; 1824156321Sdamien struct rt2560_node *rn; 1825156321Sdamien struct ieee80211_rateset *rs; 1826156321Sdamien struct ieee80211_frame *wh; 1827156321Sdamien struct ieee80211_key *k; 1828156321Sdamien struct mbuf *mnew; 1829156321Sdamien bus_dma_segment_t segs[RT2560_MAX_SCATTER]; 1830156321Sdamien uint16_t dur; 1831156321Sdamien uint32_t flags = 0; 1832156321Sdamien int nsegs, rate, error; 1833156321Sdamien 1834156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1835156321Sdamien 1836156321Sdamien if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) { 1837156321Sdamien rs = &ic->ic_sup_rates[ic->ic_curmode]; 1838156321Sdamien rate = rs->rs_rates[ic->ic_fixed_rate]; 1839156321Sdamien } else { 1840156321Sdamien rs = &ni->ni_rates; 1841156321Sdamien rn = (struct rt2560_node *)ni; 1842156321Sdamien ni->ni_txrate = ral_rssadapt_choose(&rn->rssadapt, rs, wh, 1843156321Sdamien m0->m_pkthdr.len, NULL, 0); 1844156321Sdamien rate = rs->rs_rates[ni->ni_txrate]; 1845156321Sdamien } 1846156321Sdamien rate &= IEEE80211_RATE_VAL; 1847156321Sdamien 1848156321Sdamien if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1849156321Sdamien k = ieee80211_crypto_encap(ic, ni, m0); 1850156321Sdamien if (k == NULL) { 1851156321Sdamien m_freem(m0); 1852156321Sdamien return ENOBUFS; 1853156321Sdamien } 1854156321Sdamien 1855156321Sdamien /* packet header may have moved, reset our local pointer */ 1856156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1857156321Sdamien } 1858156321Sdamien 1859156321Sdamien /* 1860156321Sdamien * IEEE Std 802.11-1999, pp 82: "A STA shall use an RTS/CTS exchange 1861156321Sdamien * for directed frames only when the length of the MPDU is greater 1862156321Sdamien * than the length threshold indicated by [...]" ic_rtsthreshold. 1863156321Sdamien */ 1864156321Sdamien if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 1865156321Sdamien m0->m_pkthdr.len > ic->ic_rtsthreshold) { 1866156321Sdamien struct mbuf *m; 1867156321Sdamien uint16_t dur; 1868156321Sdamien int rtsrate, ackrate; 1869156321Sdamien 1870156321Sdamien rtsrate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2; 1871156321Sdamien ackrate = rt2560_ack_rate(ic, rate); 1872156321Sdamien 1873156321Sdamien dur = rt2560_txtime(m0->m_pkthdr.len + 4, rate, ic->ic_flags) + 1874156321Sdamien rt2560_txtime(RAL_CTS_SIZE, rtsrate, ic->ic_flags) + 1875156321Sdamien rt2560_txtime(RAL_ACK_SIZE, ackrate, ic->ic_flags) + 1876156321Sdamien 3 * RAL_SIFS; 1877156321Sdamien 1878156321Sdamien m = rt2560_get_rts(sc, wh, dur); 1879156321Sdamien 1880156321Sdamien desc = &sc->txq.desc[sc->txq.cur_encrypt]; 1881156321Sdamien data = &sc->txq.data[sc->txq.cur_encrypt]; 1882156321Sdamien 1883156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, 1884156321Sdamien m, segs, &nsegs, 0); 1885156321Sdamien if (error != 0) { 1886156321Sdamien device_printf(sc->sc_dev, 1887156321Sdamien "could not map mbuf (error %d)\n", error); 1888156321Sdamien m_freem(m); 1889156321Sdamien m_freem(m0); 1890156321Sdamien return error; 1891156321Sdamien } 1892156321Sdamien 1893156321Sdamien /* avoid multiple free() of the same node for each fragment */ 1894156321Sdamien ieee80211_ref_node(ni); 1895156321Sdamien 1896156321Sdamien data->m = m; 1897156321Sdamien data->ni = ni; 1898156321Sdamien 1899156321Sdamien /* RTS frames are not taken into account for rssadapt */ 1900156321Sdamien data->id.id_node = NULL; 1901156321Sdamien 1902156321Sdamien rt2560_setup_tx_desc(sc, desc, RT2560_TX_ACK | 1903156321Sdamien RT2560_TX_MORE_FRAG, m->m_pkthdr.len, rtsrate, 1, 1904156321Sdamien segs->ds_addr); 1905156321Sdamien 1906156321Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, 1907156321Sdamien BUS_DMASYNC_PREWRITE); 1908156321Sdamien 1909156321Sdamien sc->txq.queued++; 1910156321Sdamien sc->txq.cur_encrypt = 1911156321Sdamien (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; 1912156321Sdamien 1913156321Sdamien /* 1914156321Sdamien * IEEE Std 802.11-1999: when an RTS/CTS exchange is used, the 1915156321Sdamien * asynchronous data frame shall be transmitted after the CTS 1916156321Sdamien * frame and a SIFS period. 1917156321Sdamien */ 1918156321Sdamien flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS; 1919156321Sdamien } 1920156321Sdamien 1921156321Sdamien data = &sc->txq.data[sc->txq.cur_encrypt]; 1922156321Sdamien desc = &sc->txq.desc[sc->txq.cur_encrypt]; 1923156321Sdamien 1924156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, m0, 1925156321Sdamien segs, &nsegs, 0); 1926156321Sdamien if (error != 0 && error != EFBIG) { 1927156321Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1928156321Sdamien error); 1929156321Sdamien m_freem(m0); 1930156321Sdamien return error; 1931156321Sdamien } 1932156321Sdamien if (error != 0) { 1933156321Sdamien mnew = m_defrag(m0, M_DONTWAIT); 1934156321Sdamien if (mnew == NULL) { 1935156321Sdamien device_printf(sc->sc_dev, 1936156321Sdamien "could not defragment mbuf\n"); 1937156321Sdamien m_freem(m0); 1938156321Sdamien return ENOBUFS; 1939156321Sdamien } 1940156321Sdamien m0 = mnew; 1941156321Sdamien 1942156321Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, 1943156321Sdamien m0, segs, &nsegs, 0); 1944156321Sdamien if (error != 0) { 1945156321Sdamien device_printf(sc->sc_dev, 1946156321Sdamien "could not map mbuf (error %d)\n", error); 1947156321Sdamien m_freem(m0); 1948156321Sdamien return error; 1949156321Sdamien } 1950156321Sdamien 1951156321Sdamien /* packet header may have moved, reset our local pointer */ 1952156321Sdamien wh = mtod(m0, struct ieee80211_frame *); 1953156321Sdamien } 1954156321Sdamien 1955159180Scsjp if (bpf_peers_present(sc->sc_drvbpf)) { 1956156321Sdamien struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; 1957156321Sdamien 1958156321Sdamien tap->wt_flags = 0; 1959156321Sdamien tap->wt_rate = rate; 1960156321Sdamien tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 1961156321Sdamien tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 1962156321Sdamien tap->wt_antenna = sc->tx_ant; 1963156321Sdamien 1964156321Sdamien bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0); 1965156321Sdamien } 1966156321Sdamien 1967156321Sdamien data->m = m0; 1968156321Sdamien data->ni = ni; 1969156321Sdamien 1970156321Sdamien /* remember link conditions for rate adaptation algorithm */ 1971156321Sdamien if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) { 1972156321Sdamien data->id.id_len = m0->m_pkthdr.len; 1973156321Sdamien data->id.id_rateidx = ni->ni_txrate; 1974156321Sdamien data->id.id_node = ni; 1975156321Sdamien data->id.id_rssi = ni->ni_rssi; 1976156321Sdamien } else 1977156321Sdamien data->id.id_node = NULL; 1978156321Sdamien 1979156321Sdamien if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1980156321Sdamien flags |= RT2560_TX_ACK; 1981156321Sdamien 1982156321Sdamien dur = rt2560_txtime(RAL_ACK_SIZE, rt2560_ack_rate(ic, rate), 1983156321Sdamien ic->ic_flags) + RAL_SIFS; 1984156321Sdamien *(uint16_t *)wh->i_dur = htole16(dur); 1985156321Sdamien } 1986156321Sdamien 1987156321Sdamien rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 1, 1988156321Sdamien segs->ds_addr); 1989156321Sdamien 1990156321Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1991156321Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 1992156321Sdamien BUS_DMASYNC_PREWRITE); 1993156321Sdamien 1994156321Sdamien DPRINTFN(10, ("sending data frame len=%u idx=%u rate=%u\n", 1995156321Sdamien m0->m_pkthdr.len, sc->txq.cur_encrypt, rate)); 1996156321Sdamien 1997156321Sdamien /* kick encrypt */ 1998156321Sdamien sc->txq.queued++; 1999156321Sdamien sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; 2000156321Sdamien RAL_WRITE(sc, RT2560_SECCSR1, RT2560_KICK_ENCRYPT); 2001156321Sdamien 2002156321Sdamien return 0; 2003156321Sdamien} 2004156321Sdamien 2005156321Sdamienstatic void 2006156321Sdamienrt2560_start(struct ifnet *ifp) 2007156321Sdamien{ 2008156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 2009156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 2010156321Sdamien struct mbuf *m0; 2011156321Sdamien struct ether_header *eh; 2012156321Sdamien struct ieee80211_node *ni; 2013156321Sdamien 2014156321Sdamien RAL_LOCK(sc); 2015156321Sdamien 2016156975Sdamien /* prevent management frames from being sent if we're not ready */ 2017156975Sdamien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2018156975Sdamien RAL_UNLOCK(sc); 2019156975Sdamien return; 2020156975Sdamien } 2021156975Sdamien 2022156321Sdamien for (;;) { 2023156321Sdamien IF_POLL(&ic->ic_mgtq, m0); 2024156321Sdamien if (m0 != NULL) { 2025156321Sdamien if (sc->prioq.queued >= RT2560_PRIO_RING_COUNT) { 2026156321Sdamien ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2027156321Sdamien break; 2028156321Sdamien } 2029156321Sdamien IF_DEQUEUE(&ic->ic_mgtq, m0); 2030156321Sdamien 2031156321Sdamien ni = (struct ieee80211_node *)m0->m_pkthdr.rcvif; 2032156321Sdamien m0->m_pkthdr.rcvif = NULL; 2033156321Sdamien 2034159180Scsjp if (bpf_peers_present(ic->ic_rawbpf)) 2035156321Sdamien bpf_mtap(ic->ic_rawbpf, m0); 2036156321Sdamien 2037156321Sdamien if (rt2560_tx_mgt(sc, m0, ni) != 0) 2038156321Sdamien break; 2039156321Sdamien 2040156321Sdamien } else { 2041156321Sdamien if (ic->ic_state != IEEE80211_S_RUN) 2042156321Sdamien break; 2043156321Sdamien IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 2044156321Sdamien if (m0 == NULL) 2045156321Sdamien break; 2046156321Sdamien if (sc->txq.queued >= RT2560_TX_RING_COUNT - 1) { 2047156321Sdamien IFQ_DRV_PREPEND(&ifp->if_snd, m0); 2048156321Sdamien ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2049156321Sdamien break; 2050156321Sdamien } 2051156321Sdamien 2052156321Sdamien if (m0->m_len < sizeof (struct ether_header) && 2053156321Sdamien !(m0 = m_pullup(m0, sizeof (struct ether_header)))) 2054156321Sdamien continue; 2055156321Sdamien 2056156321Sdamien eh = mtod(m0, struct ether_header *); 2057156321Sdamien ni = ieee80211_find_txnode(ic, eh->ether_dhost); 2058156321Sdamien if (ni == NULL) { 2059156321Sdamien m_freem(m0); 2060156321Sdamien continue; 2061156321Sdamien } 2062156321Sdamien BPF_MTAP(ifp, m0); 2063156321Sdamien 2064156321Sdamien m0 = ieee80211_encap(ic, m0, ni); 2065156321Sdamien if (m0 == NULL) { 2066156321Sdamien ieee80211_free_node(ni); 2067156321Sdamien continue; 2068156321Sdamien } 2069156321Sdamien 2070159180Scsjp if (bpf_peers_present(ic->ic_rawbpf)) 2071156321Sdamien bpf_mtap(ic->ic_rawbpf, m0); 2072156321Sdamien 2073156321Sdamien if (rt2560_tx_data(sc, m0, ni) != 0) { 2074156321Sdamien ieee80211_free_node(ni); 2075156321Sdamien ifp->if_oerrors++; 2076156321Sdamien break; 2077156321Sdamien } 2078156321Sdamien } 2079156321Sdamien 2080156321Sdamien sc->sc_tx_timer = 5; 2081156321Sdamien ifp->if_timer = 1; 2082156321Sdamien } 2083156321Sdamien 2084156321Sdamien RAL_UNLOCK(sc); 2085156321Sdamien} 2086156321Sdamien 2087156321Sdamienstatic void 2088156321Sdamienrt2560_watchdog(struct ifnet *ifp) 2089156321Sdamien{ 2090156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 2091156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 2092156321Sdamien 2093156321Sdamien RAL_LOCK(sc); 2094156321Sdamien 2095156321Sdamien ifp->if_timer = 0; 2096156321Sdamien 2097156321Sdamien if (sc->sc_tx_timer > 0) { 2098156321Sdamien if (--sc->sc_tx_timer == 0) { 2099156321Sdamien device_printf(sc->sc_dev, "device timeout\n"); 2100156321Sdamien rt2560_init(sc); 2101156321Sdamien ifp->if_oerrors++; 2102156321Sdamien RAL_UNLOCK(sc); 2103156321Sdamien return; 2104156321Sdamien } 2105156321Sdamien ifp->if_timer = 1; 2106156321Sdamien } 2107156321Sdamien 2108156321Sdamien ieee80211_watchdog(ic); 2109156321Sdamien 2110156321Sdamien RAL_UNLOCK(sc); 2111156321Sdamien} 2112156321Sdamien 2113156321Sdamien/* 2114156321Sdamien * This function allows for fast channel switching in monitor mode (used by 2115156321Sdamien * net-mgmt/kismet). In IBSS mode, we must explicitly reset the interface to 2116156321Sdamien * generate a new beacon frame. 2117156321Sdamien */ 2118156321Sdamienstatic int 2119156321Sdamienrt2560_reset(struct ifnet *ifp) 2120156321Sdamien{ 2121156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 2122156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 2123156321Sdamien 2124156321Sdamien if (ic->ic_opmode != IEEE80211_M_MONITOR) 2125156321Sdamien return ENETRESET; 2126156321Sdamien 2127156321Sdamien rt2560_set_chan(sc, ic->ic_curchan); 2128156321Sdamien 2129156321Sdamien return 0; 2130156321Sdamien} 2131156321Sdamien 2132156321Sdamienstatic int 2133156321Sdamienrt2560_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 2134156321Sdamien{ 2135156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 2136156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 2137156321Sdamien int error = 0; 2138156321Sdamien 2139156321Sdamien RAL_LOCK(sc); 2140156321Sdamien 2141156321Sdamien switch (cmd) { 2142156321Sdamien case SIOCSIFFLAGS: 2143156321Sdamien if (ifp->if_flags & IFF_UP) { 2144156321Sdamien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2145156321Sdamien rt2560_update_promisc(sc); 2146156321Sdamien else 2147156321Sdamien rt2560_init(sc); 2148156321Sdamien } else { 2149156321Sdamien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2150156321Sdamien rt2560_stop(sc); 2151156321Sdamien } 2152156321Sdamien break; 2153156321Sdamien 2154156321Sdamien default: 2155156321Sdamien error = ieee80211_ioctl(ic, cmd, data); 2156156321Sdamien } 2157156321Sdamien 2158156321Sdamien if (error == ENETRESET) { 2159156321Sdamien if ((ifp->if_flags & IFF_UP) && 2160156321Sdamien (ifp->if_drv_flags & IFF_DRV_RUNNING) && 2161156321Sdamien (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)) 2162156321Sdamien rt2560_init(sc); 2163156321Sdamien error = 0; 2164156321Sdamien } 2165156321Sdamien 2166156321Sdamien RAL_UNLOCK(sc); 2167156321Sdamien 2168156321Sdamien return error; 2169156321Sdamien} 2170156321Sdamien 2171156321Sdamienstatic void 2172156321Sdamienrt2560_bbp_write(struct rt2560_softc *sc, uint8_t reg, uint8_t val) 2173156321Sdamien{ 2174156321Sdamien uint32_t tmp; 2175156321Sdamien int ntries; 2176156321Sdamien 2177156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2178156321Sdamien if (!(RAL_READ(sc, RT2560_BBPCSR) & RT2560_BBP_BUSY)) 2179156321Sdamien break; 2180156321Sdamien DELAY(1); 2181156321Sdamien } 2182156321Sdamien if (ntries == 100) { 2183156321Sdamien device_printf(sc->sc_dev, "could not write to BBP\n"); 2184156321Sdamien return; 2185156321Sdamien } 2186156321Sdamien 2187156321Sdamien tmp = RT2560_BBP_WRITE | RT2560_BBP_BUSY | reg << 8 | val; 2188156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR, tmp); 2189156321Sdamien 2190156321Sdamien DPRINTFN(15, ("BBP R%u <- 0x%02x\n", reg, val)); 2191156321Sdamien} 2192156321Sdamien 2193156321Sdamienstatic uint8_t 2194156321Sdamienrt2560_bbp_read(struct rt2560_softc *sc, uint8_t reg) 2195156321Sdamien{ 2196156321Sdamien uint32_t val; 2197156321Sdamien int ntries; 2198156321Sdamien 2199156321Sdamien val = RT2560_BBP_BUSY | reg << 8; 2200156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR, val); 2201156321Sdamien 2202156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2203156321Sdamien val = RAL_READ(sc, RT2560_BBPCSR); 2204156321Sdamien if (!(val & RT2560_BBP_BUSY)) 2205156321Sdamien return val & 0xff; 2206156321Sdamien DELAY(1); 2207156321Sdamien } 2208156321Sdamien 2209156321Sdamien device_printf(sc->sc_dev, "could not read from BBP\n"); 2210156321Sdamien return 0; 2211156321Sdamien} 2212156321Sdamien 2213156321Sdamienstatic void 2214156321Sdamienrt2560_rf_write(struct rt2560_softc *sc, uint8_t reg, uint32_t val) 2215156321Sdamien{ 2216156321Sdamien uint32_t tmp; 2217156321Sdamien int ntries; 2218156321Sdamien 2219156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2220156321Sdamien if (!(RAL_READ(sc, RT2560_RFCSR) & RT2560_RF_BUSY)) 2221156321Sdamien break; 2222156321Sdamien DELAY(1); 2223156321Sdamien } 2224156321Sdamien if (ntries == 100) { 2225156321Sdamien device_printf(sc->sc_dev, "could not write to RF\n"); 2226156321Sdamien return; 2227156321Sdamien } 2228156321Sdamien 2229156321Sdamien tmp = RT2560_RF_BUSY | RT2560_RF_20BIT | (val & 0xfffff) << 2 | 2230156321Sdamien (reg & 0x3); 2231156321Sdamien RAL_WRITE(sc, RT2560_RFCSR, tmp); 2232156321Sdamien 2233156321Sdamien /* remember last written value in sc */ 2234156321Sdamien sc->rf_regs[reg] = val; 2235156321Sdamien 2236156321Sdamien DPRINTFN(15, ("RF R[%u] <- 0x%05x\n", reg & 0x3, val & 0xfffff)); 2237156321Sdamien} 2238156321Sdamien 2239156321Sdamienstatic void 2240156321Sdamienrt2560_set_chan(struct rt2560_softc *sc, struct ieee80211_channel *c) 2241156321Sdamien{ 2242156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 2243156321Sdamien uint8_t power, tmp; 2244156321Sdamien u_int i, chan; 2245156321Sdamien 2246156321Sdamien chan = ieee80211_chan2ieee(ic, c); 2247156321Sdamien if (chan == 0 || chan == IEEE80211_CHAN_ANY) 2248156321Sdamien return; 2249156321Sdamien 2250156321Sdamien if (IEEE80211_IS_CHAN_2GHZ(c)) 2251156321Sdamien power = min(sc->txpow[chan - 1], 31); 2252156321Sdamien else 2253156321Sdamien power = 31; 2254156321Sdamien 2255156321Sdamien /* adjust txpower using ifconfig settings */ 2256156321Sdamien power -= (100 - ic->ic_txpowlimit) / 8; 2257156321Sdamien 2258156321Sdamien DPRINTFN(2, ("setting channel to %u, txpower to %u\n", chan, power)); 2259156321Sdamien 2260156321Sdamien switch (sc->rf_rev) { 2261156321Sdamien case RT2560_RF_2522: 2262156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x00814); 2263156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2522_r2[chan - 1]); 2264156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2265156321Sdamien break; 2266156321Sdamien 2267156321Sdamien case RT2560_RF_2523: 2268156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08804); 2269156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2523_r2[chan - 1]); 2270156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x38044); 2271156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2272156321Sdamien break; 2273156321Sdamien 2274156321Sdamien case RT2560_RF_2524: 2275156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x0c808); 2276156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2524_r2[chan - 1]); 2277156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2278156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2279156321Sdamien break; 2280156321Sdamien 2281156321Sdamien case RT2560_RF_2525: 2282156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2283156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_hi_r2[chan - 1]); 2284156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2285156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2286156321Sdamien 2287156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2288156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_r2[chan - 1]); 2289156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2290156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 2291156321Sdamien break; 2292156321Sdamien 2293156321Sdamien case RT2560_RF_2525E: 2294156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08808); 2295156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525e_r2[chan - 1]); 2296156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2297156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00286 : 0x00282); 2298156321Sdamien break; 2299156321Sdamien 2300156321Sdamien case RT2560_RF_2526: 2301156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_hi_r2[chan - 1]); 2302156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); 2303156321Sdamien rt2560_rf_write(sc, RAL_RF1, 0x08804); 2304156321Sdamien 2305156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_r2[chan - 1]); 2306156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 2307156321Sdamien rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); 2308156321Sdamien break; 2309156321Sdamien 2310156321Sdamien /* dual-band RF */ 2311156321Sdamien case RT2560_RF_5222: 2312156321Sdamien for (i = 0; rt2560_rf5222[i].chan != chan; i++); 2313156321Sdamien 2314156321Sdamien rt2560_rf_write(sc, RAL_RF1, rt2560_rf5222[i].r1); 2315156321Sdamien rt2560_rf_write(sc, RAL_RF2, rt2560_rf5222[i].r2); 2316156321Sdamien rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 2317156321Sdamien rt2560_rf_write(sc, RAL_RF4, rt2560_rf5222[i].r4); 2318156321Sdamien break; 2319156321Sdamien } 2320156321Sdamien 2321156321Sdamien if (ic->ic_state != IEEE80211_S_SCAN) { 2322156321Sdamien /* set Japan filter bit for channel 14 */ 2323156321Sdamien tmp = rt2560_bbp_read(sc, 70); 2324156321Sdamien 2325156321Sdamien tmp &= ~RT2560_JAPAN_FILTER; 2326156321Sdamien if (chan == 14) 2327156321Sdamien tmp |= RT2560_JAPAN_FILTER; 2328156321Sdamien 2329156321Sdamien rt2560_bbp_write(sc, 70, tmp); 2330156321Sdamien 2331156321Sdamien /* clear CRC errors */ 2332156321Sdamien RAL_READ(sc, RT2560_CNT0); 2333156321Sdamien } 2334156321Sdamien} 2335156321Sdamien 2336156321Sdamien#if 0 2337156321Sdamien/* 2338156321Sdamien * Disable RF auto-tuning. 2339156321Sdamien */ 2340156321Sdamienstatic void 2341156321Sdamienrt2560_disable_rf_tune(struct rt2560_softc *sc) 2342156321Sdamien{ 2343156321Sdamien uint32_t tmp; 2344156321Sdamien 2345156321Sdamien if (sc->rf_rev != RT2560_RF_2523) { 2346156321Sdamien tmp = sc->rf_regs[RAL_RF1] & ~RAL_RF1_AUTOTUNE; 2347156321Sdamien rt2560_rf_write(sc, RAL_RF1, tmp); 2348156321Sdamien } 2349156321Sdamien 2350156321Sdamien tmp = sc->rf_regs[RAL_RF3] & ~RAL_RF3_AUTOTUNE; 2351156321Sdamien rt2560_rf_write(sc, RAL_RF3, tmp); 2352156321Sdamien 2353156321Sdamien DPRINTFN(2, ("disabling RF autotune\n")); 2354156321Sdamien} 2355156321Sdamien#endif 2356156321Sdamien 2357156321Sdamien/* 2358156321Sdamien * Refer to IEEE Std 802.11-1999 pp. 123 for more information on TSF 2359156321Sdamien * synchronization. 2360156321Sdamien */ 2361156321Sdamienstatic void 2362156321Sdamienrt2560_enable_tsf_sync(struct rt2560_softc *sc) 2363156321Sdamien{ 2364156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 2365156321Sdamien uint16_t logcwmin, preload; 2366156321Sdamien uint32_t tmp; 2367156321Sdamien 2368156321Sdamien /* first, disable TSF synchronization */ 2369156321Sdamien RAL_WRITE(sc, RT2560_CSR14, 0); 2370156321Sdamien 2371156321Sdamien tmp = 16 * ic->ic_bss->ni_intval; 2372156321Sdamien RAL_WRITE(sc, RT2560_CSR12, tmp); 2373156321Sdamien 2374156321Sdamien RAL_WRITE(sc, RT2560_CSR13, 0); 2375156321Sdamien 2376156321Sdamien logcwmin = 5; 2377156321Sdamien preload = (ic->ic_opmode == IEEE80211_M_STA) ? 384 : 1024; 2378156321Sdamien tmp = logcwmin << 16 | preload; 2379156321Sdamien RAL_WRITE(sc, RT2560_BCNOCSR, tmp); 2380156321Sdamien 2381156321Sdamien /* finally, enable TSF synchronization */ 2382156321Sdamien tmp = RT2560_ENABLE_TSF | RT2560_ENABLE_TBCN; 2383156321Sdamien if (ic->ic_opmode == IEEE80211_M_STA) 2384156321Sdamien tmp |= RT2560_ENABLE_TSF_SYNC(1); 2385156321Sdamien else 2386156321Sdamien tmp |= RT2560_ENABLE_TSF_SYNC(2) | 2387156321Sdamien RT2560_ENABLE_BEACON_GENERATOR; 2388156321Sdamien RAL_WRITE(sc, RT2560_CSR14, tmp); 2389156321Sdamien 2390156321Sdamien DPRINTF(("enabling TSF synchronization\n")); 2391156321Sdamien} 2392156321Sdamien 2393156321Sdamienstatic void 2394156321Sdamienrt2560_update_plcp(struct rt2560_softc *sc) 2395156321Sdamien{ 2396156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 2397156321Sdamien 2398156321Sdamien /* no short preamble for 1Mbps */ 2399156321Sdamien RAL_WRITE(sc, RT2560_PLCP1MCSR, 0x00700400); 2400156321Sdamien 2401156321Sdamien if (!(ic->ic_flags & IEEE80211_F_SHPREAMBLE)) { 2402156321Sdamien /* values taken from the reference driver */ 2403156321Sdamien RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380401); 2404156321Sdamien RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x00150402); 2405156321Sdamien RAL_WRITE(sc, RT2560_PLCP11MCSR, 0x000b8403); 2406156321Sdamien } else { 2407156321Sdamien /* same values as above or'ed 0x8 */ 2408156321Sdamien RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380409); 2409156321Sdamien RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x0015040a); 2410156321Sdamien RAL_WRITE(sc, RT2560_PLCP11MCSR, 0x000b840b); 2411156321Sdamien } 2412156321Sdamien 2413156321Sdamien DPRINTF(("updating PLCP for %s preamble\n", 2414156321Sdamien (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? "short" : "long")); 2415156321Sdamien} 2416156321Sdamien 2417156321Sdamien/* 2418156321Sdamien * This function can be called by ieee80211_set_shortslottime(). Refer to 2419156321Sdamien * IEEE Std 802.11-1999 pp. 85 to know how these values are computed. 2420156321Sdamien */ 2421156321Sdamienstatic void 2422156321Sdamienrt2560_update_slot(struct ifnet *ifp) 2423156321Sdamien{ 2424156321Sdamien struct rt2560_softc *sc = ifp->if_softc; 2425156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 2426156321Sdamien uint8_t slottime; 2427156321Sdamien uint16_t tx_sifs, tx_pifs, tx_difs, eifs; 2428156321Sdamien uint32_t tmp; 2429156321Sdamien 2430156321Sdamien slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; 2431156321Sdamien 2432156321Sdamien /* update the MAC slot boundaries */ 2433156321Sdamien tx_sifs = RAL_SIFS - RT2560_TXRX_TURNAROUND; 2434156321Sdamien tx_pifs = tx_sifs + slottime; 2435156321Sdamien tx_difs = tx_sifs + 2 * slottime; 2436156321Sdamien eifs = (ic->ic_curmode == IEEE80211_MODE_11B) ? 364 : 60; 2437156321Sdamien 2438156321Sdamien tmp = RAL_READ(sc, RT2560_CSR11); 2439156321Sdamien tmp = (tmp & ~0x1f00) | slottime << 8; 2440156321Sdamien RAL_WRITE(sc, RT2560_CSR11, tmp); 2441156321Sdamien 2442156321Sdamien tmp = tx_pifs << 16 | tx_sifs; 2443156321Sdamien RAL_WRITE(sc, RT2560_CSR18, tmp); 2444156321Sdamien 2445156321Sdamien tmp = eifs << 16 | tx_difs; 2446156321Sdamien RAL_WRITE(sc, RT2560_CSR19, tmp); 2447156321Sdamien 2448156321Sdamien DPRINTF(("setting slottime to %uus\n", slottime)); 2449156321Sdamien} 2450156321Sdamien 2451156321Sdamienstatic void 2452156321Sdamienrt2560_set_basicrates(struct rt2560_softc *sc) 2453156321Sdamien{ 2454156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 2455156321Sdamien 2456156321Sdamien /* update basic rate set */ 2457156321Sdamien if (ic->ic_curmode == IEEE80211_MODE_11B) { 2458156321Sdamien /* 11b basic rates: 1, 2Mbps */ 2459156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x3); 2460156321Sdamien } else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) { 2461156321Sdamien /* 11a basic rates: 6, 12, 24Mbps */ 2462156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x150); 2463156321Sdamien } else { 2464156321Sdamien /* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */ 2465156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x15f); 2466156321Sdamien } 2467156321Sdamien} 2468156321Sdamien 2469156321Sdamienstatic void 2470156321Sdamienrt2560_update_led(struct rt2560_softc *sc, int led1, int led2) 2471156321Sdamien{ 2472156321Sdamien uint32_t tmp; 2473156321Sdamien 2474156321Sdamien /* set ON period to 70ms and OFF period to 30ms */ 2475156321Sdamien tmp = led1 << 16 | led2 << 17 | 70 << 8 | 30; 2476156321Sdamien RAL_WRITE(sc, RT2560_LEDCSR, tmp); 2477156321Sdamien} 2478156321Sdamien 2479156321Sdamienstatic void 2480156321Sdamienrt2560_set_bssid(struct rt2560_softc *sc, uint8_t *bssid) 2481156321Sdamien{ 2482156321Sdamien uint32_t tmp; 2483156321Sdamien 2484156321Sdamien tmp = bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24; 2485156321Sdamien RAL_WRITE(sc, RT2560_CSR5, tmp); 2486156321Sdamien 2487156321Sdamien tmp = bssid[4] | bssid[5] << 8; 2488156321Sdamien RAL_WRITE(sc, RT2560_CSR6, tmp); 2489156321Sdamien 2490156321Sdamien DPRINTF(("setting BSSID to %6D\n", bssid, ":")); 2491156321Sdamien} 2492156321Sdamien 2493156321Sdamienstatic void 2494156321Sdamienrt2560_set_macaddr(struct rt2560_softc *sc, uint8_t *addr) 2495156321Sdamien{ 2496156321Sdamien uint32_t tmp; 2497156321Sdamien 2498156321Sdamien tmp = addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24; 2499156321Sdamien RAL_WRITE(sc, RT2560_CSR3, tmp); 2500156321Sdamien 2501156321Sdamien tmp = addr[4] | addr[5] << 8; 2502156321Sdamien RAL_WRITE(sc, RT2560_CSR4, tmp); 2503156321Sdamien 2504156321Sdamien DPRINTF(("setting MAC address to %6D\n", addr, ":")); 2505156321Sdamien} 2506156321Sdamien 2507156321Sdamienstatic void 2508156321Sdamienrt2560_get_macaddr(struct rt2560_softc *sc, uint8_t *addr) 2509156321Sdamien{ 2510156321Sdamien uint32_t tmp; 2511156321Sdamien 2512156321Sdamien tmp = RAL_READ(sc, RT2560_CSR3); 2513156321Sdamien addr[0] = tmp & 0xff; 2514156321Sdamien addr[1] = (tmp >> 8) & 0xff; 2515156321Sdamien addr[2] = (tmp >> 16) & 0xff; 2516156321Sdamien addr[3] = (tmp >> 24); 2517156321Sdamien 2518156321Sdamien tmp = RAL_READ(sc, RT2560_CSR4); 2519156321Sdamien addr[4] = tmp & 0xff; 2520156321Sdamien addr[5] = (tmp >> 8) & 0xff; 2521156321Sdamien} 2522156321Sdamien 2523156321Sdamienstatic void 2524156321Sdamienrt2560_update_promisc(struct rt2560_softc *sc) 2525156321Sdamien{ 2526156321Sdamien struct ifnet *ifp = sc->sc_ic.ic_ifp; 2527156321Sdamien uint32_t tmp; 2528156321Sdamien 2529156321Sdamien tmp = RAL_READ(sc, RT2560_RXCSR0); 2530156321Sdamien 2531156321Sdamien tmp &= ~RT2560_DROP_NOT_TO_ME; 2532156321Sdamien if (!(ifp->if_flags & IFF_PROMISC)) 2533156321Sdamien tmp |= RT2560_DROP_NOT_TO_ME; 2534156321Sdamien 2535156321Sdamien RAL_WRITE(sc, RT2560_RXCSR0, tmp); 2536156321Sdamien 2537156321Sdamien DPRINTF(("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ? 2538156321Sdamien "entering" : "leaving")); 2539156321Sdamien} 2540156321Sdamien 2541156321Sdamienstatic const char * 2542156321Sdamienrt2560_get_rf(int rev) 2543156321Sdamien{ 2544156321Sdamien switch (rev) { 2545156321Sdamien case RT2560_RF_2522: return "RT2522"; 2546156321Sdamien case RT2560_RF_2523: return "RT2523"; 2547156321Sdamien case RT2560_RF_2524: return "RT2524"; 2548156321Sdamien case RT2560_RF_2525: return "RT2525"; 2549156321Sdamien case RT2560_RF_2525E: return "RT2525e"; 2550156321Sdamien case RT2560_RF_2526: return "RT2526"; 2551156321Sdamien case RT2560_RF_5222: return "RT5222"; 2552156321Sdamien default: return "unknown"; 2553156321Sdamien } 2554156321Sdamien} 2555156321Sdamien 2556156321Sdamienstatic void 2557156321Sdamienrt2560_read_eeprom(struct rt2560_softc *sc) 2558156321Sdamien{ 2559156321Sdamien uint16_t val; 2560156321Sdamien int i; 2561156321Sdamien 2562156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_CONFIG0); 2563156321Sdamien sc->rf_rev = (val >> 11) & 0x7; 2564156321Sdamien sc->hw_radio = (val >> 10) & 0x1; 2565156321Sdamien sc->led_mode = (val >> 6) & 0x7; 2566156321Sdamien sc->rx_ant = (val >> 4) & 0x3; 2567156321Sdamien sc->tx_ant = (val >> 2) & 0x3; 2568156321Sdamien sc->nb_ant = val & 0x3; 2569156321Sdamien 2570156321Sdamien /* read default values for BBP registers */ 2571156321Sdamien for (i = 0; i < 16; i++) { 2572156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_BBP_BASE + i); 2573156321Sdamien sc->bbp_prom[i].reg = val >> 8; 2574156321Sdamien sc->bbp_prom[i].val = val & 0xff; 2575156321Sdamien } 2576156321Sdamien 2577156321Sdamien /* read Tx power for all b/g channels */ 2578156321Sdamien for (i = 0; i < 14 / 2; i++) { 2579156321Sdamien val = rt2560_eeprom_read(sc, RT2560_EEPROM_TXPOWER + i); 2580156321Sdamien sc->txpow[i * 2] = val >> 8; 2581156321Sdamien sc->txpow[i * 2 + 1] = val & 0xff; 2582156321Sdamien } 2583156321Sdamien} 2584156321Sdamien 2585156321Sdamienstatic int 2586156321Sdamienrt2560_bbp_init(struct rt2560_softc *sc) 2587156321Sdamien{ 2588156321Sdamien#define N(a) (sizeof (a) / sizeof ((a)[0])) 2589156321Sdamien int i, ntries; 2590156321Sdamien 2591156321Sdamien /* wait for BBP to be ready */ 2592156321Sdamien for (ntries = 0; ntries < 100; ntries++) { 2593156321Sdamien if (rt2560_bbp_read(sc, RT2560_BBP_VERSION) != 0) 2594156321Sdamien break; 2595156321Sdamien DELAY(1); 2596156321Sdamien } 2597156321Sdamien if (ntries == 100) { 2598156321Sdamien device_printf(sc->sc_dev, "timeout waiting for BBP\n"); 2599156321Sdamien return EIO; 2600156321Sdamien } 2601156321Sdamien 2602156321Sdamien /* initialize BBP registers to default values */ 2603156321Sdamien for (i = 0; i < N(rt2560_def_bbp); i++) { 2604156321Sdamien rt2560_bbp_write(sc, rt2560_def_bbp[i].reg, 2605156321Sdamien rt2560_def_bbp[i].val); 2606156321Sdamien } 2607156321Sdamien#if 0 2608156321Sdamien /* initialize BBP registers to values stored in EEPROM */ 2609156321Sdamien for (i = 0; i < 16; i++) { 2610156321Sdamien if (sc->bbp_prom[i].reg == 0xff) 2611156321Sdamien continue; 2612156321Sdamien rt2560_bbp_write(sc, sc->bbp_prom[i].reg, sc->bbp_prom[i].val); 2613156321Sdamien } 2614156321Sdamien#endif 2615156321Sdamien 2616156321Sdamien return 0; 2617156321Sdamien#undef N 2618156321Sdamien} 2619156321Sdamien 2620156321Sdamienstatic void 2621156321Sdamienrt2560_set_txantenna(struct rt2560_softc *sc, int antenna) 2622156321Sdamien{ 2623156321Sdamien uint32_t tmp; 2624156321Sdamien uint8_t tx; 2625156321Sdamien 2626156321Sdamien tx = rt2560_bbp_read(sc, RT2560_BBP_TX) & ~RT2560_BBP_ANTMASK; 2627156321Sdamien if (antenna == 1) 2628156321Sdamien tx |= RT2560_BBP_ANTA; 2629156321Sdamien else if (antenna == 2) 2630156321Sdamien tx |= RT2560_BBP_ANTB; 2631156321Sdamien else 2632156321Sdamien tx |= RT2560_BBP_DIVERSITY; 2633156321Sdamien 2634156321Sdamien /* need to force I/Q flip for RF 2525e, 2526 and 5222 */ 2635156321Sdamien if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526 || 2636156321Sdamien sc->rf_rev == RT2560_RF_5222) 2637156321Sdamien tx |= RT2560_BBP_FLIPIQ; 2638156321Sdamien 2639156321Sdamien rt2560_bbp_write(sc, RT2560_BBP_TX, tx); 2640156321Sdamien 2641156321Sdamien /* update values for CCK and OFDM in BBPCSR1 */ 2642156321Sdamien tmp = RAL_READ(sc, RT2560_BBPCSR1) & ~0x00070007; 2643156321Sdamien tmp |= (tx & 0x7) << 16 | (tx & 0x7); 2644156321Sdamien RAL_WRITE(sc, RT2560_BBPCSR1, tmp); 2645156321Sdamien} 2646156321Sdamien 2647156321Sdamienstatic void 2648156321Sdamienrt2560_set_rxantenna(struct rt2560_softc *sc, int antenna) 2649156321Sdamien{ 2650156321Sdamien uint8_t rx; 2651156321Sdamien 2652156321Sdamien rx = rt2560_bbp_read(sc, RT2560_BBP_RX) & ~RT2560_BBP_ANTMASK; 2653156321Sdamien if (antenna == 1) 2654156321Sdamien rx |= RT2560_BBP_ANTA; 2655156321Sdamien else if (antenna == 2) 2656156321Sdamien rx |= RT2560_BBP_ANTB; 2657156321Sdamien else 2658156321Sdamien rx |= RT2560_BBP_DIVERSITY; 2659156321Sdamien 2660156321Sdamien /* need to force no I/Q flip for RF 2525e and 2526 */ 2661156321Sdamien if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526) 2662156321Sdamien rx &= ~RT2560_BBP_FLIPIQ; 2663156321Sdamien 2664156321Sdamien rt2560_bbp_write(sc, RT2560_BBP_RX, rx); 2665156321Sdamien} 2666156321Sdamien 2667156321Sdamienstatic void 2668156321Sdamienrt2560_init(void *priv) 2669156321Sdamien{ 2670156321Sdamien#define N(a) (sizeof (a) / sizeof ((a)[0])) 2671156321Sdamien struct rt2560_softc *sc = priv; 2672156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 2673156321Sdamien struct ifnet *ifp = ic->ic_ifp; 2674156321Sdamien uint32_t tmp; 2675156321Sdamien int i; 2676156321Sdamien 2677156975Sdamien RAL_LOCK(sc); 2678156975Sdamien 2679156321Sdamien rt2560_stop(sc); 2680156321Sdamien 2681156321Sdamien /* setup tx rings */ 2682156321Sdamien tmp = RT2560_PRIO_RING_COUNT << 24 | 2683156321Sdamien RT2560_ATIM_RING_COUNT << 16 | 2684156321Sdamien RT2560_TX_RING_COUNT << 8 | 2685156321Sdamien RT2560_TX_DESC_SIZE; 2686156321Sdamien 2687156321Sdamien /* rings must be initialized in this exact order */ 2688156321Sdamien RAL_WRITE(sc, RT2560_TXCSR2, tmp); 2689156321Sdamien RAL_WRITE(sc, RT2560_TXCSR3, sc->txq.physaddr); 2690156321Sdamien RAL_WRITE(sc, RT2560_TXCSR5, sc->prioq.physaddr); 2691156321Sdamien RAL_WRITE(sc, RT2560_TXCSR4, sc->atimq.physaddr); 2692156321Sdamien RAL_WRITE(sc, RT2560_TXCSR6, sc->bcnq.physaddr); 2693156321Sdamien 2694156321Sdamien /* setup rx ring */ 2695156321Sdamien tmp = RT2560_RX_RING_COUNT << 8 | RT2560_RX_DESC_SIZE; 2696156321Sdamien 2697156321Sdamien RAL_WRITE(sc, RT2560_RXCSR1, tmp); 2698156321Sdamien RAL_WRITE(sc, RT2560_RXCSR2, sc->rxq.physaddr); 2699156321Sdamien 2700156321Sdamien /* initialize MAC registers to default values */ 2701156321Sdamien for (i = 0; i < N(rt2560_def_mac); i++) 2702156321Sdamien RAL_WRITE(sc, rt2560_def_mac[i].reg, rt2560_def_mac[i].val); 2703156321Sdamien 2704156321Sdamien IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp)); 2705156321Sdamien rt2560_set_macaddr(sc, ic->ic_myaddr); 2706156321Sdamien 2707156321Sdamien /* set basic rate set (will be updated later) */ 2708156321Sdamien RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x153); 2709156321Sdamien 2710156321Sdamien rt2560_set_txantenna(sc, sc->tx_ant); 2711156321Sdamien rt2560_set_rxantenna(sc, sc->rx_ant); 2712156321Sdamien rt2560_update_slot(ifp); 2713156321Sdamien rt2560_update_plcp(sc); 2714156321Sdamien rt2560_update_led(sc, 0, 0); 2715156321Sdamien 2716156321Sdamien RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 2717156321Sdamien RAL_WRITE(sc, RT2560_CSR1, RT2560_HOST_READY); 2718156321Sdamien 2719156321Sdamien if (rt2560_bbp_init(sc) != 0) { 2720156321Sdamien rt2560_stop(sc); 2721156975Sdamien RAL_UNLOCK(sc); 2722156321Sdamien return; 2723156321Sdamien } 2724156321Sdamien 2725156321Sdamien /* set default BSS channel */ 2726156321Sdamien rt2560_set_chan(sc, ic->ic_curchan); 2727156321Sdamien 2728156321Sdamien /* kick Rx */ 2729156321Sdamien tmp = RT2560_DROP_PHY_ERROR | RT2560_DROP_CRC_ERROR; 2730156321Sdamien if (ic->ic_opmode != IEEE80211_M_MONITOR) { 2731156321Sdamien tmp |= RT2560_DROP_CTL | RT2560_DROP_VERSION_ERROR; 2732156321Sdamien if (ic->ic_opmode != IEEE80211_M_HOSTAP) 2733156321Sdamien tmp |= RT2560_DROP_TODS; 2734156321Sdamien if (!(ifp->if_flags & IFF_PROMISC)) 2735156321Sdamien tmp |= RT2560_DROP_NOT_TO_ME; 2736156321Sdamien } 2737156321Sdamien RAL_WRITE(sc, RT2560_RXCSR0, tmp); 2738156321Sdamien 2739156321Sdamien /* clear old FCS and Rx FIFO errors */ 2740156321Sdamien RAL_READ(sc, RT2560_CNT0); 2741156321Sdamien RAL_READ(sc, RT2560_CNT4); 2742156321Sdamien 2743156321Sdamien /* clear any pending interrupts */ 2744156321Sdamien RAL_WRITE(sc, RT2560_CSR7, 0xffffffff); 2745156321Sdamien 2746156321Sdamien /* enable interrupts */ 2747156321Sdamien RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); 2748156321Sdamien 2749156321Sdamien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2750156321Sdamien ifp->if_drv_flags |= IFF_DRV_RUNNING; 2751156321Sdamien 2752156321Sdamien if (ic->ic_opmode != IEEE80211_M_MONITOR) { 2753156321Sdamien if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) 2754156321Sdamien ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 2755156321Sdamien } else 2756156321Sdamien ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 2757156975Sdamien 2758156975Sdamien RAL_UNLOCK(sc); 2759156321Sdamien#undef N 2760156321Sdamien} 2761156321Sdamien 2762156321Sdamienvoid 2763156321Sdamienrt2560_stop(void *priv) 2764156321Sdamien{ 2765156321Sdamien struct rt2560_softc *sc = priv; 2766156321Sdamien struct ieee80211com *ic = &sc->sc_ic; 2767156321Sdamien struct ifnet *ifp = ic->ic_ifp; 2768156321Sdamien 2769156321Sdamien sc->sc_tx_timer = 0; 2770156321Sdamien ifp->if_timer = 0; 2771156321Sdamien ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2772156321Sdamien 2773156975Sdamien ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 2774156975Sdamien 2775156321Sdamien /* abort Tx */ 2776156321Sdamien RAL_WRITE(sc, RT2560_TXCSR0, RT2560_ABORT_TX); 2777156321Sdamien 2778156321Sdamien /* disable Rx */ 2779156321Sdamien RAL_WRITE(sc, RT2560_RXCSR0, RT2560_DISABLE_RX); 2780156321Sdamien 2781156321Sdamien /* reset ASIC (imply reset BBP) */ 2782156321Sdamien RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 2783156321Sdamien RAL_WRITE(sc, RT2560_CSR1, 0); 2784156321Sdamien 2785156321Sdamien /* disable interrupts */ 2786156321Sdamien RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 2787156321Sdamien 2788156321Sdamien /* reset Tx and Rx rings */ 2789156321Sdamien rt2560_reset_tx_ring(sc, &sc->txq); 2790156321Sdamien rt2560_reset_tx_ring(sc, &sc->atimq); 2791156321Sdamien rt2560_reset_tx_ring(sc, &sc->prioq); 2792156321Sdamien rt2560_reset_tx_ring(sc, &sc->bcnq); 2793156321Sdamien rt2560_reset_rx_ring(sc, &sc->rxq); 2794156321Sdamien} 2795160691Ssam 2796160691Ssamstatic int 2797160691Ssamrt2560_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 2798160691Ssam const struct ieee80211_bpf_params *params) 2799160691Ssam{ 2800160691Ssam struct ieee80211com *ic = ni->ni_ic; 2801160691Ssam struct ifnet *ifp = ic->ic_ifp; 2802160691Ssam struct rt2560_softc *sc = ifp->if_softc; 2803160691Ssam 2804160691Ssam RAL_LOCK(sc); 2805160691Ssam 2806160691Ssam /* prevent management frames from being sent if we're not ready */ 2807160691Ssam if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2808160691Ssam RAL_UNLOCK(sc); 2809160691Ssam return ENETDOWN; 2810160691Ssam } 2811160691Ssam if (sc->prioq.queued >= RT2560_PRIO_RING_COUNT) { 2812160691Ssam ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2813160691Ssam RAL_UNLOCK(sc); 2814160691Ssam return ENOBUFS; /* XXX */ 2815160691Ssam } 2816160691Ssam 2817160691Ssam if (bpf_peers_present(ic->ic_rawbpf)) 2818160691Ssam bpf_mtap(ic->ic_rawbpf, m); 2819160691Ssam 2820160691Ssam ifp->if_opackets++; 2821160691Ssam 2822160691Ssam if (params == NULL) { 2823160691Ssam /* 2824160691Ssam * Legacy path; interpret frame contents to decide 2825160691Ssam * precisely how to send the frame. 2826160691Ssam */ 2827160691Ssam if (rt2560_tx_mgt(sc, m, ni) != 0) 2828160691Ssam goto bad; 2829160691Ssam } else { 2830160691Ssam /* 2831160691Ssam * Caller supplied explicit parameters to use in 2832160691Ssam * sending the frame. 2833160691Ssam */ 2834160691Ssam if (rt2560_tx_raw(sc, m, ni, params)) 2835160691Ssam goto bad; 2836160691Ssam } 2837160691Ssam sc->sc_tx_timer = 5; 2838160691Ssam ifp->if_timer = 1; 2839160691Ssam 2840160691Ssam RAL_UNLOCK(sc); 2841160691Ssam 2842160691Ssam return 0; 2843160691Ssambad: 2844160691Ssam ifp->if_oerrors++; 2845160905Ssam ieee80211_free_node(ni); 2846160691Ssam RAL_UNLOCK(sc); 2847160691Ssam return EIO; /* XXX */ 2848160691Ssam} 2849