Author: colin Date: 2010-10-23 22:03:37 +0200 (Sat, 23 Oct 2010) New Revision: 39080 Changeset: http://dev.haiku-os.org/changeset/39080 Added: haiku/vendor/freebsd/current/dev/rt2860/ haiku/vendor/freebsd/current/dev/rt2860/Makefile haiku/vendor/freebsd/current/dev/rt2860/rt2860.c haiku/vendor/freebsd/current/dev/rt2860/rt2860_amrr.c haiku/vendor/freebsd/current/dev/rt2860/rt2860_amrr.h haiku/vendor/freebsd/current/dev/rt2860/rt2860_debug.h haiku/vendor/freebsd/current/dev/rt2860/rt2860_eeprom.h haiku/vendor/freebsd/current/dev/rt2860/rt2860_io.c haiku/vendor/freebsd/current/dev/rt2860/rt2860_io.h haiku/vendor/freebsd/current/dev/rt2860/rt2860_led.c haiku/vendor/freebsd/current/dev/rt2860/rt2860_led.h haiku/vendor/freebsd/current/dev/rt2860/rt2860_read_eeprom.c haiku/vendor/freebsd/current/dev/rt2860/rt2860_read_eeprom.h haiku/vendor/freebsd/current/dev/rt2860/rt2860_reg.h haiku/vendor/freebsd/current/dev/rt2860/rt2860_rf.c haiku/vendor/freebsd/current/dev/rt2860/rt2860_rf.h haiku/vendor/freebsd/current/dev/rt2860/rt2860_rxdesc.h haiku/vendor/freebsd/current/dev/rt2860/rt2860_rxwi.h haiku/vendor/freebsd/current/dev/rt2860/rt2860_softc.h haiku/vendor/freebsd/current/dev/rt2860/rt2860_txdesc.h haiku/vendor/freebsd/current/dev/rt2860/rt2860_txwi.h haiku/vendor/freebsd/current/dev/rt2860/rt2860_ucode.h Log: Importing Ralink 2860 driver from git-repository http://repo.or.cz/w/ralink_drivers/rt2860_fbsd8.git using commit hash c58bf9b6971dbfa96770ee2b8358a04e37536971. Added: haiku/vendor/freebsd/current/dev/rt2860/Makefile =================================================================== --- haiku/vendor/freebsd/current/dev/rt2860/Makefile (rev 0) +++ haiku/vendor/freebsd/current/dev/rt2860/Makefile 2010-10-23 20:03:37 UTC (rev 39080) @@ -0,0 +1,18 @@ + +SRCS = device_if.h \ + bus_if.h \ + pci_if.h \ + rt2860_io.c \ + rt2860_read_eeprom.c \ + rt2860_led.c \ + rt2860_rf.c \ + rt2860_amrr.c \ + rt2860.c + +KMOD = rt2860 + +DEBUG_FLAGS = -g +WERROR = +CFLAGS += -DRT2860_DEBUG + +.include <bsd.kmod.mk> Added: haiku/vendor/freebsd/current/dev/rt2860/rt2860.c =================================================================== --- haiku/vendor/freebsd/current/dev/rt2860/rt2860.c (rev 0) +++ haiku/vendor/freebsd/current/dev/rt2860/rt2860.c 2010-10-23 20:03:37 UTC (rev 39080) @@ -0,0 +1,7182 @@ + +/*- + * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@xxxxxxxxx> + * Copyright (c) 2009 Damien Bergamini <damien.bergamini@xxxxxxx> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "rt2860_softc.h" +#include "rt2860_reg.h" +#include "rt2860_eeprom.h" +#include "rt2860_ucode.h" +#include "rt2860_txwi.h" +#include "rt2860_rxwi.h" +#include "rt2860_io.h" +#include "rt2860_read_eeprom.h" +#include "rt2860_led.h" +#include "rt2860_rf.h" +#include "rt2860_debug.h" + +/* + * Defines and macros + */ + +#define PCI_VENDOR_RALINK 0x1814 +#define PCI_PRODUCT_RALINK_RT2860_PCI 0x0601 +#define PCI_PRODUCT_RALINK_RT2860_PCIe 0x0681 +#define PCI_PRODUCT_RALINK_RT2760_PCI 0x0701 +#define PCI_PRODUCT_RALINK_RT2790_PCIe 0x0781 + +#define RT2860_MAX_AGG_SIZE 3840 + +#define RT2860_TX_DATA_SEG0_SIZE \ + (sizeof(struct rt2860_txwi) + sizeof(struct ieee80211_qosframe_addr4)) + +#define RT2860_NOISE_FLOOR -95 + +#define IEEE80211_HAS_ADDR4(wh) \ + (((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) + +#define RT2860_MS(_v, _f) (((_v) & _f) >> _f##_S) +#define RT2860_SM(_v, _f) (((_v) << _f##_S) & _f) + +#define RT2860_TX_WATCHDOG_TIMEOUT 5 + +#define RT2860_WCID_RESERVED 0xff +#define RT2860_WCID_MCAST 0xf7 + +/* + * Data structures and types + */ + +struct rt2860_pci_ident +{ + uint16_t vendor; + uint16_t device; + const char *name; +}; + +/* + * Static function prototypes + */ + +static int rt2860_probe(device_t dev); + +static int rt2860_attach(device_t dev); + +static int rt2860_detach(device_t dev); + +static int rt2860_shutdown(device_t dev); + +static int rt2860_suspend(device_t dev); + +static int rt2860_resume(device_t dev); + +static void rt2860_init_channels(struct rt2860_softc *sc); + +static void rt2860_init_channels_ht40(struct rt2860_softc *sc); + +static void rt2860_init_locked(void *priv); + +static void rt2860_init(void *priv); + +static int rt2860_init_bbp(struct rt2860_softc *sc); + +static void rt2860_stop_locked(void *priv); + +static void rt2860_stop(void *priv); + +static void rt2860_start(struct ifnet *ifp); + +static int rt2860_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); + +static struct ieee80211vap *rt2860_vap_create(struct ieee80211com *ic, + const char name[IFNAMSIZ], int unit, int opmode, int flags, + const uint8_t bssid[IEEE80211_ADDR_LEN], + const uint8_t mac[IEEE80211_ADDR_LEN]); + +static void rt2860_vap_delete(struct ieee80211vap *vap); + +static int rt2860_vap_reset(struct ieee80211vap *vap, u_long cmd); + +static int rt2860_vap_newstate(struct ieee80211vap *vap, + enum ieee80211_state nstate, int arg); + +static void rt2860_vap_key_update_begin(struct ieee80211vap *vap); + +static void rt2860_vap_key_update_end(struct ieee80211vap *vap); + +static int rt2860_vap_key_set(struct ieee80211vap *vap, + const struct ieee80211_key *k, const uint8_t mac[IEEE80211_ADDR_LEN]); + +static int rt2860_vap_key_delete(struct ieee80211vap *vap, + const struct ieee80211_key *k); + +static void rt2860_vap_update_beacon(struct ieee80211vap *vap, int what); + +static int rt2860_media_change(struct ifnet *ifp); + +static struct ieee80211_node *rt2860_node_alloc(struct ieee80211vap *vap, + const uint8_t mac[IEEE80211_ADDR_LEN]); + +static void rt2860_node_cleanup(struct ieee80211_node *ni); + +static void rt2860_node_getmimoinfo(const struct ieee80211_node *ni, + struct ieee80211_mimo_info *mi); + +static int rt2860_setregdomain(struct ieee80211com *ic, + struct ieee80211_regdomain *reg, + int nchans, struct ieee80211_channel chans[]); + +static void rt2860_getradiocaps(struct ieee80211com *ic, + int maxchans, int *nchans, struct ieee80211_channel chans[]); + +static void rt2860_scan_start(struct ieee80211com *ic); + +static void rt2860_scan_end(struct ieee80211com *ic); + +static void rt2860_set_channel(struct ieee80211com *ic); + +static void rt2860_newassoc(struct ieee80211_node *ni, int isnew); + +static void rt2860_updateslot(struct ifnet *ifp); + +static void rt2860_update_promisc(struct ifnet *ifp); + +static void rt2860_update_mcast(struct ifnet *ifp); + +static int rt2860_wme_update(struct ieee80211com *ic); + +static int rt2860_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, + const struct ieee80211_bpf_params *params); + +static int rt2860_recv_action(struct ieee80211_node *ni, + const struct ieee80211_frame *wh, + const uint8_t *frm, const uint8_t *efrm); + +static int rt2860_send_action(struct ieee80211_node *ni, + int cat, int act, void *sa); + +static int rt2860_addba_response(struct ieee80211_node *ni, + struct ieee80211_tx_ampdu *tap, + int status, int baparamset, int batimeout); + +static void rt2860_addba_stop(struct ieee80211_node *ni, + struct ieee80211_tx_ampdu *tap); + +static int rt2860_ampdu_rx_start(struct ieee80211_node *ni, + struct ieee80211_rx_ampdu *rap, + int baparamset, int batimeout, int baseqctl); + +static void rt2860_ampdu_rx_stop(struct ieee80211_node *ni, + struct ieee80211_rx_ampdu *rap); + +static int rt2860_send_bar(struct ieee80211_node *ni, + struct ieee80211_tx_ampdu *tap, ieee80211_seq seqno); + +static void rt2860_amrr_update_iter_func(void *arg, struct ieee80211_node *ni); + +static void rt2860_periodic(void *arg); + +static void rt2860_tx_watchdog(void *arg); + +static int rt2860_staid_alloc(struct rt2860_softc *sc, int aid); + +static void rt2860_staid_delete(struct rt2860_softc *sc, int staid); + +static void rt2860_asic_set_bssid(struct rt2860_softc *sc, + const uint8_t *bssid); + +static void rt2860_asic_set_macaddr(struct rt2860_softc *sc, + const uint8_t *addr); + +static void rt2860_asic_enable_tsf_sync(struct rt2860_softc *sc); + +static void rt2860_asic_disable_tsf_sync(struct rt2860_softc *sc); + +static void rt2860_asic_enable_mrr(struct rt2860_softc *sc); + +static void rt2860_asic_set_txpreamble(struct rt2860_softc *sc); + +static void rt2860_asic_set_basicrates(struct rt2860_softc *sc); + +static void rt2860_asic_update_rtsthreshold(struct rt2860_softc *sc); + +static void rt2860_asic_update_txpower(struct rt2860_softc *sc); + +static void rt2860_asic_update_promisc(struct rt2860_softc *sc); + +static void rt2860_asic_updateprot(struct rt2860_softc *sc); + +static void rt2860_asic_updateslot(struct rt2860_softc *sc); + +static void rt2860_asic_wme_update(struct rt2860_softc *sc); + +static void rt2860_asic_update_beacon(struct rt2860_softc *sc, + struct ieee80211vap *vap); + +static void rt2860_asic_clear_keytables(struct rt2860_softc *sc); + +static void rt2860_asic_add_ba_session(struct rt2860_softc *sc, + uint8_t wcid, int tid); + +static void rt2860_asic_del_ba_session(struct rt2860_softc *sc, + uint8_t wcid, int tid); + +static int rt2860_beacon_alloc(struct rt2860_softc *sc, + struct ieee80211vap *vap); + +static uint8_t rt2860_rxrate(struct rt2860_rxwi *rxwi); + +static uint8_t rt2860_maxrssi_rxpath(struct rt2860_softc *sc, + const struct rt2860_rxwi *rxwi); + +static int8_t rt2860_rssi2dbm(struct rt2860_softc *sc, + uint8_t rssi, uint8_t rxpath); + +static uint8_t rt2860_rate2mcs(uint8_t rate); + +static int rt2860_tx_mgmt(struct rt2860_softc *sc, + struct mbuf *m, struct ieee80211_node *ni, int qid); + +static int rt2860_tx_data(struct rt2860_softc *sc, + struct mbuf *m, struct ieee80211_node *ni, int qid); + +static int rt2860_tx_raw(struct rt2860_softc *sc, + struct mbuf *m, struct ieee80211_node *ni, + const struct ieee80211_bpf_params *params); + +static void rt2860_intr(void *arg); + +static void rt2860_tx_coherent_intr(struct rt2860_softc *sc); + +static void rt2860_rx_coherent_intr(struct rt2860_softc *sc); + +static void rt2860_txrx_coherent_intr(struct rt2860_softc *sc); + +static void rt2860_fifo_sta_full_intr(struct rt2860_softc *sc); + +static void rt2860_rx_intr(struct rt2860_softc *sc); + +static void rt2860_rx_delay_intr(struct rt2860_softc *sc); + +static void rt2860_tx_intr(struct rt2860_softc *sc, int qid); + +static void rt2860_tx_delay_intr(struct rt2860_softc *sc); + +static void rt2860_pre_tbtt_intr(struct rt2860_softc *sc); + +static void rt2860_tbtt_intr(struct rt2860_softc *sc); + +static void rt2860_mcu_cmd_intr(struct rt2860_softc *sc); + +static void rt2860_auto_wakeup_intr(struct rt2860_softc *sc); + +static void rt2860_gp_timer_intr(struct rt2860_softc *sc); + +static void rt2860_rx_done_task(void *context, int pending); + +static void rt2860_tx_done_task(void *context, int pending); + +static void rt2860_fifo_sta_full_task(void *context, int pending); + +static void rt2860_periodic_task(void *context, int pending); + +static int rt2860_rx_eof(struct rt2860_softc *sc, int limit); + +static void rt2860_tx_eof(struct rt2860_softc *sc, + struct rt2860_softc_tx_ring *ring); + +static void rt2860_update_stats(struct rt2860_softc *sc); + +static void rt2860_bbp_tuning(struct rt2860_softc *sc); + +static void rt2860_watchdog(struct rt2860_softc *sc); + +static void rt2860_drain_fifo_stats(struct rt2860_softc *sc); + +static void rt2860_update_raw_counters(struct rt2860_softc *sc); + +static void rt2860_intr_enable(struct rt2860_softc *sc, uint32_t intr_mask); + +static void rt2860_intr_disable(struct rt2860_softc *sc, uint32_t intr_mask); + +static int rt2860_txrx_enable(struct rt2860_softc *sc); + +static int rt2860_alloc_rx_ring(struct rt2860_softc *sc, + struct rt2860_softc_rx_ring *ring); + +static void rt2860_reset_rx_ring(struct rt2860_softc *sc, + struct rt2860_softc_rx_ring *ring); + +static void rt2860_free_rx_ring(struct rt2860_softc *sc, + struct rt2860_softc_rx_ring *ring); + +static int rt2860_alloc_tx_ring(struct rt2860_softc *sc, + struct rt2860_softc_tx_ring *ring, int qid); + +static void rt2860_reset_tx_ring(struct rt2860_softc *sc, + struct rt2860_softc_tx_ring *ring); + +static void rt2860_free_tx_ring(struct rt2860_softc *sc, + struct rt2860_softc_tx_ring *ring); + +static void rt2860_dma_map_addr(void *arg, bus_dma_segment_t *segs, + int nseg, int error); + +static void rt2860_sysctl_attach(struct rt2860_softc *sc); + +/* + * Static variables + */ + +static const struct rt2860_pci_ident rt2860_pci_ids[] = +{ + { PCI_VENDOR_RALINK, PCI_PRODUCT_RALINK_RT2860_PCI, "Ralink RT2860 PCI" }, + { PCI_VENDOR_RALINK, PCI_PRODUCT_RALINK_RT2860_PCIe, "Ralink RT2860 PCIe" }, + { PCI_VENDOR_RALINK, PCI_PRODUCT_RALINK_RT2760_PCI, "Ralink RT2760 PCI" }, + { PCI_VENDOR_RALINK, PCI_PRODUCT_RALINK_RT2790_PCIe, "Ralink RT2790 PCIe" }, + { 0, 0, NULL } +}; + +static const struct +{ + uint32_t reg; + uint32_t val; +} rt2860_def_mac[] = +{ + { RT2860_REG_PBF_BCN_OFFSET0, 0xf8f0e8e0 }, + { RT2860_REG_PBF_BCN_OFFSET1, 0x6f77d0c8 }, + { RT2860_REG_LEGACY_BASIC_RATE, 0x0000013f }, + { RT2860_REG_HT_BASIC_RATE, 0x00008003 }, + { RT2860_REG_SYS_CTRL, 0x00000000 }, + { RT2860_REG_RX_FILTER_CFG, 0x00017f97 }, + { RT2860_REG_BKOFF_SLOT_CFG, 0x00000209 }, + { RT2860_REG_TX_SW_CFG0, 0x00000000 }, + { RT2860_REG_TX_SW_CFG1, 0x00080606 }, + { RT2860_REG_TX_LINK_CFG, 0x00001020 }, + { RT2860_REG_TX_TIMEOUT_CFG, 0x000a2090 }, + { RT2860_REG_MAX_LEN_CFG, (1 << 12) | RT2860_MAX_AGG_SIZE }, + { RT2860_REG_LED_CFG, 0x7f031e46 }, + { RT2860_REG_PBF_MAX_PCNT, 0x1f3fbf9f }, + { RT2860_REG_TX_RTY_CFG, 0x47d01f0f }, + { RT2860_REG_AUTO_RSP_CFG, 0x00000013 }, + { RT2860_REG_TX_CCK_PROT_CFG, 0x05740003 }, + { RT2860_REG_TX_OFDM_PROT_CFG, 0x05740003 }, + { RT2860_REG_TX_GF20_PROT_CFG, 0x01744004 }, + { RT2860_REG_TX_GF40_PROT_CFG, 0x03f44084 }, + { RT2860_REG_TX_MM20_PROT_CFG, 0x01744004 }, + { RT2860_REG_TX_MM40_PROT_CFG, 0x03f54084 }, + { RT2860_REG_TX_TXOP_CTRL_CFG, 0x0000583f }, + { RT2860_REG_TX_RTS_CFG, 0x00092b20 }, + { RT2860_REG_TX_EXP_ACK_TIME, 0x002400ca }, + { RT2860_REG_HCCAPSMP_TXOP_HLDR_ET, 0x00000002 }, + { RT2860_REG_XIFS_TIME_CFG, 0x33a41010 }, + { RT2860_REG_PWR_PIN_CFG, 0x00000003 }, + { RT2860_REG_SCHDMA_WMM_AIFSN_CFG, 0x00002273 }, + { RT2860_REG_SCHDMA_WMM_CWMIN_CFG, 0x00002344 }, + { RT2860_REG_SCHDMA_WMM_CWMAX_CFG, 0x000034aa }, +}; + +#define RT2860_DEF_MAC_SIZE (sizeof(rt2860_def_mac) / sizeof(rt2860_def_mac[0])) + +static const struct +{ + uint8_t reg; + uint8_t val; +} rt2860_def_bbp[] = +{ + { 65, 0x2c }, + { 66, 0x38 }, + { 69, 0x12 }, + { 70, 0x0a }, + { 73, 0x10 }, + { 81, 0x37 }, + { 82, 0x62 }, + { 83, 0x6a }, + { 84, 0x99 }, + { 86, 0x00 }, + { 91, 0x04 }, + { 92, 0x00 }, + { 103, 0x00 }, + { 105, 0x05 }, + { 106, 0x35 }, +}; + +#define RT2860_DEF_BBP_SIZE (sizeof(rt2860_def_bbp) / sizeof(rt2860_def_bbp[0])) + +SYSCTL_NODE(_hw, OID_AUTO, rt2860, CTLFLAG_RD, 0, "RT2860 driver parameters"); + +static int rt2860_tx_stbc = 1; +SYSCTL_INT(_hw_rt2860, OID_AUTO, tx_stbc, CTLFLAG_RW, &rt2860_tx_stbc, 0, "RT2860 Tx STBC"); +TUNABLE_INT("hw.rt2860.tx_stbc", &rt2860_tx_stbc); + +#ifdef RT2860_DEBUG +static int rt2860_debug = 0; +SYSCTL_INT(_hw_rt2860, OID_AUTO, debug, CTLFLAG_RW, &rt2860_debug, 0, "RT2860 debug level"); +TUNABLE_INT("hw.rt2860.debug", &rt2860_debug); +#endif + +/* + * rt2860_probe + */ +static int rt2860_probe(device_t dev) +{ + const struct rt2860_pci_ident *ident; + + for (ident = rt2860_pci_ids; ident->name != NULL; ident++) + { + if (pci_get_vendor(dev) == ident->vendor && + pci_get_device(dev) == ident->device) + { + device_set_desc(dev, ident->name); + return 0; + } + } + + return ENXIO; +} + +/* + * rt2860_attach + */ +static int rt2860_attach(device_t dev) +{ + struct rt2860_softc *sc; + struct ifnet *ifp; + struct ieee80211com *ic; + int error, ntries, i; + + sc = device_get_softc(dev); + + if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) + { + printf("%s: chip is in D%d power mode, setting to D0\n", + device_get_nameunit(dev), pci_get_powerstate(dev)); + pci_set_powerstate(dev, PCI_POWERSTATE_D0); + } + + /* enable bus-mastering */ + + pci_enable_busmaster(dev); + + sc->dev = dev; + + mtx_init(&sc->lock, device_get_nameunit(dev), + MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); + + sc->mem_rid = PCIR_BAR(0); + sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->mem_rid, RF_ACTIVE); + if (sc->mem == NULL) + { + printf("%s: could not allocate memory resource\n", + device_get_nameunit(dev)); + error = ENXIO; + goto fail; + } + + sc->bst = rman_get_bustag(sc->mem); + sc->bsh = rman_get_bushandle(sc->mem); + + sc->irq_rid = 0; + sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &sc->irq_rid, RF_ACTIVE | RF_SHAREABLE); + if (sc->irq == NULL) + { + printf("%s: could not allocate interrupt resource\n", + device_get_nameunit(dev)); + error = ENXIO; + goto fail; + } + + sc->tx_stbc = rt2860_tx_stbc; + +#ifdef RT2860_DEBUG + sc->debug = rt2860_debug; + + SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, + "debug", CTLFLAG_RW, &sc->debug, 0, "rt2860 debug level"); +#endif + + RT2860_DPRINTF(sc, RT2860_DEBUG_ANY, + "%s: attaching\n", + device_get_nameunit(sc->dev)); + + /* wait for NIC to initialize */ + + for (ntries = 0; ntries < 100; ntries++) + { + sc->mac_rev = rt2860_io_mac_read(sc, RT2860_REG_MAC_CSR0); + if (sc->mac_rev != 0x00000000 && sc->mac_rev != 0xffffffff) + break; + + DELAY(10); + } + + if (ntries == 100) + { + printf("%s: timeout waiting for NIC to initialize\n", + device_get_nameunit(dev)); + error = EIO; + goto fail; + } + + rt2860_read_eeprom(sc); + + printf("%s: MAC/BBP RT2860 (rev 0x%08x), RF %s\n", + device_get_nameunit(sc->dev), sc->mac_rev, + rt2860_rf_name(sc->rf_rev)); + + /* clear key tables */ + + rt2860_asic_clear_keytables(sc); + + /* allocate Tx and Rx rings */ + + for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++) + { + error = rt2860_alloc_tx_ring(sc, &sc->tx_ring[i], i); + if (error != 0) + { + printf("%s: could not allocate Tx ring #%d\n", + device_get_nameunit(sc->dev), i); + goto fail; + } + } + + sc->tx_ring_mgtqid = 5; + + error = rt2860_alloc_rx_ring(sc, &sc->rx_ring); + if (error != 0) + { + printf("%s: could not allocate Rx ring\n", + device_get_nameunit(sc->dev)); + goto fail; + } + + callout_init(&sc->periodic_ch, 0); + callout_init_mtx(&sc->tx_watchdog_ch, &sc->lock, 0); + + ifp = sc->ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) + { + printf("%s: could not if_alloc()\n", + device_get_nameunit(sc->dev)); + error = ENOMEM; + goto fail; + } + + ifp->if_softc = sc; + + if_initname(ifp, "rt2860", device_get_unit(sc->dev)); + + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + + ifp->if_init = rt2860_init; + ifp->if_ioctl = rt2860_ioctl; + ifp->if_start = rt2860_start; + + IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); + ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; + IFQ_SET_READY(&ifp->if_snd); + + ic = ifp->if_l2com; + + ic->ic_ifp = ifp; + + ic->ic_phytype = IEEE80211_T_HT; + ic->ic_opmode = IEEE80211_M_STA; + + ic->ic_caps = IEEE80211_C_MONITOR | + IEEE80211_C_IBSS | + IEEE80211_C_STA | + IEEE80211_C_AHDEMO | + IEEE80211_C_HOSTAP | + IEEE80211_C_WDS | + IEEE80211_C_MBSS | + IEEE80211_C_BGSCAN | + IEEE80211_C_TXPMGT | + IEEE80211_C_SHPREAMBLE | + IEEE80211_C_SHSLOT | + IEEE80211_C_TXFRAG | + IEEE80211_C_BURST | + IEEE80211_C_WME | + IEEE80211_C_WPA; + + ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP | + IEEE80211_CRYPTO_TKIP | + IEEE80211_CRYPTO_TKIPMIC | + IEEE80211_CRYPTO_AES_CCM; + + ic->ic_htcaps = IEEE80211_HTC_HT | + IEEE80211_HTC_AMSDU | /* A-MSDU Tx */ + IEEE80211_HTC_AMPDU | /* A-MPDU Tx */ + IEEE80211_HTC_SMPS | /* MIMO power save */ + IEEE80211_HTCAP_MAXAMSDU_3839 | /* max. A-MSDU Rx length */ + IEEE80211_HTCAP_CHWIDTH40 | /* HT 40MHz channel width */ + IEEE80211_HTCAP_GREENFIELD | /* HT greenfield */ + IEEE80211_HTCAP_SHORTGI20 | /* HT 20MHz short GI */ + IEEE80211_HTCAP_SHORTGI40 | /* HT 40MHz short GI */ + IEEE80211_HTCAP_SMPS_OFF; /* MIMO power save disabled */ + + /* spatial streams */ + + if (sc->nrxpath == 2) + ic->ic_htcaps |= IEEE80211_HTCAP_RXSTBC_2STREAM; + else if (sc->nrxpath == 3) + ic->ic_htcaps |= IEEE80211_HTCAP_RXSTBC_3STREAM; + else + ic->ic_htcaps |= IEEE80211_HTCAP_RXSTBC_1STREAM; + + if (sc->ntxpath > 1) + ic->ic_htcaps |= IEEE80211_HTCAP_TXSTBC; + + /* delayed BA */ + + if (sc->mac_rev != 0x28600100) + ic->ic_htcaps |= IEEE80211_HTCAP_DELBA; + + /* init channels */ + + ic->ic_nchans = 0; + + rt2860_init_channels(sc); + + rt2860_init_channels_ht40(sc); + + ieee80211_ifattach(ic, sc->mac_addr); + + ic->ic_vap_create = rt2860_vap_create; + ic->ic_vap_delete = rt2860_vap_delete; + + ic->ic_node_alloc = rt2860_node_alloc; + + sc->node_cleanup = ic->ic_node_cleanup; + ic->ic_node_cleanup = rt2860_node_cleanup; + + ic->ic_node_getmimoinfo = rt2860_node_getmimoinfo; + ic->ic_setregdomain = rt2860_setregdomain; + ic->ic_getradiocaps = rt2860_getradiocaps; + ic->ic_scan_start = rt2860_scan_start; + ic->ic_scan_end = rt2860_scan_end; + ic->ic_set_channel = rt2860_set_channel; + ic->ic_newassoc = rt2860_newassoc; + ic->ic_updateslot = rt2860_updateslot; + ic->ic_update_promisc = rt2860_update_promisc; + ic->ic_update_mcast = rt2860_update_mcast; + ic->ic_wme.wme_update = rt2860_wme_update; + ic->ic_raw_xmit = rt2860_raw_xmit; + + sc->recv_action = ic->ic_recv_action; + ic->ic_recv_action = rt2860_recv_action; + + sc->send_action = ic->ic_send_action; + ic->ic_send_action = rt2860_send_action; + + sc->addba_response = ic->ic_addba_response; + ic->ic_addba_response = rt2860_addba_response; + + sc->addba_stop = ic->ic_addba_stop; + ic->ic_addba_stop = rt2860_addba_stop; + + sc->ampdu_rx_start = ic->ic_ampdu_rx_start; + ic->ic_ampdu_rx_start = rt2860_ampdu_rx_start; + + sc->ampdu_rx_stop = ic->ic_ampdu_rx_stop; + ic->ic_ampdu_rx_stop = rt2860_ampdu_rx_stop; + + /* hardware requires padding between 802.11 frame header and body */ + + ic->ic_flags |= IEEE80211_F_DATAPAD | IEEE80211_F_DOTH; + + ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; + + ieee80211_radiotap_attach(ic, + &sc->txtap.ihdr, sizeof(sc->txtap), + RT2860_SOFTC_TX_RADIOTAP_PRESENT, + &sc->rxtap.ihdr, sizeof(sc->rxtap), + RT2860_SOFTC_RX_RADIOTAP_PRESENT); + + /* init task queue */ + + TASK_INIT(&sc->rx_done_task, 0, rt2860_rx_done_task, sc); + TASK_INIT(&sc->tx_done_task, 0, rt2860_tx_done_task, sc); + TASK_INIT(&sc->fifo_sta_full_task, 0, rt2860_fifo_sta_full_task, sc); + TASK_INIT(&sc->periodic_task, 0, rt2860_periodic_task, sc); + + sc->rx_process_limit = 100; + + sc->taskqueue = taskqueue_create("rt2860_taskq", M_NOWAIT, + taskqueue_thread_enqueue, &sc->taskqueue); + + taskqueue_start_threads(&sc->taskqueue, 1, PI_NET, "%s taskq", + device_get_nameunit(sc->dev)); + + rt2860_sysctl_attach(sc); + + if (bootverbose) + ieee80211_announce(ic); + + /* set up interrupt */ + + error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE, + NULL, rt2860_intr, sc, &sc->irqh); + if (error != 0) + { + printf("%s: could not set up interrupt\n", + device_get_nameunit(dev)); + goto fail; + } + + return 0; + +fail: + + /* free Tx and Rx rings */ + + for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++) + rt2860_free_tx_ring(sc, &sc->tx_ring[i]); + + rt2860_free_rx_ring(sc, &sc->rx_ring); + + mtx_destroy(&sc->lock); + + if (sc->mem != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem); + + if (sc->irq != NULL) + bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); + + return error; +} + +/* + * rt2860_detach + */ +static int rt2860_detach(device_t dev) +{ + struct rt2860_softc *sc; + struct ifnet *ifp; + struct ieee80211com *ic; + int i; + + sc = device_get_softc(dev); + ifp = sc->ifp; + ic = ifp->if_l2com; + + RT2860_DPRINTF(sc, RT2860_DEBUG_ANY, + "%s: detaching\n", + device_get_nameunit(sc->dev)); + + RT2860_SOFTC_LOCK(sc); + + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + + callout_stop(&sc->periodic_ch); + callout_stop(&sc->tx_watchdog_ch); + + taskqueue_drain(sc->taskqueue, &sc->rx_done_task); + taskqueue_drain(sc->taskqueue, &sc->tx_done_task); + taskqueue_drain(sc->taskqueue, &sc->fifo_sta_full_task); + taskqueue_drain(sc->taskqueue, &sc->periodic_task); + + /* free Tx and Rx rings */ + + for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++) + rt2860_free_tx_ring(sc, &sc->tx_ring[i]); + + rt2860_free_rx_ring(sc, &sc->rx_ring); + + RT2860_SOFTC_UNLOCK(sc); + + ieee80211_ifdetach(ic); + + if_free(ifp); + + taskqueue_free(sc->taskqueue); + + mtx_destroy(&sc->lock); + + bus_generic_detach(dev); + + bus_teardown_intr(dev, sc->irq, sc->irqh); + + bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); + + bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem); + + return 0; +} + +/* + * rt2860_shutdown + */ +static int rt2860_shutdown(device_t dev) +{ + struct rt2860_softc *sc; + + sc = device_get_softc(dev); + + RT2860_DPRINTF(sc, RT2860_DEBUG_ANY, + "%s: shutting down\n", + device_get_nameunit(sc->dev)); + + rt2860_stop(sc); + + sc->flags &= ~RT2860_SOFTC_FLAGS_UCODE_LOADED; + + return 0; +} + +/* + * rt2860_suspend + */ +static int rt2860_suspend(device_t dev) +{ + struct rt2860_softc *sc; + + sc = device_get_softc(dev); + + RT2860_DPRINTF(sc, RT2860_DEBUG_ANY, + "%s: suspending\n", + device_get_nameunit(sc->dev)); + + rt2860_stop(sc); + + sc->flags &= ~RT2860_SOFTC_FLAGS_UCODE_LOADED; + + return 0; +} + +/* + * rt2860_resume + */ +static int rt2860_resume(device_t dev) +{ + struct rt2860_softc *sc; + struct ifnet *ifp; + + sc = device_get_softc(dev); + ifp = sc->ifp; + + RT2860_DPRINTF(sc, RT2860_DEBUG_ANY, + "%s: resuming\n", + device_get_nameunit(sc->dev)); + + if (ifp->if_flags & IFF_UP) + rt2860_init(sc); + + return 0; +} + +/* + * rt2860_init_channels + */ +static void rt2860_init_channels(struct rt2860_softc *sc) +{ + struct ifnet *ifp; + struct ieee80211com *ic; + struct ieee80211_channel *c; + int i, flags; + + ifp = sc->ifp; + ic = ifp->if_l2com; + + /* set supported channels for 2GHz band */ + + for (i = 1; i <= 14; i++) + { + c = &ic->ic_channels[ic->ic_nchans++]; + flags = IEEE80211_CHAN_B; + + c->ic_freq = ieee80211_ieee2mhz(i, flags); + c->ic_ieee = i; + c->ic_flags = flags; + + c = &ic->ic_channels[ic->ic_nchans++]; + flags = IEEE80211_CHAN_B | IEEE80211_CHAN_HT20; + + c->ic_freq = ieee80211_ieee2mhz(i, flags); + c->ic_ieee = i; + c->ic_flags = flags; + + c = &ic->ic_channels[ic->ic_nchans++]; + flags = IEEE80211_CHAN_G; + + c->ic_freq = ieee80211_ieee2mhz(i, flags); + c->ic_ieee = i; + c->ic_flags = flags; + + c = &ic->ic_channels[ic->ic_nchans++]; + flags = IEEE80211_CHAN_G | IEEE80211_CHAN_HT20; + + c->ic_freq = ieee80211_ieee2mhz(i, flags); + c->ic_ieee = i; + c->ic_flags = flags; + } + + /* set supported channels for 5GHz band */ + + if (sc->rf_rev == RT2860_EEPROM_RF_2850 || + sc->rf_rev == RT2860_EEPROM_RF_2750) + { + for (i = 36; i <= 64; i += 4) + { + c = &ic->ic_channels[ic->ic_nchans++]; + flags = IEEE80211_CHAN_A; + + c->ic_freq = ieee80211_ieee2mhz(i, flags); + c->ic_ieee = i; + c->ic_flags = flags; + + c = &ic->ic_channels[ic->ic_nchans++]; + flags = IEEE80211_CHAN_A | IEEE80211_CHAN_HT20; + + c->ic_freq = ieee80211_ieee2mhz(i, flags); + c->ic_ieee = i; + c->ic_flags = flags; + } + + for (i = 100; i <= 140; i += 4) + { + c = &ic->ic_channels[ic->ic_nchans++]; + flags = IEEE80211_CHAN_A; + + c->ic_freq = ieee80211_ieee2mhz(i, flags); + c->ic_ieee = i; + c->ic_flags = flags; + + c = &ic->ic_channels[ic->ic_nchans++]; + flags = IEEE80211_CHAN_A | IEEE80211_CHAN_HT20; + + c->ic_freq = ieee80211_ieee2mhz(i, flags); + c->ic_ieee = i; + c->ic_flags = flags; + } + + for (i = 149; i <= 165; i += 4) + { [... truncated: 10075 lines follow ...]