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-head
mailing list