svn commit: r235233 - in head/sys: conf dev/ral modules/ral

Bernhard Schmidt bschmidt at FreeBSD.org
Thu May 10 17:41:17 UTC 2012


Author: bschmidt
Date: Thu May 10 17:41:16 2012
New Revision: 235233
URL: http://svn.freebsd.org/changeset/base/235233

Log:
  Add support for Ralink RT2800/RT3000 chipsets.
  
  Thanks to ray@, Sevan and Sergey Dyatko for feedback and testing!
  
  Obtained from:	OpenBSD
  MFC after:	3 weeks

Added:
  head/sys/dev/ral/rt2860.c   (contents, props changed)
  head/sys/dev/ral/rt2860reg.h   (contents, props changed)
  head/sys/dev/ral/rt2860var.h   (contents, props changed)
Modified:
  head/sys/conf/files
  head/sys/dev/ral/if_ral_pci.c
  head/sys/modules/ral/Makefile

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Thu May 10 15:23:20 2012	(r235232)
+++ head/sys/conf/files	Thu May 10 17:41:16 2012	(r235233)
@@ -1759,6 +1759,7 @@ dev/puc/pucdata.c		optional puc pci
 dev/quicc/quicc_core.c		optional quicc
 dev/ral/rt2560.c		optional ral
 dev/ral/rt2661.c		optional ral
+dev/ral/rt2860.c		optional ral
 dev/ral/if_ral_pci.c		optional ral pci
 rt2561fw.c			optional rt2561fw | ralfw		\
 	compile-with	"${AWK} -f $S/tools/fw_stub.awk rt2561.fw:rt2561fw -mrt2561 -c${.TARGET}" \

Modified: head/sys/dev/ral/if_ral_pci.c
==============================================================================
--- head/sys/dev/ral/if_ral_pci.c	Thu May 10 15:23:20 2012	(r235232)
+++ head/sys/dev/ral/if_ral_pci.c	Thu May 10 17:41:16 2012	(r235233)
@@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$");
 
 #include <dev/ral/rt2560var.h>
 #include <dev/ral/rt2661var.h>
+#include <dev/ral/rt2860var.h>
 
 MODULE_DEPEND(ral, pci, 1, 1, 1);
 MODULE_DEPEND(ral, firmware, 1, 1, 1);
@@ -70,11 +71,37 @@ struct ral_pci_ident {
 };
 
 static const struct ral_pci_ident ral_pci_ids[] = {
+	{ 0x1432, 0x7708, "Edimax RT2860" },
+	{ 0x1432, 0x7711, "Edimax RT3591" },
+	{ 0x1432, 0x7722, "Edimax RT3591" },
+	{ 0x1432, 0x7727, "Edimax RT2860" },
+	{ 0x1432, 0x7728, "Edimax RT2860" },
+	{ 0x1432, 0x7738, "Edimax RT2860" },
+	{ 0x1432, 0x7748, "Edimax RT2860" },
+	{ 0x1432, 0x7758, "Edimax RT2860" },
+	{ 0x1432, 0x7768, "Edimax RT2860" },
+	{ 0x1462, 0x891a, "MSI RT3090" },
 	{ 0x1814, 0x0201, "Ralink Technology RT2560" },
 	{ 0x1814, 0x0301, "Ralink Technology RT2561S" },
 	{ 0x1814, 0x0302, "Ralink Technology RT2561" },
 	{ 0x1814, 0x0401, "Ralink Technology RT2661" },
-
+	{ 0x1814, 0x0601, "Ralink Technology RT2860" },
+	{ 0x1814, 0x0681, "Ralink Technology RT2890" },
+	{ 0x1814, 0x0701, "Ralink Technology RT2760" },
+	{ 0x1814, 0x0781, "Ralink Technology RT2790" },
+	{ 0x1814, 0x3060, "Ralink Technology RT3060" },
+	{ 0x1814, 0x3062, "Ralink Technology RT3062" },
+	{ 0x1814, 0x3090, "Ralink Technology RT3090" },
+	{ 0x1814, 0x3091, "Ralink Technology RT3091" },
+	{ 0x1814, 0x3092, "Ralink Technology RT3092" },
+	{ 0x1814, 0x3390, "Ralink Technology RT3390" },
+	{ 0x1814, 0x3562, "Ralink Technology RT3562" },
+	{ 0x1814, 0x3592, "Ralink Technology RT3592" },
+	{ 0x1814, 0x3593, "Ralink Technology RT3593" },
+	{ 0x1814, 0x5390, "Ralink Technology RT5390" },
+	{ 0x1814, 0x539a, "Ralink Technology RT5390" },
+	{ 0x1814, 0x539f, "Ralink Technology RT5390" },
+	{ 0x1a3b, 0x1059, "AWT RT2890" },
 	{ 0, 0, NULL }
 };
 
@@ -101,12 +128,20 @@ static struct ral_opns {
 	rt2661_suspend,
 	rt2661_resume,
 	rt2661_intr
+}, ral_rt2860_opns = {
+	rt2860_attach,
+	rt2860_detach,
+	rt2860_shutdown,
+	rt2860_suspend,
+	rt2860_resume,
+	rt2860_intr
 };
 
 struct ral_pci_softc {
 	union {
 		struct rt2560_softc sc_rt2560;
 		struct rt2661_softc sc_rt2661;
+		struct rt2860_softc sc_rt2860;
 	} u;
 
 	struct ral_opns		*sc_opns;
@@ -180,8 +215,19 @@ ral_pci_attach(device_t dev)
 	/* enable bus-mastering */
 	pci_enable_busmaster(dev);
 
-	psc->sc_opns = (pci_get_device(dev) == 0x0201) ? &ral_rt2560_opns :
-	    &ral_rt2661_opns;
+	switch (pci_get_device(dev)) {
+	case 0x0201:
+		psc->sc_opns = &ral_rt2560_opns;
+		break;
+	case 0x0301:
+	case 0x0302:
+	case 0x0401:
+		psc->sc_opns = &ral_rt2661_opns;
+		break;
+	default:
+		psc->sc_opns = &ral_rt2860_opns;
+		break;
+	}
 
 	psc->mem_rid = RAL_PCI_BAR0;
 	psc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &psc->mem_rid,

Added: head/sys/dev/ral/rt2860.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/ral/rt2860.c	Thu May 10 17:41:16 2012	(r235233)
@@ -0,0 +1,4103 @@
+/*-
+ * Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini at free.fr>
+ * Copyright (c) 2012 Bernhard Schmidt <bschmidt at FreeBSD.org>
+ *
+ * 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.
+ *
+ * $OpenBSD: rt2860.c,v 1.65 2010/10/23 14:24:54 damien Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*-
+ * Ralink Technology RT2860/RT3090/RT3390/RT3562 chipset driver
+ * http://www.ralinktech.com/
+ */
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/firmware.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_regdomain.h>
+#include <net80211/ieee80211_ratectl.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+
+#include <dev/ral/rt2860reg.h>
+#include <dev/ral/rt2860var.h>
+
+#define RAL_DEBUG
+#ifdef RAL_DEBUG
+#define DPRINTF(x)	do { if (sc->sc_debug > 0) printf x; } while (0)
+#define DPRINTFN(n, x)	do { if (sc->sc_debug >= (n)) printf x; } while (0)
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n, x)
+#endif
+
+static struct ieee80211vap *rt2860_vap_create(struct ieee80211com *,
+			    const char [IFNAMSIZ], int, enum ieee80211_opmode,
+			    int, const uint8_t [IEEE80211_ADDR_LEN],
+			    const uint8_t [IEEE80211_ADDR_LEN]);
+static void	rt2860_vap_delete(struct ieee80211vap *);
+static void	rt2860_dma_map_addr(void *, bus_dma_segment_t *, int, int);
+static int	rt2860_alloc_tx_ring(struct rt2860_softc *,
+		    struct rt2860_tx_ring *);
+static void	rt2860_reset_tx_ring(struct rt2860_softc *,
+		    struct rt2860_tx_ring *);
+static void	rt2860_free_tx_ring(struct rt2860_softc *,
+		    struct rt2860_tx_ring *);
+static int	rt2860_alloc_tx_pool(struct rt2860_softc *);
+static void	rt2860_free_tx_pool(struct rt2860_softc *);
+static int	rt2860_alloc_rx_ring(struct rt2860_softc *,
+		    struct rt2860_rx_ring *);
+static void	rt2860_reset_rx_ring(struct rt2860_softc *,
+		    struct rt2860_rx_ring *);
+static void	rt2860_free_rx_ring(struct rt2860_softc *,
+		    struct rt2860_rx_ring *);
+static void	rt2860_updatestats(struct rt2860_softc *);
+static void	rt2860_newassoc(struct ieee80211_node *, int);
+static void	rt2860_node_free(struct ieee80211_node *);
+#ifdef IEEE80211_HT
+static int	rt2860_ampdu_rx_start(struct ieee80211com *,
+		    struct ieee80211_node *, uint8_t);
+static void	rt2860_ampdu_rx_stop(struct ieee80211com *,
+		    struct ieee80211_node *, uint8_t);
+#endif
+static int	rt2860_newstate(struct ieee80211vap *, enum ieee80211_state,
+		    int);
+static uint16_t	rt3090_efuse_read_2(struct rt2860_softc *, uint16_t);
+static uint16_t	rt2860_eeprom_read_2(struct rt2860_softc *, uint16_t);
+static void	rt2860_intr_coherent(struct rt2860_softc *);
+static void	rt2860_drain_stats_fifo(struct rt2860_softc *);
+static void	rt2860_tx_intr(struct rt2860_softc *, int);
+static void	rt2860_rx_intr(struct rt2860_softc *);
+static void	rt2860_tbtt_intr(struct rt2860_softc *);
+static void	rt2860_gp_intr(struct rt2860_softc *);
+static int	rt2860_tx(struct rt2860_softc *, struct mbuf *,
+		    struct ieee80211_node *);
+static int	rt2860_raw_xmit(struct ieee80211_node *, struct mbuf *,
+		    const struct ieee80211_bpf_params *);
+static int	rt2860_tx_raw(struct rt2860_softc *, struct mbuf *,
+		    struct ieee80211_node *,
+		    const struct ieee80211_bpf_params *params);
+static void	rt2860_start(struct ifnet *);
+static void	rt2860_start_locked(struct ifnet *);
+static void	rt2860_watchdog(void *);
+static int	rt2860_ioctl(struct ifnet *, u_long, caddr_t);
+static void	rt2860_mcu_bbp_write(struct rt2860_softc *, uint8_t, uint8_t);
+static uint8_t	rt2860_mcu_bbp_read(struct rt2860_softc *, uint8_t);
+static void	rt2860_rf_write(struct rt2860_softc *, uint8_t, uint32_t);
+static uint8_t	rt3090_rf_read(struct rt2860_softc *, uint8_t);
+static void	rt3090_rf_write(struct rt2860_softc *, uint8_t, uint8_t);
+static int	rt2860_mcu_cmd(struct rt2860_softc *, uint8_t, uint16_t, int);
+static void	rt2860_enable_mrr(struct rt2860_softc *);
+static void	rt2860_set_txpreamble(struct rt2860_softc *);
+static void	rt2860_set_basicrates(struct rt2860_softc *,
+		    const struct ieee80211_rateset *);
+static void	rt2860_scan_start(struct ieee80211com *);
+static void	rt2860_scan_end(struct ieee80211com *);
+static void	rt2860_set_channel(struct ieee80211com *);
+static void	rt2860_select_chan_group(struct rt2860_softc *, int);
+static void	rt2860_set_chan(struct rt2860_softc *, u_int);
+static void	rt3090_set_chan(struct rt2860_softc *, u_int);
+static int	rt3090_rf_init(struct rt2860_softc *);
+static void	rt3090_rf_wakeup(struct rt2860_softc *);
+static int	rt3090_filter_calib(struct rt2860_softc *, uint8_t, uint8_t,
+		    uint8_t *);
+static void	rt3090_rf_setup(struct rt2860_softc *);
+static void	rt2860_set_leds(struct rt2860_softc *, uint16_t);
+static void	rt2860_set_gp_timer(struct rt2860_softc *, int);
+static void	rt2860_set_bssid(struct rt2860_softc *, const uint8_t *);
+static void	rt2860_set_macaddr(struct rt2860_softc *, const uint8_t *);
+static void	rt2860_update_promisc(struct ifnet *);
+static void	rt2860_updateslot(struct ifnet *);
+static void	rt2860_updateprot(struct ifnet *);
+static int	rt2860_updateedca(struct ieee80211com *);
+#ifdef HW_CRYPTO
+static int	rt2860_set_key(struct ieee80211com *, struct ieee80211_node *,
+		    struct ieee80211_key *);
+static void	rt2860_delete_key(struct ieee80211com *,
+		    struct ieee80211_node *, struct ieee80211_key *);
+#endif
+static int8_t	rt2860_rssi2dbm(struct rt2860_softc *, uint8_t, uint8_t);
+static const char *rt2860_get_rf(uint8_t);
+static int	rt2860_read_eeprom(struct rt2860_softc *,
+		    uint8_t macaddr[IEEE80211_ADDR_LEN]);
+static int	rt2860_bbp_init(struct rt2860_softc *);
+static int	rt2860_txrx_enable(struct rt2860_softc *);
+static void	rt2860_init(void *);
+static void	rt2860_init_locked(struct rt2860_softc *);
+static void	rt2860_stop(void *);
+static void	rt2860_stop_locked(struct rt2860_softc *);
+static int	rt2860_load_microcode(struct rt2860_softc *);
+#ifdef NOT_YET
+static void	rt2860_calib(struct rt2860_softc *);
+#endif
+static void	rt3090_set_rx_antenna(struct rt2860_softc *, int);
+static void	rt2860_switch_chan(struct rt2860_softc *,
+		    struct ieee80211_channel *);
+static int	rt2860_setup_beacon(struct rt2860_softc *,
+		    struct ieee80211vap *);
+static void	rt2860_enable_tsf_sync(struct rt2860_softc *);
+
+static const struct {
+	uint32_t	reg;
+	uint32_t	val;
+} rt2860_def_mac[] = {
+	RT2860_DEF_MAC
+};
+
+static const struct {
+	uint8_t	reg;
+	uint8_t	val;
+} rt2860_def_bbp[] = {
+	RT2860_DEF_BBP
+};
+
+static const struct rfprog {
+	uint8_t		chan;
+	uint32_t	r1, r2, r3, r4;
+} rt2860_rf2850[] = {
+	RT2860_RF2850
+};
+
+struct {
+	uint8_t	n, r, k;
+} rt3090_freqs[] = {
+	RT3070_RF3052
+};
+
+static const struct {
+	uint8_t	reg;
+	uint8_t	val;
+}  rt3090_def_rf[] = {
+	RT3070_DEF_RF
+};
+
+int
+rt2860_attach(device_t dev, int id)
+{
+	struct rt2860_softc *sc = device_get_softc(dev);
+	struct ieee80211com *ic;
+	struct ifnet *ifp;
+	uint32_t tmp;
+	int error, ntries, qid;
+	uint8_t bands;
+	uint8_t macaddr[IEEE80211_ADDR_LEN];
+
+	sc->sc_dev = dev;
+	sc->sc_debug = 0;
+
+	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
+	if (ifp == NULL) {
+		device_printf(sc->sc_dev, "can not if_alloc()\n");
+		return ENOMEM;
+	}
+	ic = ifp->if_l2com;
+
+	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+	    MTX_DEF | MTX_RECURSE);
+
+	callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0);
+
+	/* wait for NIC to initialize */
+	for (ntries = 0; ntries < 100; ntries++) {
+		tmp = RAL_READ(sc, RT2860_ASIC_VER_ID);
+		if (tmp != 0 && tmp != 0xffffffff)
+			break;
+		DELAY(10);
+	}
+	if (ntries == 100) {
+		device_printf(sc->sc_dev,
+		    "timeout waiting for NIC to initialize\n");
+		error = EIO;
+		goto fail1;
+	}
+	sc->mac_ver = tmp >> 16;
+	sc->mac_rev = tmp & 0xffff;
+
+	if (sc->mac_ver != 0x2860 &&
+	    (id == 0x0681 || id == 0x0781 || id == 0x1059))
+		sc->sc_flags |= RT2860_ADVANCED_PS;
+
+	/* retrieve RF rev. no and various other things from EEPROM */
+	rt2860_read_eeprom(sc, macaddr);
+	if (bootverbose) {
+		device_printf(sc->sc_dev, "MAC/BBP RT%X (rev 0x%04X), "
+		    "RF %s (MIMO %dT%dR), address %6D\n",
+		    sc->mac_ver, sc->mac_rev, rt2860_get_rf(sc->rf_rev),
+		    sc->ntxchains, sc->nrxchains, macaddr, ":");
+	}
+
+	/*
+	 * Allocate Tx (4 EDCAs + HCCA + Mgt) and Rx rings.
+	 */
+	for (qid = 0; qid < 6; qid++) {
+		if ((error = rt2860_alloc_tx_ring(sc, &sc->txq[qid])) != 0) {
+			device_printf(sc->sc_dev,
+			    "could not allocate Tx ring %d\n", qid);
+			goto fail2;
+		}
+	}
+
+	if ((error = rt2860_alloc_rx_ring(sc, &sc->rxq)) != 0) {
+		device_printf(sc->sc_dev, "could not allocate Rx ring\n");
+		goto fail2;
+	}
+
+	if ((error = rt2860_alloc_tx_pool(sc)) != 0) {
+		device_printf(sc->sc_dev, "could not allocate Tx pool\n");
+		goto fail3;
+	}
+
+	/* mgmt ring is broken on RT2860C, use EDCA AC VO ring instead */
+	sc->mgtqid = (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) ?
+	    WME_AC_VO : 5;
+
+	ifp->if_softc = sc;
+	if_initname(ifp, device_get_name(dev), device_get_unit(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, ifqmaxlen);
+	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
+	IFQ_SET_READY(&ifp->if_snd);
+
+	ic->ic_ifp = ifp;
+	ic->ic_opmode = IEEE80211_M_STA;
+	ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
+
+	/* set device capabilities */
+	ic->ic_caps =
+		  IEEE80211_C_STA		/* station mode */
+		| IEEE80211_C_IBSS		/* ibss, nee adhoc, mode */
+		| IEEE80211_C_HOSTAP		/* hostap mode */
+		| IEEE80211_C_MONITOR		/* monitor mode */
+		| IEEE80211_C_AHDEMO		/* adhoc demo mode */
+		| IEEE80211_C_WDS		/* 4-address traffic works */
+		| IEEE80211_C_MBSS		/* mesh point link mode */
+		| IEEE80211_C_SHPREAMBLE	/* short preamble supported */
+		| IEEE80211_C_SHSLOT		/* short slot time supported */
+		| IEEE80211_C_WPA		/* capable of WPA1+WPA2 */
+#if 0
+		| IEEE80211_C_BGSCAN		/* capable of bg scanning */
+#endif
+		| IEEE80211_C_WME		/* 802.11e */
+		;
+
+	bands = 0;
+	setbit(&bands, IEEE80211_MODE_11B);
+	setbit(&bands, IEEE80211_MODE_11G);
+	if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850)
+		setbit(&bands, IEEE80211_MODE_11A);
+	ieee80211_init_channels(ic, NULL, &bands);
+
+	ieee80211_ifattach(ic, macaddr);
+
+	ic->ic_wme.wme_update = rt2860_updateedca;
+	ic->ic_scan_start = rt2860_scan_start;
+	ic->ic_scan_end = rt2860_scan_end;
+	ic->ic_set_channel = rt2860_set_channel;
+	ic->ic_updateslot = rt2860_updateslot;
+	ic->ic_update_promisc = rt2860_update_promisc;
+	ic->ic_raw_xmit = rt2860_raw_xmit;
+	sc->sc_node_free = ic->ic_node_free;
+	ic->ic_node_free = rt2860_node_free;
+	ic->ic_newassoc = rt2860_newassoc;
+
+	ic->ic_vap_create = rt2860_vap_create;
+	ic->ic_vap_delete = rt2860_vap_delete;
+
+	ieee80211_radiotap_attach(ic,
+	    &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
+		RT2860_TX_RADIOTAP_PRESENT,
+	    &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
+		RT2860_RX_RADIOTAP_PRESENT);
+
+#ifdef RAL_DEBUG
+	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+	    "debug", CTLFLAG_RW, &sc->sc_debug, 0, "debug msgs");
+#endif
+	if (bootverbose)
+		ieee80211_announce(ic);
+
+	return 0;
+
+fail3:	rt2860_free_rx_ring(sc, &sc->rxq);
+fail2:	while (--qid >= 0)
+		rt2860_free_tx_ring(sc, &sc->txq[qid]);
+fail1:	mtx_destroy(&sc->sc_mtx);
+	if_free(ifp);
+	return error;
+}
+
+int
+rt2860_detach(void *xsc)
+{
+	struct rt2860_softc *sc = xsc;
+	struct ifnet *ifp =  sc->sc_ifp;
+	struct ieee80211com *ic = ifp->if_l2com;
+	int qid;
+
+	RAL_LOCK(sc);
+	rt2860_stop_locked(sc);
+	RAL_UNLOCK(sc);
+
+	ieee80211_ifdetach(ic);
+
+	for (qid = 0; qid < 6; qid++)
+		rt2860_free_tx_ring(sc, &sc->txq[qid]);
+	rt2860_free_rx_ring(sc, &sc->rxq);
+	rt2860_free_tx_pool(sc);
+
+	if_free(ifp);
+
+	mtx_destroy(&sc->sc_mtx);
+
+	return 0;
+}
+
+void
+rt2860_shutdown(void *xsc)
+{
+	struct rt2860_softc *sc = xsc;
+
+	rt2860_stop(sc);
+}
+
+void
+rt2860_suspend(void *xsc)
+{
+	struct rt2860_softc *sc = xsc;
+
+	rt2860_stop(sc);
+}
+
+void
+rt2860_resume(void *xsc)
+{
+	struct rt2860_softc *sc = xsc;
+	struct ifnet *ifp = sc->sc_ifp;
+
+	if (ifp->if_flags & IFF_UP)
+		rt2860_init(sc);
+}
+
+static struct ieee80211vap *
+rt2860_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
+    enum ieee80211_opmode opmode, int flags,
+    const uint8_t bssid[IEEE80211_ADDR_LEN],
+    const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+	struct ifnet *ifp = ic->ic_ifp;
+	struct rt2860_vap *rvp;
+	struct ieee80211vap *vap;
+
+	switch (opmode) {
+	case IEEE80211_M_STA:
+	case IEEE80211_M_IBSS:
+	case IEEE80211_M_AHDEMO:
+	case IEEE80211_M_MONITOR:
+	case IEEE80211_M_HOSTAP:
+	case IEEE80211_M_MBSS:
+		/* XXXRP: TBD */
+		if (!TAILQ_EMPTY(&ic->ic_vaps)) {
+			if_printf(ifp, "only 1 vap supported\n");
+			return NULL;
+		}
+		if (opmode == IEEE80211_M_STA)
+			flags |= IEEE80211_CLONE_NOBEACONS;
+		break;
+	case IEEE80211_M_WDS:
+		if (TAILQ_EMPTY(&ic->ic_vaps) ||
+		    ic->ic_opmode != IEEE80211_M_HOSTAP) {
+			if_printf(ifp, "wds only supported in ap mode\n");
+			return NULL;
+		}
+		/*
+		 * Silently remove any request for a unique
+		 * bssid; WDS vap's always share the local
+		 * mac address.
+		 */
+		flags &= ~IEEE80211_CLONE_BSSID;
+		break;
+	default:
+		if_printf(ifp, "unknown opmode %d\n", opmode);
+		return NULL;
+	}
+	rvp = malloc(sizeof(struct rt2860_vap), M_80211_VAP, M_NOWAIT | M_ZERO);
+	if (rvp == NULL)
+		return NULL;
+	vap = &rvp->ral_vap;
+	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
+
+	/* override state transition machine */
+	rvp->ral_newstate = vap->iv_newstate;
+	vap->iv_newstate = rt2860_newstate;
+#if 0
+	vap->iv_update_beacon = rt2860_beacon_update;
+#endif
+
+	/* HW supports up to 255 STAs (0-254) in HostAP and IBSS modes */
+	vap->iv_max_aid = min(IEEE80211_AID_MAX, RT2860_WCID_MAX);
+
+	ieee80211_ratectl_init(vap);
+	/* complete setup */
+	ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status);
+	if (TAILQ_FIRST(&ic->ic_vaps) == vap)
+		ic->ic_opmode = opmode;
+	return vap;
+}
+
+static void
+rt2860_vap_delete(struct ieee80211vap *vap)
+{
+	struct rt2860_vap *rvp = RT2860_VAP(vap);
+
+	ieee80211_ratectl_deinit(vap);
+	ieee80211_vap_detach(vap);
+	free(rvp, M_80211_VAP);
+}
+
+static void
+rt2860_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+	if (error != 0)
+		return;
+
+	KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
+
+	*(bus_addr_t *)arg = segs[0].ds_addr;
+}
+
+
+static int
+rt2860_alloc_tx_ring(struct rt2860_softc *sc, struct rt2860_tx_ring *ring)
+{
+	int size, error;
+
+	size = RT2860_TX_RING_COUNT * sizeof (struct rt2860_txd);
+
+	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 16, 0,
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    size, 1, size, 0, NULL, NULL, &ring->desc_dmat);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not create desc DMA map\n");
+		goto fail;
+	}
+
+	error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->txd,
+	    BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not allocate DMA memory\n");
+		goto fail;
+	}
+
+	error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->txd,
+	    size, rt2860_dma_map_addr, &ring->paddr, 0);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not load desc DMA map\n");
+		goto fail;
+	}
+
+	bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE);
+
+	return 0;
+
+fail:	rt2860_free_tx_ring(sc, ring);
+	return error;
+}
+
+void
+rt2860_reset_tx_ring(struct rt2860_softc *sc, struct rt2860_tx_ring *ring)
+{
+	struct rt2860_tx_data *data;
+	int i;
+
+	for (i = 0; i < RT2860_TX_RING_COUNT; i++) {
+		if ((data = ring->data[i]) == NULL)
+			continue;	/* nothing mapped in this slot */
+
+		if (data->m != NULL) {
+			bus_dmamap_sync(sc->txwi_dmat, data->map,
+			    BUS_DMASYNC_POSTWRITE);
+			bus_dmamap_unload(sc->txwi_dmat, data->map);
+			m_freem(data->m);
+			data->m = NULL;
+		}
+		if (data->ni != NULL) {
+			ieee80211_free_node(data->ni);
+			data->ni = NULL;
+		}
+
+		SLIST_INSERT_HEAD(&sc->data_pool, data, next);
+		ring->data[i] = NULL;
+	}
+
+	ring->queued = 0;
+	ring->cur = ring->next = 0;
+}
+
+void
+rt2860_free_tx_ring(struct rt2860_softc *sc, struct rt2860_tx_ring *ring)
+{
+	struct rt2860_tx_data *data;
+	int i;
+
+	if (ring->txd != NULL) {
+		bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
+		    BUS_DMASYNC_POSTWRITE);
+		bus_dmamap_unload(ring->desc_dmat, ring->desc_map);
+		bus_dmamem_free(ring->desc_dmat, ring->txd, ring->desc_map);
+	}
+	if (ring->desc_dmat != NULL)
+		bus_dma_tag_destroy(ring->desc_dmat);
+
+	for (i = 0; i < RT2860_TX_RING_COUNT; i++) {
+		if ((data = ring->data[i]) == NULL)
+			continue;	/* nothing mapped in this slot */
+
+		if (data->m != NULL) {
+			bus_dmamap_sync(sc->txwi_dmat, data->map,
+			    BUS_DMASYNC_POSTWRITE);
+			bus_dmamap_unload(sc->txwi_dmat, data->map);
+			m_freem(data->m);
+		}
+		if (data->ni != NULL)
+			ieee80211_free_node(data->ni);
+
+		SLIST_INSERT_HEAD(&sc->data_pool, data, next);
+	}
+}
+
+/*
+ * Allocate a pool of TX Wireless Information blocks.
+ */
+int
+rt2860_alloc_tx_pool(struct rt2860_softc *sc)
+{
+	caddr_t vaddr;
+	bus_addr_t paddr;
+	int i, size, error;
+
+	size = RT2860_TX_POOL_COUNT * RT2860_TXWI_DMASZ;
+
+	/* init data_pool early in case of failure.. */
+	SLIST_INIT(&sc->data_pool);
+
+	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0,
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    size, 1, size, 0, NULL, NULL, &sc->txwi_dmat);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not create txwi DMA tag\n");
+		goto fail;
+	}
+
+	error = bus_dmamem_alloc(sc->txwi_dmat, (void **)&sc->txwi_vaddr,
+	    BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sc->txwi_map);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not allocate DMA memory\n");
+		goto fail;
+	}
+
+	error = bus_dmamap_load(sc->txwi_dmat, sc->txwi_map,
+	    sc->txwi_vaddr, size, rt2860_dma_map_addr, &paddr, 0);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not load txwi DMA map\n");
+		goto fail;
+	}
+
+	bus_dmamap_sync(sc->txwi_dmat, sc->txwi_map, BUS_DMASYNC_PREWRITE);
+
+	vaddr = sc->txwi_vaddr;
+	for (i = 0; i < RT2860_TX_POOL_COUNT; i++) {
+		struct rt2860_tx_data *data = &sc->data[i];
+
+		error = bus_dmamap_create(sc->txwi_dmat, 0, &data->map);
+		if (error != 0) {
+			device_printf(sc->sc_dev, "could not create DMA map\n");
+			goto fail;
+		}
+		data->txwi = (struct rt2860_txwi *)vaddr;
+		data->paddr = paddr;
+		vaddr += RT2860_TXWI_DMASZ;
+		paddr += RT2860_TXWI_DMASZ;
+
+		SLIST_INSERT_HEAD(&sc->data_pool, data, next);
+	}
+
+	return 0;
+
+fail:	rt2860_free_tx_pool(sc);
+	return error;
+}
+
+void
+rt2860_free_tx_pool(struct rt2860_softc *sc)
+{
+	if (sc->txwi_vaddr != NULL) {
+		bus_dmamap_sync(sc->txwi_dmat, sc->txwi_map,
+		    BUS_DMASYNC_POSTWRITE);
+		bus_dmamap_unload(sc->txwi_dmat, sc->txwi_map);
+		bus_dmamem_free(sc->txwi_dmat, sc->txwi_vaddr, sc->txwi_map);
+	}
+	if (sc->txwi_dmat != NULL)
+		bus_dma_tag_destroy(sc->txwi_dmat);
+
+	while (!SLIST_EMPTY(&sc->data_pool)) {
+		struct rt2860_tx_data *data;
+		data = SLIST_FIRST(&sc->data_pool);
+		bus_dmamap_destroy(sc->txwi_dmat, data->map);
+		SLIST_REMOVE_HEAD(&sc->data_pool, next);
+	}
+}
+
+int
+rt2860_alloc_rx_ring(struct rt2860_softc *sc, struct rt2860_rx_ring *ring)
+{
+	bus_addr_t physaddr;
+	int i, size, error;
+
+	size = RT2860_RX_RING_COUNT * sizeof (struct rt2860_rxd);
+
+	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 16, 0,
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    size, 1, size, 0, NULL, NULL, &ring->desc_dmat);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not create desc DMA tag\n");
+		goto fail;
+	}
+
+	error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->rxd,
+	    BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not allocate DMA memory\n");
+		goto fail;
+	}
+
+	error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->rxd,
+	    size, rt2860_dma_map_addr, &ring->paddr, 0);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not load desc DMA map\n");
+		goto fail;
+	}
+
+	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0,
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES,
+	    1, MCLBYTES, 0, NULL, NULL, &ring->data_dmat);
+	if (error != 0) {
+		device_printf(sc->sc_dev, "could not create data DMA tag\n");
+		goto fail;
+	}
+
+	for (i = 0; i < RT2860_RX_RING_COUNT; i++) {
+		struct rt2860_rx_data *data = &ring->data[i];
+		struct rt2860_rxd *rxd = &ring->rxd[i];
+
+		error = bus_dmamap_create(ring->data_dmat, 0, &data->map);
+		if (error != 0) {
+			device_printf(sc->sc_dev, "could not create DMA map\n");
+			goto fail;
+		}
+
+		data->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+		if (data->m == NULL) {
+			device_printf(sc->sc_dev,
+			    "could not allocate rx mbuf\n");
+			error = ENOMEM;
+			goto fail;
+		}
+
+		error = bus_dmamap_load(ring->data_dmat, data->map,
+		    mtod(data->m, void *), MCLBYTES, rt2860_dma_map_addr,
+		    &physaddr, 0);
+		if (error != 0) {
+			device_printf(sc->sc_dev,
+			    "could not load rx buf DMA map");
+			goto fail;
+		}
+
+		rxd->sdp0 = htole32(physaddr);
+		rxd->sdl0 = htole16(MCLBYTES);
+	}
+
+	bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE);
+
+	return 0;
+
+fail:	rt2860_free_rx_ring(sc, ring);
+	return error;
+}
+
+void
+rt2860_reset_rx_ring(struct rt2860_softc *sc, struct rt2860_rx_ring *ring)
+{
+	int i;
+
+	for (i = 0; i < RT2860_RX_RING_COUNT; i++)
+		ring->rxd[i].sdl0 &= ~htole16(RT2860_RX_DDONE);
+
+	bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE);
+
+	ring->cur = 0;
+}
+
+void
+rt2860_free_rx_ring(struct rt2860_softc *sc, struct rt2860_rx_ring *ring)
+{
+	int i;
+
+	if (ring->rxd != NULL) {
+		bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
+		    BUS_DMASYNC_POSTWRITE);
+		bus_dmamap_unload(ring->desc_dmat, ring->desc_map);
+		bus_dmamem_free(ring->desc_dmat, ring->rxd, ring->desc_map);
+	}
+	if (ring->desc_dmat != NULL)
+		bus_dma_tag_destroy(ring->desc_dmat);
+
+	for (i = 0; i < RT2860_RX_RING_COUNT; i++) {
+		struct rt2860_rx_data *data = &ring->data[i];
+
+		if (data->m != NULL) {
+			bus_dmamap_sync(ring->data_dmat, data->map,
+			    BUS_DMASYNC_POSTREAD);
+			bus_dmamap_unload(ring->data_dmat, data->map);
+			m_freem(data->m);
+		}
+		if (data->map != NULL)
+			bus_dmamap_destroy(ring->data_dmat, data->map);
+	}
+	if (ring->data_dmat != NULL)
+		bus_dma_tag_destroy(ring->data_dmat);
+}
+
+static void
+rt2860_updatestats(struct rt2860_softc *sc)
+{
+	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+
+	/*
+	 * In IBSS or HostAP modes (when the hardware sends beacons), the
+	 * MAC can run into a livelock and start sending CTS-to-self frames
+	 * like crazy if protection is enabled.  Fortunately, we can detect
+	 * when such a situation occurs and reset the MAC.
+	 */
+	if (ic->ic_curmode != IEEE80211_M_STA) {
+		/* check if we're in a livelock situation.. */
+		uint32_t tmp = RAL_READ(sc, RT2860_DEBUG);
+		if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) {
+			/* ..and reset MAC/BBP for a while.. */
+			DPRINTF(("CTS-to-self livelock detected\n"));
+			RAL_WRITE(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST);
+			RAL_BARRIER_WRITE(sc);
+			DELAY(1);
+			RAL_WRITE(sc, RT2860_MAC_SYS_CTRL,
+			    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
+		}
+	}
+}
+
+static void
+rt2860_newassoc(struct ieee80211_node *ni, int isnew)
+{
+	struct ieee80211com *ic = ni->ni_ic;
+	struct rt2860_softc *sc = ic->ic_ifp->if_softc;
+	uint8_t wcid;
+
+	wcid = IEEE80211_AID(ni->ni_associd);
+	if (isnew && ni->ni_associd != 0) {
+		sc->wcid2ni[wcid] = ni;
+
+		/* init WCID table entry */
+		RAL_WRITE_REGION_1(sc, RT2860_WCID_ENTRY(wcid),
+		    ni->ni_macaddr, IEEE80211_ADDR_LEN);
+	}
+	DPRINTF(("new assoc isnew=%d addr=%s WCID=%d\n",
+	    isnew, ether_sprintf(ni->ni_macaddr), wcid));
+}
+
+static void
+rt2860_node_free(struct ieee80211_node *ni)
+{
+	struct ieee80211com *ic = ni->ni_ic;
+	struct rt2860_softc *sc = ic->ic_ifp->if_softc;
+	uint8_t wcid;
+
+	if (ni->ni_associd != 0) {
+		wcid = IEEE80211_AID(ni->ni_associd);
+
+		/* clear Rx WCID search table entry */
+		RAL_SET_REGION_4(sc, RT2860_WCID_ENTRY(wcid), 0, 2);
+	}
+	sc->sc_node_free(ni);
+}
+
+#ifdef IEEE80211_HT
+static int
+rt2860_ampdu_rx_start(struct ieee80211com *ic, struct ieee80211_node *ni,
+    uint8_t tid)
+{
+	struct rt2860_softc *sc = ic->ic_softc;
+	uint8_t wcid = ((struct rt2860_node *)ni)->wcid;
+	uint32_t tmp;
+
+	/* update BA session mask */
+	tmp = RAL_READ(sc, RT2860_WCID_ENTRY(wcid) + 4);
+	tmp |= (1 << tid) << 16;
+	RAL_WRITE(sc, RT2860_WCID_ENTRY(wcid) + 4, tmp);
+	return 0;
+}
+
+static void

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list