Page MenuHomeFreeBSD

D15943.id.diff
No OneTemporary

D15943.id.diff

This file is larger than 256 KB, so syntax highlighting was skipped.
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -2833,6 +2833,14 @@
dev/rp/rp_isa.c optional rp isa
dev/rp/rp_pci.c optional rp pci
#
+dev/rt2860/rt2860_fdt.c optional rt2860 fdt
+dev/rt2860/rt2860.c optional rt2860
+dev/rt2860/rt2860_amrr.c optional rt2860
+dev/rt2860/rt2860_io.c optional rt2860
+dev/rt2860/rt2860_led.c optional rt2860
+dev/rt2860/rt2860_read_eeprom.c optional rt2860
+dev/rt2860/rt2860_rf.c optional rt2860
+#
dev/rtwn/if_rtwn.c optional rtwn
dev/rtwn/if_rtwn_beacon.c optional rtwn
dev/rtwn/if_rtwn_calib.c optional rtwn
Index: sys/dev/rt2860/rt2860.c
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860.c
@@ -0,0 +1,7098 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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 <dev/rt2860/rt2860_softc.h>
+#include <dev/rt2860/rt2860_reg.h>
+#include <dev/rt2860/rt2860_eeprom.h>
+#include <dev/rt2860/rt2860_txwi.h>
+#include <dev/rt2860/rt2860_rxwi.h>
+#include <dev/rt2860/rt2860_io.h>
+#include <dev/rt2860/rt2860_read_eeprom.h>
+#include <dev/rt2860/rt2860_led.h>
+#include <dev/rt2860/rt2860_rf.h>
+#include <dev/rt2860/rt2860_debug.h>
+
+/*
+ * Defines and macros
+ */
+
+#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 RUN_AID2WCID(aid) ((aid) & 0xff)
+#define RT2860_WCID_RESERVED 0xff
+#define RT2860_WCID_MCAST 0xf7
+
+/*
+ * Global function prototypes, used in bus depended interfaces
+ */
+
+int rt2860_attach(device_t dev, int id);
+
+int rt2860_detach(device_t dev);
+
+int rt2860_shutdown(device_t dev);
+
+int rt2860_suspend(device_t dev);
+
+int rt2860_resume(device_t dev);
+
+/*
+ * Static function prototypes
+ */
+
+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 rt2860_softc *sc);
+
+static struct ieee80211vap *rt2860_vap_create(struct ieee80211com *ic,
+ const char name[IFNAMSIZ], int unit, enum ieee80211_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);
+
+#ifdef RT2860_HW_CRYPTO
+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);
+
+static int rt2860_vap_key_delete(struct ieee80211vap *vap,
+ const struct ieee80211_key *k);
+#endif
+
+static void rt2860_vap_update_beacon(struct ieee80211vap *vap, int what);
+
+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 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 ieee80211com *ic);
+
+static void rt2860_update_promisc(struct ieee80211com *ic);
+
+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_parent(struct ieee80211com *);
+static int rt2860_transmit(struct ieee80211com *, struct mbuf *);
+
+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
+{
+ uint32_t reg;
+ uint32_t val;
+} rt2860_def_mac[] =
+{
+#if 1
+ { 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 },
+#else
+
+ { RT2860_REG_PBF_BCN_OFFSET0, 0xf8f0e8e0}, /* 0x3800(e0), 0x3A00(e8), 0x3C00(f0), 0x3E00(f8), 512B for each beacon */
+ { RT2860_REG_PBF_BCN_OFFSET1, 0x6f77d0c8}, /* 0x3200(c8), 0x3400(d0), 0x1DC0(77), 0x1BC0(6f), 512B for each beacon */
+ { RT2860_REG_LEGACY_BASIC_RATE, 0x0000013f}, // Basic rate set bitmap
+ { RT2860_REG_HT_BASIC_RATE, 0x00008003}, // Basic HT rate set , 20M, MCS=3, MM. Format is the same as in TXWI.
+ { RT2860_REG_SYS_CTRL, 0x00000000}, // 0x1004, , default Disable RX
+ { RT2860_REG_RX_FILTER_CFG, 0x00017f97}, //0x1400 , RX filter control,
+ { RT2860_REG_BKOFF_SLOT_CFG, 0x00000209}, // default set short slot time, CC_DELAY_TIME should be 2
+ { RT2860_REG_TX_SW_CFG0, 0x00000400}, // Gary,2008-05-21 0x0 for CWC test , 2008-06-19 0x400 for rf reason
+ { RT2860_REG_TX_SW_CFG1, 0x00000000}, // Gary,2008-06-18
+ { RT2860_REG_TX_SW_CFG2, 0x00000030}, // Bruce, CwC IOT issue
+ { RT2860_REG_TX_LINK_CFG, 0x00001020}, // Gary,2006-08-23
+ { RT2860_REG_TX_TIMEOUT_CFG, 0x000a2090}, // CCK has some problem. So increase timieout value. 2006-10-09// MArvek RT , Modify for 2860E ,2007-08-01
+ { RT2860_REG_MAX_LEN_CFG, (1 << 12) | RT2860_MAX_AGG_SIZE }, // 0x3018, MAX frame length. Max PSDU = 16kbytes.
+ { RT2860_REG_LED_CFG, 0x7f031e46}, // Gary, 2006-08-23
+ { RT2860_REG_PBF_MAX_PCNT, 0x1F3FBF9F}, //0x1F3f7f9f}, //Jan, 2006/04/20
+ { RT2860_REG_TX_RTY_CFG, 0x47d01f0f}, // Jan, 2006/11/16, Set TxWI->ACK =0 in Probe Rsp Modify for 2860E ,2007-08-03
+ { RT2860_REG_AUTO_RSP_CFG, 0x00000053}, // Initial Auto_Responder, because QA will turn off Auto-Responder
+ { RT2860_REG_TX_CCK_PROT_CFG, 0x05740003}, // Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled.
+ { RT2860_REG_TX_OFDM_PROT_CFG, 0x05740003}, // Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled.
+ { RT2860_REG_TX_GF20_PROT_CFG, 0x01744004}, // set 19:18 --> Short NAV for MIMO PS
+ { 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}, //Extension channel backoff.
+ { RT2860_REG_TX_RTS_CFG, 0x00092b20},
+ { RT2860_REG_TX_EXP_ACK_TIME, 0x002400ca}, // default value
+ { RT2860_REG_HCCAPSMP_TXOP_HLDR_ET, 0x00000002},
+ { RT2860_REG_XIFS_TIME_CFG, 0x33a41010},
+ { RT2860_REG_PWR_PIN_CFG, 0x00000003}, // patch for 2880-E
+#if 1 /* CONFIG_AP_SUPPORT */
+ { RT2860_REG_SCHDMA_WMM_AIFSN_CFG, 0x00001173},
+ { RT2860_REG_SCHDMA_WMM_CWMIN_CFG, 0x00002344},
+ { RT2860_REG_SCHDMA_WMM_CWMAX_CFG, 0x000034a6},
+ { RT2860_REG_SCHDMA_WMM_TXOP0_CFG, 0x00100020},
+ { RT2860_REG_SCHDMA_WMM_TXOP1_CFG, 0x002F0038},
+ { RT2860_REG_TBTT_SYNC_CFG, 0x00012000},
+#else /* CONFIG_STA_SUPPORT */
+ { RT2860_REG_SCHDMA_WMM_AIFSN_CFG, 0x00002273},
+ { RT2860_REG_SCHDMA_WMM_CWMIN_CFG, 0x00002344},
+ { RT2860_REG_SCHDMA_WMM_CWMAX_CFG, 0x000034aa},
+#endif // CONFIG_AP_SUPPORT //
+#endif
+};
+
+#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[] =
+{
+#if 1 /* orig */
+ { 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 },
+#else
+ { 31, 0x08}, //gary recommend for ACE
+ { 65, 0x2C}, // fix rssi issue
+ { 66, 0x38}, // Also set this default value to pAd->BbpTuning.R66CurrentValue at initial
+ { 68, 0x0B}, // improve Rx sensitivity.
+ { 69, 0x12},
+ { 70, 0xa}, // BBP_R70 will change to 0x8 in ApStartUp and LinkUp for rt2860C, otherwise value is 0xa
+ { 73, 0x10},
+ { 78, 0x0E},
+ { 80, 0x08}, // requested by Gary for high power
+ { 81, 0x37},
+ { 82, 0x62},
+ { 83, 0x6A},
+ { 84, 0x99}, // 0x19 is for rt2860E and after. This is for extension channel overlapping IOT. 0x99 is for rt2860D and before
+ { 86, 0x00}, // middle range issue, Rory @2008-01-28
+ { 91, 0x04}, // middle range issue, Rory @2008-01-28
+ { 92, 0x00}, // middle range issue, Rory @2008-01-28
+ { 103, 0xC0},
+ { 105, 0x01},/*kurtis:0x01 ori*/// 0x05 is for rt2860E to turn on FEQ control. It is safe for rt2860D and before, because Bit 7:2 are reserved in rt2860D and before.
+ { 106, 0x35}, // Optimizing the Short GI sampling request from Gray @2009-0409
+#endif
+};
+
+#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_attach
+ */
+int rt2860_attach(device_t dev, int id)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ int error, ntries, i;
+
+ sc = device_get_softc(dev);
+ ic = &sc->sc_ic;
+
+ sc->dev = dev;
+ sc->pid = id;
+
+ mtx_init(&sc->lock, device_get_nameunit(dev),
+ MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE);
+
+ 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);
+ memcpy(ic->ic_macaddr, sc->mac_addr, 6);
+
+ 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));
+
+ RT2860_SOFTC_LOCK(sc);
+ /* clear key tables */
+ rt2860_asic_clear_keytables(sc);
+ RT2860_SOFTC_UNLOCK(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);
+ mbufq_init(&sc->sc_snd, ifqmaxlen);
+
+ ic->ic_softc = sc;
+ ic->ic_name = device_get_nameunit(dev);
+ ic->ic_opmode = IEEE80211_M_STA;
+ ic->ic_phytype = IEEE80211_T_HT;
+
+ 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;
+
+#ifdef RT2860_HW_CRYPTO
+ ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP |
+ IEEE80211_CRYPTO_TKIP |
+ IEEE80211_CRYPTO_TKIPMIC |
+ IEEE80211_CRYPTO_AES_CCM;
+#endif
+ 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)
+ if (sc->mac_rev != 0x28600102)
+ ic->ic_htcaps |= IEEE80211_HTCAP_DELBA;
+
+ /* init channels */
+
+ ic->ic_nchans = 0;
+
+ rt2860_init_channels(sc);
+
+ rt2860_init_channels_ht40(sc);
+
+ ieee80211_ifattach(ic);
+
+ ic->ic_vap_create = rt2860_vap_create;
+ ic->ic_vap_delete = rt2860_vap_delete;
+ ic->ic_parent = rt2860_parent;
+ ic->ic_transmit = rt2860_transmit;
+
+ ic->ic_node_alloc = rt2860_node_alloc;
+
+ sc->node_cleanup = ic->ic_node_cleanup;
+ ic->ic_node_cleanup = rt2860_node_cleanup;
+
+ 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_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
+ */
+int rt2860_detach(device_t dev)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ int i;
+
+ sc = device_get_softc(dev);
+ ic = &sc->sc_ic;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_ANY,
+ "%s: detaching\n",
+ device_get_nameunit(sc->dev));
+
+ RT2860_SOFTC_LOCK(sc);
+
+ sc->sc_flags &= ~RT2860_RUNNING;
+
+ 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);
+ mbufq_drain(&sc->sc_snd);
+
+ 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
+ */
+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
+ */
+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
+ */
+int rt2860_resume(device_t dev)
+{
+ struct rt2860_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_ANY,
+ "%s: resuming\n",
+ device_get_nameunit(sc->dev));
+
+ if (sc->sc_ic.ic_nrunning > 0)
+ rt2860_init(sc);
+
+ return 0;
+}
+
+/*
+ * rt2860_init_channels
+ */
+static void rt2860_init_channels(struct rt2860_softc *sc)
+{
+ struct ieee80211com *ic;
+ struct ieee80211_channel *c;
+ int i, flags;
+
+ ic = &sc->sc_ic;
+
+ /* 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 ||
+ sc->rf_rev == RT2860_EEPROM_RF_3052)
+ {
+ 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)
+ {
+ 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;
+ }
+ }
+}
+
+/*
+ * rt2860_init_channels_ht40
+ */
+static void rt2860_init_channels_ht40(struct rt2860_softc *sc)
+{
+ struct ieee80211com *ic;
+ struct ieee80211_channel *c, *cent, *ext;
+ int i, flags;
+
+ ic = &sc->sc_ic;
+
+ /* set supported channels for 2GHz band */
+
+ for (i = 1; i <= 14; i++)
+ {
+ flags = IEEE80211_CHAN_G | IEEE80211_CHAN_HT40;
+
+ /* find the center channel */
+
+ cent = ieee80211_find_channel_byieee(ic, i,
+ flags & ~IEEE80211_CHAN_HT);
+ if (cent == NULL)
+ {
+ printf("%s: skip channel %d, could not find center channel\n",
+ device_get_nameunit(sc->dev), i);
+ continue;
+ }
+
+ /* find the extension channel */
+
+ ext = ieee80211_find_channel(ic, cent->ic_freq + 20,
+ flags & ~IEEE80211_CHAN_HT);
+ if (ext == NULL)
+ {
+ printf("%s: skip channel %d, could not find extension channel\n",
+ device_get_nameunit(sc->dev), i);
+ continue;
+ }
+
+ c = &ic->ic_channels[ic->ic_nchans++];
+
+ *c = *cent;
+ c->ic_extieee = ext->ic_ieee;
+ c->ic_flags &= ~IEEE80211_CHAN_HT;
+ c->ic_flags |= IEEE80211_CHAN_HT40U;
+
+ c = &ic->ic_channels[ic->ic_nchans++];
+
+ *c = *ext;
+ c->ic_extieee = cent->ic_ieee;
+ c->ic_flags &= ~IEEE80211_CHAN_HT;
+ c->ic_flags |= IEEE80211_CHAN_HT40D;
+ }
+
+ /* set supported channels for 5GHz band */
+
+ if (sc->rf_rev == RT2860_EEPROM_RF_2850 ||
+ sc->rf_rev == RT2860_EEPROM_RF_2750 ||
+ sc->rf_rev == RT2860_EEPROM_RF_3052)
+ {
+ for (i = 36; i <= 64; i += 4)
+ {
+ flags = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40;
+
+ /* find the center channel */
+
+ cent = ieee80211_find_channel_byieee(ic, i,
+ flags & ~IEEE80211_CHAN_HT);
+ if (cent == NULL)
+ {
+ printf("%s: skip channel %d, could not find center channel\n",
+ device_get_nameunit(sc->dev), i);
+ continue;
+ }
+
+ /* find the extension channel */
+
+ ext = ieee80211_find_channel(ic, cent->ic_freq + 20,
+ flags & ~IEEE80211_CHAN_HT);
+ if (ext == NULL)
+ {
+ printf("%s: skip channel %d, could not find extension channel\n",
+ device_get_nameunit(sc->dev), i);
+ continue;
+ }
+
+ c = &ic->ic_channels[ic->ic_nchans++];
+
+ *c = *cent;
+ c->ic_extieee = ext->ic_ieee;
+ c->ic_flags &= ~IEEE80211_CHAN_HT;
+ c->ic_flags |= IEEE80211_CHAN_HT40U;
+
+ c = &ic->ic_channels[ic->ic_nchans++];
+
+ *c = *ext;
+ c->ic_extieee = cent->ic_ieee;
+ c->ic_flags &= ~IEEE80211_CHAN_HT;
+ c->ic_flags |= IEEE80211_CHAN_HT40D;
+ }
+
+ for (i = 100; i <= 140; i += 4)
+ {
+ flags = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40;
+
+ /* find the center channel */
+
+ cent = ieee80211_find_channel_byieee(ic, i,
+ flags & ~IEEE80211_CHAN_HT);
+ if (cent == NULL)
+ {
+ printf("%s: skip channel %d, could not find center channel\n",
+ device_get_nameunit(sc->dev), i);
+ continue;
+ }
+
+ /* find the extension channel */
+
+ ext = ieee80211_find_channel(ic, cent->ic_freq + 20,
+ flags & ~IEEE80211_CHAN_HT);
+ if (ext == NULL)
+ {
+ printf("%s: skip channel %d, could not find extension channel\n",
+ device_get_nameunit(sc->dev), i);
+ continue;
+ }
+
+ c = &ic->ic_channels[ic->ic_nchans++];
+
+ *c = *cent;
+ c->ic_extieee = ext->ic_ieee;
+ c->ic_flags &= ~IEEE80211_CHAN_HT;
+ c->ic_flags |= IEEE80211_CHAN_HT40U;
+
+ c = &ic->ic_channels[ic->ic_nchans++];
+
+ *c = *ext;
+ c->ic_extieee = cent->ic_ieee;
+ c->ic_flags &= ~IEEE80211_CHAN_HT;
+ c->ic_flags |= IEEE80211_CHAN_HT40D;
+ }
+
+ for (i = 149; i <= 165; i += 4)
+ {
+ flags = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40;
+
+ /* find the center channel */
+
+ cent = ieee80211_find_channel_byieee(ic, i,
+ flags & ~IEEE80211_CHAN_HT);
+ if (cent == NULL)
+ {
+ printf("%s: skip channel %d, could not find center channel\n",
+ device_get_nameunit(sc->dev), i);
+ continue;
+ }
+
+ /* find the extension channel */
+
+ ext = ieee80211_find_channel(ic, cent->ic_freq + 20,
+ flags & ~IEEE80211_CHAN_HT);
+ if (ext == NULL)
+ {
+ printf("%s: skip channel %d, could not find extension channel\n",
+ device_get_nameunit(sc->dev), i);
+ continue;
+ }
+
+ c = &ic->ic_channels[ic->ic_nchans++];
+
+ *c = *cent;
+ c->ic_extieee = ext->ic_ieee;
+ c->ic_flags &= ~IEEE80211_CHAN_HT;
+ c->ic_flags |= IEEE80211_CHAN_HT40U;
+
+ c = &ic->ic_channels[ic->ic_nchans++];
+
+ *c = *ext;
+ c->ic_extieee = cent->ic_ieee;
+ c->ic_flags &= ~IEEE80211_CHAN_HT;
+ c->ic_flags |= IEEE80211_CHAN_HT40D;
+ }
+ }
+}
+
+/*
+ * rt2860_init_locked
+ */
+static void rt2860_init_locked(void *priv)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ struct ieee80211vap *vap;
+ int error, i, ntries;
+ uint32_t tmp, stacnt[6];
+ const struct firmware *fp;
+
+ sc = priv;
+ ic = &sc->sc_ic;
+ vap = TAILQ_FIRST(&ic->ic_vaps);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_ANY,
+ "%s: initializing\n",
+ device_get_nameunit(sc->dev));
+
+ RT2860_SOFTC_ASSERT_LOCKED(sc);
+
+ if (sc->mac_rev != 0x28720200)
+ {
+ if (!(sc->flags & RT2860_SOFTC_FLAGS_UCODE_LOADED))
+ {
+ RT2860_DPRINTF(sc, RT2860_DEBUG_ANY,
+ "%s: loading 8051 microcode\n",
+ device_get_nameunit(sc->dev));
+
+ fp = firmware_get("rt2860fw");
+ if (fp == NULL) {
+ device_printf(sc->dev,
+ "unable to receive rt2860fw firmware image\n");
+ goto fail;
+ }
+
+ error = rt2860_io_mcu_load_ucode(sc, fp->data, fp->datasize);
+ if (error != 0)
+ {
+ printf("%s: could not load 8051 microcode\n",
+ device_get_nameunit(sc->dev));
+ goto fail;
+ }
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_ANY,
+ "%s: 8051 microcode was successfully loaded\n",
+ device_get_nameunit(sc->dev));
+
+ sc->flags |= RT2860_SOFTC_FLAGS_UCODE_LOADED;
+ }
+ }
+ else
+ {
+ sc->flags |= RT2860_SOFTC_FLAGS_UCODE_LOADED;
+
+ /* Blink every TX */
+#define LED_CFG_LED_POLARITY (1<<30)
+#define LED_CFG_Y_LED_MODE_ONTX (1<<28)
+#define LED_CFG_G_LED_MODE_ONTX (1<<26)
+#define LED_CFG_R_LED_MODE_ONTX (1<<24)
+#define LED_CFG_SLOW_BLK_TIME (0x03<<16) /* sec */
+#define LED_CFG_LED_OFF_TIME (0x1e<<8) /* msec */
+#define LED_CFG_LED_ON_TIME (0x46) /* msec */
+ rt2860_io_mac_write(sc, RT2860_REG_LED_CFG,
+ LED_CFG_LED_POLARITY |
+ LED_CFG_Y_LED_MODE_ONTX |
+ LED_CFG_G_LED_MODE_ONTX |
+ LED_CFG_R_LED_MODE_ONTX |
+ LED_CFG_SLOW_BLK_TIME |
+ LED_CFG_LED_OFF_TIME |
+ LED_CFG_LED_ON_TIME);
+ }
+
+ rt2860_io_mac_write(sc, RT2860_REG_PWR_PIN_CFG, 0x2);
+
+ /* disable DMA engine */
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG);
+
+ tmp &= 0xff0;
+ tmp |= RT2860_REG_TX_WB_DDONE;
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG, tmp);
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WPDMA_RST_IDX, 0xffffffff);
+
+ /* PBF hardware reset */
+
+ rt2860_io_mac_write(sc, RT2860_REG_PBF_SYS_CTRL, 0xe1f);
+ rt2860_io_mac_write(sc, RT2860_REG_PBF_SYS_CTRL, 0xe00);
+
+ /* wait while DMA engine is busy */
+
+ for (ntries = 0; ntries < 100; ntries++)
+ {
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG);
+ if (!(tmp & (RT2860_REG_TX_DMA_BUSY | RT2860_REG_RX_DMA_BUSY)))
+ break;
+
+ DELAY(1000);
+ }
+
+ if (ntries == 100)
+ {
+ printf("%s: timeout waiting for DMA engine\n",
+ device_get_nameunit(sc->dev));
+ goto fail;
+ }
+
+ tmp &= 0xff0;
+ tmp |= RT2860_REG_TX_WB_DDONE;
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG, tmp);
+
+ /* reset Rx and Tx rings */
+
+ tmp = RT2860_REG_RST_IDX_RX |
+ RT2860_REG_RST_IDX_TX_MGMT |
+ RT2860_REG_RST_IDX_TX_HCCA |
+ RT2860_REG_RST_IDX_TX_AC3 |
+ RT2860_REG_RST_IDX_TX_AC2 |
+ RT2860_REG_RST_IDX_TX_AC1 |
+ RT2860_REG_RST_IDX_TX_AC0;
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WPDMA_RST_IDX, tmp);
+
+ /* PBF hardware reset */
+
+ rt2860_io_mac_write(sc, RT2860_REG_PBF_SYS_CTRL, 0xe1f);
+ rt2860_io_mac_write(sc, RT2860_REG_PBF_SYS_CTRL, 0xe00);
+
+ rt2860_io_mac_write(sc, RT2860_REG_PWR_PIN_CFG, 0x3);
+
+ rt2860_io_mac_write(sc, RT2860_REG_SYS_CTRL,
+ RT2860_REG_MAC_SRST | RT2860_REG_BBP_HRST);
+ rt2860_io_mac_write(sc, RT2860_REG_SYS_CTRL, 0);
+
+ /* init Tx power per rate */
+
+ for (i = 0; i < RT2860_SOFTC_TXPOW_RATE_COUNT; i++)
+ {
+ if (sc->txpow_rate_20mhz[i] == 0xffffffff)
+ continue;
+
+ rt2860_io_mac_write(sc, RT2860_REG_TX_PWR_CFG(i),
+ sc->txpow_rate_20mhz[i]);
+ }
+
+ for (i = 0; i < RT2860_DEF_MAC_SIZE; i++)
+ rt2860_io_mac_write(sc, rt2860_def_mac[i].reg,
+ rt2860_def_mac[i].val);
+
+ /* wait while MAC is busy */
+
+ for (ntries = 0; ntries < 100; ntries++)
+ {
+ if (!(rt2860_io_mac_read(sc, RT2860_REG_STATUS_CFG) &
+ (RT2860_REG_STATUS_TX_BUSY | RT2860_REG_STATUS_RX_BUSY)))
+ break;
+
+ DELAY(1000);
+ }
+
+ if (ntries == 100)
+ {
+ printf("%s: timeout waiting for MAC\n",
+ device_get_nameunit(sc->dev));
+ goto fail;
+ }
+
+ /* clear Host to MCU mailbox */
+
+ rt2860_io_mac_write(sc, RT2860_REG_H2M_MAILBOX_BBP_AGENT, 0);
+ rt2860_io_mac_write(sc, RT2860_REG_H2M_MAILBOX, 0);
+
+ rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_BOOT,
+ RT2860_REG_H2M_TOKEN_NO_INTR, 0);
+
+ DELAY(1000);
+
+ error = rt2860_init_bbp(sc);
+ if (error != 0)
+ goto fail;
+
+ /* set up maximum buffer sizes */
+
+ tmp = (1 << 12) | RT2860_MAX_AGG_SIZE;
+
+ rt2860_io_mac_write(sc, RT2860_REG_MAX_LEN_CFG, tmp);
+
+ if (sc->mac_rev == 0x28720200)
+ {
+ /* set max. PSDU length from 16K to 32K bytes */
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_MAX_LEN_CFG);
+
+ tmp &= ~(3 << 12);
+ tmp |= (2 << 12);
+
+ rt2860_io_mac_write(sc, RT2860_REG_MAX_LEN_CFG, tmp);
+ }
+
+ if (sc->mac_rev >= 0x28720200 && sc->mac_rev < 0x30700200)
+ {
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_MAX_LEN_CFG);
+
+ tmp &= 0xfff;
+ tmp |= 0x2000;
+
+ rt2860_io_mac_write(sc, RT2860_REG_MAX_LEN_CFG, tmp);
+ }
+
+ /* set mac address */
+
+ rt2860_asic_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr);
+
+ /* clear statistic registers */
+
+ rt2860_io_mac_read_multi(sc, RT2860_REG_RX_STA_CNT0,
+ stacnt, sizeof(stacnt));
+
+ /* set RTS threshold */
+
+ rt2860_asic_update_rtsthreshold(sc);
+
+ /* set Tx power */
+
+ rt2860_asic_update_txpower(sc);
+
+ /* set up protection mode */
+
+ sc->tx_ampdu_sessions = 0;
+
+ rt2860_asic_updateprot(sc);
+
+ /* clear beacon frame space (entries = 8, entry size = 512) */
+
+ rt2860_io_mac_set_region_4(sc, RT2860_REG_BEACON_BASE(0), 0, 1024);
+
+ taskqueue_unblock(sc->taskqueue);
+
+ /* init Tx rings (4 EDCAs + HCCA + MGMT) */
+
+ for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++)
+ rt2860_reset_tx_ring(sc, &sc->tx_ring[i]);
+
+ for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++)
+ {
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_BASE_PTR(i),
+ sc->tx_ring[i].desc_phys_addr);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_MAX_CNT(i),
+ RT2860_SOFTC_TX_RING_DESC_COUNT);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_CTX_IDX(i), 0);
+ }
+
+ /* init Rx ring */
+
+ rt2860_reset_rx_ring(sc, &sc->rx_ring);
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_BASE_PTR,
+ sc->rx_ring.desc_phys_addr);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_MAX_CNT,
+ RT2860_SOFTC_RX_RING_DATA_COUNT);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_CALC_IDX,
+ RT2860_SOFTC_RX_RING_DATA_COUNT - 1);
+
+ /* wait while DMA engine is busy */
+
+ for (ntries = 0; ntries < 100; ntries++)
+ {
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG);
+ if (!(tmp & (RT2860_REG_TX_DMA_BUSY | RT2860_REG_RX_DMA_BUSY)))
+ break;
+
+ DELAY(1000);
+ }
+
+ if (ntries == 100)
+ {
+ printf("%s: timeout waiting for DMA engine\n",
+ device_get_nameunit(sc->dev));
+ goto fail;
+ }
+
+ tmp &= 0xff0;
+ tmp |= RT2860_REG_TX_WB_DDONE;
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG, tmp);
+
+ /* disable interrupts mitigation */
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_DELAY_INT_CFG, 0);
+
+ /* select Main antenna for 1T1R devices */
+ if (sc->rf_rev == RT2860_EEPROM_RF_2020 ||
+ sc->rf_rev == RT2860_EEPROM_RF_3020 ||
+ sc->rf_rev == RT2860_EEPROM_RF_3320)
+ rt3090_set_rx_antenna(sc, 0);
+
+ /* send LEDs operating mode to microcontroller */
+ rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_LED1,
+ RT2860_REG_H2M_TOKEN_NO_INTR, sc->led_off[0]);
+ rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_LED2,
+ RT2860_REG_H2M_TOKEN_NO_INTR, sc->led_off[1]);
+ rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_LED3,
+ RT2860_REG_H2M_TOKEN_NO_INTR, sc->led_off[2]);
+
+ /* turn radio LED on */
+
+ rt2860_led_cmd(sc, RT2860_LED_CMD_RADIO_ON);
+
+ /* write vendor-specific BBP values (from EEPROM) */
+
+ for (i = 0; i < RT2860_SOFTC_BBP_EEPROM_COUNT; i++)
+ {
+ if (sc->bbp_eeprom[i].reg == 0x00 ||
+ sc->bbp_eeprom[i].reg == 0xff)
+ continue;
+
+ rt2860_io_bbp_write(sc, sc->bbp_eeprom[i].reg,
+ sc->bbp_eeprom[i].val);
+ }
+
+ if ((sc->mac_rev & 0xffff0000) >= 0x30710000)
+ rt3090_rf_init(sc);
+
+ if (sc->mac_rev != 0x28720200) {
+ /* 0x28720200 don`t have RT2860_REG_SCHDMA_GPIO_CTRL_CFG */
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_GPIO_CTRL_CFG);
+ if (tmp & (1 << 2)) {
+ rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_SLEEP,
+ RT2860_REG_H2M_TOKEN_RADIOOFF, 0x02ff);
+ rt2860_io_mcu_cmd_check(sc, RT2860_REG_H2M_TOKEN_RADIOOFF);
+
+ rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_WAKEUP,
+ RT2860_REG_H2M_TOKEN_WAKEUP, 0);
+ rt2860_io_mcu_cmd_check(sc, RT2860_REG_H2M_TOKEN_WAKEUP);
+ }
+ }
+
+ if ((sc->mac_rev & 0xffff0000) >= 0x30710000)
+ rt3090_rf_wakeup(sc);
+
+ /* disable non-existing Rx chains */
+
+ tmp = rt2860_io_bbp_read(sc, 3);
+
+ tmp &= ~((1 << 4) | (1 << 3));
+
+ if (sc->nrxpath == 3)
+ tmp |= (1 << 4);
+ else if (sc->nrxpath == 2)
+ tmp |= (1 << 3);
+
+ rt2860_io_bbp_write(sc, 3, tmp);
+
+ /* disable non-existing Tx chains */
+
+ tmp = rt2860_io_bbp_read(sc, 1);
+
+ tmp &= ~((1 << 4) | (1 << 3));
+
+ if (sc->ntxpath == 2)
+ tmp |= (1 << 4);
+
+ rt2860_io_bbp_write(sc, 1, tmp);
+
+ if ((sc->mac_rev & 0xffff0000) >= 0x30710000)
+ rt3090_rf_setup(sc);
+
+ /* RT3050 and RT3052 */
+ if (sc->rf_rev == RT2860_EEPROM_RF_3020 ||
+ sc->rf_rev == RT2860_EEPROM_RF_3022)
+ {
+ /* calibrate RF */
+ tmp = rt2860_io_rf_read(sc, 30);
+ tmp |= 0x80;
+ rt2860_io_rf_write(sc, 30, tmp);
+ DELAY(1000);
+ tmp &= 0x7F;
+ rt2860_io_rf_write(sc, 30, tmp);
+
+ /* Initialize RF register to default value */
+ rt2860_io_rf_load_defaults(sc);
+ }
+
+ /* set current channel */
+ rt2860_rf_set_chan(sc, ic->ic_curchan);
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WMM_TXOP0_CFG, 0);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WMM_TXOP1_CFG,
+ (48 << 16) | 96);
+
+ if ((sc->mac_rev & 0xffff) != 0x0101)
+ rt2860_io_mac_write(sc, RT2860_REG_TX_TXOP_CTRL_CFG, 0x583f);
+
+ /* clear pending interrupts */
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_INT_STATUS, 0xffffffff);
+
+ /* enable interrupts */
+
+ tmp = RT2860_REG_INT_TX_COHERENT |
+ RT2860_REG_INT_RX_COHERENT |
+ RT2860_REG_INT_GP_TIMER |
+ RT2860_REG_INT_AUTO_WAKEUP |
+ RT2860_REG_INT_FIFO_STA_FULL |
+ RT2860_REG_INT_PRE_TBTT |
+ RT2860_REG_INT_TBTT |
+ RT2860_REG_INT_TXRX_COHERENT |
+ RT2860_REG_INT_MCU_CMD |
+ RT2860_REG_INT_TX_MGMT_DONE |
+ RT2860_REG_INT_TX_HCCA_DONE |
+ RT2860_REG_INT_TX_AC3_DONE |
+ RT2860_REG_INT_TX_AC2_DONE |
+ RT2860_REG_INT_TX_AC1_DONE |
+ RT2860_REG_INT_TX_AC0_DONE |
+ RT2860_REG_INT_RX_DONE;
+
+ sc->intr_enable_mask = tmp;
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_INT_MASK, tmp);
+
+ if (rt2860_txrx_enable(sc) != 0)
+ goto fail;
+
+ /* clear garbage interrupts */
+
+ tmp = rt2860_io_mac_read(sc, 0x1300);
+
+ sc->sc_flags |= RT2860_RUNNING;
+
+ sc->periodic_round = 0;
+
+ callout_reset(&sc->periodic_ch, hz / 10, rt2860_periodic, sc);
+
+ return;
+
+fail:
+
+ rt2860_stop_locked(sc);
+}
+
+/*
+ * rt2860_init
+ */
+static void rt2860_init(void *priv)
+{
+ struct rt2860_softc *sc;
+
+ sc = priv;
+
+ RT2860_SOFTC_LOCK(sc);
+
+ rt2860_init_locked(sc);
+
+ RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_init_bbp
+ */
+static int rt2860_init_bbp(struct rt2860_softc *sc)
+{
+ int ntries, i;
+ uint8_t tmp;
+
+ for (ntries = 0; ntries < 20; ntries++)
+ {
+ tmp = rt2860_io_bbp_read(sc, 0);
+ if (tmp != 0x00 && tmp != 0xff)
+ break;
+ }
+
+ if (tmp == 0x00 || tmp == 0xff)
+ {
+ printf("%s: timeout waiting for BBP to wakeup\n",
+ device_get_nameunit(sc->dev));
+ return ETIMEDOUT;
+ }
+
+ for (i = 0; i < RT2860_DEF_BBP_SIZE; i++)
+ rt2860_io_bbp_write(sc, rt2860_def_bbp[i].reg,
+ rt2860_def_bbp[i].val);
+
+ if ((sc->mac_rev & 0xffff) != 0x0101)
+ rt2860_io_bbp_write(sc, 84, 0x19);
+
+// if (sc->mac_rev == 0x28600100)
+ if (sc->mac_rev == 0x28600102)
+ {
+ rt2860_io_bbp_write(sc, 69, 0x16);
+ rt2860_io_bbp_write(sc, 73, 0x12);
+ }
+
+ return 0;
+}
+
+/*
+ * rt2860_stop_locked
+ */
+static void rt2860_stop_locked(void *priv)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ uint32_t tmp;
+
+ sc = priv;
+ ic = &sc->sc_ic;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_ANY,
+ "%s: stopping\n",
+ device_get_nameunit(sc->dev));
+
+ RT2860_SOFTC_ASSERT_LOCKED(sc);
+
+ sc->tx_timer = 0;
+
+ if (sc->sc_flags & RT2860_RUNNING)
+ rt2860_led_cmd(sc, RT2860_LED_CMD_RADIO_OFF);
+
+ sc->sc_flags &= ~RT2860_RUNNING;
+
+ callout_stop(&sc->periodic_ch);
+ callout_stop(&sc->tx_watchdog_ch);
+
+ RT2860_SOFTC_UNLOCK(sc);
+
+ taskqueue_block(sc->taskqueue);
+
+ 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);
+
+ RT2860_SOFTC_LOCK(sc);
+
+ /* clear key tables */
+
+ rt2860_asic_clear_keytables(sc);
+
+ /* disable interrupts */
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_INT_MASK, 0);
+
+ /* disable Tx/Rx */
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_SYS_CTRL);
+
+ tmp &= ~(RT2860_REG_RX_ENABLE | RT2860_REG_TX_ENABLE);
+
+ rt2860_io_mac_write(sc, RT2860_REG_SYS_CTRL, tmp);
+
+ /* reset adapter */
+
+ rt2860_io_mac_write(sc, RT2860_REG_SYS_CTRL,
+ RT2860_REG_MAC_SRST | RT2860_REG_BBP_HRST);
+ rt2860_io_mac_write(sc, RT2860_REG_SYS_CTRL, 0);
+}
+
+/*
+ * rt2860_stop
+ */
+static void rt2860_stop(void *priv)
+{
+ struct rt2860_softc *sc;
+
+ sc = priv;
+
+ RT2860_SOFTC_LOCK(sc);
+
+ rt2860_stop_locked(sc);
+
+ RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_start
+ */
+static void rt2860_start(struct rt2860_softc *sc)
+{
+ struct ieee80211_frame *wh;
+ struct ieee80211_node *ni;
+ struct ieee80211_key *k;
+ struct mbuf *m;
+ int qid;
+
+ if (!(sc->sc_flags & RT2860_RUNNING))
+ return;
+
+ RT2860_SOFTC_LOCK(sc);
+
+ for (;;)
+ {
+ m = mbufq_dequeue(&sc->sc_snd);
+ if (m == NULL)
+ break;
+
+ ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
+
+ KASSERT(ni != NULL, ("%s:%d: fail", __func__, __LINE__));
+ wh = mtod(m, struct ieee80211_frame *);
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
+ k = ieee80211_crypto_encap(ni, m);
+ if (k == NULL) {
+ ieee80211_free_node(ni);
+ m_freem(m);
+ counter_u64_add(sc->sc_ic.ic_oerrors, 1);
+ continue;
+ }
+ }
+ wh = NULL; /* Catch any invalid use */
+
+ m->m_pkthdr.rcvif = NULL;
+
+ qid = M_WME_GETAC(m);
+
+ RT2860_SOFTC_TX_RING_LOCK(&sc->tx_ring[qid]);
+
+ if (sc->tx_ring[qid].data_queued >= RT2860_SOFTC_TX_RING_DATA_COUNT)
+ {
+ RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[qid]);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+ "%s: if_start: Tx ring with qid=%d is full\n",
+ device_get_nameunit(sc->dev), qid);
+
+ m_freem(m);
+ ieee80211_free_node(ni);
+
+ counter_u64_add(sc->sc_ic.ic_oerrors, 1);
+
+ sc->tx_data_queue_full[qid]++;
+
+ break;
+ }
+
+ if (rt2860_tx_data(sc, m, ni, qid) != 0)
+ {
+ RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[qid]);
+
+ ieee80211_free_node(ni);
+
+ counter_u64_add(sc->sc_ic.ic_oerrors, 1);
+
+ break;
+ }
+
+ RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[qid]);
+
+ rt2860_drain_fifo_stats(sc);
+
+ sc->tx_timer = RT2860_TX_WATCHDOG_TIMEOUT;
+
+ callout_reset(&sc->tx_watchdog_ch, hz, rt2860_tx_watchdog, sc);
+ }
+ RT2860_SOFTC_UNLOCK(sc);
+
+}
+
+/*
+ * rt2860_vap_create
+ */
+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 rt2860_softc *sc;
+ struct rt2860_softc_vap *rvap;
+ struct ieee80211vap *vap;
+
+ sc = ic->ic_softc;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_STATE,
+ "%s: VAP create: opmode=%s\n",
+ device_get_nameunit(sc->dev),
+ ieee80211_opmode_name[opmode]);
+
+ switch (opmode)
+ {
+ case IEEE80211_M_IBSS:
+ case IEEE80211_M_STA:
+ case IEEE80211_M_AHDEMO:
+ case IEEE80211_M_HOSTAP:
+ case IEEE80211_M_MBSS:
+ if ((sc->napvaps + sc->nadhocvaps + sc->nstavaps) != 0)
+ {
+ device_printf(sc->dev, "only 1 VAP supported\n");
+ return NULL;
+ }
+
+ if (opmode == IEEE80211_M_STA)
+ flags |= IEEE80211_CLONE_NOBEACONS;
+ break;
+
+ case IEEE80211_M_WDS:
+ if (sc->napvaps == 0)
+ {
+ device_printf(sc->dev, "WDS only supported in AP mode\n");
+ return NULL;
+ }
+ break;
+
+ case IEEE80211_M_MONITOR:
+ break;
+
+ default:
+ device_printf(sc->dev, "unknown opmode %d\n", opmode);
+ return NULL;
+ }
+
+ rvap = (struct rt2860_softc_vap *) malloc(sizeof(struct rt2860_softc_vap),
+ M_80211_VAP, M_NOWAIT | M_ZERO);
+ if (rvap == NULL)
+ return NULL;
+
+ vap = &rvap->vap;
+
+ ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid);
+
+ rvap->newstate = vap->iv_newstate;
+ vap->iv_newstate = rt2860_vap_newstate;
+
+ vap->iv_reset = rt2860_vap_reset;
+#ifdef RT2860_HW_CRYPTO
+ vap->iv_key_update_begin = rt2860_vap_key_update_begin;
+ vap->iv_key_update_end = rt2860_vap_key_update_end;
+ vap->iv_key_set = rt2860_vap_key_set;
+ vap->iv_key_delete = rt2860_vap_key_delete;
+#endif
+ vap->iv_update_beacon = rt2860_vap_update_beacon;
+
+ rt2860_amrr_init(&rvap->amrr, vap,
+ sc->ntxpath,
+ RT2860_AMRR_MIN_SUCCESS_THRESHOLD,
+ RT2860_AMRR_MAX_SUCCESS_THRESHOLD,
+ 500);
+
+ vap->iv_max_aid = RT2860_SOFTC_STAID_COUNT;
+
+ /* overwrite default Rx A-MPDU factor */
+
+ vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_32K;
+ vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_NA;
+ vap->iv_ampdu_limit = vap->iv_ampdu_rxmax;
+
+ ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status,
+ mac);
+
+ switch (vap->iv_opmode)
+ {
+ case IEEE80211_M_HOSTAP:
+ case IEEE80211_M_MBSS:
+ case IEEE80211_M_AHDEMO:
+ sc->napvaps++;
+ break;
+
+ case IEEE80211_M_IBSS:
+ sc->nadhocvaps++;
+ break;
+
+ case IEEE80211_M_STA:
+ sc->nstavaps++;
+ break;
+
+ case IEEE80211_M_WDS:
+ sc->nwdsvaps++;
+ break;
+
+ default:
+ break;
+ }
+
+ sc->nvaps++;
+
+ if (sc->napvaps > 0)
+ ic->ic_opmode = IEEE80211_M_HOSTAP;
+ else if (sc->nadhocvaps > 0)
+ ic->ic_opmode = IEEE80211_M_IBSS;
+ else if (sc->nstavaps > 0)
+ ic->ic_opmode = IEEE80211_M_STA;
+ else
+ ic->ic_opmode = opmode;
+
+ return vap;
+}
+
+/*
+ * rt2860_vap_delete
+ */
+static void rt2860_vap_delete(struct ieee80211vap *vap)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ struct rt2860_softc_vap *rvap;
+ enum ieee80211_opmode opmode;
+
+ ic = vap->iv_ic;
+ sc = ic->ic_softc;
+ rvap = (struct rt2860_softc_vap *) vap;
+ opmode = vap->iv_opmode;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_STATE,
+ "%s: VAP delete: opmode=%s\n",
+ device_get_nameunit(sc->dev), ieee80211_opmode_name[opmode]);
+
+ rt2860_amrr_cleanup(&rvap->amrr);
+
+ ieee80211_vap_detach(vap);
+
+ if (rvap->beacon_mbuf != NULL)
+ {
+ m_free(rvap->beacon_mbuf);
+ rvap->beacon_mbuf = NULL;
+ }
+
+ switch (opmode)
+ {
+ case IEEE80211_M_HOSTAP:
+ case IEEE80211_M_MBSS:
+ case IEEE80211_M_AHDEMO:
+ sc->napvaps--;
+ break;
+
+ case IEEE80211_M_IBSS:
+ sc->nadhocvaps--;
+ break;
+
+ case IEEE80211_M_STA:
+ sc->nstavaps--;
+ break;
+
+ case IEEE80211_M_WDS:
+ sc->nwdsvaps--;
+ break;
+
+ default:
+ break;
+ }
+
+ sc->nvaps--;
+
+ if (sc->napvaps > 0)
+ ic->ic_opmode = IEEE80211_M_HOSTAP;
+ else if (sc->nadhocvaps > 0)
+ ic->ic_opmode = IEEE80211_M_IBSS;
+ else if (sc->nstavaps > 0)
+ ic->ic_opmode = IEEE80211_M_STA;
+
+ free(rvap, M_80211_VAP);
+}
+
+/*
+ * rt2860_reset_vap
+ */
+static int rt2860_vap_reset(struct ieee80211vap *vap, u_long cmd)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ struct rt2860_softc_vap *rvap;
+ int error;
+
+ ic = vap->iv_ic;
+ sc = ic->ic_softc;
+ rvap = (struct rt2860_softc_vap *) vap;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_STATE,
+ "%s: VAP reset: cmd=%lu\n",
+ device_get_nameunit(sc->dev), cmd);
+
+ error = 0;
+
+ RT2860_SOFTC_LOCK(sc);
+
+ switch (cmd)
+ {
+ case IEEE80211_IOC_RTSTHRESHOLD:
+ case IEEE80211_IOC_AMSDU:
+ rt2860_asic_update_rtsthreshold(sc);
+ break;
+
+ case IEEE80211_IOC_PROTMODE:
+ case IEEE80211_IOC_HTPROTMODE:
+ rt2860_asic_updateprot(sc);
+ break;
+
+ case IEEE80211_IOC_TXPOWER:
+ rt2860_asic_update_txpower(sc);
+ break;
+
+ case IEEE80211_IOC_BURST:
+ rt2860_asic_updateslot(sc);
+ break;
+
+ case IEEE80211_IOC_SHORTGI:
+ case IEEE80211_IOC_AMPDU_DENSITY:
+ case IEEE80211_IOC_SMPS:
+ break;
+
+ default:
+ error = ENETRESET;
+ break;
+ }
+
+ RT2860_SOFTC_UNLOCK(sc);
+
+ return error;
+}
+
+/*
+ * rt2860_vap_newstate
+ */
+static int rt2860_vap_newstate(struct ieee80211vap *vap,
+ enum ieee80211_state nstate, int arg)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ struct rt2860_softc_vap *rvap;
+ struct ieee80211_node *ni;
+ enum ieee80211_state ostate;
+ int error;
+
+ ic = vap->iv_ic;
+ sc = ic->ic_softc;
+ rvap = (struct rt2860_softc_vap *) vap;
+
+ ostate = vap->iv_state;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_STATE,
+ "%s: VAP newstate: %s -> %s\n",
+ device_get_nameunit(sc->dev),
+ ieee80211_state_name[ostate], ieee80211_state_name[nstate]);
+
+ error = rvap->newstate(vap, nstate, arg);
+ if (error != 0)
+ return error;
+
+ IEEE80211_UNLOCK(ic);
+
+ RT2860_SOFTC_LOCK(sc);
+
+ /* turn link LED off */
+
+ if (nstate != IEEE80211_S_RUN)
+ rt2860_led_cmd(sc, RT2860_LED_CMD_RADIO_OFF);
+
+ switch (nstate)
+ {
+ case IEEE80211_S_INIT:
+ rt2860_asic_disable_tsf_sync(sc);
+ break;
+
+ case IEEE80211_S_RUN:
+ ni = vap->iv_bss;
+
+ rt2860_rf_set_chan(sc, ni->ni_chan);
+
+ if (vap->iv_opmode != IEEE80211_M_MONITOR)
+ {
+ rt2860_asic_enable_mrr(sc);
+ rt2860_asic_set_txpreamble(sc);
+ rt2860_asic_set_basicrates(sc);
+ rt2860_asic_update_txpower(sc);
+ rt2860_asic_set_bssid(sc, ni->ni_bssid);
+ }
+
+ if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
+ vap->iv_opmode == IEEE80211_M_IBSS ||
+ vap->iv_opmode == IEEE80211_M_MBSS)
+ {
+ error = rt2860_beacon_alloc(sc, vap);
+ if (error != 0)
+ break;
+
+ rt2860_asic_update_beacon(sc, vap);
+ }
+
+ if (vap->iv_opmode != IEEE80211_M_MONITOR)
+ rt2860_asic_enable_tsf_sync(sc);
+
+ /* turn link LED on */
+
+ if (vap->iv_opmode != IEEE80211_M_MONITOR)
+ {
+ rt2860_led_cmd(sc, RT2860_LED_CMD_RADIO_ON |
+ (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) ?
+ RT2860_LED_CMD_LINK_2GHZ : RT2860_LED_CMD_LINK_5GHZ));
+ }
+ break;
+
+ case IEEE80211_S_SLEEP:
+ break;
+
+ default:
+ break;
+ }
+
+ RT2860_SOFTC_UNLOCK(sc);
+
+ IEEE80211_LOCK(ic);
+
+ return error;
+}
+
+#ifdef RT2860_HW_CRYPTO
+/*
+ * rt2860_vap_key_update_begin
+ */
+static void rt2860_vap_key_update_begin(struct ieee80211vap *vap)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+
+ ic = vap->iv_ic;
+ sc = ic->ic_softc;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_KEY,
+ "%s: VAP key update begin\n",
+ device_get_nameunit(sc->dev));
+
+ taskqueue_block(sc->taskqueue);
+
+// IF_LOCK(&ifp->if_snd);
+}
+
+/*
+ * rt2860_vap_key_update_end
+ */
+static void rt2860_vap_key_update_end(struct ieee80211vap *vap)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+
+ ic = vap->iv_ic;
+ sc = ic->ic_softc;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_KEY,
+ "%s: VAP key update end\n",
+ device_get_nameunit(sc->dev));
+
+// IF_UNLOCK(&ifp->if_snd);
+
+ taskqueue_unblock(sc->taskqueue);
+}
+
+/*
+ * rt2860_vap_key_set
+ */
+static int rt2860_vap_key_set(struct ieee80211vap *vap,
+ const struct ieee80211_key *k)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ struct ieee80211_node *ni;
+ struct rt2860_softc_node *rni;
+ uint16_t key_base, keymode_base;
+ uint8_t mode, vapid, wcid, iv[8];
+ uint32_t tmp;
+
+ switch (k->wk_cipher->ic_cipher)
+ {
+ case IEEE80211_CIPHER_WEP:
+ if(k->wk_keylen < 8)
+ mode = RT2860_REG_CIPHER_MODE_WEP40;
+ else
+ mode = RT2860_REG_CIPHER_MODE_WEP104;
+ break;
+
+ case IEEE80211_CIPHER_TKIP:
+ mode = RT2860_REG_CIPHER_MODE_TKIP;
+ break;
+
+ case IEEE80211_CIPHER_AES_CCM:
+ mode = RT2860_REG_CIPHER_MODE_AES_CCMP;
+ break;
+
+ default:
+ printf("Wrong key CIPHER (%d)\n", k->wk_cipher->ic_cipher);
+ return 0;
+ }
+
+ ic = vap->iv_ic;
+ sc = ic->ic_softc;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_KEY,
+ "%s: VAP key set: keyix=%d, keylen=%d, macaddr=%s, mode=%d, group=%d\n",
+ device_get_nameunit(sc->dev), k->wk_keyix, k->wk_keylen, ether_sprintf(k->wk_macaddr),
+ mode, (k->wk_flags & IEEE80211_KEY_GROUP) ? 1 : 0);
+
+ if (!(k->wk_flags & IEEE80211_KEY_GROUP))
+ {
+ /* install pairwise key */
+
+ if (vap->iv_opmode == IEEE80211_M_HOSTAP)
+ ni = ieee80211_find_vap_node(&ic->ic_sta, vap, ic->ic_macaddr);
+ else
+ ni = vap->iv_bss;
+
+ rni = (struct rt2860_softc_node *) ni;
+
+ vapid = 0;
+ wcid = (ni != NULL) ? rni->staid : 0;
+ key_base = RT2860_REG_PKEY(wcid);
+
+ if (ni != NULL)
+ ieee80211_free_node(ni);
+
+ if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_WEP)
+ {
+ memset(iv, 0, 8);
+
+ iv[3] = (k->wk_keyix << 6);
+ }
+ else
+ {
+ if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP)
+ {
+ iv[0] = (k->wk_keytsc >> 8);
+ iv[1] = ((iv[0] | 0x20) & 0x7f);
+ iv[2] = k->wk_keytsc;
+ }
+ else
+ {
+ /* AES CCMP */
+ iv[0] = k->wk_keytsc;
+ iv[1] = k->wk_keytsc >> 8;
+ iv[2] = 0;
+ }
+
+ iv[3] = ((k->wk_keyix << 6) | IEEE80211_WEP_EXTIV);
+ iv[4] = (k->wk_keytsc >> 16);
+ iv[5] = (k->wk_keytsc >> 24);
+ iv[6] = (k->wk_keytsc >> 32);
+ iv[7] = (k->wk_keytsc >> 40);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_KEY,
+ "%s: VAP key set: iv=%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ device_get_nameunit(sc->dev),
+ iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]);
+ }
+
+ rt2860_io_mac_write_multi(sc, RT2860_REG_IVEIV(wcid), iv, 8);
+
+ if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP)
+ {
+ rt2860_io_mac_write_multi(sc, key_base, k->wk_key, 16);
+
+ if (vap->iv_opmode != IEEE80211_M_HOSTAP)
+ {
+ rt2860_io_mac_write_multi(sc, key_base + 16, &k->wk_key[16], 8);
+ rt2860_io_mac_write_multi(sc, key_base + 24, &k->wk_key[24], 8);
+ }
+ else
+ {
+ rt2860_io_mac_write_multi(sc, key_base + 16, &k->wk_key[24], 8);
+ rt2860_io_mac_write_multi(sc, key_base + 24, &k->wk_key[16], 8);
+ }
+ }
+ else
+ {
+ rt2860_io_mac_write_multi(sc, key_base, k->wk_key, k->wk_keylen);
+ }
+ tmp = ((vapid & RT2860_REG_VAP_MASK) << RT2860_REG_VAP_SHIFT) |
+ (mode << RT2860_REG_CIPHER_MODE_SHIFT) | RT2860_REG_PKEY_ENABLE;
+
+ rt2860_io_mac_write(sc, RT2860_REG_WCID_ATTR(wcid), tmp);
+ }
+
+ if ((k->wk_flags & IEEE80211_KEY_GROUP) ||
+ (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_WEP))
+ {
+ /* install group key */
+
+ vapid = 0;
+ wcid = RT2860_WCID_MCAST;
+ key_base = RT2860_REG_SKEY(vapid, k->wk_keyix);
+ keymode_base = RT2860_REG_SKEY_MODE(vapid);
+
+ if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP)
+ {
+ rt2860_io_mac_write_multi(sc, key_base, k->wk_key, 16);
+
+ if (vap->iv_opmode != IEEE80211_M_HOSTAP)
+ {
+ rt2860_io_mac_write_multi(sc, key_base + 16, &k->wk_key[16], 8);
+ rt2860_io_mac_write_multi(sc, key_base + 24, &k->wk_key[24], 8);
+ }
+ else
+ {
+ rt2860_io_mac_write_multi(sc, key_base + 16, &k->wk_key[24], 8);
+ rt2860_io_mac_write_multi(sc, key_base + 24, &k->wk_key[16], 8);
+ }
+ }
+ else
+ {
+ rt2860_io_mac_write_multi(sc, key_base, k->wk_key, k->wk_keylen);
+ }
+
+ tmp = rt2860_io_mac_read(sc, keymode_base);
+
+ tmp &= ~(0xf << (k->wk_keyix * 4 + 16 * (vapid % 2)));
+ tmp |= (mode << (k->wk_keyix * 4 + 16 * (vapid % 2)));
+
+ rt2860_io_mac_write(sc, keymode_base, tmp);
+
+ if (vap->iv_opmode == IEEE80211_M_HOSTAP)
+ {
+ if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_WEP)
+ {
+ memset(iv, 0, 8);
+
+ iv[3] = (k->wk_keyix << 6);
+ }
+ else
+ {
+ if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP)
+ {
+ iv[0] = (k->wk_keytsc >> 8);
+ iv[1] = ((iv[0] | 0x20) & 0x7f);
+ iv[2] = k->wk_keytsc;
+ }
+ else
+ {
+ /* AES CCMP */
+
+ iv[0] = k->wk_keytsc;
+ iv[1] = k->wk_keytsc >> 8;
+ iv[2] = 0;
+ }
+
+ iv[3] = ((k->wk_keyix << 6) | IEEE80211_WEP_EXTIV);
+ iv[4] = (k->wk_keytsc >> 16);
+ iv[5] = (k->wk_keytsc >> 24);
+ iv[6] = (k->wk_keytsc >> 32);
+ iv[7] = (k->wk_keytsc >> 40);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_KEY,
+ "%s: VAP key set: iv=%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ device_get_nameunit(sc->dev),
+ iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]);
+ }
+
+ rt2860_io_mac_write_multi(sc, RT2860_REG_IVEIV(wcid), iv, 8);
+
+ tmp = ((vapid & RT2860_REG_VAP_MASK) << RT2860_REG_VAP_SHIFT) |
+ (mode << RT2860_REG_CIPHER_MODE_SHIFT);
+
+ rt2860_io_mac_write(sc, RT2860_REG_WCID_ATTR(wcid), tmp);
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * rt2860_vap_key_delete
+ */
+static int rt2860_vap_key_delete(struct ieee80211vap *vap,
+ const struct ieee80211_key *k)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ uint8_t vapid, wcid;
+ uint32_t tmp;
+
+ ic = vap->iv_ic;
+ sc = ic->ic_softc;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_KEY,
+ "%s: VAP key delete: keyix=%d, keylen=%d, macaddr=%s, group=%d\n",
+ device_get_nameunit(sc->dev), k->wk_keyix, k->wk_keylen, ether_sprintf(k->wk_macaddr),
+ (k->wk_flags & IEEE80211_KEY_GROUP) ? 1 : 0);
+
+ if (k->wk_flags & IEEE80211_KEY_GROUP)
+ {
+ /* remove group key */
+
+ vapid = 0;
+ wcid = RT2860_WCID_MCAST;
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_SKEY_MODE(vapid));
+
+ tmp &= ~(0xf << (k->wk_keyix * 4 + 16 * (vapid % 2)));
+ tmp |= (RT2860_REG_CIPHER_MODE_NONE << (k->wk_keyix * 4 + 16 * (vapid % 2)));
+
+ rt2860_io_mac_write(sc, RT2860_REG_SKEY_MODE(vapid), tmp);
+
+ if (vap->iv_opmode == IEEE80211_M_HOSTAP)
+ {
+ tmp = ((vapid & RT2860_REG_VAP_MASK) << RT2860_REG_VAP_SHIFT) |
+ (RT2860_REG_CIPHER_MODE_NONE << RT2860_REG_CIPHER_MODE_SHIFT) | RT2860_REG_PKEY_ENABLE;
+
+ rt2860_io_mac_write(sc, RT2860_REG_WCID_ATTR(wcid), tmp);
+ }
+ }
+
+ return 1;
+}
+#endif
+
+/*
+ * rt2860_vap_update_beacon
+ */
+static void rt2860_vap_update_beacon(struct ieee80211vap *vap, int what)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ struct rt2860_softc_vap *rvap;
+ struct mbuf *m;
+ struct ieee80211_beacon_offsets *bo;
+ int error;
+
+ ic = vap->iv_ic;
+ sc = ic->ic_softc;
+ rvap = (struct rt2860_softc_vap *) vap;
+ m = rvap->beacon_mbuf;
+ bo = &rvap->beacon_offsets;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_BEACON,
+ "%s: VAP update beacon: what=%d\n",
+ device_get_nameunit(sc->dev), what);
+
+ setbit(bo->bo_flags, what);
+
+ if (m == NULL)
+ {
+ error = rt2860_beacon_alloc(sc, vap);
+ if (error != 0)
+ return;
+
+ m = rvap->beacon_mbuf;
+ }
+
+ ieee80211_beacon_update(vap->iv_bss, m, 0);
+
+ rt2860_asic_update_beacon(sc, vap);
+}
+
+/*
+ * rt2860_node_alloc
+ */
+static struct ieee80211_node *rt2860_node_alloc(struct ieee80211vap *vap,
+ const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+ return malloc(sizeof(struct rt2860_softc_node),
+ M_80211_NODE, M_NOWAIT | M_ZERO);
+}
+
+/*
+ * rt2860_node_cleanup
+ */
+static void rt2860_node_cleanup(struct ieee80211_node *ni)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ struct rt2860_softc_node *rni;
+ uint8_t vapid, wcid;
+ uint32_t tmp;
+
+ ic = ni->ni_ic;
+ sc = ic->ic_softc;
+ rni = (struct rt2860_softc_node *) ni;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_NODE,
+ "%s: node cleanup: macaddr=%s, associd=0x%04x, staid=0x%02x\n",
+ device_get_nameunit(sc->dev), ether_sprintf(ni->ni_macaddr),
+ ni->ni_associd, rni->staid);
+
+ if (rni->staid != 0)
+ {
+ vapid = 0;
+ wcid = rni->staid;
+
+ tmp = ((vapid & RT2860_REG_VAP_MASK) << RT2860_REG_VAP_SHIFT) |
+ (RT2860_REG_CIPHER_MODE_NONE << RT2860_REG_CIPHER_MODE_SHIFT) | RT2860_REG_PKEY_ENABLE;
+
+ rt2860_io_mac_write(sc, RT2860_REG_WCID_ATTR(wcid), tmp);
+
+ rt2860_io_mac_write(sc, RT2860_REG_WCID(wcid), 0x00000000);
+ rt2860_io_mac_write(sc, RT2860_REG_WCID(wcid) + 4, 0x00000000);
+
+ rt2860_staid_delete(sc, rni->staid);
+
+ rni->staid = 0;
+ }
+
+ sc->node_cleanup(ni);
+}
+
+/*
+ * rt2860_setregdomain
+ */
+static int rt2860_setregdomain(struct ieee80211com *ic,
+ struct ieee80211_regdomain *reg,
+ int nchans, struct ieee80211_channel chans[])
+{
+ struct rt2860_softc *sc;
+
+ sc = ic->ic_softc;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_STATE,
+ "%s: set regulatory domain: country=%d, country code string=%c%c, location=%c\n",
+ device_get_nameunit(sc->dev),
+ reg->country, reg->isocc[0], reg->isocc[1], reg->location);
+
+ return 0;
+}
+
+/*
+ * rt2860_getradiocaps
+ */
+static void rt2860_getradiocaps(struct ieee80211com *ic,
+ int maxchans, int *nchans, struct ieee80211_channel chans[])
+{
+ *nchans = (ic->ic_nchans >= maxchans) ? maxchans : ic->ic_nchans;
+
+ memcpy(chans, ic->ic_channels, (*nchans) * sizeof(struct ieee80211_channel));
+}
+
+/*
+ * rt2860_scan_start
+ */
+static void rt2860_scan_start(struct ieee80211com *ic)
+{
+ struct rt2860_softc *sc;
+
+ sc = ic->ic_softc;
+
+ RT2860_SOFTC_LOCK(sc);
+
+ rt2860_asic_disable_tsf_sync(sc);
+
+ RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_scan_end
+ */
+static void rt2860_scan_end(struct ieee80211com *ic)
+{
+ struct rt2860_softc *sc;
+
+ sc = ic->ic_softc;
+
+ RT2860_SOFTC_LOCK(sc);
+
+ rt2860_asic_enable_tsf_sync(sc);
+
+ RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_set_channel
+ */
+static void rt2860_set_channel(struct ieee80211com *ic)
+{
+ struct rt2860_softc *sc;
+
+ sc = ic->ic_softc;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_CHAN,
+ "%s: set channel: channel=%u, HT%s%s\n",
+ device_get_nameunit(sc->dev),
+ ieee80211_chan2ieee(ic, ic->ic_curchan),
+ !IEEE80211_IS_CHAN_HT(ic->ic_curchan) ? " disabled" :
+ IEEE80211_IS_CHAN_HT20(ic->ic_curchan) ? "20":
+ IEEE80211_IS_CHAN_HT40U(ic->ic_curchan) ? "40U" : "40D",
+ (ic->ic_flags & IEEE80211_F_SCAN) ? ", scanning" : "");
+
+ RT2860_SOFTC_LOCK(sc);
+
+ rt2860_rf_set_chan(sc, ic->ic_curchan);
+
+ RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_newassoc
+ */
+static void rt2860_newassoc(struct ieee80211_node *ni, int isnew)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ struct ieee80211vap *vap;
+ struct rt2860_softc_vap *rvap;
+ struct rt2860_softc_node *rni;
+ uint16_t aid;
+ uint8_t wcid;
+ uint32_t tmp;
+
+ vap = ni->ni_vap;
+ ic = vap->iv_ic;
+ sc = ic->ic_softc;
+ rvap = (struct rt2860_softc_vap *) vap;
+ rni = (struct rt2860_softc_node *) ni;
+
+ if (isnew)
+ {
+ aid = IEEE80211_AID(ni->ni_associd);
+ rni->staid = rt2860_staid_alloc(sc, aid);
+ wcid = rni->staid;
+
+ tmp = (ni->ni_macaddr[3] << 24) |
+ (ni->ni_macaddr[2] << 16) |
+ (ni->ni_macaddr[1] << 8) |
+ ni->ni_macaddr[0];
+
+ rt2860_io_mac_write(sc, RT2860_REG_WCID(wcid), tmp);
+
+ tmp = (ni->ni_macaddr[5] << 8) |
+ ni->ni_macaddr[4];
+
+ rt2860_io_mac_write(sc, RT2860_REG_WCID(wcid) + 4, tmp);
+
+ rt2860_amrr_node_init(&rvap->amrr, &sc->amrr_node[wcid], ni);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_RATE,
+ "%s: initial%s node Tx rate: associd=0x%04x, rate=0x%02x, max rate=0x%02x\n",
+ device_get_nameunit(sc->dev),
+ (ni->ni_flags & IEEE80211_NODE_HT) ? " HT" : "",
+ ni->ni_associd, ni->ni_txrate,
+ (ni->ni_flags & IEEE80211_NODE_HT) ?
+ (ni->ni_htrates.rs_rates[ni->ni_htrates.rs_nrates - 1] | IEEE80211_RATE_MCS) :
+ (ni->ni_rates.rs_rates[ni->ni_rates.rs_nrates - 1] & IEEE80211_RATE_VAL));
+
+ rt2860_asic_updateprot(sc);
+ rt2860_asic_updateslot(sc);
+ rt2860_asic_set_txpreamble(sc);
+ }
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_NODE,
+ "%s: new association: isnew=%d, macaddr=%s, associd=0x%04x, staid=0x%02x, QoS %s, ERP %s, HT %s\n",
+ device_get_nameunit(sc->dev), isnew, ether_sprintf(ni->ni_macaddr),
+ ni->ni_associd, rni->staid,
+ (ni->ni_flags & IEEE80211_NODE_QOS) ? "enabled" : "disabled",
+ (ni->ni_flags & IEEE80211_NODE_ERP) ? "enabled" : "disabled",
+ (ni->ni_flags & IEEE80211_NODE_HT) ? "enabled" : "disabled");
+}
+
+/*
+ * rt2860_updateslot
+ */
+static void rt2860_updateslot(struct ieee80211com *ic)
+{
+ struct rt2860_softc *sc;
+
+ sc = ic->ic_softc;
+
+ rt2860_asic_updateslot(sc);
+}
+
+/*
+ * rt2860_update_promisc
+ */
+static void rt2860_update_promisc(struct ieee80211com *ic)
+{
+ struct rt2860_softc *sc;
+
+ sc = ic->ic_softc;
+
+ RT2860_SOFTC_LOCK(sc);
+ rt2860_asic_update_promisc(sc);
+ RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_wme_update
+ */
+static int rt2860_wme_update(struct ieee80211com *ic)
+{
+ struct rt2860_softc *sc;
+
+ sc = ic->ic_softc;
+
+ rt2860_asic_wme_update(sc);
+
+ return 0;
+}
+
+/*
+ * rt2860_raw_xmit
+ */
+static int rt2860_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
+ const struct ieee80211_bpf_params *params)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+
+ ic = ni->ni_ic;
+ sc = ic->ic_softc;
+
+ if (!(sc->sc_flags & RT2860_RUNNING))
+ {
+ m_freem(m);
+ ieee80211_free_node(ni);
+
+ return ENETDOWN;
+ }
+
+ RT2860_SOFTC_TX_RING_LOCK(&sc->tx_ring[sc->tx_ring_mgtqid]);
+
+ if (sc->tx_ring[sc->tx_ring_mgtqid].data_queued >= RT2860_SOFTC_TX_RING_DATA_COUNT)
+ {
+ RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[sc->tx_ring_mgtqid]);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+ "%s: raw xmit: Tx ring with qid=%d is full\n",
+ device_get_nameunit(sc->dev), sc->tx_ring_mgtqid);
+
+ m_freem(m);
+ ieee80211_free_node(ni);
+
+ sc->tx_data_queue_full[sc->tx_ring_mgtqid]++;
+
+ return ENOBUFS;
+ }
+
+ if (rt2860_tx_mgmt(sc, m, ni, sc->tx_ring_mgtqid) != 0)
+ {
+ RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[sc->tx_ring_mgtqid]);
+
+ counter_u64_add(sc->sc_ic.ic_oerrors, 1);
+
+ ieee80211_free_node(ni);
+
+ return EIO;
+ }
+
+ RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[sc->tx_ring_mgtqid]);
+
+ sc->tx_timer = RT2860_TX_WATCHDOG_TIMEOUT;
+
+ return 0;
+}
+
+/*
+ * rt2860_recv_action
+ */
+
+#define LE_READ_2(p) \
+ ((uint16_t) \
+ ((((const uint8_t *)(p))[0] ) | \
+ (((const uint8_t *)(p))[1] << 8)))
+
+static int rt2860_recv_action(struct ieee80211_node *ni,
+ const struct ieee80211_frame *wh,
+ const uint8_t *frm, const uint8_t *efrm)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ struct rt2860_softc_node *rni;
+ const struct ieee80211_action *ia;
+ uint16_t baparamset;
+ uint8_t wcid;
+ int tid;
+
+ ic = ni->ni_ic;
+ sc = ic->ic_softc;
+ rni = (struct rt2860_softc_node *) ni;
+
+ ia = (const struct ieee80211_action *) frm;
+
+ if (ia->ia_category == IEEE80211_ACTION_CAT_BA)
+ {
+ switch (ia->ia_action)
+ {
+ /* IEEE80211_ACTION_BA_DELBA */
+ case IEEE80211_ACTION_BA_DELBA:
+ baparamset = LE_READ_2(frm + 2);
+ tid = RT2860_MS(baparamset, IEEE80211_BAPS_TID);
+ wcid = rni->staid;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+ "%s: received DELBA request: associd=0x%04x, staid=0x%02x, tid=%d\n",
+ device_get_nameunit(sc->dev), ni->ni_associd, rni->staid, tid);
+
+ if (rni->staid != 0) {
+ RT2860_SOFTC_LOCK(sc);
+
+ rt2860_asic_del_ba_session(sc, wcid, tid);
+ RT2860_SOFTC_UNLOCK(sc);
+
+ }
+ break;
+ }
+ }
+
+ return sc->recv_action(ni, wh, frm, efrm);
+}
+
+/*
+ * rt2860_send_action
+ */
+static int rt2860_send_action(struct ieee80211_node *ni,
+ int cat, int act, void *sa)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ struct rt2860_softc_node *rni;
+ uint16_t *args, status, baparamset;
+ uint8_t wcid;
+ int tid, bufsize;
+
+ ic = ni->ni_ic;
+ sc = ic->ic_softc;
+ rni = (struct rt2860_softc_node *) ni;
+
+ wcid = rni->staid;
+ args = sa;
+
+ if (cat == IEEE80211_ACTION_CAT_BA)
+ {
+ switch (act)
+ {
+ /* IEEE80211_ACTION_BA_ADDBA_RESPONSE */
+ case IEEE80211_ACTION_BA_ADDBA_RESPONSE:
+ status = args[1];
+ baparamset = args[2];
+ tid = RT2860_MS(baparamset, IEEE80211_BAPS_TID);
+ bufsize = RT2860_MS(baparamset, IEEE80211_BAPS_BUFSIZ);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+ "%s: sending ADDBA response: associd=0x%04x, staid=0x%02x, status=%d, tid=%d, bufsize=%d\n",
+ device_get_nameunit(sc->dev), ni->ni_associd, rni->staid, status, tid, bufsize);
+
+ if (status == IEEE80211_STATUS_SUCCESS) {
+ RT2860_SOFTC_LOCK(sc);
+
+ rt2860_asic_add_ba_session(sc, wcid, tid);
+ RT2860_SOFTC_UNLOCK(sc);
+
+ }
+ break;
+
+ /* IEEE80211_ACTION_BA_DELBA */
+ case IEEE80211_ACTION_BA_DELBA:
+ baparamset = RT2860_SM(args[0], IEEE80211_DELBAPS_TID) | args[1];
+ tid = RT2860_MS(baparamset, IEEE80211_DELBAPS_TID);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+ "%s: sending DELBA request: associd=0x%04x, staid=0x%02x, tid=%d\n",
+ device_get_nameunit(sc->dev), ni->ni_associd, rni->staid, tid);
+
+ if (RT2860_MS(baparamset, IEEE80211_DELBAPS_INIT) != IEEE80211_DELBAPS_INIT) {
+ RT2860_SOFTC_LOCK(sc);
+
+ rt2860_asic_del_ba_session(sc, wcid, tid);
+ RT2860_SOFTC_UNLOCK(sc);
+
+ }
+ break;
+ }
+ }
+
+ return sc->send_action(ni, cat, act, sa);
+}
+
+/*
+ * rt2860_addba_response
+ */
+static int rt2860_addba_response(struct ieee80211_node *ni,
+ struct ieee80211_tx_ampdu *tap,
+ int status, int baparamset, int batimeout)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ struct rt2860_softc_node *rni;
+ ieee80211_seq seqno;
+ int ret, tid, old_bufsize, new_bufsize;
+
+ ic = ni->ni_ic;
+ sc = ic->ic_softc;
+ rni = (struct rt2860_softc_node *) ni;
+
+ tid = RT2860_MS(baparamset, IEEE80211_BAPS_TID);
+ old_bufsize = RT2860_MS(baparamset, IEEE80211_BAPS_BUFSIZ);
+ new_bufsize = old_bufsize;
+
+ if (status == IEEE80211_STATUS_SUCCESS)
+ {
+ if (sc->mac_rev >= 0x28830300)
+ {
+ if (sc->mac_rev >= 0x30700200)
+ new_bufsize = 13;
+ else
+ new_bufsize = 31;
+ }
+ else if (sc->mac_rev >= 0x28720200)
+ {
+ new_bufsize = 13;
+ }
+ else
+ {
+ new_bufsize = 7;
+ }
+
+ if (old_bufsize > new_bufsize)
+ {
+ baparamset &= ~IEEE80211_BAPS_BUFSIZ;
+ baparamset = RT2860_SM(new_bufsize, IEEE80211_BAPS_BUFSIZ);
+ }
+
+ if (!(tap->txa_flags & IEEE80211_AGGR_RUNNING))
+ {
+ sc->tx_ampdu_sessions++;
+
+ if (sc->tx_ampdu_sessions == 1) {
+ RT2860_SOFTC_LOCK(sc);
+
+ rt2860_asic_updateprot(sc);
+ RT2860_SOFTC_UNLOCK(sc);
+
+ }
+ }
+ }
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+ "%s: received ADDBA response: associd=0x%04x, staid=0x%02x, status=%d, tid=%d, "
+ "old bufsize=%d, new bufsize=%d\n",
+ device_get_nameunit(sc->dev), ni->ni_associd, rni->staid, status, tid,
+ old_bufsize, new_bufsize);
+
+ ret = sc->addba_response(ni, tap, status, baparamset, batimeout);
+
+ if (status == IEEE80211_STATUS_SUCCESS)
+ {
+ seqno = ni->ni_txseqs[tid];
+
+ rt2860_send_bar(ni, tap, seqno);
+ }
+
+ return ret;
+}
+
+/*
+ * rt2860_addba_stop
+ */
+static void rt2860_addba_stop(struct ieee80211_node *ni,
+ struct ieee80211_tx_ampdu *tap)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ struct rt2860_softc_node *rni;
+ int tid;
+
+ ic = ni->ni_ic;
+ sc = ic->ic_softc;
+ rni = (struct rt2860_softc_node *) ni;
+
+// tid = WME_AC_TO_TID(tap->txa_ac);
+ tid = WME_AC_TO_TID(tap->txa_tid);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+ "%s: stopping A-MPDU Tx: associd=0x%04x, staid=0x%02x, tid=%d\n",
+ device_get_nameunit(sc->dev), ni->ni_associd, rni->staid, tid);
+
+ if (tap->txa_flags & IEEE80211_AGGR_RUNNING)
+ {
+ if (sc->tx_ampdu_sessions > 0)
+ {
+ sc->tx_ampdu_sessions--;
+
+ if (sc->tx_ampdu_sessions == 0) {
+ RT2860_SOFTC_LOCK(sc);
+
+ rt2860_asic_updateprot(sc);
+ RT2860_SOFTC_UNLOCK(sc);
+
+ }
+ }
+ else
+ {
+ printf("%s: number of A-MPDU Tx sessions cannot be negative\n",
+ device_get_nameunit(sc->dev));
+ }
+ }
+
+ sc->addba_stop(ni, tap);
+}
+
+/*
+ * rt2860_ampdu_rx_start
+ */
+static int rt2860_ampdu_rx_start(struct ieee80211_node *ni,
+ struct ieee80211_rx_ampdu *rap,
+ int baparamset, int batimeout, int baseqctl)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ struct rt2860_softc_node *rni;
+ int tid;
+
+ ic = ni->ni_ic;
+ sc = ic->ic_softc;
+ rni = (struct rt2860_softc_node *) ni;
+
+ tid = RT2860_MS(baparamset, IEEE80211_BAPS_TID);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+ "%s: starting A-MPDU Rx: associd=0x%04x, staid=0x%02x, tid=%d\n",
+ device_get_nameunit(sc->dev), ni->ni_associd, rni->staid, tid);
+
+ if (!(rap->rxa_flags & IEEE80211_AGGR_RUNNING))
+ sc->rx_ampdu_sessions++;
+
+ return sc->ampdu_rx_start(ni, rap, baparamset, batimeout, baseqctl);
+}
+
+/*
+ * rt2860_ampdu_rx_stop
+ */
+static void rt2860_ampdu_rx_stop(struct ieee80211_node *ni,
+ struct ieee80211_rx_ampdu *rap)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ struct rt2860_softc_node *rni;
+
+ ic = ni->ni_ic;
+ sc = ic->ic_softc;
+ rni = (struct rt2860_softc_node *) ni;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+ "%s: stopping A-MPDU Rx: associd=0x%04x, staid=0x%02x\n",
+ device_get_nameunit(sc->dev), ni->ni_associd, rni->staid);
+
+ if (rap->rxa_flags & IEEE80211_AGGR_RUNNING)
+ {
+ if (sc->rx_ampdu_sessions > 0)
+ sc->rx_ampdu_sessions--;
+ else
+ printf("%s: number of A-MPDU Rx sessions cannot be negative\n",
+ device_get_nameunit(sc->dev));
+ }
+
+ sc->ampdu_rx_stop(ni, rap);
+}
+
+/*
+ * rt2860_send_bar
+ */
+static int rt2860_send_bar(struct ieee80211_node *ni,
+ struct ieee80211_tx_ampdu *tap, ieee80211_seq seqno)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ struct ieee80211vap *vap;
+ struct ieee80211_frame_bar *bar;
+ struct rt2860_softc_node *rni;
+ struct mbuf *m;
+ uint16_t barctl, barseqctl;
+ uint8_t *frm;
+ int ret, tid;
+
+ ic = ni->ni_ic;
+ sc = ic->ic_softc;
+ vap = ni->ni_vap;
+ rni = (struct rt2860_softc_node *) ni;
+
+ if (!(tap->txa_flags & IEEE80211_AGGR_RUNNING))
+ return EINVAL;
+
+ m = ieee80211_getmgtframe(&frm, ic->ic_headroom, sizeof(struct ieee80211_frame_bar));
+ if (m == NULL)
+ return ENOMEM;
+
+ bar = mtod(m, struct ieee80211_frame_bar *);
+
+ bar->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_BAR;
+ bar->i_fc[1] = 0;
+
+ IEEE80211_ADDR_COPY(bar->i_ra, ni->ni_macaddr);
+ IEEE80211_ADDR_COPY(bar->i_ta, vap->iv_myaddr);
+
+// tid = WME_AC_TO_TID(tap->txa_ac);
+ tid = WME_AC_TO_TID(tap->txa_tid);
+
+ barctl = (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE ? 0 : IEEE80211_BAR_NOACK) |
+ IEEE80211_BAR_COMP |
+ RT2860_SM(tid, IEEE80211_BAR_TID);
+ barseqctl = RT2860_SM(seqno, IEEE80211_BAR_SEQ_START);
+
+ bar->i_ctl = htole16(barctl);
+ bar->i_seq = htole16(barseqctl);
+
+ m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_bar);
+
+ tap->txa_start = seqno;
+
+ ieee80211_ref_node(ni);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+ "%s: sending BAR: associd=0x%04x, staid=0x%02x, tid=%d, seqno=%d\n",
+ device_get_nameunit(sc->dev), ni->ni_associd, rni->staid, tid, seqno);
+
+ ret = ic->ic_raw_xmit(ni, m, NULL);
+ if (ret != 0)
+ ieee80211_free_node(ni);
+
+ return ret;
+}
+
+/*
+ * rt2860_amrr_update_iter_func
+ */
+static void rt2860_amrr_update_iter_func(void *arg, struct ieee80211_node *ni)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ struct ieee80211vap *vap;
+ struct rt2860_softc_vap *rvap;
+ struct rt2860_softc_node *rni;
+ uint8_t wcid;
+
+ vap = arg;
+ ic = vap->iv_ic;
+ sc = ic->ic_softc;
+ rvap = (struct rt2860_softc_vap *) vap;
+ rni = (struct rt2860_softc_node *) ni;
+
+ /* only associated stations */
+
+ if ((ni->ni_vap == vap) && (rni->staid != 0))
+ {
+ wcid = rni->staid;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_RATE,
+ "%s: AMRR node: staid=0x%02x, txcnt=%d, success=%d, retrycnt=%d\n",
+ device_get_nameunit(sc->dev),
+ rni->staid, sc->amrr_node[wcid].txcnt, sc->amrr_node[wcid].success, sc->amrr_node[wcid].retrycnt);
+
+ rt2860_amrr_choose(ni, &sc->amrr_node[wcid]);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_RATE,
+ "%s:%s node Tx rate: associd=0x%04x, staid=0x%02x, rate=0x%02x, max rate=0x%02x\n",
+ device_get_nameunit(sc->dev),
+ (ni->ni_flags & IEEE80211_NODE_HT) ? " HT" : "",
+ ni->ni_associd, rni->staid, ni->ni_txrate,
+ (ni->ni_flags & IEEE80211_NODE_HT) ?
+ (ni->ni_htrates.rs_rates[ni->ni_htrates.rs_nrates - 1] | IEEE80211_RATE_MCS) :
+ (ni->ni_rates.rs_rates[ni->ni_rates.rs_nrates - 1] & IEEE80211_RATE_VAL));
+ }
+}
+
+/*
+ * rt2860_periodic
+ */
+static void rt2860_periodic(void *arg)
+{
+ struct rt2860_softc *sc;
+
+ sc = arg;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_PERIODIC,
+ "%s: periodic\n",
+ device_get_nameunit(sc->dev));
+
+ taskqueue_enqueue(sc->taskqueue, &sc->periodic_task);
+}
+
+/*
+ * rt2860_tx_watchdog
+ */
+static void rt2860_tx_watchdog(void *arg)
+{
+ struct rt2860_softc *sc;
+
+ sc = arg;
+
+ if (sc->tx_timer == 0)
+ return;
+
+ if (--sc->tx_timer == 0)
+ {
+ printf("%s: Tx watchdog timeout: resetting\n",
+ device_get_nameunit(sc->dev));
+
+ rt2860_stop_locked(sc);
+ rt2860_init_locked(sc);
+
+ counter_u64_add(sc->sc_ic.ic_oerrors, 1);
+
+ sc->tx_watchdog_timeouts++;
+ }
+
+ callout_reset(&sc->tx_watchdog_ch, hz, rt2860_tx_watchdog, sc);
+}
+
+/*
+ * rt2860_staid_alloc
+ */
+static int rt2860_staid_alloc(struct rt2860_softc *sc, int aid)
+{
+ int staid;
+
+ if ((aid > 0 && aid < RT2860_SOFTC_STAID_COUNT) && isclr(sc->staid_mask, aid))
+ {
+ staid = aid;
+ }
+ else
+ {
+ for (staid = 1; staid < RT2860_SOFTC_STAID_COUNT; staid++)
+ {
+ if (isclr(sc->staid_mask, staid))
+ break;
+ }
+ }
+
+ setbit(sc->staid_mask, staid);
+
+ return staid;
+}
+
+/*
+ * rt2860_staid_delete
+ */
+static void rt2860_staid_delete(struct rt2860_softc *sc, int staid)
+{
+ clrbit(sc->staid_mask, staid);
+}
+
+/*
+ * rt2860_asic_set_bssid
+ */
+static void rt2860_asic_set_bssid(struct rt2860_softc *sc,
+ const uint8_t *bssid)
+{
+ uint32_t tmp;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_STATE,
+ "%s: set bssid: bssid=%s\n",
+ device_get_nameunit(sc->dev),
+ ether_sprintf(bssid));
+
+ tmp = bssid[0] | (bssid[1]) << 8 | (bssid[2] << 16) | (bssid[3] << 24);
+
+ rt2860_io_mac_write(sc, RT2860_REG_BSSID_DW0, tmp);
+
+ tmp = bssid[4] | (bssid[5] << 8);
+
+ rt2860_io_mac_write(sc, RT2860_REG_BSSID_DW1, tmp);
+}
+
+/*
+ * rt2860_asic_set_macaddr
+ */
+static void rt2860_asic_set_macaddr(struct rt2860_softc *sc,
+ const uint8_t *addr)
+{
+ uint32_t tmp;
+
+ tmp = addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24);
+
+ rt2860_io_mac_write(sc, RT2860_REG_ADDR_DW0, tmp);
+
+ tmp = addr[4] | (addr[5] << 8) | (0xff << 16);
+
+ rt2860_io_mac_write(sc, RT2860_REG_ADDR_DW1, tmp);
+}
+
+/*
+ * rt2860_asic_enable_tsf_sync
+ */
+static void rt2860_asic_enable_tsf_sync(struct rt2860_softc *sc)
+{
+ struct ieee80211com *ic;
+ struct ieee80211vap *vap;
+ uint32_t tmp;
+
+ ic = &sc->sc_ic;
+ vap = TAILQ_FIRST(&ic->ic_vaps);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_BEACON,
+ "%s: enabling TSF\n",
+ device_get_nameunit(sc->dev));
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_BCN_TIME_CFG);
+
+ tmp &= ~0x1fffff;
+ tmp |= vap->iv_bss->ni_intval * 16;
+ tmp |= (RT2860_REG_TSF_TIMER_ENABLE | RT2860_REG_TBTT_TIMER_ENABLE);
+
+ if (vap->iv_opmode == IEEE80211_M_STA)
+ {
+ tmp |= (RT2860_REG_TSF_SYNC_MODE_STA << RT2860_REG_TSF_SYNC_MODE_SHIFT);
+ }
+ else if (vap->iv_opmode == IEEE80211_M_IBSS)
+ {
+ tmp |= RT2860_REG_BCN_TX_ENABLE;
+ tmp |= (RT2860_REG_TSF_SYNC_MODE_IBSS << RT2860_REG_TSF_SYNC_MODE_SHIFT);
+ }
+ else if (vap->iv_opmode == IEEE80211_M_HOSTAP)
+ {
+ tmp |= RT2860_REG_BCN_TX_ENABLE;
+ tmp |= (RT2860_REG_TSF_SYNC_MODE_HOSTAP << RT2860_REG_TSF_SYNC_MODE_SHIFT);
+ }
+
+ rt2860_io_mac_write(sc, RT2860_REG_BCN_TIME_CFG, tmp);
+}
+
+/*
+ * rt2860_asic_disable_tsf_sync
+ */
+static void rt2860_asic_disable_tsf_sync(struct rt2860_softc *sc)
+{
+ uint32_t tmp;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_BEACON,
+ "%s: disabling TSF\n",
+ device_get_nameunit(sc->dev));
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_BCN_TIME_CFG);
+
+ tmp &= ~(RT2860_REG_BCN_TX_ENABLE |
+ RT2860_REG_TSF_TIMER_ENABLE |
+ RT2860_REG_TBTT_TIMER_ENABLE);
+
+ tmp &= ~(RT2860_REG_TSF_SYNC_MODE_MASK << RT2860_REG_TSF_SYNC_MODE_SHIFT);
+ tmp |= (RT2860_REG_TSF_SYNC_MODE_DISABLE << RT2860_REG_TSF_SYNC_MODE_SHIFT);
+
+ rt2860_io_mac_write(sc, RT2860_REG_BCN_TIME_CFG, tmp);
+}
+
+/*
+ * rt2860_asic_enable_mrr
+ */
+static void rt2860_asic_enable_mrr(struct rt2860_softc *sc)
+{
+#define CCK(mcs) (mcs)
+#define OFDM(mcs) ((1 << 3) | (mcs))
+#define HT(mcs) (mcs)
+
+ rt2860_io_mac_write(sc, RT2860_REG_TX_LG_FBK_CFG0,
+ (OFDM(6) << 28) | /* 54 -> 48 */
+ (OFDM(5) << 24) | /* 48 -> 36 */
+ (OFDM(4) << 20) | /* 36 -> 24 */
+ (OFDM(3) << 16) | /* 24 -> 18 */
+ (OFDM(2) << 12) | /* 18 -> 12 */
+ (OFDM(1) << 8) | /* 12 -> 9 */
+ (OFDM(0) << 4) | /* 9 -> 6 */
+ OFDM(0)); /* 6 -> 6 */
+
+ rt2860_io_mac_write(sc, RT2860_REG_TX_LG_FBK_CFG1,
+ (CCK(2) << 12) | /* 11 -> 5.5 */
+ (CCK(1) << 8) | /* 5.5 -> 2 */
+ (CCK(0) << 4) | /* 2 -> 1 */
+ CCK(0)); /* 1 -> 1 */
+
+ rt2860_io_mac_write(sc, RT2860_REG_TX_HT_FBK_CFG0,
+ (HT(6) << 28) |
+ (HT(5) << 24) |
+ (HT(4) << 20) |
+ (HT(3) << 16) |
+ (HT(2) << 12) |
+ (HT(1) << 8) |
+ (HT(0) << 4) |
+ HT(0));
+
+ rt2860_io_mac_write(sc, RT2860_REG_TX_HT_FBK_CFG1,
+ (HT(14) << 28) |
+ (HT(13) << 24) |
+ (HT(12) << 20) |
+ (HT(11) << 16) |
+ (HT(10) << 12) |
+ (HT(9) << 8) |
+ (HT(8) << 4) |
+ HT(7));
+
+#undef HT
+#undef OFDM
+#undef CCK
+}
+
+/*
+ * rt2860_asic_set_txpreamble
+ */
+static void rt2860_asic_set_txpreamble(struct rt2860_softc *sc)
+{
+ struct ieee80211com *ic;
+ uint32_t tmp;
+
+ ic = &sc->sc_ic;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_STATE,
+ "%s: %s short Tx preamble\n",
+ device_get_nameunit(sc->dev),
+ (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? "enabling" : "disabling");
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_AUTO_RSP_CFG);
+
+ tmp &= ~RT2860_REG_CCK_SHORT_ENABLE;
+
+ if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
+ tmp |= RT2860_REG_CCK_SHORT_ENABLE;
+
+ rt2860_io_mac_write(sc, RT2860_REG_AUTO_RSP_CFG, tmp);
+}
+
+/*
+ * rt2860_asic_set_basicrates
+ */
+static void rt2860_asic_set_basicrates(struct rt2860_softc *sc)
+{
+ struct ieee80211com *ic;
+
+ ic = &sc->sc_ic;
+
+ if (ic->ic_curmode == IEEE80211_MODE_11B)
+ rt2860_io_mac_write(sc, RT2860_REG_LEGACY_BASIC_RATE, 0xf);
+ else if (ic->ic_curmode == IEEE80211_MODE_11A)
+ rt2860_io_mac_write(sc, RT2860_REG_LEGACY_BASIC_RATE, 0x150);
+ else
+ rt2860_io_mac_write(sc, RT2860_REG_LEGACY_BASIC_RATE, 0x15f);
+}
+
+/*
+ * rt2860_asic_update_rtsthreshold
+ */
+static void rt2860_asic_update_rtsthreshold(struct rt2860_softc *sc)
+{
+ struct ieee80211com *ic;
+ struct ieee80211vap *vap;
+ uint32_t tmp;
+ uint16_t threshold;
+
+ ic = &sc->sc_ic;
+ vap = TAILQ_FIRST(&ic->ic_vaps);
+
+ if (vap == NULL)
+ threshold = IEEE80211_RTS_MAX;
+ else if (vap->iv_flags_ht & IEEE80211_FHT_AMSDU_TX)
+ threshold = 0x1000;
+ else
+ threshold = vap->iv_rtsthreshold;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_PROT,
+ "%s: updating RTS threshold: %d\n",
+ device_get_nameunit(sc->dev), threshold);
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_RTS_CFG);
+
+ tmp &= ~(RT2860_REG_TX_RTS_THRESHOLD_MASK << RT2860_REG_TX_RTS_THRESHOLD_SHIFT);
+
+ tmp |= ((threshold & RT2860_REG_TX_RTS_THRESHOLD_MASK) <<
+ RT2860_REG_TX_RTS_THRESHOLD_SHIFT);
+
+ rt2860_io_mac_write(sc, RT2860_REG_TX_RTS_CFG, tmp);
+}
+
+/*
+ * rt2860_asic_update_txpower
+ */
+static void rt2860_asic_update_txpower(struct rt2860_softc *sc)
+{
+ struct ieee80211com *ic;
+ uint32_t *txpow_rate;
+ int8_t delta;
+ uint8_t val;
+ uint32_t tmp;
+ int i;
+
+ ic = &sc->sc_ic;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_STATE,
+ "%s: updating Tx power: %d\n",
+ device_get_nameunit(sc->dev), ic->ic_txpowlimit);
+
+ if (!IEEE80211_IS_CHAN_HT40(ic->ic_curchan))
+ {
+ txpow_rate = sc->txpow_rate_20mhz;
+ }
+ else
+ {
+ if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
+ txpow_rate = sc->txpow_rate_40mhz_2ghz;
+ else
+ txpow_rate = sc->txpow_rate_40mhz_5ghz;
+ }
+
+ delta = 0;
+
+ val = rt2860_io_bbp_read(sc, 1);
+ val &= 0xfc;
+
+ if (ic->ic_txpowlimit > 90)
+ {
+ /* do nothing */
+ }
+ else if (ic->ic_txpowlimit > 60)
+ {
+ delta -= 1;
+ }
+ else if (ic->ic_txpowlimit > 30)
+ {
+ delta -= 3;
+ }
+ else if (ic->ic_txpowlimit > 15)
+ {
+ val |= 0x1;
+ }
+ else if (ic->ic_txpowlimit > 9)
+ {
+ val |= 0x1;
+ delta -= 3;
+ }
+ else
+ {
+ val |= 0x2;
+ }
+
+ rt2860_io_bbp_write(sc, 1, val);
+
+ for (i = 0; i < RT2860_SOFTC_TXPOW_RATE_COUNT; i++)
+ {
+ if (txpow_rate[i] == 0xffffffff)
+ continue;
+
+ tmp = rt2860_read_eeprom_txpow_rate_add_delta(txpow_rate[i], delta);
+
+ rt2860_io_mac_write(sc, RT2860_REG_TX_PWR_CFG(i), tmp);
+ }
+}
+
+/*
+ * rt2860_asic_update_promisc
+ */
+static void rt2860_asic_update_promisc(struct rt2860_softc *sc)
+{
+ struct ieee80211com *ic;
+ uint32_t tmp;
+
+ ic = &sc->sc_ic;
+
+ printf("%s: %s promiscuous mode\n",
+ device_get_nameunit(sc->dev),
+ (ic->ic_promisc == 1) ? "entering" : "leaving");
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_RX_FILTER_CFG);
+
+ tmp &= ~RT2860_REG_RX_FILTER_DROP_UC_NOME;
+
+ if (ic->ic_promisc == 0)
+ tmp |= RT2860_REG_RX_FILTER_DROP_UC_NOME;
+
+ rt2860_io_mac_write(sc, RT2860_REG_RX_FILTER_CFG, tmp);
+}
+
+/*
+ * rt2860_asic_updateprot
+ */
+static void rt2860_asic_updateprot(struct rt2860_softc *sc)
+{
+ struct ieee80211com *ic;
+ struct ieee80211vap *vap;
+ uint32_t cck_prot, ofdm_prot, mm20_prot, mm40_prot, gf20_prot, gf40_prot;
+ uint8_t htopmode;
+ enum ieee80211_protmode htprotmode;
+
+ ic = &sc->sc_ic;
+ vap = TAILQ_FIRST(&ic->ic_vaps);
+
+ /* CCK frame protection */
+
+ cck_prot = RT2860_REG_RTSTH_ENABLE | RT2860_REG_PROT_NAV_SHORT |
+ RT2860_REG_TXOP_ALLOW_ALL | RT2860_REG_PROT_CTRL_NONE;
+
+ /* set up protection frame phy mode and rate (MCS code) */
+
+ if (ic->ic_curmode == IEEE80211_MODE_11A)
+ cck_prot |= (RT2860_REG_PROT_PHYMODE_OFDM << RT2860_REG_PROT_PHYMODE_SHIFT) |
+ (0 << RT2860_REG_PROT_MCS_SHIFT);
+ else
+ cck_prot |= ((RT2860_REG_PROT_PHYMODE_CCK << RT2860_REG_PROT_PHYMODE_SHIFT) |
+ (3 << RT2860_REG_PROT_MCS_SHIFT));
+
+ rt2860_io_mac_write(sc, RT2860_REG_TX_CCK_PROT_CFG, cck_prot);
+
+ /* OFDM frame protection */
+
+ ofdm_prot = RT2860_REG_RTSTH_ENABLE | RT2860_REG_PROT_NAV_SHORT |
+ RT2860_REG_TXOP_ALLOW_ALL;
+
+ if (ic->ic_flags & IEEE80211_F_USEPROT)
+ {
+ RT2860_DPRINTF(sc, RT2860_DEBUG_PROT,
+ "%s: updating protection mode: b/g protection mode=%s\n",
+ device_get_nameunit(sc->dev),
+ (ic->ic_protmode == IEEE80211_PROT_RTSCTS) ? "RTS/CTS" :
+ ((ic->ic_protmode == IEEE80211_PROT_CTSONLY) ? "CTS-to-self" : "none"));
+
+ if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
+ ofdm_prot |= RT2860_REG_PROT_CTRL_RTS_CTS;
+ else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
+ ofdm_prot |= RT2860_REG_PROT_CTRL_CTS;
+ else
+ ofdm_prot |= RT2860_REG_PROT_CTRL_NONE;
+ }
+ else
+ {
+ RT2860_DPRINTF(sc, RT2860_DEBUG_PROT,
+ "%s: updating protection mode: b/g protection mode=%s\n",
+ device_get_nameunit(sc->dev), "none");
+
+ ofdm_prot |= RT2860_REG_PROT_CTRL_NONE;
+ }
+
+ rt2860_io_mac_write(sc, RT2860_REG_TX_OFDM_PROT_CFG, ofdm_prot);
+
+ /* HT frame protection */
+
+ if ((vap != NULL) && (vap->iv_opmode == IEEE80211_M_STA) && (vap->iv_state == IEEE80211_S_RUN))
+ htopmode = vap->iv_bss->ni_htopmode;
+ else
+ htopmode = ic->ic_curhtprotmode;
+
+ htprotmode = ic->ic_htprotmode;
+
+ /* force HT mixed mode and RTS/CTS protection if A-MPDU Tx aggregation is enabled */
+
+ if (sc->tx_ampdu_sessions > 0)
+ {
+ RT2860_DPRINTF(sc, RT2860_DEBUG_PROT,
+ "%s: updating protection mode: forcing HT mixed mode and RTS/CTS protection\n",
+ device_get_nameunit(sc->dev));
+
+ htopmode = IEEE80211_HTINFO_OPMODE_MIXED;
+ htprotmode = IEEE80211_PROT_RTSCTS;
+ }
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_PROT,
+ "%s: updating protection mode: HT operation mode=0x%02x, protection mode=%s\n",
+ device_get_nameunit(sc->dev),
+ htopmode & IEEE80211_HTINFO_OPMODE,
+ (htprotmode == IEEE80211_PROT_RTSCTS) ? "RTS/CTS" :
+ ((htprotmode == IEEE80211_PROT_CTSONLY) ? "CTS-to-self" : "none"));
+
+ switch (htopmode & IEEE80211_HTINFO_OPMODE)
+ {
+ /* IEEE80211_HTINFO_OPMODE_HT20PR */
+ case IEEE80211_HTINFO_OPMODE_HT20PR:
+ mm20_prot = RT2860_REG_PROT_NAV_SHORT | RT2860_REG_PROT_CTRL_NONE |
+ RT2860_REG_TXOP_ALLOW_CCK | RT2860_REG_TXOP_ALLOW_OFDM |
+ RT2860_REG_TXOP_ALLOW_MM20 | RT2860_REG_TXOP_ALLOW_GF20 |
+ (RT2860_REG_PROT_PHYMODE_OFDM << RT2860_REG_PROT_PHYMODE_SHIFT) |
+ (4 << RT2860_REG_PROT_MCS_SHIFT);
+
+ gf20_prot = mm20_prot;
+
+ mm40_prot = RT2860_REG_PROT_NAV_SHORT | RT2860_REG_TXOP_ALLOW_ALL |
+ (RT2860_REG_PROT_PHYMODE_OFDM << RT2860_REG_PROT_PHYMODE_SHIFT) |
+ (0x84 << RT2860_REG_PROT_MCS_SHIFT);
+
+ if (htprotmode == IEEE80211_PROT_RTSCTS)
+ mm40_prot |= RT2860_REG_PROT_CTRL_RTS_CTS;
+ else if (htprotmode == IEEE80211_PROT_CTSONLY)
+ mm40_prot |= RT2860_REG_PROT_CTRL_CTS;
+ else
+ mm40_prot |= RT2860_REG_PROT_CTRL_NONE;
+
+ gf40_prot = mm40_prot;
+ break;
+
+ /* IEEE80211_HTINFO_OPMODE_MIXED */
+ case IEEE80211_HTINFO_OPMODE_MIXED:
+ mm20_prot = RT2860_REG_PROT_NAV_SHORT |
+ RT2860_REG_TXOP_ALLOW_CCK | RT2860_REG_TXOP_ALLOW_OFDM |
+ RT2860_REG_TXOP_ALLOW_MM20 | RT2860_REG_TXOP_ALLOW_GF20;
+
+ if (ic->ic_flags & IEEE80211_F_USEPROT)
+ mm20_prot |= (RT2860_REG_PROT_PHYMODE_CCK << RT2860_REG_PROT_PHYMODE_SHIFT) |
+ (3 << RT2860_REG_PROT_MCS_SHIFT);
+ else
+ mm20_prot |= (RT2860_REG_PROT_PHYMODE_OFDM << RT2860_REG_PROT_PHYMODE_SHIFT) |
+ (4 << RT2860_REG_PROT_MCS_SHIFT);
+
+ if (htprotmode == IEEE80211_PROT_RTSCTS)
+ mm20_prot |= RT2860_REG_PROT_CTRL_RTS_CTS;
+ else if (htprotmode == IEEE80211_PROT_CTSONLY)
+ mm20_prot |= RT2860_REG_PROT_CTRL_CTS;
+ else
+ mm20_prot |= RT2860_REG_PROT_CTRL_NONE;
+
+ gf20_prot = mm20_prot;
+
+ mm40_prot = RT2860_REG_PROT_NAV_SHORT | RT2860_REG_TXOP_ALLOW_ALL;
+
+ if (ic->ic_flags & IEEE80211_F_USEPROT)
+ mm40_prot |= (RT2860_REG_PROT_PHYMODE_CCK << RT2860_REG_PROT_PHYMODE_SHIFT) |
+ (3 << RT2860_REG_PROT_MCS_SHIFT);
+ else
+ mm40_prot |= (RT2860_REG_PROT_PHYMODE_OFDM << RT2860_REG_PROT_PHYMODE_SHIFT) |
+ (0x84 << RT2860_REG_PROT_MCS_SHIFT);
+
+ if (htprotmode == IEEE80211_PROT_RTSCTS)
+ mm40_prot |= RT2860_REG_PROT_CTRL_RTS_CTS;
+ else if (htprotmode == IEEE80211_PROT_CTSONLY)
+ mm40_prot |= RT2860_REG_PROT_CTRL_CTS;
+ else
+ mm40_prot |= RT2860_REG_PROT_CTRL_NONE;
+
+ gf40_prot = mm40_prot;
+ break;
+
+ /*
+ * IEEE80211_HTINFO_OPMODE_PURE
+ * IEEE80211_HTINFO_OPMODE_PROTOPT
+ */
+ case IEEE80211_HTINFO_OPMODE_PURE:
+ case IEEE80211_HTINFO_OPMODE_PROTOPT:
+ default:
+ mm20_prot = RT2860_REG_PROT_NAV_SHORT | RT2860_REG_PROT_CTRL_NONE |
+ RT2860_REG_TXOP_ALLOW_CCK | RT2860_REG_TXOP_ALLOW_OFDM |
+ RT2860_REG_TXOP_ALLOW_MM20 | RT2860_REG_TXOP_ALLOW_GF20 |
+ (RT2860_REG_PROT_PHYMODE_OFDM << RT2860_REG_PROT_PHYMODE_SHIFT) |
+ (4 << RT2860_REG_PROT_MCS_SHIFT);
+
+ gf20_prot = mm20_prot;
+
+ mm40_prot = RT2860_REG_PROT_NAV_SHORT | RT2860_REG_PROT_CTRL_NONE |
+ RT2860_REG_TXOP_ALLOW_ALL |
+ (RT2860_REG_PROT_PHYMODE_OFDM << RT2860_REG_PROT_PHYMODE_SHIFT) |
+ (0x84 << RT2860_REG_PROT_MCS_SHIFT);
+
+ gf40_prot = mm40_prot;
+ break;
+ }
+
+ rt2860_io_mac_write(sc, RT2860_REG_TX_MM20_PROT_CFG, mm20_prot);
+ rt2860_io_mac_write(sc, RT2860_REG_TX_MM40_PROT_CFG, mm40_prot);
+ rt2860_io_mac_write(sc, RT2860_REG_TX_GF20_PROT_CFG, gf20_prot);
+ rt2860_io_mac_write(sc, RT2860_REG_TX_GF40_PROT_CFG, gf40_prot);
+}
+
+/*
+ * rt2860_asic_updateslot
+ */
+static void rt2860_asic_updateslot(struct rt2860_softc *sc)
+{
+ struct ieee80211com *ic;
+ struct ieee80211vap *vap;
+ uint32_t tmp;
+
+ ic = &sc->sc_ic;
+ vap = TAILQ_FIRST(&ic->ic_vaps);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_STATE,
+ "%s: %s short slot time\n",
+ device_get_nameunit(sc->dev),
+ ((ic->ic_flags & IEEE80211_F_SHSLOT) ||
+ ((vap != NULL) && (vap->iv_flags & IEEE80211_F_BURST))) ? "enabling" : "disabling");
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_BKOFF_SLOT_CFG);
+
+ tmp &= ~0xff;
+
+ if ((ic->ic_flags & IEEE80211_F_SHSLOT) ||
+ ((vap != NULL) && (vap->iv_flags & IEEE80211_F_BURST)))
+ tmp |= IEEE80211_DUR_SHSLOT;
+ else
+ tmp |= IEEE80211_DUR_SLOT;
+
+ rt2860_io_mac_write(sc, RT2860_REG_BKOFF_SLOT_CFG, tmp);
+}
+
+/*
+ * rt2860_asic_wme_update
+ */
+static void rt2860_asic_wme_update(struct rt2860_softc *sc)
+{
+ struct ieee80211com *ic;
+ struct ieee80211_wme_state *wme;
+ const struct wmeParams *wmep;
+ int i;
+
+ ic = &sc->sc_ic;
+ wme = &ic->ic_wme;
+ wmep = wme->wme_chanParams.cap_wmeParams;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_WME,
+ "%s: wme update: WME_AC_VO=%d/%d/%d/%d, WME_AC_VI=%d/%d/%d/%d, "
+ "WME_AC_BK=%d/%d/%d/%d, WME_AC_BE=%d/%d/%d/%d\n",
+ device_get_nameunit(sc->dev),
+ wmep[WME_AC_VO].wmep_aifsn,
+ wmep[WME_AC_VO].wmep_logcwmin, wmep[WME_AC_VO].wmep_logcwmax,
+ wmep[WME_AC_VO].wmep_txopLimit,
+ wmep[WME_AC_VI].wmep_aifsn,
+ wmep[WME_AC_VI].wmep_logcwmin, wmep[WME_AC_VI].wmep_logcwmax,
+ wmep[WME_AC_VI].wmep_txopLimit,
+ wmep[WME_AC_BK].wmep_aifsn,
+ wmep[WME_AC_BK].wmep_logcwmin, wmep[WME_AC_BK].wmep_logcwmax,
+ wmep[WME_AC_BK].wmep_txopLimit,
+ wmep[WME_AC_BE].wmep_aifsn,
+ wmep[WME_AC_BE].wmep_logcwmin, wmep[WME_AC_BE].wmep_logcwmax,
+ wmep[WME_AC_BE].wmep_txopLimit);
+
+ for (i = 0; i < WME_NUM_AC; i++)
+ rt2860_io_mac_write(sc, RT2860_REG_TX_EDCA_AC_CFG(i),
+ (wmep[i].wmep_logcwmax << 16) | (wmep[i].wmep_logcwmin << 12) |
+ (wmep[i].wmep_aifsn << 8) | wmep[i].wmep_txopLimit);
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WMM_AIFSN_CFG,
+ (wmep[WME_AC_VO].wmep_aifsn << 12) | (wmep[WME_AC_VI].wmep_aifsn << 8) |
+ (wmep[WME_AC_BK].wmep_aifsn << 4) | wmep[WME_AC_BE].wmep_aifsn);
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WMM_CWMIN_CFG,
+ (wmep[WME_AC_VO].wmep_logcwmin << 12) | (wmep[WME_AC_VI].wmep_logcwmin << 8) |
+ (wmep[WME_AC_BK].wmep_logcwmin << 4) | wmep[WME_AC_BE].wmep_logcwmin);
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WMM_CWMAX_CFG,
+ (wmep[WME_AC_VO].wmep_logcwmax << 12) | (wmep[WME_AC_VI].wmep_logcwmax << 8) |
+ (wmep[WME_AC_BK].wmep_logcwmax << 4) | wmep[WME_AC_BE].wmep_logcwmax);
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WMM_TXOP0_CFG,
+ (wmep[WME_AC_BK].wmep_txopLimit << 16) | wmep[WME_AC_BE].wmep_txopLimit);
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WMM_TXOP1_CFG,
+ (wmep[WME_AC_VO].wmep_txopLimit << 16) | wmep[WME_AC_VI].wmep_txopLimit);
+}
+
+/*
+ * rt2860_asic_update_beacon
+ */
+static void rt2860_asic_update_beacon(struct rt2860_softc *sc,
+ struct ieee80211vap *vap)
+{
+ struct rt2860_softc_vap *rvap;
+ struct mbuf *m;
+ struct rt2860_txwi *txwi;
+ uint32_t tmp;
+
+ rvap = (struct rt2860_softc_vap *) vap;
+
+ m = rvap->beacon_mbuf;
+ txwi = &rvap->beacon_txwi;
+
+ /* disable temporarily TSF sync */
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_BCN_TIME_CFG);
+
+ tmp &= ~(RT2860_REG_BCN_TX_ENABLE |
+ RT2860_REG_TSF_TIMER_ENABLE |
+ RT2860_REG_TBTT_TIMER_ENABLE);
+
+ rt2860_io_mac_write(sc, RT2860_REG_BCN_TIME_CFG, tmp);
+
+ /* write Tx wireless info and beacon frame to on-chip memory */
+
+ rt2860_io_mac_write_multi(sc, RT2860_REG_BEACON_BASE(0),
+ txwi, sizeof(struct rt2860_txwi));
+
+ rt2860_io_mac_write_multi(sc, RT2860_REG_BEACON_BASE(0) + sizeof(struct rt2860_txwi),
+ mtod(m, uint8_t *), m->m_pkthdr.len);
+
+ /* enable again TSF sync */
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_BCN_TIME_CFG);
+
+ tmp |= (RT2860_REG_BCN_TX_ENABLE |
+ RT2860_REG_TSF_TIMER_ENABLE |
+ RT2860_REG_TBTT_TIMER_ENABLE);
+
+ rt2860_io_mac_write(sc, RT2860_REG_BCN_TIME_CFG, tmp);
+}
+
+/*
+ * rt2860_asic_clear_keytables
+ */
+static void rt2860_asic_clear_keytables(struct rt2860_softc *sc)
+{
+ int i;
+
+ /* clear Rx WCID search table (entries = 256, entry size = 8) */
+
+ for (i = 0; i < 256; i++)
+ {
+ rt2860_io_mac_write(sc, RT2860_REG_WCID(i), 0xffffffff);
+ rt2860_io_mac_write(sc, RT2860_REG_WCID(i) + 4, 0x0000ffff);
+ }
+
+ /* clear WCID attribute table (entries = 256, entry size = 4) */
+
+ rt2860_io_mac_set_region_4(sc, RT2860_REG_WCID_ATTR(0), RT2860_REG_PKEY_ENABLE, 256);
+
+ /* clear IV/EIV table (entries = 256, entry size = 8) */
+
+ rt2860_io_mac_set_region_4(sc, RT2860_REG_IVEIV(0), 0, 2 * 256);
+
+ /* clear pairwise key table (entries = 64, entry size = 32) */
+
+ rt2860_io_mac_set_region_4(sc, RT2860_REG_PKEY(0), 0, 8 * 64);
+
+ /* clear shared key table (entries = 32, entry size = 32) */
+
+ rt2860_io_mac_set_region_4(sc, RT2860_REG_SKEY(0, 0), 0, 8 * 32);
+
+ /* clear shared key mode (entries = 32, entry size = 2) */
+
+ rt2860_io_mac_set_region_4(sc, RT2860_REG_SKEY_MODE(0), 0, 16);
+}
+
+/*
+ * rt2860_asic_add_ba_session
+ */
+static void rt2860_asic_add_ba_session(struct rt2860_softc *sc,
+ uint8_t wcid, int tid)
+{
+ uint32_t tmp;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+ "%s: adding BA session: wcid=0x%02x, tid=%d\n",
+ device_get_nameunit(sc->dev), wcid, tid);
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_WCID(wcid) + 4);
+
+ tmp |= (0x10000 << tid);
+
+ rt2860_io_mac_write(sc, RT2860_REG_WCID(wcid) + 4, tmp);
+}
+
+/*
+ * rt2860_asic_del_ba_session
+ */
+static void rt2860_asic_del_ba_session(struct rt2860_softc *sc,
+ uint8_t wcid, int tid)
+{
+ uint32_t tmp;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_BA,
+ "%s: deleting BA session: wcid=0x%02x, tid=%d\n",
+ device_get_nameunit(sc->dev), wcid, tid);
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_WCID(wcid) + 4);
+
+ tmp &= ~(0x10000 << tid);
+
+ rt2860_io_mac_write(sc, RT2860_REG_WCID(wcid) + 4, tmp);
+}
+
+/*
+ * rt2860_beacon_alloc
+ */
+static int rt2860_beacon_alloc(struct rt2860_softc *sc,
+ struct ieee80211vap *vap)
+{
+ struct ieee80211com *ic;
+ struct rt2860_softc_vap *rvap;
+ struct mbuf *m;
+ struct rt2860_txwi txwi;
+ uint8_t rate, mcs;
+
+ ic = vap->iv_ic;
+ rvap = (struct rt2860_softc_vap *) vap;
+
+ m = ieee80211_beacon_alloc(vap->iv_bss);
+ if (m == NULL)
+ return ENOMEM;
+
+ rate = IEEE80211_IS_CHAN_5GHZ(vap->iv_bss->ni_chan) ? 12 : 2;
+ mcs = rt2860_rate2mcs(rate);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_BEACON,
+ "%s: beacon allocate: mcs=0x%02x\n",
+ device_get_nameunit(sc->dev), mcs);
+
+ memset(&txwi, 0, sizeof(struct rt2860_txwi));
+
+ txwi.wcid = RT2860_WCID_RESERVED;
+ txwi.pid_mpdu_len = ((htole16(m->m_pkthdr.len) & RT2860_TXWI_MPDU_LEN_MASK) <<
+ RT2860_TXWI_MPDU_LEN_SHIFT);
+ txwi.txop = (RT2860_TXWI_TXOP_HT << RT2860_TXWI_TXOP_SHIFT);
+ txwi.mpdu_density_flags |=
+ (RT2860_TXWI_FLAGS_TS << RT2860_TXWI_FLAGS_SHIFT);
+ txwi.bawin_size_xflags |=
+ (RT2860_TXWI_XFLAGS_NSEQ << RT2860_TXWI_XFLAGS_SHIFT);
+
+ if (rate == 2)
+ {
+ txwi.phymode_ifs_stbc_shortgi =
+ (RT2860_TXWI_PHYMODE_CCK << RT2860_TXWI_PHYMODE_SHIFT);
+
+ if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
+ mcs |= RT2860_TXWI_MCS_SHOTPRE;
+ }
+ else
+ {
+ txwi.phymode_ifs_stbc_shortgi =
+ (RT2860_TXWI_PHYMODE_OFDM << RT2860_TXWI_PHYMODE_SHIFT);
+ }
+
+ txwi.bw_mcs = (RT2860_TXWI_BW_20 << RT2860_TXWI_BW_SHIFT) |
+ ((mcs & RT2860_TXWI_MCS_MASK) << RT2860_TXWI_MCS_SHIFT);
+
+ if (rvap->beacon_mbuf != NULL)
+ {
+ m_free(rvap->beacon_mbuf);
+ rvap->beacon_mbuf = NULL;
+ }
+
+ rvap->beacon_mbuf = m;
+ rvap->beacon_txwi = txwi;
+
+ return 0;
+}
+
+/*
+ * rt2860_rxrate
+ */
+static uint8_t rt2860_rxrate(struct rt2860_rxwi *rxwi)
+{
+ uint8_t mcs, phymode;
+ uint8_t rate;
+
+ mcs = (rxwi->bw_mcs >> RT2860_RXWI_MCS_SHIFT) & RT2860_RXWI_MCS_MASK;
+ phymode = (rxwi->phymode_stbc_shortgi >> RT2860_RXWI_PHYMODE_SHIFT) &
+ RT2860_RXWI_PHYMODE_MASK;
+
+ rate = 2;
+
+ switch (phymode) {
+ case RT2860_RXWI_PHYMODE_CCK:
+ switch (mcs & ~RT2860_RXWI_MCS_SHOTPRE)
+ {
+ case 0: rate = 2; break; /* 1 Mbps */
+ case 1: rate = 4; break; /* 2 MBps */
+ case 2: rate = 11; break; /* 5.5 Mbps */
+ case 3: rate = 22; break; /* 11 Mbps */
+ }
+ break;
+
+ case RT2860_RXWI_PHYMODE_OFDM:
+ switch (mcs)
+ {
+ case 0: rate = 12; break; /* 6 Mbps */
+ case 1: rate = 18; break; /* 9 Mbps */
+ case 2: rate = 24; break; /* 12 Mbps */
+ case 3: rate = 36; break; /* 18 Mbps */
+ case 4: rate = 48; break; /* 24 Mbps */
+ case 5: rate = 72; break; /* 36 Mbps */
+ case 6: rate = 96; break; /* 48 Mbps */
+ case 7: rate = 108; break; /* 54 Mbps */
+ }
+ break;
+
+ case RT2860_RXWI_PHYMODE_HT_MIXED:
+ case RT2860_RXWI_PHYMODE_HT_GF:
+ break;
+ }
+
+ return rate;
+}
+
+/*
+ * rt2860_maxrssi_rxpath
+ */
+static uint8_t rt2860_maxrssi_rxpath(struct rt2860_softc *sc,
+ const struct rt2860_rxwi *rxwi)
+{
+ uint8_t rxpath;
+
+ rxpath = 0;
+
+ if (sc->nrxpath > 1)
+ if (rxwi->rssi[1] > rxwi->rssi[rxpath])
+ rxpath = 1;
+
+ if (sc->nrxpath > 2)
+ if (rxwi->rssi[2] > rxwi->rssi[rxpath])
+ rxpath = 2;
+
+ return rxpath;
+}
+
+/*
+ * rt2860_rssi2dbm
+ */
+static int8_t rt2860_rssi2dbm(struct rt2860_softc *sc,
+ uint8_t rssi, uint8_t rxpath)
+{
+ struct ieee80211com *ic;
+ struct ieee80211_channel *c;
+ int chan;
+ int8_t rssi_off, lna_gain;
+
+ if (rssi == 0)
+ return -99;
+
+ ic = &sc->sc_ic;
+ c = ic->ic_curchan;
+ chan = ieee80211_chan2ieee(ic, c);
+
+ if (IEEE80211_IS_CHAN_5GHZ(c))
+ {
+ rssi_off = sc->rssi_off_5ghz[rxpath];
+
+ if (chan <= 64)
+ lna_gain = sc->lna_gain[1];
+ else if (chan <= 128)
+ lna_gain = sc->lna_gain[2];
+ else
+ lna_gain = sc->lna_gain[3];
+ }
+ else
+ {
+ rssi_off = sc->rssi_off_2ghz[rxpath] - sc->lna_gain[0];
+ lna_gain = sc->lna_gain[0];
+ }
+
+ return (-12 - rssi_off - lna_gain - rssi);
+}
+
+/*
+ * rt2860_rate2mcs
+ */
+static uint8_t rt2860_rate2mcs(uint8_t rate)
+{
+ switch (rate)
+ {
+ /* CCK rates */
+ case 2: return 0;
+ case 4: return 1;
+ case 11: return 2;
+ case 22: return 3;
+
+ /* OFDM rates */
+ case 12: return 0;
+ case 18: return 1;
+ case 24: return 2;
+ case 36: return 3;
+ case 48: return 4;
+ case 72: return 5;
+ case 96: return 6;
+ case 108: return 7;
+ }
+
+ return 0;
+}
+
+/*
+ * rt2860_tx_mgmt
+ */
+static int rt2860_tx_mgmt(struct rt2860_softc *sc,
+ struct mbuf *m, struct ieee80211_node *ni, int qid)
+{
+ struct ieee80211com *ic;
+ struct ieee80211vap *vap;
+ const struct ieee80211_txparam *tp;
+ struct rt2860_softc_node *rni;
+ struct rt2860_softc_tx_ring *ring;
+ struct rt2860_softc_tx_data *data;
+ struct rt2860_txdesc *desc;
+ struct rt2860_txwi *txwi;
+ struct ieee80211_frame *wh;
+ struct rt2860_softc_tx_radiotap_header *tap;
+ bus_dma_segment_t dma_seg[RT2860_SOFTC_MAX_SCATTER];
+ struct mbuf *m_d;
+ u_int hdrsize, hdrspace;
+ uint8_t rate, mcs, pid, qsel;
+ uint16_t len, dmalen, mpdu_len, dur;
+ int error, mimops, ndmasegs, ndescs, i, j;
+
+ KASSERT(qid >= 0 && qid < RT2860_SOFTC_TX_RING_COUNT,
+ ("%s: Tx MGMT: invalid qid=%d\n",
+ device_get_nameunit(sc->dev), qid));
+
+ RT2860_SOFTC_TX_RING_ASSERT_LOCKED(&sc->tx_ring[qid]);
+
+ ic = &sc->sc_ic;
+ vap = ni->ni_vap;
+ rni = (struct rt2860_softc_node *) ni;
+ tp = ni->ni_txparms;
+
+ ring = &sc->tx_ring[qid];
+ desc = &ring->desc[ring->desc_cur];
+ data = &ring->data[ring->data_cur];
+ txwi = (struct rt2860_txwi *) (ring->seg0 + ring->data_cur * RT2860_TX_DATA_SEG0_SIZE);
+
+ wh = mtod(m, struct ieee80211_frame *);
+
+ rate = tp->mgmtrate & IEEE80211_RATE_VAL;
+/* XXX */
+ if (!rate)
+ return EFBIG;
+
+ /* fill Tx wireless info */
+
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ mcs = rate;
+ else
+ mcs = rt2860_rate2mcs(rate);
+
+ /* calculate MPDU length without padding */
+
+ hdrsize = ieee80211_anyhdrsize(wh);
+ hdrspace = ieee80211_anyhdrspace(ic, wh);
+ mpdu_len = m->m_pkthdr.len - hdrspace + hdrsize;
+
+ memset(txwi, 0, sizeof(struct rt2860_txwi));
+
+ /* management frames do not need encryption */
+
+ txwi->wcid = RT2860_WCID_RESERVED;
+
+ /* MIMO power save */
+
+ if ((ni->ni_flags & IEEE80211_NODE_HT) && (ni->ni_flags & IEEE80211_NODE_MIMO_PS))
+ {
+ if (mcs > 7)
+ {
+ if (ni->ni_flags & IEEE80211_NODE_MIMO_RTS)
+ {
+ /* dynamic MIMO power save */
+
+ txwi->mpdu_density_flags |=
+ (RT2860_TXWI_FLAGS_MIMOPS << RT2860_TXWI_FLAGS_SHIFT);
+ }
+ else
+ {
+ /* static MIMO power save */
+
+ mcs = 7;
+ }
+ }
+
+ mimops = 1;
+ }
+ else
+ {
+ mimops = 0;
+ }
+
+ pid = (mcs < 0xf) ? (mcs + 1) : mcs;
+
+ txwi->pid_mpdu_len = ((htole16(pid) & RT2860_TXWI_PID_MASK) <<
+ RT2860_TXWI_PID_SHIFT) | ((htole16(mpdu_len) & RT2860_TXWI_MPDU_LEN_MASK) <<
+ RT2860_TXWI_MPDU_LEN_SHIFT);
+
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ {
+ txwi->phymode_ifs_stbc_shortgi |=
+ (RT2860_TXWI_PHYMODE_HT_MIXED << RT2860_TXWI_PHYMODE_SHIFT);
+ }
+ else
+ {
+ if (ieee80211_rate2phytype(ic->ic_rt, rate) != IEEE80211_T_OFDM)
+ {
+ txwi->phymode_ifs_stbc_shortgi |=
+ (RT2860_TXWI_PHYMODE_CCK << RT2860_TXWI_PHYMODE_SHIFT);
+
+ if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
+ mcs |= RT2860_TXWI_MCS_SHOTPRE;
+ }
+ else
+ {
+ txwi->phymode_ifs_stbc_shortgi |=
+ (RT2860_TXWI_PHYMODE_OFDM << RT2860_TXWI_PHYMODE_SHIFT);
+ }
+ }
+
+ txwi->bw_mcs = (RT2860_TXWI_BW_20 << RT2860_TXWI_BW_SHIFT) |
+ ((mcs & RT2860_TXWI_MCS_MASK) << RT2860_TXWI_MCS_SHIFT);
+
+ txwi->txop = (RT2860_TXWI_TXOP_BACKOFF << RT2860_TXWI_TXOP_SHIFT);
+
+ /* skip ACKs for multicast frames */
+
+ if (!IEEE80211_IS_MULTICAST(wh->i_addr1))
+ {
+ txwi->bawin_size_xflags |=
+ (RT2860_TXWI_XFLAGS_ACK << RT2860_TXWI_XFLAGS_SHIFT);
+
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ {
+ /* preamble + plcp + signal extension + SIFS */
+
+ dur = 16 + 4 + 6 + 10;
+ }
+ else
+ {
+ dur = ieee80211_ack_duration(ic->ic_rt, rate,
+ ic->ic_flags & IEEE80211_F_SHPREAMBLE);
+ }
+
+ *(uint16_t *) wh->i_dur = htole16(dur);
+ }
+
+ /* ask MAC to insert timestamp into probe responses */
+
+ if ((wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
+ (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
+ txwi->mpdu_density_flags |=
+ (RT2860_TXWI_FLAGS_TS << RT2860_TXWI_FLAGS_SHIFT);
+
+ if (ieee80211_radiotap_active_vap(vap))
+ {
+ tap = &sc->txtap;
+
+ tap->flags = IEEE80211_RADIOTAP_F_DATAPAD;
+ tap->chan_flags = htole32(ic->ic_curchan->ic_flags);
+ tap->chan_freq = htole16(ic->ic_curchan->ic_freq);
+ tap->chan_ieee = ic->ic_curchan->ic_ieee;
+ tap->chan_maxpow = 0;
+
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ tap->rate = mcs | IEEE80211_RATE_MCS;
+ else
+ tap->rate = rate;
+
+ if (mcs & RT2860_TXWI_MCS_SHOTPRE)
+ tap->flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
+ tap->flags |= IEEE80211_RADIOTAP_F_WEP;
+
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
+ {
+ wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
+
+ ieee80211_radiotap_tx(vap, m);
+
+ wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
+ }
+ else
+ {
+ ieee80211_radiotap_tx(vap, m);
+ }
+ }
+
+ /* copy and trim 802.11 header */
+
+ m_copydata(m, 0, hdrsize, (caddr_t) (txwi + 1));
+ m_adj(m, hdrspace);
+
+ error = bus_dmamap_load_mbuf_sg(ring->data_dma_tag, data->dma_map, m,
+ dma_seg, &ndmasegs, BUS_DMA_NOWAIT);
+ if (error != 0)
+ {
+ /* too many fragments, linearize */
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+ "%s: could not load mbuf DMA map, trying to linearize mbuf: ndmasegs=%d, len=%d, error=%d\n",
+ device_get_nameunit(sc->dev), ndmasegs, m->m_pkthdr.len, error);
+
+ m_d = m_collapse(m, M_NOWAIT, 16);
+ if (m_d == NULL) {
+ m_freem(m);
+ m = NULL;
+ return (ENOMEM);
+ }
+ m = m_d;
+
+ sc->tx_defrag_packets++;
+
+ error = bus_dmamap_load_mbuf_sg(ring->data_dma_tag, data->dma_map, m,
+ dma_seg, &ndmasegs, BUS_DMA_NOWAIT);
+ if (error != 0)
+ {
+ printf("%s: could not load mbuf DMA map: ndmasegs=%d, len=%d, error=%d\n",
+ device_get_nameunit(sc->dev), ndmasegs, m->m_pkthdr.len, error);
+ m_freem(m);
+ return error;
+ }
+ }
+
+ if (m->m_pkthdr.len == 0)
+ ndmasegs = 0;
+
+ /* determine how many Tx descs are required */
+
+ ndescs = 1 + ndmasegs / 2;
+ if ((ring->desc_queued + ndescs) > (RT2860_SOFTC_TX_RING_DESC_COUNT - 2))
+ {
+ RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+ "%s: there are not enough Tx descs\n",
+ device_get_nameunit(sc->dev));
+
+ sc->no_tx_desc_avail++;
+
+ bus_dmamap_unload(ring->data_dma_tag, data->dma_map);
+ m_freem(m);
+ return EFBIG;
+ }
+
+ data->m = m;
+ data->ni = ni;
+
+ /* set up Tx descs */
+
+ /* first segment is Tx wireless info and 802.11 header */
+
+ len = sizeof(struct rt2860_txwi) + hdrsize;
+
+ /* align end on a 4-bytes boundary */
+
+ dmalen = (len + 3) & ~ 3;
+
+ memset((caddr_t) txwi + len, 0, dmalen - len);
+
+ qsel = RT2860_TXDESC_QSEL_EDCA;
+
+ desc->sdp0 = htole32(ring->seg0_phys_addr + ring->data_cur * RT2860_TX_DATA_SEG0_SIZE);
+ desc->sdl0 = htole16(dmalen);
+ desc->qsel_flags = (qsel << RT2860_TXDESC_QSEL_SHIFT);
+
+ /* set up payload segments */
+
+ for (i = ndmasegs, j = 0; i >= 2; i -= 2)
+ {
+ desc->sdp1 = htole32(dma_seg[j].ds_addr);
+ desc->sdl1 = htole16(dma_seg[j].ds_len);
+
+ ring->desc_queued++;
+ ring->desc_cur = (ring->desc_cur + 1) % RT2860_SOFTC_TX_RING_DESC_COUNT;
+
+ j++;
+
+ desc = &ring->desc[ring->desc_cur];
+
+ desc->sdp0 = htole32(dma_seg[j].ds_addr);
+ desc->sdl0 = htole16(dma_seg[j].ds_len);
+ desc->qsel_flags = (qsel << RT2860_TXDESC_QSEL_SHIFT);
+
+ j++;
+ }
+
+ /* finalize last payload segment */
+
+ if (i > 0)
+ {
+ desc->sdp1 = htole32(dma_seg[j].ds_addr);
+ desc->sdl1 = htole16(dma_seg[j].ds_len | RT2860_TXDESC_SDL1_LASTSEG);
+ }
+ else
+ {
+ desc->sdl0 |= htole16(RT2860_TXDESC_SDL0_LASTSEG);
+ desc->sdl1 = 0;
+ }
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+ "%s: sending MGMT frame: qid=%d, hdrsize=%d, hdrspace=%d, len=%d, "
+ "mcs=%d, mimops=%d, DMA len=%d, ndmasegs=%d, DMA ds_len=%d/%d/%d/%d/%d\n",
+ device_get_nameunit(sc->dev),
+ qid, hdrsize, hdrspace, m->m_pkthdr.len + hdrsize,
+ mcs, mimops, dmalen, ndmasegs,
+ (int) dma_seg[0].ds_len, (int) dma_seg[1].ds_len, (int) dma_seg[2].ds_len, (int) dma_seg[3].ds_len, (int) dma_seg[4].ds_len);
+
+ bus_dmamap_sync(ring->seg0_dma_tag, ring->seg0_dma_map,
+ BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(ring->data_dma_tag, data->dma_map,
+ BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+ BUS_DMASYNC_PREWRITE);
+
+ ring->desc_queued++;
+ ring->desc_cur = (ring->desc_cur + 1) % RT2860_SOFTC_TX_RING_DESC_COUNT;
+
+ ring->data_queued++;
+ ring->data_cur = (ring->data_cur + 1) % RT2860_SOFTC_TX_RING_DATA_COUNT;
+
+ /* kick Tx */
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_CTX_IDX(qid), ring->desc_cur);
+
+ return 0;
+}
+
+/*
+ * rt2860_tx_data
+ */
+static int rt2860_tx_data(struct rt2860_softc *sc,
+ struct mbuf *m, struct ieee80211_node *ni, int qid)
+{
+ struct ieee80211com *ic;
+ struct ieee80211vap *vap;
+ const struct ieee80211_txparam *tp;
+ struct rt2860_softc_node *rni;
+ struct rt2860_softc_tx_ring *ring;
+ struct rt2860_softc_tx_data *data;
+ struct rt2860_txdesc *desc;
+ struct rt2860_txwi *txwi;
+ struct ieee80211_frame *wh;
+ struct ieee80211_tx_ampdu *tx_ampdu;
+ ieee80211_seq seqno;
+ struct rt2860_softc_tx_radiotap_header *tap;
+ bus_dma_segment_t dma_seg[RT2860_SOFTC_MAX_SCATTER];
+ u_int hdrsize, hdrspace;
+ uint8_t type, rate, bw, stbc, shortgi, mcs, pid, wcid, mpdu_density, bawin_size, qsel;
+ uint16_t qos, len, dmalen, mpdu_len, dur;
+ int error, hasqos, ac, tid, ampdu, mimops, ndmasegs, ndescs, i, j;
+
+ KASSERT(qid >= 0 && qid < RT2860_SOFTC_TX_RING_COUNT,
+ ("%s: Tx data: invalid qid=%d\n",
+ device_get_nameunit(sc->dev), qid));
+
+ RT2860_SOFTC_TX_RING_ASSERT_LOCKED(&sc->tx_ring[qid]);
+
+ ic = &sc->sc_ic;
+ vap = ni->ni_vap;
+ rni = (struct rt2860_softc_node *) ni;
+ tp = ni->ni_txparms;
+
+ ring = &sc->tx_ring[qid];
+ desc = &ring->desc[ring->desc_cur];
+ data = &ring->data[ring->data_cur];
+ txwi = (struct rt2860_txwi *) (ring->seg0 + ring->data_cur * RT2860_TX_DATA_SEG0_SIZE);
+
+ wh = mtod(m, struct ieee80211_frame *);
+
+ type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+
+ hasqos = IEEE80211_QOS_HAS_SEQ(wh);
+ if (hasqos)
+ {
+ if (IEEE80211_HAS_ADDR4(wh))
+ qos = le16toh(*(const uint16_t *)
+ (((struct ieee80211_qosframe_addr4 *) wh)->i_qos));
+ else
+ qos = le16toh(*(const uint16_t *)
+ (((struct ieee80211_qosframe *) wh)->i_qos));
+ }
+ else
+ {
+ qos = 0;
+ }
+
+ if (IEEE80211_IS_MULTICAST(wh->i_addr1))
+ rate = tp->mcastrate;
+ else if (m->m_flags & M_EAPOL)
+ rate = tp->mgmtrate;
+ else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
+ rate = tp->ucastrate;
+ else
+ rate = ni->ni_txrate;
+
+ rate &= IEEE80211_RATE_VAL;
+/* XXX */
+ if (!rate)
+ return EFBIG;
+
+ /* fill Tx wireless info */
+
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ mcs = rate;
+ else
+ mcs = rt2860_rate2mcs(rate);
+
+ if (type == IEEE80211_FC0_TYPE_DATA)
+ wcid = !IEEE80211_IS_MULTICAST(wh->i_addr1) ? rni->staid : RT2860_WCID_MCAST;
+ else
+ wcid = RT2860_WCID_RESERVED;
+
+ /* calculate MPDU length without padding */
+
+ hdrsize = ieee80211_anyhdrsize(wh);
+ hdrspace = ieee80211_anyhdrspace(ic, wh);
+ mpdu_len = m->m_pkthdr.len - hdrspace + hdrsize;
+
+ memset(txwi, 0, sizeof(struct rt2860_txwi));
+
+ txwi->wcid = wcid;
+
+ /* MIMO power save */
+
+ if ((ni->ni_flags & IEEE80211_NODE_HT) && (ni->ni_flags & IEEE80211_NODE_MIMO_PS))
+ {
+ if (mcs > 7)
+ {
+ if (ni->ni_flags & IEEE80211_NODE_MIMO_RTS)
+ {
+ /* dynamic MIMO power save */
+
+ txwi->mpdu_density_flags |=
+ (RT2860_TXWI_FLAGS_MIMOPS << RT2860_TXWI_FLAGS_SHIFT);
+ }
+ else
+ {
+ /* static MIMO power save */
+
+ mcs = 7;
+ }
+ }
+
+ mimops = 1;
+ }
+ else
+ {
+ mimops = 0;
+ }
+
+ pid = (mcs < 0xf) ? (mcs + 1) : mcs;
+
+ txwi->pid_mpdu_len = ((htole16(pid) & RT2860_TXWI_PID_MASK) <<
+ RT2860_TXWI_PID_SHIFT) | ((htole16(mpdu_len) & RT2860_TXWI_MPDU_LEN_MASK) <<
+ RT2860_TXWI_MPDU_LEN_SHIFT);
+
+ stbc = sc->tx_stbc && (mcs <= 7) && (vap->iv_htcaps & IEEE80211_HTCAP_TXSTBC) &&
+ (ni->ni_flags & IEEE80211_NODE_HT) && (ni->ni_htcap & IEEE80211_HTCAP_RXSTBC);
+
+ shortgi = ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) && (ni->ni_flags & IEEE80211_NODE_SGI20) && (ni->ni_chw == 20)) ||
+ ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40) && (ni->ni_flags & IEEE80211_NODE_SGI40) && (ni->ni_chw == 40));
+
+ txwi->phymode_ifs_stbc_shortgi |=
+ ((stbc & RT2860_TXWI_STBC_MASK) << RT2860_TXWI_STBC_SHIFT) |
+ ((shortgi & RT2860_TXWI_SHORTGI_MASK) << RT2860_TXWI_SHORTGI_SHIFT);
+
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ {
+ txwi->phymode_ifs_stbc_shortgi |=
+ (RT2860_TXWI_PHYMODE_HT_MIXED << RT2860_TXWI_PHYMODE_SHIFT);
+ }
+ else
+ {
+ if (ieee80211_rate2phytype(ic->ic_rt, rate) != IEEE80211_T_OFDM)
+ {
+ txwi->phymode_ifs_stbc_shortgi |=
+ (RT2860_TXWI_PHYMODE_CCK << RT2860_TXWI_PHYMODE_SHIFT);
+
+ if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
+ mcs |= RT2860_TXWI_MCS_SHOTPRE;
+ }
+ else
+ {
+ txwi->phymode_ifs_stbc_shortgi |=
+ (RT2860_TXWI_PHYMODE_OFDM << RT2860_TXWI_PHYMODE_SHIFT);
+ }
+ }
+
+ if ((ni->ni_flags & IEEE80211_NODE_HT) && (ni->ni_chw == 40))
+ bw = RT2860_TXWI_BW_40;
+ else
+ bw = RT2860_TXWI_BW_20;
+
+ txwi->bw_mcs = ((bw & RT2860_TXWI_BW_MASK) << RT2860_TXWI_BW_SHIFT) |
+ ((mcs & RT2860_TXWI_MCS_MASK) << RT2860_TXWI_MCS_SHIFT);
+
+ txwi->txop = (RT2860_TXWI_TXOP_HT << RT2860_TXWI_TXOP_SHIFT);
+
+ if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+ (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) != IEEE80211_QOS_ACKPOLICY_NOACK))
+ {
+ txwi->bawin_size_xflags |=
+ (RT2860_TXWI_XFLAGS_ACK << RT2860_TXWI_XFLAGS_SHIFT);
+
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ {
+ /* preamble + plcp + signal extension + SIFS */
+
+ dur = 16 + 4 + 6 + 10;
+ }
+ else
+ {
+ dur = ieee80211_ack_duration(ic->ic_rt, rate,
+ ic->ic_flags & IEEE80211_F_SHPREAMBLE);
+ }
+
+ *(uint16_t *) wh->i_dur = htole16(dur);
+ }
+
+ /* check for A-MPDU */
+
+ if (m->m_flags & M_AMPDU_MPDU)
+ {
+ ac = M_WME_GETAC(m);
+ tid = WME_AC_TO_TID(ac);
+ tx_ampdu = &ni->ni_tx_ampdu[ac];
+
+ mpdu_density = RT2860_MS(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY);
+ bawin_size = tx_ampdu->txa_wnd;
+
+ txwi->mpdu_density_flags |=
+ ((mpdu_density & RT2860_TXWI_MPDU_DENSITY_MASK) << RT2860_TXWI_MPDU_DENSITY_SHIFT) |
+ (RT2860_TXWI_FLAGS_AMPDU << RT2860_TXWI_FLAGS_SHIFT);
+
+ txwi->bawin_size_xflags |=
+ ((bawin_size & RT2860_TXWI_BAWIN_SIZE_MASK) << RT2860_TXWI_BAWIN_SIZE_SHIFT);
+
+ seqno = ni->ni_txseqs[tid]++;
+
+ *(uint16_t *) &wh->i_seq[0] = htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
+
+ ampdu = 1;
+ }
+ else
+ {
+ mpdu_density = 0;
+ bawin_size = 0;
+ ampdu = 0;
+ }
+
+ /* ask MAC to insert timestamp into probe responses */
+
+ if ((wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
+ (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
+ txwi->mpdu_density_flags |=
+ (RT2860_TXWI_FLAGS_TS << RT2860_TXWI_FLAGS_SHIFT);
+
+ if (ieee80211_radiotap_active_vap(vap))
+ {
+ tap = &sc->txtap;
+
+ tap->flags = IEEE80211_RADIOTAP_F_DATAPAD;
+ tap->chan_flags = htole32(ic->ic_curchan->ic_flags);
+ tap->chan_freq = htole16(ic->ic_curchan->ic_freq);
+ tap->chan_ieee = ic->ic_curchan->ic_ieee;
+ tap->chan_maxpow = 0;
+
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ tap->rate = mcs | IEEE80211_RATE_MCS;
+ else
+ tap->rate = rate;
+
+ if (mcs & RT2860_TXWI_MCS_SHOTPRE)
+ tap->flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+ if (shortgi)
+ tap->flags |= IEEE80211_RADIOTAP_F_SHORTGI;
+
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
+ tap->flags |= IEEE80211_RADIOTAP_F_WEP;
+
+ /* XXX use temporarily radiotap CFP flag as A-MPDU flag */
+
+ if (ampdu)
+ tap->flags |= IEEE80211_RADIOTAP_F_CFP;
+
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
+ {
+ wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
+
+ ieee80211_radiotap_tx(vap, m);
+
+ wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
+ }
+ else
+ {
+ ieee80211_radiotap_tx(vap, m);
+ }
+ }
+
+ /* copy and trim 802.11 header */
+
+ m_copydata(m, 0, hdrsize, (caddr_t) (txwi + 1));
+ m_adj(m, hdrspace);
+
+ error = bus_dmamap_load_mbuf_sg(ring->data_dma_tag, data->dma_map, m,
+ dma_seg, &ndmasegs, BUS_DMA_NOWAIT);
+ if (error != 0)
+ {
+ /* too many fragments, linearize */
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+ "%s: could not load mbuf DMA map, trying to linearize mbuf: ndmasegs=%d, len=%d, error=%d\n",
+ device_get_nameunit(sc->dev), ndmasegs, m->m_pkthdr.len, error);
+
+ m = m_defrag(m, M_NOWAIT);
+ if (m == NULL)
+ return ENOMEM;
+
+ sc->tx_defrag_packets++;
+
+ error = bus_dmamap_load_mbuf_sg(ring->data_dma_tag, data->dma_map, m,
+ dma_seg, &ndmasegs, BUS_DMA_NOWAIT);
+ if (error != 0)
+ {
+ printf("%s: could not load mbuf DMA map: ndmasegs=%d, len=%d, error=%d\n",
+ device_get_nameunit(sc->dev), ndmasegs, m->m_pkthdr.len, error);
+ m_freem(m);
+ return error;
+ }
+ }
+
+ if (m->m_pkthdr.len == 0)
+ ndmasegs = 0;
+
+ /* determine how many Tx descs are required */
+
+ ndescs = 1 + ndmasegs / 2;
+ if ((ring->desc_queued + ndescs) > (RT2860_SOFTC_TX_RING_DESC_COUNT - 2))
+ {
+ RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+ "%s: there are not enough Tx descs\n",
+ device_get_nameunit(sc->dev));
+
+ sc->no_tx_desc_avail++;
+
+ bus_dmamap_unload(ring->data_dma_tag, data->dma_map);
+ m_freem(m);
+ return EFBIG;
+ }
+
+ data->m = m;
+ data->ni = ni;
+
+ /* set up Tx descs */
+
+ /* first segment is Tx wireless info and 802.11 header */
+
+ len = sizeof(struct rt2860_txwi) + hdrsize;
+
+ /* align end on a 4-bytes boundary */
+
+ dmalen = (len + 3) & ~ 3;
+
+ memset((caddr_t) txwi + len, 0, dmalen - len);
+
+ qsel = RT2860_TXDESC_QSEL_EDCA;
+
+ desc->sdp0 = htole32(ring->seg0_phys_addr + ring->data_cur * RT2860_TX_DATA_SEG0_SIZE);
+ desc->sdl0 = htole16(dmalen);
+ desc->qsel_flags = (qsel << RT2860_TXDESC_QSEL_SHIFT);
+
+ /* set up payload segments */
+
+ for (i = ndmasegs, j = 0; i >= 2; i -= 2)
+ {
+ desc->sdp1 = htole32(dma_seg[j].ds_addr);
+ desc->sdl1 = htole16(dma_seg[j].ds_len);
+
+ ring->desc_queued++;
+ ring->desc_cur = (ring->desc_cur + 1) % RT2860_SOFTC_TX_RING_DESC_COUNT;
+
+ j++;
+
+ desc = &ring->desc[ring->desc_cur];
+
+ desc->sdp0 = htole32(dma_seg[j].ds_addr);
+ desc->sdl0 = htole16(dma_seg[j].ds_len);
+ desc->qsel_flags = (qsel << RT2860_TXDESC_QSEL_SHIFT);
+
+ j++;
+ }
+
+ /* finalize last payload segment */
+
+ if (i > 0)
+ {
+ desc->sdp1 = htole32(dma_seg[j].ds_addr);
+ desc->sdl1 = htole16(dma_seg[j].ds_len | RT2860_TXDESC_SDL1_LASTSEG);
+ }
+ else
+ {
+ desc->sdl0 |= htole16(RT2860_TXDESC_SDL0_LASTSEG);
+ desc->sdl1 = 0;
+ }
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+ "%s: sending data: qid=%d, hdrsize=%d, hdrspace=%d, len=%d, "
+ "bw=%d, stbc=%d, shortgi=%d, mcs=%d, wcid=0x%02x, "
+ "ampdu=%d (density=%d, winsize=%d), mimops=%d, DMA len=%d, ndmasegs=%d, DMA ds_len=%d/%d/%d/%d/%d\n",
+ device_get_nameunit(sc->dev),
+ qid, hdrsize, hdrspace, m->m_pkthdr.len + hdrsize,
+ bw, stbc, shortgi, mcs, wcid, ampdu, mpdu_density, bawin_size, mimops, dmalen, ndmasegs,
+ (int) dma_seg[0].ds_len, (int) dma_seg[1].ds_len, (int) dma_seg[2].ds_len, (int) dma_seg[3].ds_len, (int) dma_seg[4].ds_len);
+
+ bus_dmamap_sync(ring->seg0_dma_tag, ring->seg0_dma_map,
+ BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(ring->data_dma_tag, data->dma_map,
+ BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+ BUS_DMASYNC_PREWRITE);
+
+ ring->desc_queued++;
+ ring->desc_cur = (ring->desc_cur + 1) % RT2860_SOFTC_TX_RING_DESC_COUNT;
+
+ ring->data_queued++;
+ ring->data_cur = (ring->data_cur + 1) % RT2860_SOFTC_TX_RING_DATA_COUNT;
+
+ /* kick Tx */
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_CTX_IDX(qid), ring->desc_cur);
+
+ return 0;
+}
+
+/*
+ * rt2860_tx_raw
+static int rt2860_tx_raw(struct rt2860_softc *sc,
+ struct mbuf *m, struct ieee80211_node *ni,
+ const struct ieee80211_bpf_params *params)
+{
+ RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+ "%s: Tx raw\n",
+ device_get_nameunit(sc->dev));
+
+ return 0;
+}
+ */
+
+/*
+ * rt2860_intr
+ */
+static void rt2860_intr(void *arg)
+{
+ struct rt2860_softc *sc;
+ uint32_t status;
+
+ sc = arg;
+
+ /* acknowledge interrupts */
+
+ status = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_INT_STATUS);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_INT_STATUS, status);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+ "%s: interrupt: status = 0x%08x\n",
+ device_get_nameunit(sc->dev), status);
+
+ if (status == 0xffffffff || /* device likely went away */
+ status == 0) /* not for us */
+ return;
+
+ sc->interrupts++;
+
+ if (!(sc->sc_flags & RT2860_RUNNING))
+ return;
+
+ if (status & RT2860_REG_INT_TX_COHERENT)
+ rt2860_tx_coherent_intr(sc);
+
+ if (status & RT2860_REG_INT_RX_COHERENT)
+ rt2860_rx_coherent_intr(sc);
+
+ if (status & RT2860_REG_INT_TXRX_COHERENT)
+ rt2860_txrx_coherent_intr(sc);
+
+ if (status & RT2860_REG_INT_FIFO_STA_FULL)
+ rt2860_fifo_sta_full_intr(sc);
+
+ if (status & RT2860_REG_INT_TX_MGMT_DONE)
+ rt2860_tx_intr(sc, 5);
+
+ if (status & RT2860_REG_INT_RX_DONE)
+ rt2860_rx_intr(sc);
+
+ if (status & RT2860_REG_INT_RX_DELAY_DONE)
+ rt2860_rx_delay_intr(sc);
+
+ if (status & RT2860_REG_INT_TX_HCCA_DONE)
+ rt2860_tx_intr(sc, 4);
+
+ if (status & RT2860_REG_INT_TX_AC3_DONE)
+ rt2860_tx_intr(sc, 3);
+
+ if (status & RT2860_REG_INT_TX_AC2_DONE)
+ rt2860_tx_intr(sc, 2);
+
+ if (status & RT2860_REG_INT_TX_AC1_DONE)
+ rt2860_tx_intr(sc, 1);
+
+ if (status & RT2860_REG_INT_TX_AC0_DONE)
+ rt2860_tx_intr(sc, 0);
+
+ if (status & RT2860_REG_INT_TX_DELAY_DONE)
+ rt2860_tx_delay_intr(sc);
+
+ if (status & RT2860_REG_INT_PRE_TBTT)
+ rt2860_pre_tbtt_intr(sc);
+
+ if (status & RT2860_REG_INT_TBTT)
+ rt2860_tbtt_intr(sc);
+
+ if (status & RT2860_REG_INT_MCU_CMD)
+ rt2860_mcu_cmd_intr(sc);
+
+ if (status & RT2860_REG_INT_AUTO_WAKEUP)
+ rt2860_auto_wakeup_intr(sc);
+
+ if (status & RT2860_REG_INT_GP_TIMER)
+ rt2860_gp_timer_intr(sc);
+
+}
+
+/*
+ * rt2860_tx_coherent_intr
+ */
+static void rt2860_tx_coherent_intr(struct rt2860_softc *sc)
+{
+ uint32_t tmp;
+ int i;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+ "%s: Tx coherent interrupt\n",
+ device_get_nameunit(sc->dev));
+
+ sc->tx_coherent_interrupts++;
+
+ /* restart DMA engine */
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG);
+
+ tmp &= ~(RT2860_REG_TX_WB_DDONE |
+ RT2860_REG_RX_DMA_ENABLE |
+ RT2860_REG_TX_DMA_ENABLE);
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG, tmp);
+
+ /* init Tx rings (4 EDCAs + HCCA + MGMT) */
+
+ for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++)
+ rt2860_reset_tx_ring(sc, &sc->tx_ring[i]);
+
+ for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++)
+ {
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_BASE_PTR(i),
+ sc->tx_ring[i].desc_phys_addr);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_MAX_CNT(i),
+ RT2860_SOFTC_TX_RING_DESC_COUNT);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_CTX_IDX(i), 0);
+ }
+
+ /* init Rx ring */
+
+ rt2860_reset_rx_ring(sc, &sc->rx_ring);
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_BASE_PTR,
+ sc->rx_ring.desc_phys_addr);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_MAX_CNT,
+ RT2860_SOFTC_RX_RING_DATA_COUNT);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_CALC_IDX,
+ RT2860_SOFTC_RX_RING_DATA_COUNT - 1);
+
+ rt2860_txrx_enable(sc);
+}
+
+/*
+ * rt2860_rx_coherent_intr
+ */
+static void rt2860_rx_coherent_intr(struct rt2860_softc *sc)
+{
+ uint32_t tmp;
+ int i;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+ "%s: Rx coherent interrupt\n",
+ device_get_nameunit(sc->dev));
+
+ sc->rx_coherent_interrupts++;
+
+ /* restart DMA engine */
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG);
+
+ tmp &= ~(RT2860_REG_TX_WB_DDONE |
+ RT2860_REG_RX_DMA_ENABLE |
+ RT2860_REG_TX_DMA_ENABLE);
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG, tmp);
+
+ /* init Tx rings (4 EDCAs + HCCA + MGMT) */
+
+ for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++)
+ rt2860_reset_tx_ring(sc, &sc->tx_ring[i]);
+
+ for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++)
+ {
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_BASE_PTR(i),
+ sc->tx_ring[i].desc_phys_addr);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_MAX_CNT(i),
+ RT2860_SOFTC_TX_RING_DESC_COUNT);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_CTX_IDX(i), 0);
+ }
+
+ /* init Rx ring */
+
+ rt2860_reset_rx_ring(sc, &sc->rx_ring);
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_BASE_PTR,
+ sc->rx_ring.desc_phys_addr);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_MAX_CNT,
+ RT2860_SOFTC_RX_RING_DATA_COUNT);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_CALC_IDX,
+ RT2860_SOFTC_RX_RING_DATA_COUNT - 1);
+
+ rt2860_txrx_enable(sc);
+}
+
+/*
+ * rt2860_txrx_coherent_intr
+ */
+static void rt2860_txrx_coherent_intr(struct rt2860_softc *sc)
+{
+ uint32_t tmp;
+ int i;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+ "%s: Tx/Rx coherent interrupt\n",
+ device_get_nameunit(sc->dev));
+
+ sc->txrx_coherent_interrupts++;
+
+ /* restart DMA engine */
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG);
+
+ tmp &= ~(RT2860_REG_TX_WB_DDONE |
+ RT2860_REG_RX_DMA_ENABLE |
+ RT2860_REG_TX_DMA_ENABLE);
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG, tmp);
+
+ /* init Tx rings (4 EDCAs + HCCA + MGMT) */
+
+ for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++)
+ rt2860_reset_tx_ring(sc, &sc->tx_ring[i]);
+
+ for (i = 0; i < RT2860_SOFTC_TX_RING_COUNT; i++)
+ {
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_BASE_PTR(i),
+ sc->tx_ring[i].desc_phys_addr);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_MAX_CNT(i),
+ RT2860_SOFTC_TX_RING_DESC_COUNT);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_TX_CTX_IDX(i), 0);
+ }
+
+ /* init Rx ring */
+
+ rt2860_reset_rx_ring(sc, &sc->rx_ring);
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_BASE_PTR,
+ sc->rx_ring.desc_phys_addr);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_MAX_CNT,
+ RT2860_SOFTC_RX_RING_DATA_COUNT);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_CALC_IDX,
+ RT2860_SOFTC_RX_RING_DATA_COUNT - 1);
+
+ rt2860_txrx_enable(sc);
+}
+
+/*
+ * rt2860_fifo_sta_full_intr
+ */
+static void rt2860_fifo_sta_full_intr(struct rt2860_softc *sc)
+{
+ RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+ "%s: FIFO statistic full interrupt\n",
+ device_get_nameunit(sc->dev));
+
+ sc->fifo_sta_full_interrupts++;
+
+ RT2860_SOFTC_LOCK(sc);
+
+ if (!(sc->intr_disable_mask & RT2860_REG_INT_FIFO_STA_FULL))
+ {
+ rt2860_intr_disable(sc, RT2860_REG_INT_FIFO_STA_FULL);
+
+ taskqueue_enqueue(sc->taskqueue, &sc->fifo_sta_full_task);
+ }
+
+ sc->intr_pending_mask |= RT2860_REG_INT_FIFO_STA_FULL;
+
+ RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_rx_intr
+ */
+static void rt2860_rx_intr(struct rt2860_softc *sc)
+{
+ RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+ "%s: Rx interrupt\n",
+ device_get_nameunit(sc->dev));
+
+ sc->rx_interrupts++;
+
+ RT2860_SOFTC_LOCK(sc);
+
+ if (!(sc->intr_disable_mask & RT2860_REG_INT_RX_DONE))
+ {
+ rt2860_intr_disable(sc, RT2860_REG_INT_RX_DONE);
+
+ taskqueue_enqueue(sc->taskqueue, &sc->rx_done_task);
+ }
+
+ sc->intr_pending_mask |= RT2860_REG_INT_RX_DONE;
+
+ RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_rx_delay_intr
+ */
+static void rt2860_rx_delay_intr(struct rt2860_softc *sc)
+{
+ RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+ "%s: Rx delay interrupt\n",
+ device_get_nameunit(sc->dev));
+
+ sc->rx_delay_interrupts++;
+}
+
+/*
+ * rt2860_tx_intr
+ */
+static void rt2860_tx_intr(struct rt2860_softc *sc, int qid)
+{
+ KASSERT(qid >= 0 && qid < RT2860_SOFTC_TX_RING_COUNT,
+ ("%s: Tx interrupt: invalid qid=%d\n",
+ device_get_nameunit(sc->dev), qid));
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+ "%s: Tx interrupt: qid=%d\n",
+ device_get_nameunit(sc->dev), qid);
+
+ sc->tx_interrupts[qid]++;
+
+ RT2860_SOFTC_LOCK(sc);
+
+ if (!(sc->intr_disable_mask & (RT2860_REG_INT_TX_AC0_DONE << qid)))
+ {
+ rt2860_intr_disable(sc, (RT2860_REG_INT_TX_AC0_DONE << qid));
+
+ taskqueue_enqueue(sc->taskqueue, &sc->tx_done_task);
+ }
+
+ sc->intr_pending_mask |= (RT2860_REG_INT_TX_AC0_DONE << qid);
+
+ RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_tx_delay_intr
+ */
+static void rt2860_tx_delay_intr(struct rt2860_softc *sc)
+{
+ RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+ "%s: Tx delay interrupt\n",
+ device_get_nameunit(sc->dev));
+
+ sc->tx_delay_interrupts++;
+}
+
+/*
+ * rt2860_pre_tbtt_intr
+ */
+static void rt2860_pre_tbtt_intr(struct rt2860_softc *sc)
+{
+ RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+ "%s: Pre-TBTT interrupt\n",
+ device_get_nameunit(sc->dev));
+
+ sc->pre_tbtt_interrupts++;
+}
+
+/*
+ * rt2860_tbtt_intr
+ */
+static void rt2860_tbtt_intr(struct rt2860_softc *sc)
+{
+ RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+ "%s: TBTT interrupt\n",
+ device_get_nameunit(sc->dev));
+
+ sc->tbtt_interrupts++;
+}
+
+/*
+ * rt2860_mcu_cmd_intr
+ */
+static void rt2860_mcu_cmd_intr(struct rt2860_softc *sc)
+{
+ RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+ "%s: MCU command interrupt\n",
+ device_get_nameunit(sc->dev));
+
+ sc->mcu_cmd_interrupts++;
+}
+
+/*
+ * rt2860_auto_wakeup_intr
+ */
+static void rt2860_auto_wakeup_intr(struct rt2860_softc *sc)
+{
+ RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+ "%s: auto wakeup interrupt\n",
+ device_get_nameunit(sc->dev));
+
+ sc->auto_wakeup_interrupts++;
+}
+
+/*
+ * rt2860_gp_timer_intr
+ */
+static void rt2860_gp_timer_intr(struct rt2860_softc *sc)
+{
+ RT2860_DPRINTF(sc, RT2860_DEBUG_INTR,
+ "%s: GP timer interrupt\n",
+ device_get_nameunit(sc->dev));
+
+ sc->gp_timer_interrupts++;
+}
+
+/*
+ * rt2860_rx_done_task
+ */
+static void rt2860_rx_done_task(void *context, int pending)
+{
+ struct rt2860_softc *sc;
+ int again;
+
+ sc = context;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_RX,
+ "%s: Rx done task\n",
+ device_get_nameunit(sc->dev));
+
+ if (!(sc->sc_flags & RT2860_RUNNING))
+ return;
+
+ sc->intr_pending_mask &= ~RT2860_REG_INT_RX_DONE;
+
+ again = rt2860_rx_eof(sc, sc->rx_process_limit);
+
+ RT2860_SOFTC_LOCK(sc);
+
+ if ((sc->intr_pending_mask & RT2860_REG_INT_RX_DONE) || again)
+ {
+ RT2860_DPRINTF(sc, RT2860_DEBUG_RX,
+ "%s: Rx done task: scheduling again\n",
+ device_get_nameunit(sc->dev));
+
+ taskqueue_enqueue(sc->taskqueue, &sc->rx_done_task);
+ }
+ else
+ {
+ rt2860_intr_enable(sc, RT2860_REG_INT_RX_DONE);
+ }
+
+ RT2860_SOFTC_UNLOCK(sc);
+}
+
+/*
+ * rt2860_tx_done_task
+ */
+static void rt2860_tx_done_task(void *context, int pending)
+{
+ struct rt2860_softc *sc;
+ uint32_t intr_mask;
+ int i;
+
+ sc = context;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+ "%s: Tx done task\n",
+ device_get_nameunit(sc->dev));
+
+ if (!(sc->sc_flags & RT2860_RUNNING))
+ return;
+
+ for (i = RT2860_SOFTC_TX_RING_COUNT - 1; i >= 0; i--)
+ {
+ if (sc->intr_pending_mask & (RT2860_REG_INT_TX_AC0_DONE << i))
+ {
+ sc->intr_pending_mask &= ~(RT2860_REG_INT_TX_AC0_DONE << i);
+
+ rt2860_tx_eof(sc, &sc->tx_ring[i]);
+ }
+ }
+
+ sc->tx_timer = 0;
+
+ intr_mask = (RT2860_REG_INT_TX_MGMT_DONE |
+ RT2860_REG_INT_TX_HCCA_DONE |
+ RT2860_REG_INT_TX_AC3_DONE |
+ RT2860_REG_INT_TX_AC2_DONE |
+ RT2860_REG_INT_TX_AC1_DONE |
+ RT2860_REG_INT_TX_AC0_DONE);
+
+ RT2860_SOFTC_LOCK(sc);
+
+ rt2860_intr_enable(sc, ~sc->intr_pending_mask &
+ (sc->intr_disable_mask & intr_mask));
+
+ if (sc->intr_pending_mask & intr_mask)
+ {
+ RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+ "%s: Tx done task: scheduling again\n",
+ device_get_nameunit(sc->dev));
+
+ taskqueue_enqueue(sc->taskqueue, &sc->tx_done_task);
+ }
+
+ RT2860_SOFTC_UNLOCK(sc);
+
+// if (!IFQ_IS_EMPTY(&ifp->if_snd))
+ rt2860_start(sc);
+}
+
+/*
+ * rt2860_fifo_sta_full_task
+ */
+static void rt2860_fifo_sta_full_task(void *context, int pending)
+{
+ struct rt2860_softc *sc;
+
+ sc = context;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_STATS,
+ "%s: FIFO statistic full task\n",
+ device_get_nameunit(sc->dev));
+
+ if (!(sc->sc_flags & RT2860_RUNNING))
+ return;
+
+ sc->intr_pending_mask &= ~RT2860_REG_INT_FIFO_STA_FULL;
+
+ rt2860_drain_fifo_stats(sc);
+
+ RT2860_SOFTC_LOCK(sc);
+
+ if (sc->intr_pending_mask & RT2860_REG_INT_FIFO_STA_FULL)
+ {
+ RT2860_DPRINTF(sc, RT2860_DEBUG_STATS,
+ "%s: FIFO statistic full task: scheduling again\n",
+ device_get_nameunit(sc->dev));
+
+ taskqueue_enqueue(sc->taskqueue, &sc->fifo_sta_full_task);
+ }
+ else
+ {
+ rt2860_intr_enable(sc, RT2860_REG_INT_FIFO_STA_FULL);
+ }
+
+ RT2860_SOFTC_UNLOCK(sc);
+
+// if (!IFQ_IS_EMPTY(&ifp->if_snd))
+ rt2860_start(sc);
+}
+
+/*
+ * rt2860_periodic_task
+ */
+static void rt2860_periodic_task(void *context, int pending)
+{
+ struct rt2860_softc *sc;
+ struct ieee80211com *ic;
+ struct ieee80211vap *vap;
+
+ sc = context;
+ ic = &sc->sc_ic;
+ vap = TAILQ_FIRST(&ic->ic_vaps);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_PERIODIC,
+ "%s: periodic task: round=%lu\n",
+ device_get_nameunit(sc->dev), sc->periodic_round);
+
+ if (!(sc->sc_flags & RT2860_RUNNING))
+ return;
+
+ RT2860_SOFTC_LOCK(sc);
+
+ sc->periodic_round++;
+
+ rt2860_update_stats(sc);
+
+ if ((sc->periodic_round % 10) == 0)
+ {
+ rt2860_bbp_tuning(sc);
+
+ rt2860_update_raw_counters(sc);
+
+ rt2860_watchdog(sc);
+
+ if (vap != NULL && vap->iv_opmode != IEEE80211_M_MONITOR && vap->iv_state == IEEE80211_S_RUN)
+ {
+ if (vap->iv_opmode == IEEE80211_M_STA)
+ rt2860_amrr_update_iter_func(vap, vap->iv_bss);
+ else
+ ieee80211_iterate_nodes(&ic->ic_sta, rt2860_amrr_update_iter_func, vap);
+ }
+ }
+
+ RT2860_SOFTC_UNLOCK(sc);
+
+ callout_reset(&sc->periodic_ch, hz / 10, rt2860_periodic, sc);
+}
+
+/*
+ * rt2860_rx_eof
+ */
+static int rt2860_rx_eof(struct rt2860_softc *sc, int limit)
+{
+ struct ieee80211com *ic;
+ struct ieee80211_frame *wh;
+ struct ieee80211_node *ni;
+ struct rt2860_softc_node *rni;
+ struct rt2860_softc_rx_radiotap_header *tap;
+ struct rt2860_softc_rx_ring *ring;
+ struct rt2860_rxdesc *desc;
+ struct rt2860_softc_rx_data *data;
+ struct rt2860_rxwi *rxwi;
+ struct mbuf *m, *mnew;
+ bus_dma_segment_t segs[1];
+ bus_dmamap_t dma_map;
+ uint32_t index, desc_flags;
+ uint8_t rssi, ant, phymode, bw, shortgi, stbc, mcs, tid, frag;
+#ifdef RT2860_HW_CRYPTO
+ uint8_t cipher_err, keyidx;
+#endif
+ uint16_t seq;
+ int8_t rssi_dbm;
+ int error, nsegs, len, ampdu, amsdu, rssi_dbm_rel, nframes, i;
+
+ ic = &sc->sc_ic;
+ ring = &sc->rx_ring;
+
+ nframes = 0;
+
+ while (limit != 0)
+ {
+ index = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_RX_DRX_IDX);
+ if (ring->cur == index)
+ break;
+
+ desc = &ring->desc[ring->cur];
+ data = &ring->data[ring->cur];
+
+ bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+#ifdef XXX_TESTED_AND_WORKED
+ if (!(desc->sdl0 & htole16(RT2860_RXDESC_SDL0_DDONE)))
+ break;
+#endif
+
+ nframes++;
+
+ mnew = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE);
+ if (mnew == NULL)
+ {
+ sc->rx_mbuf_alloc_errors++;
+ counter_u64_add(ic->ic_ierrors, 1);
+ goto skip;
+ }
+
+ mnew->m_len = mnew->m_pkthdr.len = MJUMPAGESIZE;
+
+ error = bus_dmamap_load_mbuf_sg(ring->data_dma_tag, ring->spare_dma_map,
+ mnew, segs, &nsegs, BUS_DMA_NOWAIT);
+ if (error != 0)
+ {
+ RT2860_DPRINTF(sc, RT2860_DEBUG_RX,
+ "%s: could not load Rx mbuf DMA map: error=%d, nsegs=%d\n",
+ device_get_nameunit(sc->dev), error, nsegs);
+
+ m_freem(mnew);
+
+ sc->rx_mbuf_dmamap_errors++;
+ counter_u64_add(ic->ic_ierrors, 1);
+
+ goto skip;
+ }
+
+ KASSERT(nsegs == 1, ("%s: too many DMA segments",
+ device_get_nameunit(sc->dev)));
+
+ bus_dmamap_sync(ring->data_dma_tag, data->dma_map,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(ring->data_dma_tag, data->dma_map);
+
+ dma_map = data->dma_map;
+ data->dma_map = ring->spare_dma_map;
+ ring->spare_dma_map = dma_map;
+
+ bus_dmamap_sync(ring->data_dma_tag, data->dma_map,
+ BUS_DMASYNC_PREREAD);
+
+ m = data->m;
+
+ data->m = mnew;
+ desc->sdp0 = htole32(segs[0].ds_addr);
+
+ desc_flags = le32toh(desc->flags);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_RX,
+ "%s: Rx frame: rxdesc flags=0x%08x\n",
+ device_get_nameunit(sc->dev), desc_flags);
+
+ /* get Rx wireless info */
+
+ rxwi = mtod(m, struct rt2860_rxwi *);
+ len = (le16toh(rxwi->tid_size) >> RT2860_RXWI_SIZE_SHIFT) &
+ RT2860_RXWI_SIZE_MASK;
+
+ /* check for L2 padding between IEEE 802.11 frame header and body */
+
+ if (desc_flags & RT2860_RXDESC_FLAGS_L2PAD)
+ {
+ RT2860_DPRINTF(sc, RT2860_DEBUG_RX,
+ "%s: L2 padding: len=%d\n",
+ device_get_nameunit(sc->dev), len);
+
+ len += 2;
+ }
+
+// m->m_pkthdr.rcvif = ifp;
+ m->m_data = (caddr_t) (rxwi + 1);
+ m->m_pkthdr.len = m->m_len = len;
+
+ /* check for crc errors */
+
+ if (desc_flags & RT2860_RXDESC_FLAGS_CRC_ERR)
+ {
+ RT2860_DPRINTF(sc, RT2860_DEBUG_RX,
+ "%s: rxdesc: crc error\n",
+ device_get_nameunit(sc->dev));
+
+ counter_u64_add(ic->ic_ierrors, 1);
+
+ if (ic->ic_promisc == 0)
+ {
+ m_freem(m);
+ goto skip;
+ }
+ }
+
+ wh = (struct ieee80211_frame *) (rxwi + 1);
+
+ /* check for cipher errors */
+#ifdef RT2860_HW_CRYPTO
+ if (desc_flags & RT2860_RXDESC_FLAGS_DECRYPTED)
+ {
+ cipher_err = ((desc_flags >> RT2860_RXDESC_FLAGS_CIPHER_ERR_SHIFT) &
+ RT2860_RXDESC_FLAGS_CIPHER_ERR_MASK);
+ if (cipher_err == RT2860_RXDESC_FLAGS_CIPHER_ERR_NONE)
+ {
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
+ wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
+
+ m->m_flags |= M_WEP;
+
+ sc->rx_cipher_no_errors++;
+ }
+ else
+ {
+ RT2860_DPRINTF(sc, RT2860_DEBUG_RX_CRYPT,
+ "%s: rxdesc: cipher error=0x%02x keyidx=%d\n",
+ device_get_nameunit(sc->dev), cipher_err,
+ (rxwi->udf_bssidx_keyidx >> RT2860_RXWI_KEYIDX_SHIFT) &
+ RT2860_RXWI_KEYIDX_MASK);
+
+ if (cipher_err == RT2860_RXDESC_FLAGS_CIPHER_ERR_ICV)
+ sc->rx_cipher_icv_errors++;
+ else if (cipher_err == RT2860_RXDESC_FLAGS_CIPHER_ERR_MIC)
+ sc->rx_cipher_mic_errors++;
+ else if (cipher_err == RT2860_RXDESC_FLAGS_CIPHER_ERR_INVALID_KEY)
+ sc->rx_cipher_invalid_key_errors++;
+
+ if ((cipher_err == RT2860_RXDESC_FLAGS_CIPHER_ERR_MIC) &&
+ (desc_flags & RT2860_RXDESC_FLAGS_MYBSS))
+ {
+ ni = ieee80211_find_rxnode(ic, (const struct ieee80211_frame_min *) wh);
+ if (ni != NULL)
+ {
+ keyidx = (rxwi->udf_bssidx_keyidx >> RT2860_RXWI_KEYIDX_SHIFT) &
+ RT2860_RXWI_KEYIDX_MASK;
+
+ ieee80211_notify_michael_failure(ni->ni_vap, wh, keyidx);
+
+ ieee80211_free_node(ni);
+ }
+ }
+
+ counter_u64_add(ic->ic_ierrors, 1);
+
+ if (ic->ic_promisc == 0)
+ {
+ m_free(m);
+ goto skip;
+ }
+ }
+ }
+ else
+ {
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
+ {
+ RT2860_DPRINTF(sc, RT2860_DEBUG_RX,
+ "%s: rxdesc: not decrypted but protected flag set\n",
+ device_get_nameunit(sc->dev));
+
+ counter_u64_add(ic->ic_ierrors, 1);
+
+ if (ic->ic_promisc == 0)
+ {
+ m_free(m);
+ goto skip;
+ }
+ }
+ }
+#endif
+ /* check for A-MPDU */
+
+ if (desc_flags & RT2860_RXDESC_FLAGS_BA)
+ {
+ m->m_flags |= M_AMPDU;
+
+ sc->rx_ampdu++;
+
+ if (wh->i_fc[1] & IEEE80211_FC1_RETRY)
+ sc->rx_ampdu_retries++;
+
+ ampdu = 1;
+ }
+ else
+ {
+ ampdu = 0;
+ }
+
+ /* check for A-MSDU */
+
+ if (desc_flags & RT2860_RXDESC_FLAGS_AMSDU)
+ {
+ sc->rx_amsdu++;
+
+ amsdu = 1;
+ }
+ else
+ {
+ amsdu = 0;
+ }
+
+ ant = rt2860_maxrssi_rxpath(sc, rxwi);
+ rssi = rxwi->rssi[ant];
+ rssi_dbm = rt2860_rssi2dbm(sc, rssi, ant);
+ phymode = ((rxwi->phymode_stbc_shortgi >> RT2860_RXWI_PHYMODE_SHIFT) &
+ RT2860_RXWI_PHYMODE_MASK);
+ bw = ((rxwi->bw_mcs >> RT2860_RXWI_BW_SHIFT) & RT2860_RXWI_BW_MASK);
+ shortgi = ((rxwi->phymode_stbc_shortgi >> RT2860_RXWI_SHORTGI_SHIFT) &
+ RT2860_RXWI_SHORTGI_MASK);
+ stbc = ((rxwi->phymode_stbc_shortgi >> RT2860_RXWI_STBC_SHIFT) &
+ RT2860_RXWI_STBC_MASK);
+ mcs = ((rxwi->bw_mcs >> RT2860_RXWI_MCS_SHIFT) & RT2860_RXWI_MCS_MASK);
+ tid = ((rxwi->tid_size >> RT2860_RXWI_TID_SHIFT) & RT2860_RXWI_TID_MASK);
+ seq = ((rxwi->seq_frag >> RT2860_RXWI_SEQ_SHIFT) & RT2860_RXWI_SEQ_MASK);
+ frag = ((rxwi->seq_frag >> RT2860_RXWI_FRAG_SHIFT) & RT2860_RXWI_FRAG_MASK);
+
+ if (ieee80211_radiotap_active(ic))
+ {
+ tap = &sc->rxtap;
+
+ tap->flags = (desc_flags & RT2860_RXDESC_FLAGS_L2PAD) ? IEEE80211_RADIOTAP_F_DATAPAD : 0;
+ tap->dbm_antsignal = rssi_dbm;
+ tap->dbm_antnoise = RT2860_NOISE_FLOOR;
+ tap->antenna = ant;
+ tap->antsignal = rssi;
+ tap->chan_flags = htole32(ic->ic_curchan->ic_flags);
+ tap->chan_freq = htole16(ic->ic_curchan->ic_freq);
+ tap->chan_ieee = ic->ic_curchan->ic_ieee;
+ tap->chan_maxpow = 0;
+
+ if (phymode == RT2860_TXWI_PHYMODE_HT_MIXED || phymode == RT2860_TXWI_PHYMODE_HT_GF)
+ tap->rate = mcs | IEEE80211_RATE_MCS;
+ else
+ tap->rate = rt2860_rxrate(rxwi);
+
+ if (desc_flags & RT2860_RXDESC_FLAGS_CRC_ERR)
+ tap->flags |= IEEE80211_RADIOTAP_F_BADFCS;
+
+ if (desc_flags & RT2860_RXDESC_FLAGS_FRAG)
+ tap->flags |= IEEE80211_RADIOTAP_F_FRAG;
+
+ if (rxwi->bw_mcs & RT2860_RXWI_MCS_SHOTPRE)
+ tap->flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+ if ((desc_flags & RT2860_RXDESC_FLAGS_DECRYPTED) ||
+ (wh->i_fc[1] & IEEE80211_FC1_PROTECTED))
+ tap->flags |= IEEE80211_RADIOTAP_F_WEP;
+
+ if (shortgi)
+ tap->flags |= IEEE80211_RADIOTAP_F_SHORTGI;
+
+ /* XXX use temporarily radiotap CFP flag as A-MPDU flag */
+
+ if (ampdu)
+ tap->flags |= IEEE80211_RADIOTAP_F_CFP;
+ }
+
+ /*
+ * net80211 assumes that RSSI data are in the range [-127..127] and
+ * in .5 dBm units relative to the current noise floor
+ */
+
+ rssi_dbm_rel = (rssi_dbm - RT2860_NOISE_FLOOR) * 2;
+ if (rssi_dbm_rel > 127)
+ rssi_dbm_rel = 127;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_RX,
+ "%s: received frame: len=%d, phymode=%d, bw=%d, shortgi=%d, stbc=0x%02x, mcs=%d, "
+ "ant=%d, rssi=%d/%d/%d, snr=%d/%d, wcid=0x%02x, ampdu=%d, amsdu=%d, tid=%d, seq=%d, frag=%d, "
+ "retry=%d, rssi_dbm=%d, rssi_dbm_rel=%d\n",
+ device_get_nameunit(sc->dev),
+ len, phymode, bw, shortgi, stbc, mcs,
+ ant, rxwi->rssi[0], rxwi->rssi[1], rxwi->rssi[2],
+ rxwi->snr[0], rxwi->snr[1],
+ rxwi->wcid, ampdu, amsdu, tid, seq, frag, (wh->i_fc[1] & IEEE80211_FC1_RETRY) ? 1 : 0,
+ rssi_dbm, rssi_dbm_rel);
+
+ ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *) wh);
+ if (ni != NULL)
+ {
+ rni = (struct rt2860_softc_node *) ni;
+
+ for (i = 0; i < RT2860_SOFTC_RSSI_COUNT; i++)
+ {
+ rni->last_rssi[i] = rxwi->rssi[i];
+ rni->last_rssi_dbm[i] = rt2860_rssi2dbm(sc, rxwi->rssi[i], i);
+ }
+
+ ieee80211_input(ni, m, rssi_dbm_rel, RT2860_NOISE_FLOOR);
+ ieee80211_free_node(ni);
+ }
+ else
+ {
+ ieee80211_input_all(ic, m, rssi_dbm_rel, RT2860_NOISE_FLOOR);
+ }
+
+skip:
+
+ desc->sdl0 &= ~htole16(RT2860_RXDESC_SDL0_DDONE);
+
+ bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ ring->cur = (ring->cur + 1) % RT2860_SOFTC_RX_RING_DATA_COUNT;
+
+ limit--;
+ }
+
+ if (ring->cur == 0)
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_CALC_IDX,
+ RT2860_SOFTC_RX_RING_DATA_COUNT - 1);
+ else
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_RX_CALC_IDX,
+ ring->cur - 1);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_RX,
+ "%s: Rx eof: nframes=%d\n",
+ device_get_nameunit(sc->dev), nframes);
+
+ sc->rx_packets += nframes;
+
+ return (limit == 0);
+}
+
+/*
+ * rt2860_tx_eof
+ */
+static void rt2860_tx_eof(struct rt2860_softc *sc,
+ struct rt2860_softc_tx_ring *ring)
+{
+ struct rt2860_txdesc *desc;
+ struct rt2860_softc_tx_data *data;
+ uint32_t index;
+ int ndescs, nframes;
+
+ ndescs = 0;
+ nframes = 0;
+
+ for (;;)
+ {
+ index = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_TX_DTX_IDX(ring->qid));
+ if (ring->desc_next == index)
+ break;
+
+ ndescs++;
+
+ rt2860_drain_fifo_stats(sc);
+
+ desc = &ring->desc[ring->desc_next];
+
+ bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ if (desc->sdl0 & htole16(RT2860_TXDESC_SDL0_LASTSEG) ||
+ desc->sdl1 & htole16(RT2860_TXDESC_SDL1_LASTSEG))
+ {
+ nframes++;
+
+ data = &ring->data[ring->data_next];
+
+ if (data->m->m_flags & M_TXCB)
+ ieee80211_process_callback(data->ni, data->m, 0);
+
+ bus_dmamap_sync(ring->data_dma_tag, data->dma_map,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(ring->data_dma_tag, data->dma_map);
+
+// m_freem(data->m);
+
+// ieee80211_free_node(data->ni);
+ ieee80211_tx_complete(data->ni, data->m, 0);
+
+ data->m = NULL;
+ data->ni = NULL;
+
+// ifp->if_opackets++;
+
+ RT2860_SOFTC_TX_RING_LOCK(ring);
+
+ ring->data_queued--;
+ ring->data_next = (ring->data_next + 1) % RT2860_SOFTC_TX_RING_DATA_COUNT;
+
+ RT2860_SOFTC_TX_RING_UNLOCK(ring);
+ }
+
+ desc->sdl0 &= ~htole16(RT2860_TXDESC_SDL0_DDONE);
+
+ bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ RT2860_SOFTC_TX_RING_LOCK(ring);
+
+ ring->desc_queued--;
+ ring->desc_next = (ring->desc_next + 1) % RT2860_SOFTC_TX_RING_DESC_COUNT;
+
+ RT2860_SOFTC_TX_RING_UNLOCK(ring);
+ }
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_TX,
+ "%s: Tx eof: qid=%d, ndescs=%d, nframes=%d\n",
+ device_get_nameunit(sc->dev), ring->qid, ndescs, nframes);
+}
+
+/*
+ * rt2860_update_stats
+ */
+static void rt2860_update_stats(struct rt2860_softc *sc)
+{
+ struct ieee80211com *ic;
+ uint32_t stacnt[3];
+ int beacons, noretryok, retryok, failed, underflows, zerolen;
+
+ ic = &sc->sc_ic;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_STATS,
+ "%s: update statistic\n",
+ device_get_nameunit(sc->dev));
+
+ rt2860_drain_fifo_stats(sc);
+
+ /* read and clear Tx statistic registers */
+
+ rt2860_io_mac_read_multi(sc, RT2860_REG_TX_STA_CNT0,
+ stacnt, sizeof(stacnt));
+
+ stacnt[0] = le32toh(stacnt[0]);
+ stacnt[1] = le32toh(stacnt[1]);
+ stacnt[2] = le32toh(stacnt[2]);
+
+ beacons = stacnt[0] >> 16;
+ noretryok = stacnt[1] & 0xffff;
+ retryok = stacnt[1] >> 16;
+ failed = stacnt[0] & 0xffff;
+ underflows = stacnt[2] >> 16;
+ zerolen = stacnt[2] & 0xffff;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_STATS,
+ "%s: update statistic: beacons=%d, noretryok=%d, retryok=%d, failed=%d, underflows=%d, zerolen=%d\n",
+ device_get_nameunit(sc->dev),
+ beacons, noretryok, retryok, failed, underflows, zerolen);
+
+ counter_u64_add(sc->sc_ic.ic_oerrors, failed);
+
+ sc->tx_beacons += beacons;
+ sc->tx_noretryok += noretryok;
+ sc->tx_retryok += retryok;
+ sc->tx_failed += failed;
+ sc->tx_underflows += underflows;
+ sc->tx_zerolen += zerolen;
+}
+
+/*
+ * rt2860_bbp_tuning
+ */
+static void rt2860_bbp_tuning(struct rt2860_softc *sc)
+{
+ struct ieee80211com *ic;
+ struct ieee80211vap *vap;
+ struct ieee80211_node *ni;
+ int chan, group;
+ int8_t rssi, old, new;
+
+ /* RT2860C does not support BBP tuning */
+
+// if (sc->mac_rev == 0x28600100)
+ if (sc->mac_rev == 0x28600102)
+ return;
+
+ ic = &sc->sc_ic;
+ vap = TAILQ_FIRST(&ic->ic_vaps);
+
+ if ((ic->ic_flags & IEEE80211_F_SCAN) || vap == NULL ||
+ vap->iv_opmode != IEEE80211_M_STA || vap->iv_state != IEEE80211_S_RUN)
+ return;
+
+ ni = vap->iv_bss;
+
+ chan = ieee80211_chan2ieee(ic, ni->ni_chan);
+
+ if (chan <= 14)
+ group = 0;
+ else if (chan <= 64)
+ group = 1;
+ else if (chan <= 128)
+ group = 2;
+ else
+ group = 3;
+
+ rssi = ieee80211_getrssi(vap);
+
+ if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
+ {
+ new = 0x2e + sc->lna_gain[group];
+ }
+ else
+ {
+ if (!IEEE80211_IS_CHAN_HT40(ni->ni_chan))
+ new = 0x32 + sc->lna_gain[group] * 5 / 3;
+ else
+ new = 0x3a + sc->lna_gain[group] * 5 / 3;
+ }
+
+ /* Tune if absolute average RSSI is greater than -80 */
+
+ if (rssi > 30)
+ new += 0x10;
+
+ old = rt2860_io_bbp_read(sc, 66);
+
+ if (old != new)
+ rt2860_io_bbp_write(sc, 66, new);
+}
+
+/*
+ * rt2860_watchdog
+ */
+static void rt2860_watchdog(struct rt2860_softc *sc)
+{
+ uint32_t tmp;
+ int ntries;
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_PBF_TXRXQ_PCNT);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_WATCHDOG,
+ "%s: watchdog: TXRXQ_PCNT=0x%08x\n",
+ device_get_nameunit(sc->dev), tmp);
+
+ if (((tmp >> RT2860_REG_TX0Q_PCNT_SHIFT) & RT2860_REG_TX0Q_PCNT_MASK) != 0)
+ {
+ sc->tx_queue_not_empty[0]++;
+
+ rt2860_io_mac_write(sc, RT2860_REG_PBF_CFG, 0xf40012);
+
+ for (ntries = 0; ntries < 10; ntries++)
+ {
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_PBF_TXRXQ_PCNT);
+ if (((tmp >> RT2860_REG_TX0Q_PCNT_SHIFT) & RT2860_REG_TX0Q_PCNT_MASK) == 0)
+ break;
+
+ DELAY(1);
+ }
+
+ rt2860_io_mac_write(sc, RT2860_REG_PBF_CFG, 0xf40006);
+ }
+
+ if (((tmp >> RT2860_REG_TX1Q_PCNT_SHIFT) & RT2860_REG_TX1Q_PCNT_MASK) != 0)
+ {
+ sc->tx_queue_not_empty[1]++;
+
+ rt2860_io_mac_write(sc, RT2860_REG_PBF_CFG, 0xf4000a);
+
+ for (ntries = 0; ntries < 10; ntries++)
+ {
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_PBF_TXRXQ_PCNT);
+ if (((tmp >> RT2860_REG_TX1Q_PCNT_SHIFT) & RT2860_REG_TX1Q_PCNT_MASK) == 0)
+ break;
+
+ DELAY(1);
+ }
+
+ rt2860_io_mac_write(sc, RT2860_REG_PBF_CFG, 0xf40006);
+ }
+}
+
+/*
+ * rt2860_drain_fifo_stats
+ */
+static void rt2860_drain_fifo_stats(struct rt2860_softc *sc)
+{
+ uint32_t stats;
+ uint8_t wcid, mcs, pid;
+ int ok, agg, retrycnt;
+
+ /* drain Tx status FIFO (maxsize = 16) */
+
+ while ((stats = rt2860_io_mac_read(sc, RT2860_REG_TX_STA_FIFO)) &
+ RT2860_REG_TX_STA_FIFO_VALID)
+ {
+ wcid = (stats >> RT2860_REG_TX_STA_FIFO_WCID_SHIFT) &
+ RT2860_REG_TX_STA_FIFO_WCID_MASK;
+
+ /* if no ACK was requested, no feedback is available */
+
+ if (!(stats & RT2860_REG_TX_STA_FIFO_ACK_REQ) || wcid == RT2860_WCID_RESERVED)
+ continue;
+
+ /* update AMRR statistic */
+
+ ok = (stats & RT2860_REG_TX_STA_FIFO_TX_OK) ? 1 : 0;
+ agg = (stats & RT2860_REG_TX_STA_FIFO_AGG) ? 1 : 0;
+ mcs = (stats >> RT2860_REG_TX_STA_FIFO_MCS_SHIFT) &
+ RT2860_REG_TX_STA_FIFO_MCS_MASK;
+ pid = (stats >> RT2860_REG_TX_STA_FIFO_PID_SHIFT) &
+ RT2860_REG_TX_STA_FIFO_PID_MASK;
+ retrycnt = (mcs < 0xf) ? (pid - mcs - 1) : 0;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_STATS,
+ "%s: FIFO statistic: wcid=0x%02x, ok=%d, agg=%d, mcs=0x%02x, pid=0x%02x, retrycnt=%d\n",
+ device_get_nameunit(sc->dev),
+ wcid, ok, agg, mcs, pid, retrycnt);
+
+ rt2860_amrr_tx_complete(&sc->amrr_node[wcid], ok, retrycnt);
+
+ if (!ok)
+ counter_u64_add(sc->sc_ic.ic_oerrors, 1);
+ }
+}
+
+/*
+ * rt2860_update_raw_counters
+ */
+static void rt2860_update_raw_counters(struct rt2860_softc *sc)
+{
+ uint32_t tmp;
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_AGG_CNT);
+
+ sc->tx_nonagg += tmp & 0xffff;
+ sc->tx_agg += tmp >> 16;
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_AGG_CNT0);
+
+ sc->tx_ampdu += (tmp & 0xffff) / 1 + (tmp >> 16) / 2;
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_AGG_CNT1);
+
+ sc->tx_ampdu += (tmp & 0xffff) / 3 + (tmp >> 16) / 4;
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_AGG_CNT2);
+
+ sc->tx_ampdu += (tmp & 0xffff) / 5 + (tmp >> 16) / 6;
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_AGG_CNT3);
+
+ sc->tx_ampdu += (tmp & 0xffff) / 7 + (tmp >> 16) / 8;
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_AGG_CNT4);
+
+ sc->tx_ampdu += (tmp & 0xffff) / 9 + (tmp >> 16) / 10;
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_AGG_CNT5);
+
+ sc->tx_ampdu += (tmp & 0xffff) / 11 + (tmp >> 16) / 12;
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_AGG_CNT6);
+
+ sc->tx_ampdu += (tmp & 0xffff) / 13 + (tmp >> 16) / 14;
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_AGG_CNT7);
+
+ sc->tx_ampdu += (tmp & 0xffff) / 15 + (tmp >> 16) / 16;
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_RX_STA_CNT0);
+
+ sc->rx_crc_errors += tmp & 0xffff;
+ sc->rx_phy_errors += tmp >> 16;
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_RX_STA_CNT1);
+
+ sc->rx_false_ccas += tmp & 0xffff;
+ sc->rx_plcp_errors += tmp >> 16;
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_RX_STA_CNT2);
+
+ sc->rx_dup_packets += tmp & 0xffff;
+ sc->rx_fifo_overflows += tmp >> 16;
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_TXRX_MPDU_DEN_CNT);
+
+ sc->tx_mpdu_zero_density += tmp & 0xffff;
+ sc->rx_mpdu_zero_density += tmp >> 16;
+}
+
+/*
+ * rt2860_intr_enable
+ */
+static void rt2860_intr_enable(struct rt2860_softc *sc, uint32_t intr_mask)
+{
+ uint32_t tmp;
+
+ sc->intr_disable_mask &= ~intr_mask;
+
+ tmp = sc->intr_enable_mask & ~sc->intr_disable_mask;
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_INT_MASK, tmp);
+}
+
+/*
+ * rt2860_intr_disable
+ */
+static void rt2860_intr_disable(struct rt2860_softc *sc, uint32_t intr_mask)
+{
+ uint32_t tmp;
+
+ sc->intr_disable_mask |= intr_mask;
+
+ tmp = sc->intr_enable_mask & ~sc->intr_disable_mask;
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_INT_MASK, tmp);
+}
+
+/*
+ * rt2860_txrx_enable
+ */
+static int rt2860_txrx_enable(struct rt2860_softc *sc)
+{
+ struct ieee80211com *ic;
+ uint32_t tmp;
+ int ntries;
+
+ ic = &sc->sc_ic;
+
+ /* enable Tx/Rx DMA engine */
+
+ rt2860_io_mac_write(sc, RT2860_REG_SYS_CTRL, RT2860_REG_TX_ENABLE);
+
+ for (ntries = 0; ntries < 200; ntries++)
+ {
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG);
+ if (!(tmp & (RT2860_REG_TX_DMA_BUSY | RT2860_REG_RX_DMA_BUSY)))
+ break;
+
+ DELAY(1000);
+ }
+
+ if (ntries == 200)
+ {
+ printf("%s: timeout waiting for DMA engine\n",
+ device_get_nameunit(sc->dev));
+ return -1;
+ }
+
+ DELAY(50);
+
+ tmp |= RT2860_REG_TX_WB_DDONE |
+ RT2860_REG_RX_DMA_ENABLE |
+ RT2860_REG_TX_DMA_ENABLE |
+ (RT2860_REG_WPDMA_BT_SIZE64 << RT2860_REG_WPDMA_BT_SIZE_SHIFT);
+
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_WPDMA_GLO_CFG, tmp);
+
+ /* set Rx filter */
+
+ tmp = RT2860_REG_RX_FILTER_DROP_CRC_ERR |
+ RT2860_REG_RX_FILTER_DROP_PHY_ERR;
+
+ if (ic->ic_opmode != IEEE80211_M_MONITOR)
+ {
+ tmp |= RT2860_REG_RX_FILTER_DROP_DUPL |
+ RT2860_REG_RX_FILTER_DROP_CTS |
+ RT2860_REG_RX_FILTER_DROP_BA |
+ RT2860_REG_RX_FILTER_DROP_ACK |
+ RT2860_REG_RX_FILTER_DROP_VER_ERR |
+ RT2860_REG_RX_FILTER_DROP_CTRL_RSV |
+ RT2860_REG_RX_FILTER_DROP_CFACK |
+ RT2860_REG_RX_FILTER_DROP_CFEND;
+
+ if (ic->ic_opmode == IEEE80211_M_STA)
+ tmp |= RT2860_REG_RX_FILTER_DROP_RTS |
+ RT2860_REG_RX_FILTER_DROP_PSPOLL;
+
+ if (ic->ic_promisc == 0)
+ tmp |= RT2860_REG_RX_FILTER_DROP_UC_NOME;
+ }
+
+ rt2860_io_mac_write(sc, RT2860_REG_RX_FILTER_CFG, tmp);
+
+ rt2860_io_mac_write(sc, RT2860_REG_SYS_CTRL,
+ RT2860_REG_RX_ENABLE | RT2860_REG_TX_ENABLE);
+
+ return 0;
+}
+
+/*
+ * rt2860_alloc_rx_ring
+ */
+static int rt2860_alloc_rx_ring(struct rt2860_softc *sc,
+ struct rt2860_softc_rx_ring *ring)
+{
+ struct rt2860_rxdesc *desc;
+ struct rt2860_softc_rx_data *data;
+ bus_dma_segment_t segs[1];
+ int i, nsegs, error;
+
+ error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), PAGE_SIZE, 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ RT2860_SOFTC_RX_RING_DATA_COUNT * sizeof(struct rt2860_rxdesc), 1,
+ RT2860_SOFTC_RX_RING_DATA_COUNT * sizeof(struct rt2860_rxdesc),
+ 0, NULL, NULL, &ring->desc_dma_tag);
+ if (error != 0)
+ {
+ printf("%s: could not create Rx desc DMA tag\n",
+ device_get_nameunit(sc->dev));
+ goto fail;
+ }
+
+ error = bus_dmamem_alloc(ring->desc_dma_tag, (void **) &ring->desc,
+ BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_dma_map);
+ if (error != 0)
+ {
+ printf("%s: could not allocate Rx desc DMA memory\n",
+ device_get_nameunit(sc->dev));
+ goto fail;
+ }
+
+ error = bus_dmamap_load(ring->desc_dma_tag, ring->desc_dma_map,
+ ring->desc,
+ RT2860_SOFTC_RX_RING_DATA_COUNT * sizeof(struct rt2860_rxdesc),
+ rt2860_dma_map_addr, &ring->desc_phys_addr, 0);
+ if (error != 0)
+ {
+ printf("%s: could not load Rx desc DMA map\n",
+ device_get_nameunit(sc->dev));
+ goto fail;
+ }
+
+ error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), PAGE_SIZE, 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ MJUMPAGESIZE, 1, MJUMPAGESIZE, 0, NULL, NULL,
+ &ring->data_dma_tag);
+ if (error != 0)
+ {
+ printf("%s: could not create Rx data DMA tag\n",
+ device_get_nameunit(sc->dev));
+ goto fail;
+ }
+
+ for (i = 0; i < RT2860_SOFTC_RX_RING_DATA_COUNT; i++)
+ {
+ desc = &ring->desc[i];
+ data = &ring->data[i];
+
+ error = bus_dmamap_create(ring->data_dma_tag, 0, &data->dma_map);
+ if (error != 0)
+ {
+ printf("%s: could not create Rx data DMA map\n",
+ device_get_nameunit(sc->dev));
+ goto fail;
+ }
+
+ data->m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE);
+ if (data->m == NULL)
+ {
+ printf("%s: could not allocate Rx mbuf\n",
+ device_get_nameunit(sc->dev));
+ error = ENOMEM;
+ goto fail;
+ }
+
+ data->m->m_len = data->m->m_pkthdr.len = MJUMPAGESIZE;
+
+ error = bus_dmamap_load_mbuf_sg(ring->data_dma_tag, data->dma_map,
+ data->m, segs, &nsegs, BUS_DMA_NOWAIT);
+ if (error != 0)
+ {
+ printf("%s: could not load Rx mbuf DMA map\n",
+ device_get_nameunit(sc->dev));
+ goto fail;
+ }
+
+ KASSERT(nsegs == 1, ("%s: too many DMA segments",
+ device_get_nameunit(sc->dev)));
+
+ desc->sdp0 = htole32(segs[0].ds_addr);
+ desc->sdl0 = htole16(MJUMPAGESIZE);
+ }
+
+ error = bus_dmamap_create(ring->data_dma_tag, 0, &ring->spare_dma_map);
+ if (error != 0)
+ {
+ printf("%s: could not create Rx spare DMA map\n",
+ device_get_nameunit(sc->dev));
+ goto fail;
+ }
+
+ bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ return 0;
+
+fail:
+
+ rt2860_free_rx_ring(sc, ring);
+
+ return error;
+}
+
+/*
+ * rt2860_reset_rx_ring
+ */
+static void rt2860_reset_rx_ring(struct rt2860_softc *sc,
+ struct rt2860_softc_rx_ring *ring)
+{
+ struct rt2860_rxdesc *desc;
+ int i;
+
+ for (i = 0; i < RT2860_SOFTC_RX_RING_DATA_COUNT; i++) {
+ desc = &ring->desc[i];
+
+ desc->sdl0 &= ~htole16(RT2860_RXDESC_SDL0_DDONE);
+ }
+
+ bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ ring->cur = 0;
+}
+
+/*
+ * rt2860_free_rx_ring
+ */
+static void rt2860_free_rx_ring(struct rt2860_softc *sc,
+ struct rt2860_softc_rx_ring *ring)
+{
+ struct rt2860_softc_rx_data *data;
+ int i;
+
+ if (ring->desc != NULL) {
+ bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(ring->desc_dma_tag, ring->desc_dma_map);
+ bus_dmamem_free(ring->desc_dma_tag, ring->desc,
+ ring->desc_dma_map);
+ }
+
+ if (ring->desc_dma_tag != NULL)
+ bus_dma_tag_destroy(ring->desc_dma_tag);
+
+ for (i = 0; i < RT2860_SOFTC_RX_RING_DATA_COUNT; i++) {
+ data = &ring->data[i];
+
+ if (data->m != NULL) {
+ bus_dmamap_sync(ring->data_dma_tag, data->dma_map,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(ring->data_dma_tag, data->dma_map);
+ m_freem(data->m);
+ }
+
+ if (data->dma_map != NULL)
+ bus_dmamap_destroy(ring->data_dma_tag, data->dma_map);
+ }
+
+ if (ring->spare_dma_map != NULL)
+ bus_dmamap_destroy(ring->data_dma_tag, ring->spare_dma_map);
+
+ if (ring->data_dma_tag != NULL)
+ bus_dma_tag_destroy(ring->data_dma_tag);
+}
+
+/*
+ * rt2860_alloc_tx_ring
+ */
+static int rt2860_alloc_tx_ring(struct rt2860_softc *sc,
+ struct rt2860_softc_tx_ring *ring, int qid)
+{
+ struct rt2860_softc_tx_data *data;
+ int error, i, size;
+
+ size = RT2860_SOFTC_TX_RING_DESC_COUNT * sizeof(struct rt2860_txdesc);
+ mtx_init(&ring->lock, device_get_nameunit(sc->dev), NULL, MTX_DEF);
+
+ error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), PAGE_SIZE, 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ size, 1, size, 0, NULL, NULL, &ring->desc_dma_tag);
+ if (error != 0) {
+ device_printf(sc->dev, "could not create Tx desc DMA tag\n");
+ goto fail;
+ }
+
+ error = bus_dmamem_alloc(ring->desc_dma_tag, (void **) &ring->desc,
+ BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_dma_map);
+ if (error != 0) {
+ device_printf(sc->dev,
+ "could not allocate Tx desc DMA memory\n");
+ goto fail;
+ }
+
+ error = bus_dmamap_load(ring->desc_dma_tag, ring->desc_dma_map,
+ ring->desc, size, rt2860_dma_map_addr, &ring->desc_phys_addr, 0);
+ if (error != 0) {
+ device_printf(sc->dev, "could not load Tx desc DMA map\n");
+ goto fail;
+ }
+
+ ring->desc_queued = 0;
+ ring->desc_cur = 0;
+ ring->desc_next = 0;
+
+ size = RT2860_SOFTC_TX_RING_DATA_COUNT * RT2860_TX_DATA_SEG0_SIZE;
+ error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), PAGE_SIZE, 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ size, 1, size, 0, NULL, NULL, &ring->seg0_dma_tag);
+ if (error != 0) {
+ device_printf(sc->dev, "could not create Tx seg0 DMA tag\n");
+ goto fail;
+ }
+
+ error = bus_dmamem_alloc(ring->seg0_dma_tag, (void **) &ring->seg0,
+ BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->seg0_dma_map);
+ if (error != 0) {
+ device_printf(sc->dev, "could not allocate Tx seg0 DMA memory\n");
+ goto fail;
+ }
+
+ error = bus_dmamap_load(ring->seg0_dma_tag, ring->seg0_dma_map,
+ ring->seg0, size, rt2860_dma_map_addr, &ring->seg0_phys_addr, 0);
+ if (error != 0) {
+ device_printf(sc->dev, "could not load Tx seg0 DMA map\n");
+ goto fail;
+ }
+
+
+ error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), PAGE_SIZE, 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ MJUMPAGESIZE, RT2860_SOFTC_MAX_SCATTER, MJUMPAGESIZE, 0,
+ NULL, NULL, &ring->data_dma_tag);
+ if (error != 0) {
+ device_printf(sc->dev, "could not create Tx data DMA tag\n");
+ goto fail;
+ }
+
+ for (i = 0; i < RT2860_SOFTC_TX_RING_DATA_COUNT; i++){
+ data = &ring->data[i];
+
+ error = bus_dmamap_create(ring->data_dma_tag, 0,
+ &data->dma_map);
+ if (error != 0) {
+ device_printf(sc->dev, "could not create Tx data DMA map\n");
+ goto fail;
+ }
+ }
+
+ ring->data_queued = 0;
+ ring->data_cur = 0;
+ ring->data_next = 0;
+
+ ring->qid = qid;
+
+ return 0;
+
+fail:
+
+ rt2860_free_tx_ring(sc, ring);
+
+ return error;
+}
+
+/*
+ * rt2860_reset_tx_ring
+ */
+static void rt2860_reset_tx_ring(struct rt2860_softc *sc,
+ struct rt2860_softc_tx_ring *ring)
+{
+ struct rt2860_softc_tx_data *data;
+ struct rt2860_txdesc *desc;
+ int i;
+
+ for (i = 0; i < RT2860_SOFTC_TX_RING_DESC_COUNT; i++)
+ {
+ desc = &ring->desc[i];
+
+ desc->sdl0 = 0;
+ desc->sdl1 = 0;
+ }
+
+ ring->desc_queued = 0;
+ ring->desc_cur = 0;
+ ring->desc_next = 0;
+
+ bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+ BUS_DMASYNC_PREWRITE);
+
+ bus_dmamap_sync(ring->seg0_dma_tag, ring->seg0_dma_map,
+ BUS_DMASYNC_PREWRITE);
+
+ for (i = 0; i < RT2860_SOFTC_TX_RING_DATA_COUNT; i++)
+ {
+ data = &ring->data[i];
+
+ if (data->m != NULL)
+ {
+ bus_dmamap_sync(ring->data_dma_tag, data->dma_map,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(ring->data_dma_tag, data->dma_map);
+ m_freem(data->m);
+ data->m = NULL;
+ }
+
+ if (data->ni != NULL)
+ {
+ ieee80211_free_node(data->ni);
+ data->ni = NULL;
+ }
+ }
+
+ ring->data_queued = 0;
+ ring->data_cur = 0;
+ ring->data_next = 0;
+}
+
+/*
+ * rt2860_free_tx_ring
+ */
+static void rt2860_free_tx_ring(struct rt2860_softc *sc,
+ struct rt2860_softc_tx_ring *ring)
+{
+ struct rt2860_softc_tx_data *data;
+ int i;
+
+ if (ring->desc != NULL)
+ {
+ bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(ring->desc_dma_tag, ring->desc_dma_map);
+ bus_dmamem_free(ring->desc_dma_tag, ring->desc,
+ ring->desc_dma_map);
+ }
+
+ if (ring->desc_dma_tag != NULL)
+ bus_dma_tag_destroy(ring->desc_dma_tag);
+
+ if (ring->seg0 != NULL)
+ {
+ bus_dmamap_sync(ring->seg0_dma_tag, ring->seg0_dma_map,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(ring->seg0_dma_tag, ring->seg0_dma_map);
+ bus_dmamem_free(ring->seg0_dma_tag, ring->seg0,
+ ring->seg0_dma_map);
+ }
+
+ if (ring->seg0_dma_tag != NULL)
+ bus_dma_tag_destroy(ring->seg0_dma_tag);
+
+ for (i = 0; i < RT2860_SOFTC_TX_RING_DATA_COUNT; i++)
+ {
+ data = &ring->data[i];
+
+ if (data->m != NULL)
+ {
+ bus_dmamap_sync(ring->data_dma_tag, data->dma_map,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(ring->data_dma_tag, data->dma_map);
+ m_freem(data->m);
+ }
+
+ if (data->ni != NULL)
+ ieee80211_free_node(data->ni);
+
+ if (data->dma_map != NULL)
+ bus_dmamap_destroy(ring->data_dma_tag, data->dma_map);
+ }
+
+ if (ring->data_dma_tag != NULL)
+ bus_dma_tag_destroy(ring->data_dma_tag);
+
+ mtx_destroy(&ring->lock);
+}
+
+/*
+ * rt2860_dma_map_addr
+ */
+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;
+}
+
+/*
+ * rt2860_sysctl_attach
+ */
+static void rt2860_sysctl_attach(struct rt2860_softc *sc)
+{
+ struct sysctl_ctx_list *ctx;
+ struct sysctl_oid *tree;
+ struct sysctl_oid *stats;
+
+ ctx = device_get_sysctl_ctx(sc->dev);
+ tree = device_get_sysctl_tree(sc->dev);
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "tx_stbc", CTLFLAG_RW, &sc->tx_stbc, 0,
+ "Tx STBC");
+
+ /* statistic counters */
+
+ stats = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "stats", CTLFLAG_RD, 0, "statistic");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "interrupts", CTLFLAG_RD, &sc->interrupts, 0,
+ "all interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_coherent_interrupts", CTLFLAG_RD, &sc->tx_coherent_interrupts, 0,
+ "Tx coherent interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_coherent_interrupts", CTLFLAG_RD, &sc->rx_coherent_interrupts, 0,
+ "Rx coherent interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "txrx_coherent_interrupts", CTLFLAG_RD, &sc->txrx_coherent_interrupts, 0,
+ "Tx/Rx coherent interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "fifo_sta_full_interrupts", CTLFLAG_RD, &sc->fifo_sta_full_interrupts, 0,
+ "FIFO statistic full interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_interrupts", CTLFLAG_RD, &sc->rx_interrupts, 0,
+ "Rx interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_delay_interrupts", CTLFLAG_RD, &sc->rx_delay_interrupts, 0,
+ "Rx delay interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_mgmt_interrupts", CTLFLAG_RD, &sc->tx_interrupts[5], 0,
+ "Tx MGMT interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_hcca_interrupts", CTLFLAG_RD, &sc->tx_interrupts[4], 0,
+ "Tx HCCA interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_ac3_interrupts", CTLFLAG_RD, &sc->tx_interrupts[3], 0,
+ "Tx AC3 interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_ac2_interrupts", CTLFLAG_RD, &sc->tx_interrupts[2], 0,
+ "Tx AC2 interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_ac1_interrupts", CTLFLAG_RD, &sc->tx_interrupts[1], 0,
+ "Tx AC1 interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_ac0_interrupts", CTLFLAG_RD, &sc->tx_interrupts[0], 0,
+ "Tx AC0 interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_delay_interrupts", CTLFLAG_RD, &sc->tx_delay_interrupts, 0,
+ "Tx delay interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "pre_tbtt_interrupts", CTLFLAG_RD, &sc->pre_tbtt_interrupts, 0,
+ "Pre-TBTT interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tbtt_interrupts", CTLFLAG_RD, &sc->tbtt_interrupts, 0,
+ "TBTT interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "mcu_cmd_interrupts", CTLFLAG_RD, &sc->mcu_cmd_interrupts, 0,
+ "MCU command interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "auto_wakeup_interrupts", CTLFLAG_RD, &sc->auto_wakeup_interrupts, 0,
+ "auto wakeup interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "gp_timer_interrupts", CTLFLAG_RD, &sc->gp_timer_interrupts, 0,
+ "GP timer interrupts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_mgmt_desc_queued", CTLFLAG_RD, &sc->tx_ring[5].desc_queued, 0,
+ "Tx MGMT descriptors queued");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_mgmt_data_queued", CTLFLAG_RD, &sc->tx_ring[5].data_queued, 0,
+ "Tx MGMT data queued");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_hcca_desc_queued", CTLFLAG_RD, &sc->tx_ring[4].desc_queued, 0,
+ "Tx HCCA descriptors queued");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_hcca_data_queued", CTLFLAG_RD, &sc->tx_ring[4].data_queued, 0,
+ "Tx HCCA data queued");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_ac3_desc_queued", CTLFLAG_RD, &sc->tx_ring[3].desc_queued, 0,
+ "Tx AC3 descriptors queued");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_ac3_data_queued", CTLFLAG_RD, &sc->tx_ring[3].data_queued, 0,
+ "Tx AC3 data queued");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_ac2_desc_queued", CTLFLAG_RD, &sc->tx_ring[2].desc_queued, 0,
+ "Tx AC2 descriptors queued");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_ac2_data_queued", CTLFLAG_RD, &sc->tx_ring[2].data_queued, 0,
+ "Tx AC2 data queued");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_ac1_desc_queued", CTLFLAG_RD, &sc->tx_ring[1].desc_queued, 0,
+ "Tx AC1 descriptors queued");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_ac1_data_queued", CTLFLAG_RD, &sc->tx_ring[1].data_queued, 0,
+ "Tx AC1 data queued");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_ac0_desc_queued", CTLFLAG_RD, &sc->tx_ring[0].desc_queued, 0,
+ "Tx AC0 descriptors queued");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_ac0_data_queued", CTLFLAG_RD, &sc->tx_ring[0].data_queued, 0,
+ "Tx AC0 data queued");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_mgmt_data_queue_full", CTLFLAG_RD, &sc->tx_data_queue_full[5], 0,
+ "Tx MGMT data queue full");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_hcca_data_queue_full", CTLFLAG_RD, &sc->tx_data_queue_full[4], 0,
+ "Tx HCCA data queue full");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_ac3_data_queue_full", CTLFLAG_RD, &sc->tx_data_queue_full[3], 0,
+ "Tx AC3 data queue full");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_ac2_data_queue_full", CTLFLAG_RD, &sc->tx_data_queue_full[2], 0,
+ "Tx AC2 data queue full");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_ac1_data_queue_full", CTLFLAG_RD, &sc->tx_data_queue_full[1], 0,
+ "Tx AC1 data queue full");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_ac0_data_queue_full", CTLFLAG_RD, &sc->tx_data_queue_full[0], 0,
+ "Tx AC0 data queue full");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_watchdog_timeouts", CTLFLAG_RD, &sc->tx_watchdog_timeouts, 0,
+ "Tx watchdog timeouts");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_defrag_packets", CTLFLAG_RD, &sc->tx_defrag_packets, 0,
+ "Tx defragmented packets");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "no_tx_desc_avail", CTLFLAG_RD, &sc->no_tx_desc_avail, 0,
+ "no Tx descriptors available");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_mbuf_alloc_errors", CTLFLAG_RD, &sc->rx_mbuf_alloc_errors, 0,
+ "Rx mbuf allocation errors");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_mbuf_dmamap_errors", CTLFLAG_RD, &sc->rx_mbuf_dmamap_errors, 0,
+ "Rx mbuf DMA mapping errors");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_queue_0_not_empty", CTLFLAG_RD, &sc->tx_queue_not_empty[0], 0,
+ "Tx queue 0 not empty");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_queue_1_not_empty", CTLFLAG_RD, &sc->tx_queue_not_empty[1], 0,
+ "Tx queue 1 not empty");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_beacons", CTLFLAG_RD, &sc->tx_beacons, 0,
+ "Tx beacons");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_noretryok", CTLFLAG_RD, &sc->tx_noretryok, 0,
+ "Tx successfull without retries");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_retryok", CTLFLAG_RD, &sc->tx_retryok, 0,
+ "Tx successfull with retries");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_failed", CTLFLAG_RD, &sc->tx_failed, 0,
+ "Tx failed");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_underflows", CTLFLAG_RD, &sc->tx_underflows, 0,
+ "Tx underflows");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_zerolen", CTLFLAG_RD, &sc->tx_zerolen, 0,
+ "Tx zero length");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_nonagg", CTLFLAG_RD, &sc->tx_nonagg, 0,
+ "Tx non-aggregated");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_agg", CTLFLAG_RD, &sc->tx_agg, 0,
+ "Tx aggregated");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_ampdu", CTLFLAG_RD, &sc->tx_ampdu, 0,
+ "Tx A-MPDU");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_mpdu_zero_density", CTLFLAG_RD, &sc->tx_mpdu_zero_density, 0,
+ "Tx MPDU with zero density");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "tx_ampdu_sessions", CTLFLAG_RD, &sc->tx_ampdu_sessions, 0,
+ "Tx A-MPDU sessions");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_packets", CTLFLAG_RD, &sc->rx_packets, 0,
+ "Rx packets");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_ampdu", CTLFLAG_RD, &sc->rx_ampdu, 0,
+ "Rx A-MPDU");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_ampdu_retries", CTLFLAG_RD, &sc->rx_ampdu_retries, 0,
+ "Rx A-MPDU retries");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_mpdu_zero_density", CTLFLAG_RD, &sc->rx_mpdu_zero_density, 0,
+ "Rx MPDU with zero density");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_ampdu_sessions", CTLFLAG_RD, &sc->rx_ampdu_sessions, 0,
+ "Rx A-MPDU sessions");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_amsdu", CTLFLAG_RD, &sc->rx_amsdu, 0,
+ "Rx A-MSDU");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_crc_errors", CTLFLAG_RD, &sc->rx_crc_errors, 0,
+ "Rx CRC errors");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_phy_errors", CTLFLAG_RD, &sc->rx_phy_errors, 0,
+ "Rx PHY errors");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_false_ccas", CTLFLAG_RD, &sc->rx_false_ccas, 0,
+ "Rx false CCAs");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_plcp_errors", CTLFLAG_RD, &sc->rx_plcp_errors, 0,
+ "Rx PLCP errors");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_dup_packets", CTLFLAG_RD, &sc->rx_dup_packets, 0,
+ "Rx duplicate packets");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_fifo_overflows", CTLFLAG_RD, &sc->rx_fifo_overflows, 0,
+ "Rx FIFO overflows");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_cipher_no_errors", CTLFLAG_RD, &sc->rx_cipher_no_errors, 0,
+ "Rx cipher no errors");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_cipher_icv_errors", CTLFLAG_RD, &sc->rx_cipher_icv_errors, 0,
+ "Rx cipher ICV errors");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_cipher_mic_errors", CTLFLAG_RD, &sc->rx_cipher_mic_errors, 0,
+ "Rx cipher MIC errors");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
+ "rx_cipher_invalid_key_errors", CTLFLAG_RD, &sc->rx_cipher_invalid_key_errors, 0,
+ "Rx cipher invalid key errors");
+}
+
+
+static void
+rt2860_parent(struct ieee80211com *ic)
+{
+ struct rt2860_softc *sc = ic->ic_softc;
+ int startall = 0;
+
+ RT2860_SOFTC_LOCK(sc);
+ if (ic->ic_nrunning> 0) {
+ if (!(sc->sc_flags & RT2860_RUNNING)) {
+ rt2860_init_locked(sc);
+ startall = 1;
+ } else
+ rt2860_update_promisc(ic);
+ } else if (sc->sc_flags & RT2860_RUNNING)
+ rt2860_stop_locked(sc);
+ RT2860_SOFTC_UNLOCK(sc);
+ if (startall)
+ ieee80211_start_all(ic);
+}
+
+static int
+rt2860_transmit(struct ieee80211com *ic, struct mbuf *m)
+{
+ struct rt2860_softc *sc = ic->ic_softc;
+ int error;
+
+ RT2860_SOFTC_LOCK(sc);
+ if ((sc->sc_flags & RT2860_RUNNING) == 0) {
+ RT2860_SOFTC_UNLOCK(sc);
+ return (ENXIO);
+ }
+ error = mbufq_enqueue(&sc->sc_snd, m);
+ if (error) {
+ RT2860_SOFTC_UNLOCK(sc);
+ return (error);
+ }
+ rt2860_start(sc);
+ RT2860_SOFTC_UNLOCK(sc);
+
+ return (0);
+}
+
Index: sys/dev/rt2860/rt2860_amrr.h
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_amrr.h
@@ -0,0 +1,80 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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.
+ */
+
+#ifndef _RT2860_AMRR_H_
+#define _RT2860_AMRR_H_
+
+#define RT2860_AMRR_MIN_SUCCESS_THRESHOLD 1
+#define RT2860_AMRR_MAX_SUCCESS_THRESHOLD 15
+
+struct rt2860_amrr
+{
+ int ntxpath;
+
+ unsigned int min_success_threshold;
+ unsigned int max_success_threshold;
+
+ int interval;
+};
+
+struct rt2860_amrr_node
+{
+ struct rt2860_amrr *amrr;
+
+ int rate_index;
+
+ int ticks;
+
+ unsigned int txcnt;
+ unsigned int success;
+ unsigned int success_threshold;
+ unsigned int recovery;
+ unsigned int retrycnt;
+};
+
+void rt2860_amrr_init(struct rt2860_amrr *amrr, struct ieee80211vap *vap,
+ int ntxpath, int min_success_threshold, int max_success_threshold, int msecs);
+
+void rt2860_amrr_cleanup(struct rt2860_amrr *amrr);
+
+void rt2860_amrr_node_init(struct rt2860_amrr *amrr,
+ struct rt2860_amrr_node *amrr_node, struct ieee80211_node *ni);
+
+int rt2860_amrr_choose(struct ieee80211_node *ni,
+ struct rt2860_amrr_node *amrr_node);
+
+static __inline void rt2860_amrr_tx_complete(struct rt2860_amrr_node *amrr_node,
+ int ok, int retries)
+{
+ amrr_node->txcnt++;
+
+ if (ok)
+ amrr_node->success++;
+
+ amrr_node->retrycnt += retries;
+}
+
+static __inline void rt2860_amrr_tx_update(struct rt2860_amrr_node *amrr_node,
+ int txcnt, int success, int retrycnt)
+{
+ amrr_node->txcnt = txcnt;
+ amrr_node->success = success;
+ amrr_node->retrycnt = retrycnt;
+}
+
+#endif /* #ifndef _RT2860_AMRR_H_ */
Index: sys/dev/rt2860/rt2860_amrr.c
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_amrr.c
@@ -0,0 +1,224 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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 <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/malloc.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_var.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 <dev/rt2860/rt2860_amrr.h>
+
+/*
+ * Defines and macros
+ */
+
+#define RT2860_AMRR_IS_SUCCESS(amrr_node) ((amrr_node)->retrycnt < (amrr_node)->txcnt / 10)
+
+#define RT2860_AMRR_IS_FAILURE(amrr_node) ((amrr_node)->retrycnt > (amrr_node)->txcnt / 3)
+
+#define RT2860_AMRR_IS_ENOUGH(amrr_node) ((amrr_node)->txcnt > 10)
+
+/*
+ * Static function prototypes
+ */
+
+static int rt2860_amrr_update(struct rt2860_amrr *amrr,
+ struct rt2860_amrr_node *amrr_node, struct ieee80211_node *ni);
+
+/*
+ * rt2860_amrr_init
+ */
+void rt2860_amrr_init(struct rt2860_amrr *amrr, struct ieee80211vap *vap,
+ int ntxpath, int min_success_threshold, int max_success_threshold, int msecs)
+{
+ int t;
+
+ amrr->ntxpath = ntxpath;
+
+ amrr->min_success_threshold = min_success_threshold;
+ amrr->max_success_threshold = max_success_threshold;
+
+ if (msecs < 100)
+ msecs = 100;
+
+ t = msecs_to_ticks(msecs);
+
+ amrr->interval = (t < 1) ? 1 : t;
+}
+
+/*
+ * rt2860_amrr_cleanup
+ */
+void rt2860_amrr_cleanup(struct rt2860_amrr *amrr)
+{
+}
+
+/*
+ * rt2860_amrr_node_init
+ */
+void rt2860_amrr_node_init(struct rt2860_amrr *amrr,
+ struct rt2860_amrr_node *amrr_node, struct ieee80211_node *ni)
+{
+ const struct ieee80211_rateset *rs;
+
+ amrr_node->amrr = amrr;
+ amrr_node->success = 0;
+ amrr_node->recovery = 0;
+ amrr_node->txcnt = 0;
+ amrr_node->retrycnt = 0;
+ amrr_node->success_threshold = amrr->min_success_threshold;
+
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ {
+ rs = (const struct ieee80211_rateset *) &ni->ni_htrates;
+
+ for (amrr_node->rate_index = rs->rs_nrates - 1;
+ amrr_node->rate_index > 0 && (rs->rs_rates[amrr_node->rate_index] & IEEE80211_RATE_VAL) > 4;
+ amrr_node->rate_index--) ;
+
+ ni->ni_txrate = rs->rs_rates[amrr_node->rate_index] | IEEE80211_RATE_MCS;
+ }
+ else
+ {
+ rs = &ni->ni_rates;
+
+ for (amrr_node->rate_index = rs->rs_nrates - 1;
+ amrr_node->rate_index > 0 && (rs->rs_rates[amrr_node->rate_index] & IEEE80211_RATE_VAL) > 72;
+ amrr_node->rate_index--) ;
+
+ ni->ni_txrate = rs->rs_rates[amrr_node->rate_index] & IEEE80211_RATE_VAL;
+ }
+
+ amrr_node->ticks = ticks;
+}
+
+/*
+ * rt2860_amrr_choose
+ */
+int rt2860_amrr_choose(struct ieee80211_node *ni,
+ struct rt2860_amrr_node *amrr_node)
+{
+ struct rt2860_amrr *amrr;
+ int rate_index;
+
+ amrr = amrr_node->amrr;
+
+ if (RT2860_AMRR_IS_ENOUGH(amrr_node) &&
+ (ticks - amrr_node->ticks) > amrr->interval)
+ {
+ rate_index = rt2860_amrr_update(amrr, amrr_node, ni);
+ if (rate_index != amrr_node->rate_index)
+ {
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ ni->ni_txrate = ni->ni_htrates.rs_rates[rate_index] | IEEE80211_RATE_MCS;
+ else
+ ni->ni_txrate = ni->ni_rates.rs_rates[rate_index] & IEEE80211_RATE_VAL;
+
+ amrr_node->rate_index = rate_index;
+ }
+
+ amrr_node->ticks = ticks;
+ }
+ else
+ {
+ rate_index = amrr_node->rate_index;
+ }
+
+ return rate_index;
+}
+
+/*
+ * rt2860_amrr_update
+ */
+static int rt2860_amrr_update(struct rt2860_amrr *amrr,
+ struct rt2860_amrr_node *amrr_node, struct ieee80211_node *ni)
+{
+ const struct ieee80211_rateset *rs;
+ int rate_index;
+
+ KASSERT(RT2860_AMRR_IS_ENOUGH(amrr_node),
+ ("not enough Tx count: txcnt=%d",
+ amrr_node->txcnt));
+
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ rs = (const struct ieee80211_rateset *) &ni->ni_htrates;
+ else
+ rs = &ni->ni_rates;
+
+ rate_index = amrr_node->rate_index;
+
+ if (RT2860_AMRR_IS_SUCCESS(amrr_node))
+ {
+ amrr_node->success++;
+ if ((amrr_node->success >= amrr_node->success_threshold) &&
+ (rate_index + 1 < rs->rs_nrates) &&
+ (!(ni->ni_flags & IEEE80211_NODE_HT) || (rs->rs_rates[rate_index + 1] & IEEE80211_RATE_VAL) < (amrr->ntxpath * 8)))
+ {
+ amrr_node->recovery = 1;
+ amrr_node->success = 0;
+
+ rate_index++;
+ }
+ else
+ {
+ amrr_node->recovery = 0;
+ }
+ }
+ else if (RT2860_AMRR_IS_FAILURE(amrr_node))
+ {
+ amrr_node->success = 0;
+
+ if (rate_index > 0)
+ {
+ if (amrr_node->recovery)
+ {
+ amrr_node->success_threshold *= 2;
+ if (amrr_node->success_threshold > amrr->max_success_threshold)
+ amrr_node->success_threshold = amrr->max_success_threshold;
+ }
+ else
+ {
+ amrr_node->success_threshold = amrr->min_success_threshold;
+ }
+
+ rate_index--;
+ }
+
+ amrr_node->recovery = 0;
+ }
+
+ amrr_node->txcnt = 0;
+ amrr_node->retrycnt = 0;
+
+ return rate_index;
+}
Index: sys/dev/rt2860/rt2860_debug.h
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_debug.h
@@ -0,0 +1,55 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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.
+ */
+
+#ifndef _RT2860_DEBUG_H_
+#define _RT2860_DEBUG_H_
+
+#ifdef RT2860_DEBUG
+
+enum
+{
+ RT2860_DEBUG_EEPROM = 0x00000001,
+ RT2860_DEBUG_RX = 0x00000002,
+ RT2860_DEBUG_TX = 0x00000004,
+ RT2860_DEBUG_INTR = 0x00000008,
+ RT2860_DEBUG_STATE = 0x00000010,
+ RT2860_DEBUG_CHAN = 0x00000020,
+ RT2860_DEBUG_NODE = 0x00000040,
+ RT2860_DEBUG_KEY = 0x00000080,
+ RT2860_DEBUG_PROT = 0x00000100,
+ RT2860_DEBUG_WME = 0x00000200,
+ RT2860_DEBUG_BEACON = 0x00000400,
+ RT2860_DEBUG_BA = 0x00000800,
+ RT2860_DEBUG_STATS = 0x00001000,
+ RT2860_DEBUG_RATE = 0x00002000,
+ RT2860_DEBUG_PERIODIC = 0x00004000,
+ RT2860_DEBUG_WATCHDOG = 0x00008000,
+ RT2860_DEBUG_RX_CRYPT = 0x00010000,
+ RT2860_DEBUG_TX_CRYPT = 0x00020000,
+ RT2860_DEBUG_ANY = 0xffffffff
+};
+
+#define RT2860_DPRINTF(sc, m, fmt, ...) do { if ((sc)->debug & (m)) printf(fmt, __VA_ARGS__); } while (0)
+
+#else
+
+#define RT2860_DPRINTF(sc, m, fmt, ...)
+
+#endif /* #ifdef RT2860_DEBUG */
+
+#endif /* #ifndef _RT2860_DEBUG_H_ */
Index: sys/dev/rt2860/rt2860_eeprom.h
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_eeprom.h
@@ -0,0 +1,91 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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.
+ */
+
+#ifndef _RT2860_EEPROM_H_
+#define _RT2860_EEPROM_H_
+
+#define RT2860_EEPROM_VERSION 0x0002
+#define RT2860_EEPROM_ADDRESS01 0x0004
+#define RT2860_EEPROM_ADDRESS23 0x0006
+#define RT2860_EEPROM_ADDRESS45 0x0008
+#define RT2860_EEPROM_POWERSAVE_LEVEL 0x0022
+#define RT2860_EEPROM_ANTENNA 0x0034
+#define RT2860_EEPROM_NIC_CONFIG 0x0036
+#define RT2860_EEPROM_COUNTRY 0x0038
+#define RT2860_EEPROM_RF_FREQ_OFF 0x003a
+#define RT2860_EEPROM_LED1_OFF 0x003c
+#define RT2860_EEPROM_LED2_OFF 0x003e
+#define RT2860_EEPROM_LED3_OFF 0x0040
+#define RT2860_EEPROM_LNA_GAIN 0x0044
+#define RT2860_EEPROM_RSSI_OFF_2GHZ_BASE 0x0046
+#define RT2860_EEPROM_RSSI2_OFF_2GHZ_BASE 0x0048
+#define RT2860_EEPROM_RSSI_OFF_5GHZ_BASE 0x004a
+#define RT2860_EEPROM_RSSI2_OFF_5GHZ_BASE 0x004c
+#define RT2860_EEPROM_TXPOW_RATE_DELTA 0x0050
+#define RT2860_EEPROM_TXPOW1_2GHZ_BASE 0x0052
+#define RT2860_EEPROM_TXPOW2_2GHZ_BASE 0x0060
+#define RT2860_EEPROM_TSSI_2GHZ_BASE 0x006e
+#define RT2860_EEPROM_TXPOW1_5GHZ_BASE 0x0078
+#define RT2860_EEPROM_TXPOW2_5GHZ_BASE 0x00a6
+#define RT2860_EEPROM_TSSI_5GHZ_BASE 0x00d4
+#define RT2860_EEPROM_TXPOW_RATE_BASE 0x00de
+#define RT2860_EEPROM_BBP_BASE 0x00f0
+#define RT3071_EEPROM_RF_BASE 0x0082
+
+#define RT2860_EEPROM_RF_2820 1 /* 2.4GHz 2T3R */
+#define RT2860_EEPROM_RF_2850 2 /* 2.4/5GHz 2T3R */
+#define RT2860_EEPROM_RF_2720 3 /* 2.4GHz 1T2R */
+#define RT2860_EEPROM_RF_2750 4 /* 2.4G/5GHz 1T2R */
+#define RT2860_EEPROM_RF_3020 5 /* 2.4G 1T1R */
+#define RT2860_EEPROM_RF_2020 6 /* 2.4G B/G */
+#define RT2860_EEPROM_RF_3021 7 /* 2.4G 1T2R */
+#define RT2860_EEPROM_RF_3022 8 /* 2.4G 2T2R */
+#define RT2860_EEPROM_RF_3052 9 /* 2.4G/5G 2T2R */
+#define RT2860_EEPROM_RF_2853 10 /* 2.4G.5G 3T3R */
+#define RT2860_EEPROM_RF_3320 11 /* 2.4G 1T1R with PA (RT3350/RT3370/RT3390) */
+#define RT2860_EEPROM_RF_3322 12 /* 2.4G 2T2R with PA (RT3352/RT3371/RT3372/RT3391/RT3392) */
+#define RT2860_EEPROM_RF_3053 13 /* 2.4G/5G 3T3R (RT3883/RT3563/RT3573/RT3593/RT3662) */
+#define RT2860_EEPROM_RF_3853 13 /* 2.4G/5G 3T3R (RT3883/RT3563/RT3573/RT3593/RT3662) */
+
+/*
+ * RT2860_EEPROM_NIC_CONFIG flags
+ */
+#define RT2860_EEPROM_EXT_LNA_5GHZ (1 << 3)
+#define RT2860_EEPROM_EXT_LNA_2GHZ (1 << 2)
+#define RT2860_EEPROM_TX_AGC_CNTL (1 << 1)
+#define RT2860_EEPROM_HW_RADIO_CNTL (1 << 0)
+
+#define RT2860_EEPROM_LED_POLARITY (1 << 7)
+#define RT2860_EEPROM_LED_MODE_MASK 0x7f
+
+#define RT2860_EEPROM_LED_CNTL_DEFAULT 0x01
+#define RT2860_EEPROM_LED1_OFF_DEFAULT 0x5555
+#define RT2860_EEPROM_LED2_OFF_DEFAULT 0x2221
+#define RT2860_EEPROM_LED3_OFF_DEFAULT 0xa9f8
+
+#define RT2860_EEPROM_RSSI_OFF_MIN -10
+#define RT2860_EEPROM_RSSI_OFF_MAX 10
+
+#define RT2860_EEPROM_TXPOW_2GHZ_MIN 0
+#define RT2860_EEPROM_TXPOW_2GHZ_MAX 31
+#define RT2860_EEPROM_TXPOW_2GHZ_DEFAULT 5
+#define RT2860_EEPROM_TXPOW_5GHZ_MIN -7
+#define RT2860_EEPROM_TXPOW_5GHZ_MAX 15
+#define RT2860_EEPROM_TXPOW_5GHZ_DEFAULT 5
+
+#endif /* #ifndef _RT2860_EEPROM_H_ */
Index: sys/dev/rt2860/rt2860_fdt.c
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_fdt.c
@@ -0,0 +1,114 @@
+
+/*-
+ * Copyright (c) 2018 Hiroki Mori
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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 <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/rt2860/rt2860_softc.h>
+#include <dev/rt2860/rt2860_reg.h>
+#include <dev/rt2860/rt2860_eeprom.h>
+#include <dev/rt2860/rt2860_txwi.h>
+#include <dev/rt2860/rt2860_rxwi.h>
+#include <dev/rt2860/rt2860_io.h>
+#include <dev/rt2860/rt2860_read_eeprom.h>
+#include <dev/rt2860/rt2860_led.h>
+#include <dev/rt2860/rt2860_rf.h>
+#include <dev/rt2860/rt2860_debug.h>
+
+
+static const struct ofw_compat_data rt_compat_data[] = {
+ { "ralink,rt3050-wmac", RT_CHIPID_RT3050 },
+ { "ralink,rt3052-wmac", RT_CHIPID_RT3052 },
+ { NULL, 0 }
+};
+
+/*
+ * Static function prototypes
+ */
+
+static int rt2860_fdt_probe(device_t dev);
+
+static int rt2860_fdt_attach(device_t dev);
+
+int rt2860_attach(device_t dev, int id);
+
+int rt2860_detach(device_t dev);
+
+int rt2860_shutdown(device_t dev);
+
+int rt2860_suspend(device_t dev);
+
+int rt2860_resume(device_t dev);
+
+/*
+ * rt2860_fdt_probe
+ */
+static int rt2860_fdt_probe(device_t dev)
+{
+ const struct ofw_compat_data * cd;
+
+
+ cd = ofw_bus_search_compatible(dev, rt_compat_data);
+ if (cd->ocd_data == 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "Ralink RT2860 802.11n MAC/BPP");
+ return 0;
+}
+
+/*
+ * rt2860_fdt_attach
+ */
+static int rt2860_fdt_attach(device_t dev)
+{
+ struct rt2860_softc *sc;
+ const struct ofw_compat_data * cd;
+
+ sc = device_get_softc(dev);
+ sc->mem_rid = 0;
+
+ cd = ofw_bus_search_compatible(dev, rt_compat_data);
+
+ return (rt2860_attach(dev, cd->ocd_data));
+}
+
+static device_method_t rt2860_fdt_dev_methods[] =
+{
+ DEVMETHOD(device_probe, rt2860_fdt_probe),
+ DEVMETHOD(device_attach, rt2860_fdt_attach),
+ DEVMETHOD(device_detach, rt2860_detach),
+ DEVMETHOD(device_shutdown, rt2860_shutdown),
+ DEVMETHOD(device_suspend, rt2860_suspend),
+ DEVMETHOD(device_resume, rt2860_resume),
+ { 0, 0 }
+};
+
+static driver_t rt2860_fdt_driver =
+{
+ "rt2860",
+ rt2860_fdt_dev_methods,
+ sizeof(struct rt2860_softc)
+};
+
+static devclass_t rt2860_fdt_dev_class;
+
+DRIVER_MODULE(rt2860, simplebus, rt2860_fdt_driver, rt2860_fdt_dev_class, 0, 0);
+MODULE_DEPEND(rt2860, wlan, 1, 1, 1);
+
Index: sys/dev/rt2860/rt2860_io.h
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_io.h
@@ -0,0 +1,73 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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.
+ */
+
+#ifndef _RT2860_IO_H_
+#define _RT2860_IO_H_
+
+#include <dev/rt2860/rt2860_softc.h>
+
+#define RT2860_IO_MCU_CMD_SLEEP 0x30
+#define RT2860_IO_MCU_CMD_WAKEUP 0x31
+#define RT2860_IO_MCU_CMD_RADIOOFF 0x35
+#define RT2860_IO_MCU_CMD_LEDS 0x50
+#define RT2860_IO_MCU_CMD_LED_BRIGHTNESS 0x51
+#define RT2860_IO_MCU_CMD_LED1 0x52
+#define RT2860_IO_MCU_CMD_LED2 0x53
+#define RT2860_IO_MCU_CMD_LED3 0x54
+#define RT2860_IO_MCU_CMD_BOOT 0x72
+#define RT2860_IO_MCU_CMD_BBP 0x80
+#define RT2860_IO_MCU_CMD_POWERSAVE_LEVEL 0x83
+
+void rt2860_io_rf_load_defaults(struct rt2860_softc *sc);
+uint32_t rt2860_io_mac_read(struct rt2860_softc *sc, uint16_t reg);
+
+void rt2860_io_mac_read_multi(struct rt2860_softc *sc,
+ uint16_t reg, void *buf, size_t len);
+
+void rt2860_io_mac_write(struct rt2860_softc *sc,
+ uint16_t reg, uint32_t val);
+
+void rt2860_io_mac_write_multi(struct rt2860_softc *sc,
+ uint16_t reg, const void *buf, size_t len);
+
+void rt2860_io_mac_set_region_4(struct rt2860_softc *sc,
+ uint16_t reg, uint32_t val, size_t len);
+
+uint16_t rt2860_io_eeprom_read(struct rt2860_softc *sc, uint16_t addr);
+
+void rt2860_io_eeprom_read_multi(struct rt2860_softc *sc,
+ uint16_t addr, void *buf, size_t len);
+
+uint8_t rt2860_io_bbp_read(struct rt2860_softc *sc, uint8_t reg);
+
+void rt2860_io_bbp_write(struct rt2860_softc *sc, uint8_t reg, uint8_t val);
+
+void rt2860_io_rf_write(struct rt2860_softc *sc, uint8_t reg, uint32_t val);
+
+int32_t rt2860_io_rf_read(struct rt2860_softc *sc, uint8_t reg);
+
+void rt2860_io_mcu_cmd(struct rt2860_softc *sc, uint8_t cmd,
+ uint8_t token, uint16_t arg);
+
+int rt2860_io_mcu_cmd_check(struct rt2860_softc *sc, uint8_t cid);
+
+int rt2860_io_mcu_load_ucode(struct rt2860_softc *sc,
+ const uint8_t *ucode, size_t len);
+
+
+#endif /* #ifndef _RT2860_IO_H_ */
Index: sys/dev/rt2860/rt2860_io.c
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_io.c
@@ -0,0 +1,864 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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 <dev/rt2860/rt2860_io.h>
+#include <dev/rt2860/rt2860_reg.h>
+
+#if defined(__mips__)
+#include <machine/cpuregs.h>
+
+#define EEPROM_IN_FLASH
+#endif
+
+/*
+ * Defines and macros
+ */
+
+/*
+ * RT2860_IO_EEPROM_RAISE_CLK
+ */
+#define RT2860_IO_EEPROM_RAISE_CLK(sc, val) \
+do \
+{ \
+ (val) |= RT2860_REG_EESK; \
+ \
+ rt2860_io_mac_write((sc), RT2860_REG_EEPROM_CSR, (val)); \
+ \
+ DELAY(1); \
+} while (0)
+
+/*
+ * RT2860_IO_EEPROM_LOWER_CLK
+ */
+#define RT2860_IO_EEPROM_LOWER_CLK(sc, val) \
+do \
+{ \
+ (val) &= ~RT2860_REG_EESK; \
+ \
+ rt2860_io_mac_write((sc), RT2860_REG_EEPROM_CSR, (val)); \
+ \
+ DELAY(1); \
+} while (0)
+
+#define RT2860_IO_BYTE_CRC16(byte, crc) \
+ ((uint16_t) (((crc) << 8) ^ rt2860_io_ccitt16[(((crc) >> 8) ^ (byte)) & 255]))
+
+/*
+ * Static function prototypes
+ */
+
+static void rt2860_io_eeprom_shiftout_bits(struct rt2860_softc *sc,
+ uint16_t val, uint16_t count);
+
+static uint16_t rt2860_io_eeprom_shiftin_bits(struct rt2860_softc *sc);
+
+static uint8_t rt2860_io_byte_rev(uint8_t byte);
+
+#if defined(__mips__) && !defined(EEPROM_IN_FLASH)
+/* Default EEPROM value for RT3050 */
+static const uint8_t rt3050_eeprom[] = {
+ 0x50, 0x30, 0x01, 0x01, 0x00, 0x0c, 0x43, 0x30, 0x52, 0x88, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0c,
+ 0x43, 0x30, 0x52, 0x77, 0x00, 0x0c, 0x43, 0x30, 0x52, 0x66, 0x11, 0x05, 0x20, 0x00,
+ 0xff, 0xff, 0x2f, 0x01, 0x55, 0x77, 0xa8, 0xaa, 0x8c, 0x88, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x0d, 0x0d,
+ 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x10, 0x10,
+ 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x66, 0x66,
+ 0xcc, 0xaa, 0x88, 0x66, 0xcc, 0xaa, 0x88, 0x66, 0xcc, 0xaa, 0x88, 0x66, 0xcc, 0xaa,
+ 0x88, 0x66, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+ };
+#endif
+
+uint8_t rt3052_rf_default[] = {
+ 0x50, /* 0 */
+ 0x01,
+ 0xF7,
+ 0x75,
+ 0x40,
+ 0x03,
+ 0x42,
+ 0x50,
+ 0x39,
+ 0x0F,
+ 0x60, /* 10 */
+ 0x21,
+ 0x75,
+ 0x75,
+ 0x90,
+ 0x58,
+ 0xB3,
+ 0x92,
+ 0x2C,
+ 0x02,
+ 0xBA, /* 20 */
+ 0xDB,
+ 0x00,
+ 0x31,
+ 0x08,
+ 0x01,
+ 0x25, /* Core Power: 0x25=1.25V */
+ 0x23, /* RF: 1.35V */
+ 0x13, /* ADC: must consist with R27 */
+ 0x83,
+ 0x00, /* 30 */
+ 0x00,
+};
+/* #endif */
+
+
+/*
+ * Static variables
+ */
+
+static const uint16_t rt2860_io_ccitt16[] =
+{
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+ 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+ 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+ 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+ 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+ 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+ 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+ 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+ 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+ 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+ 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+ 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+ 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+ 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+ 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+ 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+ 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+ 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+ 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+ 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+ 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+/*
+ * rt2860_io_mac_read
+ */
+uint32_t rt2860_io_mac_read(struct rt2860_softc *sc, uint16_t reg)
+{
+
+ return bus_space_read_4(sc->bst, sc->bsh, reg);
+}
+
+/*
+ * rt2860_io_mac_read_multi
+ */
+void rt2860_io_mac_read_multi(struct rt2860_softc *sc,
+ uint16_t reg, void *buf, size_t len)
+{
+
+ bus_space_read_region_1(sc->bst, sc->bsh, reg, buf, len);
+}
+
+/*
+ * rt2860_io_mac_write
+ */
+void rt2860_io_mac_write(struct rt2860_softc *sc,
+ uint16_t reg, uint32_t val)
+{
+
+ bus_space_write_4(sc->bst, sc->bsh, reg, val);
+}
+
+/*
+ * rt2860_io_mac_write_multi
+ */
+void rt2860_io_mac_write_multi(struct rt2860_softc *sc,
+ uint16_t reg, const void *buf, size_t len)
+{
+ int i;
+ const uint8_t *p;
+
+ p = buf;
+ for (i = 0; i < len; i ++)
+ bus_space_write_1(sc->bst, sc->bsh, reg + i, *(p+i));
+
+#ifdef notyet
+ bus_space_write_region_1(sc->bst, sc->bsh, reg, buf, len);
+#endif
+}
+
+/*
+ * rt2860_io_mac_set_region_4
+ */
+void rt2860_io_mac_set_region_4(struct rt2860_softc *sc,
+ uint16_t reg, uint32_t val, size_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i += sizeof(uint32_t))
+ rt2860_io_mac_write(sc, reg + i, val);
+}
+
+/* Read 16-bit from eFUSE ROM (>=RT3071 only.) */
+static uint16_t
+rt3090_efuse_read_2(struct rt2860_softc *sc, uint16_t addr)
+{
+ uint32_t tmp;
+ uint16_t reg;
+ int ntries;
+
+ addr *= 2;
+ /*-
+ * Read one 16-byte block into registers EFUSE_DATA[0-3]:
+ * DATA0: F E D C
+ * DATA1: B A 9 8
+ * DATA2: 7 6 5 4
+ * DATA3: 3 2 1 0
+ */
+ tmp = rt2860_io_mac_read(sc, RT3070_EFUSE_CTRL);
+ tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK);
+ tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK;
+ rt2860_io_mac_write(sc, RT3070_EFUSE_CTRL, tmp);
+ for (ntries = 0; ntries < 500; ntries++) {
+ tmp = rt2860_io_mac_read(sc, RT3070_EFUSE_CTRL);
+ if (!(tmp & RT3070_EFSROM_KICK))
+ break;
+ DELAY(2);
+ }
+ if (ntries == 500)
+ return 0xffff;
+
+ if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK)
+ return 0xffff; /* address not found */
+
+ /* determine to which 32-bit register our 16-bit word belongs */
+ reg = RT3070_EFUSE_DATA3 - (addr & 0xc);
+ tmp = rt2860_io_mac_read(sc, reg);
+
+ return (addr & 2) ? tmp >> 16 : tmp & 0xffff;
+}
+
+
+/*
+ * rt2860_io_eeprom_read
+ */
+uint16_t rt2860_io_eeprom_read(struct rt2860_softc *sc, uint16_t addr)
+{
+ uint32_t tmp;
+ uint16_t val;
+
+ addr = (addr >> 1);
+
+#if defined(__mips__)
+ if (sc->mac_rev == 0x28720200) {
+#ifdef EEPROM_IN_FLASH
+ /* xxx get from dts value */
+ uint8_t *eeprom = (uint8_t *)MIPS_PHYS_TO_KSEG1(0x1f040000);
+ return (*(eeprom + addr*2) +
+ *(eeprom + addr*2+1) * 0x100);
+#else
+ return (rt3050_eeprom[addr*2] +
+ rt3050_eeprom[addr*2+1] * 0x100);
+#endif
+ } else if ((sc->mac_rev & 0xffff0000) >= 0x30710000) {
+ tmp = rt2860_io_mac_read(sc, RT3070_EFUSE_CTRL);
+ if (tmp & RT3070_SEL_EFUSE)
+ return (rt3090_efuse_read_2(sc, addr));
+ }
+#endif
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_EEPROM_CSR);
+
+ tmp &= ~(RT2860_REG_EEDI | RT2860_REG_EEDO | RT2860_REG_EESK);
+ tmp |= RT2860_REG_EECS;
+
+ rt2860_io_mac_write(sc, RT2860_REG_EEPROM_CSR, tmp);
+
+ if (((sc->mac_rev & 0xffff0000) != 0x30710000) &&
+ ((sc->mac_rev & 0xffff0000) != 0x30900000) &&
+ ((sc->mac_rev & 0xffff0000) != 0x35720000) &&
+ ((sc->mac_rev & 0xffff0000) != 0x33900000))
+ {
+ RT2860_IO_EEPROM_RAISE_CLK(sc, tmp);
+ RT2860_IO_EEPROM_LOWER_CLK(sc, tmp);
+ }
+
+ rt2860_io_eeprom_shiftout_bits(sc, RT2860_REG_EEOP_READ, 3);
+ rt2860_io_eeprom_shiftout_bits(sc, addr, sc->eeprom_addr_num);
+
+ val = rt2860_io_eeprom_shiftin_bits(sc);
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_EEPROM_CSR);
+
+ tmp &= ~(RT2860_REG_EECS | RT2860_REG_EEDI);
+
+ rt2860_io_mac_write(sc, RT2860_REG_EEPROM_CSR, tmp);
+
+ RT2860_IO_EEPROM_RAISE_CLK(sc, tmp);
+ RT2860_IO_EEPROM_LOWER_CLK(sc, tmp);
+
+ return val;
+}
+
+/*
+ * rt2860_io_eeprom_read_multi
+ */
+void rt2860_io_eeprom_read_multi(struct rt2860_softc *sc,
+ uint16_t addr, void *buf, size_t len)
+{
+ uint16_t *ptr;
+ int i;
+
+ len += len % sizeof(uint16_t);
+ ptr = buf;
+
+ i = 0;
+
+ do
+ {
+ *ptr++ = rt2860_io_eeprom_read(sc, addr + i);
+
+ i += sizeof(uint16_t);
+ len -= sizeof(uint16_t);
+ } while (len > 0);
+}
+
+/*
+ * rt2860_io_bbp_read
+ */
+uint8_t rt2860_io_bbp_read(struct rt2860_softc *sc, uint8_t reg)
+{
+ int ntries;
+ uint32_t tmp;
+
+ if (sc->mac_rev == 0x28720200)
+ {
+ for (ntries = 0; ntries < 100; ntries ++) {
+ if ( !(rt2860_io_mac_read(sc, RT2860_REG_BBP_CSR_CFG) &
+ RT2860_REG_BBP_CSR_BUSY) )
+ break;
+ DELAY(1);
+ }
+ if (ntries == 100) {
+ printf("%s:%s: BBP busy after 100 probes\n",
+ device_get_nameunit(sc->dev), __func__);
+ return (0);
+ }
+ rt2860_io_mac_write(sc, RT2860_REG_BBP_CSR_CFG,
+ RT2860_REG_BBP_CSR_READ |
+ RT2860_REG_BBP_CSR_KICK | RT2860_REG_BBP_RW_MODE_PARALLEL |
+ (reg & RT2860_REG_BBP_REG_MASK) << RT2860_REG_BBP_REG_SHIFT);
+ for (ntries = 0; ntries < 100; ntries ++) {
+ if ( !(rt2860_io_mac_read(sc, RT2860_REG_BBP_CSR_CFG) &
+ RT2860_REG_BBP_CSR_BUSY) )
+ break;
+ DELAY(1);
+ }
+ if (ntries == 100) {
+ printf("%s:%s: BBP busy after 100 probes\n",
+ device_get_nameunit(sc->dev), __func__);
+ return (0);
+ }
+ else {
+ return
+ ((rt2860_io_mac_read(sc, RT2860_REG_BBP_CSR_CFG) >>
+ RT2860_REG_BBP_VAL_SHIFT) &
+ RT2860_REG_BBP_VAL_MASK);
+ }
+ return (0);
+ }
+
+ for (ntries = 0; ntries < 100; ntries++)
+ {
+ if (!(rt2860_io_mac_read(sc, RT2860_REG_H2M_MAILBOX_BBP_AGENT) &
+ RT2860_REG_BBP_CSR_BUSY))
+ break;
+
+ DELAY(1);
+ }
+
+ if (ntries == 100)
+ {
+ printf("%s: could not read from BBP through MCU: reg=0x%02x\n",
+ device_get_nameunit(sc->dev), reg);
+ return 0;
+ }
+
+ tmp = RT2860_REG_BBP_RW_MODE_PARALLEL |
+ RT2860_REG_BBP_CSR_BUSY |
+ RT2860_REG_BBP_CSR_READ |
+ ((reg & RT2860_REG_BBP_REG_MASK) << RT2860_REG_BBP_REG_SHIFT);
+
+ rt2860_io_mac_write(sc, RT2860_REG_H2M_MAILBOX_BBP_AGENT, tmp);
+
+ rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_BBP,
+ RT2860_REG_H2M_TOKEN_NO_INTR, 0);
+
+ DELAY(1000);
+
+ for (ntries = 0; ntries < 100; ntries++)
+ {
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_H2M_MAILBOX_BBP_AGENT);
+ if (!(tmp & RT2860_REG_BBP_CSR_BUSY))
+ return ((tmp >> RT2860_REG_BBP_VAL_SHIFT) &
+ RT2860_REG_BBP_VAL_MASK);
+
+ DELAY(1);
+ }
+
+ printf("%s: could not read from BBP through MCU: reg=0x%02x\n",
+ device_get_nameunit(sc->dev), reg);
+
+ return 0;
+}
+
+/*
+ * rt2860_io_bbp_write
+ */
+void rt2860_io_bbp_write(struct rt2860_softc *sc, uint8_t reg, uint8_t val)
+{
+ int ntries;
+ uint32_t tmp;
+
+ if (sc->mac_rev == 0x28720200)
+ {
+ for (ntries = 0; ntries < 100; ntries ++) {
+ if ( !(rt2860_io_mac_read(sc, RT2860_REG_BBP_CSR_CFG) &
+ RT2860_REG_BBP_CSR_BUSY) )
+ break;
+ DELAY(1);
+ }
+ if (ntries == 100) {
+ printf("%s:%s: BBP busy after 100 probes\n",
+ device_get_nameunit(sc->dev), __func__);
+ return;
+ }
+ rt2860_io_mac_write(sc, RT2860_REG_BBP_CSR_CFG,
+ RT2860_REG_BBP_CSR_KICK | RT2860_REG_BBP_RW_MODE_PARALLEL |
+ (reg & RT2860_REG_BBP_REG_MASK) << RT2860_REG_BBP_REG_SHIFT |
+ (val & RT2860_REG_BBP_VAL_MASK) << RT2860_REG_BBP_VAL_SHIFT );
+ rt2860_io_bbp_read(sc, reg);
+ return;
+ }
+
+ for (ntries = 0; ntries < 100; ntries++)
+ {
+ if (!(rt2860_io_mac_read(sc, RT2860_REG_H2M_MAILBOX_BBP_AGENT) &
+ RT2860_REG_BBP_CSR_BUSY))
+ break;
+
+ DELAY(1);
+ }
+
+ if (ntries == 100)
+ {
+ printf("%s: could not write to BBP through MCU: reg=0x%02x\n",
+ device_get_nameunit(sc->dev), reg);
+ return;
+ }
+
+ tmp = RT2860_REG_BBP_RW_MODE_PARALLEL |
+ RT2860_REG_BBP_CSR_BUSY |
+ ((reg & RT2860_REG_BBP_REG_MASK) << RT2860_REG_BBP_REG_SHIFT) |
+ ((val & RT2860_REG_BBP_VAL_MASK) << RT2860_REG_BBP_VAL_SHIFT);
+
+ rt2860_io_mac_write(sc, RT2860_REG_H2M_MAILBOX_BBP_AGENT, tmp);
+
+ rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_BBP,
+ RT2860_REG_H2M_TOKEN_NO_INTR, 0);
+
+ DELAY(1000);
+}
+
+/*
+ * rt2860_io_rf_write
+ */
+void rt2860_io_rf_write(struct rt2860_softc *sc, uint8_t reg, uint32_t val)
+{
+ int ntries;
+ if (sc->mac_rev == 0x28720200)
+ {
+ for (ntries = 0; ntries < 100; ntries ++) {
+ if ( !(rt2860_io_mac_read(sc, RT2872_REG_RF_CSR_CFG) &
+ RT2872_REG_RF_CSR_BUSY) )
+ break;
+ DELAY(1);
+ }
+ if (ntries == 100) {
+ printf("%s:%s: RF busy after 100 probes\n",
+ device_get_nameunit(sc->dev), __func__);
+ return;
+ }
+ rt2860_io_mac_write(sc, RT2872_REG_RF_CSR_CFG,
+ RT2872_REG_RF_CSR_KICK | RT2872_REG_RF_CSR_WRITE |
+ (reg & RT2872_REG_RF_ID_MASK) << RT2872_REG_RF_ID_SHIFT |
+ (val & RT2872_REG_RF_VAL_MASK) << RT2872_REG_RF_VAL_SHIFT );
+ rt2860_io_rf_read(sc, reg);
+ return;
+ }
+
+
+ for (ntries = 0; ntries < 100; ntries++)
+ if (!(rt2860_io_mac_read(sc, RT2860_REG_RF_CSR_CFG0) &
+ RT2860_REG_RF_BUSY))
+ break;
+
+ if (ntries == 100)
+ {
+ printf("%s: could not write to RF: reg=0x%02x\n",
+ device_get_nameunit(sc->dev), reg);
+ return;
+ }
+
+ rt2860_io_mac_write(sc, RT2860_REG_RF_CSR_CFG0, val);
+}
+
+/*
+ * rt2860_io_rf_read
+ */
+int32_t rt2860_io_rf_read(struct rt2860_softc *sc, uint8_t reg)
+{
+ int ntries;
+ if (sc->mac_rev == 0x28720200)
+ {
+ for (ntries = 0; ntries < 100; ntries ++) {
+ if ( !(rt2860_io_mac_read(sc, RT2872_REG_RF_CSR_CFG) &
+ RT2872_REG_RF_CSR_BUSY) )
+ break;
+ DELAY(1);
+ }
+ if (ntries == 100) {
+ printf("%s:%s: RF busy after 100 probes\n",
+ device_get_nameunit(sc->dev), __func__);
+ return (-1);
+ }
+ rt2860_io_mac_write(sc, RT2872_REG_RF_CSR_CFG,
+ RT2872_REG_RF_CSR_KICK |
+ (reg & RT2872_REG_RF_ID_MASK) << RT2872_REG_RF_ID_SHIFT );
+
+ for (ntries = 0; ntries < 100; ntries ++) {
+ if ( !(rt2860_io_mac_read(sc, RT2872_REG_RF_CSR_CFG) &
+ RT2872_REG_RF_CSR_BUSY) )
+ break;
+ DELAY(1);
+ }
+ if (ntries == 100) {
+ printf("%s:%s: RF busy after 100 probes\n",
+ device_get_nameunit(sc->dev), __func__);
+ }
+
+ return (rt2860_io_mac_read(sc, RT2872_REG_RF_CSR_CFG) & RT2872_REG_RF_VAL_MASK);
+ }
+ return (-1);
+}
+
+/*
+ * rt2860_io_rf_load_defaults
+ */
+void rt2860_io_rf_load_defaults(struct rt2860_softc *sc)
+{
+ int i;
+
+ if (sc->mac_rev == 0x28720200) {
+ for (i = 0; i < sizeof(rt3052_rf_default); i ++)
+ rt2860_io_rf_write(sc, i, rt3052_rf_default[i]);
+ }
+}
+
+/*
+ * rt2860_io_mcu_cmd
+ */
+void rt2860_io_mcu_cmd(struct rt2860_softc *sc, uint8_t cmd,
+ uint8_t token, uint16_t arg)
+{
+ uint32_t tmp;
+ int ntries;
+
+ if (sc->mac_rev == 0x28720200)
+ return;
+
+ for (ntries = 0; ntries < 100; ntries++)
+ {
+ if (!(rt2860_io_mac_read(sc, RT2860_REG_H2M_MAILBOX) &
+ RT2860_REG_H2M_BUSY))
+ break;
+
+ DELAY(2);
+ }
+
+ if (ntries == 100)
+ {
+ printf("%s: could not read H2M: cmd=0x%02x\n",
+ device_get_nameunit(sc->dev), cmd);
+ return;
+ }
+
+ tmp = RT2860_REG_H2M_BUSY | (token << 16) | arg;
+
+ rt2860_io_mac_write(sc, RT2860_REG_H2M_MAILBOX, tmp);
+ rt2860_io_mac_write(sc, RT2860_REG_H2M_HOST_CMD, cmd);
+}
+
+/*
+ * rt2860_io_mcu_cmd_check
+ */
+int rt2860_io_mcu_cmd_check(struct rt2860_softc *sc, uint8_t cid)
+{
+ uint32_t tmp, mask, status;
+ int result, ntries;
+
+ result = -1;
+
+ for (ntries = 0; ntries < 200; ntries++)
+ {
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_H2M_MAILBOX_CID);
+
+ if (((cid >> RT2860_REG_H2M_CID0_SHIFT) & RT2860_REG_H2M_CID_MASK) == cid)
+ {
+ mask = (RT2860_REG_H2M_CID_MASK << RT2860_REG_H2M_CID0_SHIFT);
+ break;
+ }
+ else if (((tmp >> RT2860_REG_H2M_CID1_SHIFT) & RT2860_REG_H2M_CID_MASK) == cid)
+ {
+ mask = (RT2860_REG_H2M_CID_MASK << RT2860_REG_H2M_CID1_SHIFT);
+ break;
+ }
+ else if (((tmp >> RT2860_REG_H2M_CID2_SHIFT) & RT2860_REG_H2M_CID_MASK) == cid)
+ {
+ mask = (RT2860_REG_H2M_CID_MASK << RT2860_REG_H2M_CID2_SHIFT);
+ break;
+ }
+ else if (((tmp >> RT2860_REG_H2M_CID3_SHIFT) & RT2860_REG_H2M_CID_MASK) == cid)
+ {
+ mask = (RT2860_REG_H2M_CID_MASK << RT2860_REG_H2M_CID3_SHIFT);
+ break;
+ }
+
+ DELAY(100);
+ }
+
+ status = rt2860_io_mac_read(sc, RT2860_REG_H2M_MAILBOX_STATUS);
+
+ if (ntries < 200)
+ {
+ status &= mask;
+
+ if ((status == 0x1) ||
+ (status == 0x100) ||
+ (status == 0x10000) ||
+ (status == 0x1000000))
+ result = 0;
+ }
+
+ rt2860_io_mac_write(sc, RT2860_REG_H2M_MAILBOX_STATUS, 0xffffffff);
+ rt2860_io_mac_write(sc, RT2860_REG_H2M_MAILBOX_CID, 0xffffffff);
+
+ return result;
+}
+
+/*
+ * rt2860_io_mcu_load_ucode
+ */
+int rt2860_io_mcu_load_ucode(struct rt2860_softc *sc,
+ const uint8_t *ucode, size_t len)
+{
+ int i, ntries;
+ uint16_t crc;
+
+ for (i = 0, crc = 0xffff; i < len - 2; i++)
+ crc = RT2860_IO_BYTE_CRC16(rt2860_io_byte_rev(ucode[i]), crc);
+
+ if (ucode[len - 2] != rt2860_io_byte_rev(crc >> 8) ||
+ ucode[len - 1] != rt2860_io_byte_rev(crc))
+ {
+ printf("%s: wrong microcode crc\n",
+ device_get_nameunit(sc->dev));
+ return EINVAL;
+ }
+
+ rt2860_io_mac_write(sc, RT2860_REG_PBF_SYS_CTRL, RT2860_REG_HST_PM_SEL);
+
+ for(i = 0; i < len; i += 4)
+ {
+ rt2860_io_mac_write(sc, RT2860_REG_MCU_UCODE_BASE + i,
+ (ucode[i+3] << 24) | (ucode[i+2] << 16) |
+ (ucode[i+1] << 8) | ucode[i]);
+ }
+
+ if (sc->mac_rev != 0x28720200)
+ rt2860_io_mac_write_multi(sc, RT2860_REG_MCU_UCODE_BASE,
+ ucode, len);
+
+ rt2860_io_mac_write(sc, RT2860_REG_PBF_SYS_CTRL, 0);
+
+ if (sc->mac_rev != 0x28720200)
+ rt2860_io_mac_write(sc, RT2860_REG_PBF_SYS_CTRL,
+ RT2860_REG_MCU_RESET);
+
+ DELAY(10000);
+
+ /* initialize BBP R/W access agent */
+
+ rt2860_io_mac_write(sc, RT2860_REG_H2M_MAILBOX_BBP_AGENT, 0);
+ rt2860_io_mac_write(sc, RT2860_REG_H2M_MAILBOX, 0);
+
+ if (sc->mac_rev != 0x28720200) {
+
+ for (ntries = 0; ntries < 1000; ntries++)
+ {
+ if (rt2860_io_mac_read(sc, RT2860_REG_PBF_SYS_CTRL) &
+ RT2860_REG_MCU_READY)
+ break;
+
+ DELAY(1000);
+ }
+
+ if (ntries == 1000)
+ {
+ printf("%s: timeout waiting for MCU to initialize\n",
+ device_get_nameunit(sc->dev));
+ return ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * rt2860_io_eeprom_shiftout_bits
+ */
+static void rt2860_io_eeprom_shiftout_bits(struct rt2860_softc *sc,
+ uint16_t val, uint16_t count)
+{
+ uint32_t mask, tmp;
+
+ mask = (1 << (count - 1));
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_EEPROM_CSR);
+
+ tmp &= ~(RT2860_REG_EEDO | RT2860_REG_EEDI);
+
+ do
+ {
+ tmp &= ~RT2860_REG_EEDI;
+
+ if(val & mask)
+ tmp |= RT2860_REG_EEDI;
+
+ rt2860_io_mac_write(sc, RT2860_REG_EEPROM_CSR, tmp);
+
+ RT2860_IO_EEPROM_RAISE_CLK(sc, tmp);
+ RT2860_IO_EEPROM_LOWER_CLK(sc, tmp);
+
+ mask = (mask >> 1);
+ } while (mask);
+
+ tmp &= ~RT2860_REG_EEDI;
+
+ rt2860_io_mac_write(sc, RT2860_REG_EEPROM_CSR, tmp);
+}
+
+/*
+ * rt2860_io_eeprom_shiftin_bits
+ */
+static uint16_t rt2860_io_eeprom_shiftin_bits(struct rt2860_softc *sc)
+{
+ uint32_t tmp;
+ uint16_t val;
+ int i;
+
+ val = 0;
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_EEPROM_CSR);
+
+ tmp &= ~(RT2860_REG_EEDO | RT2860_REG_EEDI);
+
+ for(i = 0; i < 16; i++)
+ {
+ val = (val << 1);
+
+ RT2860_IO_EEPROM_RAISE_CLK(sc, tmp);
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_EEPROM_CSR);
+
+ RT2860_IO_EEPROM_LOWER_CLK(sc, tmp);
+
+ tmp &= ~RT2860_REG_EEDI;
+ if(tmp & RT2860_REG_EEDO)
+ val |= 1;
+ }
+
+ return val;
+}
+
+/*
+ * rt2860_io_byte_rev
+ */
+static uint8_t rt2860_io_byte_rev(uint8_t byte)
+{
+ int i;
+ uint8_t tmp;
+
+ for(i = 0, tmp = 0; ; i++)
+ {
+ if(byte & 0x80)
+ tmp |= 0x80;
+
+ if(i == 7)
+ break;
+
+ byte <<= 1;
+ tmp >>= 1;
+ }
+
+ return tmp;
+}
Index: sys/dev/rt2860/rt2860_led.h
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_led.h
@@ -0,0 +1,33 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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.
+ */
+
+#ifndef _RT2860_LED_H_
+#define _RT2860_LED_H_
+
+#include <dev/rt2860/rt2860_softc.h>
+
+#define RT2860_LED_CMD_RADIO_OFF 0
+#define RT2860_LED_CMD_RADIO_ON (1 << 5)
+#define RT2860_LED_CMD_LINK_2GHZ (1 << 6)
+#define RT2860_LED_CMD_LINK_5GHZ (1 << 7)
+
+void rt2860_led_brightness(struct rt2860_softc *sc, uint8_t brightness);
+
+void rt2860_led_cmd(struct rt2860_softc *sc, uint8_t cmd);
+
+#endif /* #ifndef _RT2860_LED_H_ */
Index: sys/dev/rt2860/rt2860_led.c
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_led.c
@@ -0,0 +1,51 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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 <dev/rt2860/rt2860_led.h>
+#include <dev/rt2860/rt2860_reg.h>
+#include <dev/rt2860/rt2860_eeprom.h>
+#include <dev/rt2860/rt2860_io.h>
+
+/*
+ * rt2860_led_brightness
+ */
+void rt2860_led_brightness(struct rt2860_softc *sc, uint8_t brightness)
+{
+ uint8_t polarity;
+ uint16_t tmp;
+
+ polarity = (sc->led_cntl & RT2860_EEPROM_LED_POLARITY) ? 1 : 0;
+
+ tmp = (polarity << 8) | brightness;
+
+ rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_LED_BRIGHTNESS,
+ RT2860_REG_H2M_TOKEN_NO_INTR, tmp);
+}
+
+/*
+ * rt2860_led_cmd
+ */
+void rt2860_led_cmd(struct rt2860_softc *sc, uint8_t cmd)
+{
+ uint16_t tmp;
+
+ tmp = (cmd << 8) | (sc->led_cntl & RT2860_EEPROM_LED_MODE_MASK);
+
+ rt2860_io_mcu_cmd(sc, RT2860_IO_MCU_CMD_LEDS,
+ RT2860_REG_H2M_TOKEN_NO_INTR, tmp);
+}
Index: sys/dev/rt2860/rt2860_pci.c
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_pci.c
@@ -0,0 +1,163 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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 <dev/rt2860/rt2860_softc.h>
+#include <dev/rt2860/rt2860_reg.h>
+#include <dev/rt2860/rt2860_eeprom.h>
+#include <dev/rt2860/rt2860_txwi.h>
+#include <dev/rt2860/rt2860_rxwi.h>
+#include <dev/rt2860/rt2860_io.h>
+#include <dev/rt2860/rt2860_read_eeprom.h>
+#include <dev/rt2860/rt2860_led.h>
+#include <dev/rt2860/rt2860_rf.h>
+#include <dev/rt2860/rt2860_debug.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.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 PCI_PRODUCT_RALINK_RT3090_PCIe 0x3090
+
+/*
+ * Data structures and types
+ */
+
+struct rt2860_pci_ident
+{
+ uint16_t vendor;
+ uint16_t device;
+ const char *name;
+};
+
+/*
+ * Static function prototypes
+ */
+
+static int rt2860_pci_probe(device_t dev);
+
+static int rt2860_pci_attach(device_t dev);
+
+/*
+ * Bus independent methods
+ */
+
+int rt2860_attach(device_t dev, int id);
+
+int rt2860_detach(device_t dev);
+
+int rt2860_shutdown(device_t dev);
+
+int rt2860_suspend(device_t dev);
+
+int rt2860_resume(device_t dev);
+
+
+/*
+ * 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" },
+ { PCI_VENDOR_RALINK, PCI_PRODUCT_RALINK_RT2790_PCIe, "Ralink RT2790 PCIe" },
+ { PCI_VENDOR_RALINK, PCI_PRODUCT_RALINK_RT3090_PCIe, "Ralink RT3090 PCIe" },
+ { 0, 0, NULL }
+};
+
+
+/*
+ * rt2860_pci_probe
+ */
+static int rt2860_pci_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_pci_attach
+ */
+static int rt2860_pci_attach(device_t dev)
+{
+ struct rt2860_softc *sc;
+
+ 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->mem_rid = PCIR_BAR(0);
+
+ return (rt2860_attach(dev, pci_get_device(dev)));
+}
+
+static device_method_t rt2860_pci_dev_methods[] =
+{
+ /* PCI only */
+ DEVMETHOD(device_probe, rt2860_pci_probe),
+ DEVMETHOD(device_attach, rt2860_pci_attach),
+
+ /* Any bus */
+ DEVMETHOD(device_detach, rt2860_detach),
+ DEVMETHOD(device_shutdown, rt2860_shutdown),
+ DEVMETHOD(device_suspend, rt2860_suspend),
+ DEVMETHOD(device_resume, rt2860_resume),
+ { 0, 0 }
+};
+
+static driver_t rt2860_pci_driver =
+{
+ "rt2860",
+ rt2860_pci_dev_methods,
+ sizeof(struct rt2860_softc)
+};
+
+static devclass_t rt2860_pci_dev_class;
+
+DRIVER_MODULE(rt2860, pci, rt2860_pci_driver, rt2860_pci_dev_class, 0, 0);
+MODULE_DEPEND(rt2860, pci, 1, 1, 1);
+MODULE_DEPEND(rt2860, wlan, 1, 1, 1);
+
Index: sys/dev/rt2860/rt2860_read_eeprom.h
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_read_eeprom.h
@@ -0,0 +1,29 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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.
+ */
+
+#ifndef _RT2860_READ_EEPROM_H_
+#define _RT2860_READ_EEPROM_H_
+
+#include <dev/rt2860/rt2860_softc.h>
+
+void rt2860_read_eeprom(struct rt2860_softc *sc);
+
+uint32_t rt2860_read_eeprom_txpow_rate_add_delta(uint32_t txpow_rate,
+ int8_t delta);
+
+#endif /* #ifndef _RT2860_READ_EEPROM_H_ */
Index: sys/dev/rt2860/rt2860_read_eeprom.c
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_read_eeprom.c
@@ -0,0 +1,510 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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 <dev/rt2860/rt2860_read_eeprom.h>
+#include <dev/rt2860/rt2860_reg.h>
+#include <dev/rt2860/rt2860_eeprom.h>
+#include <dev/rt2860/rt2860_io.h>
+#include <dev/rt2860/rt2860_debug.h>
+
+/*
+ * rt2860_read_eeprom
+ */
+void rt2860_read_eeprom(struct rt2860_softc *sc)
+{
+ uint32_t tmp;
+ uint16_t val;
+ int i;
+
+ /* read EEPROM address number */
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_EEPROM_CSR);
+
+ if((tmp & 0x30) == 0)
+ sc->eeprom_addr_num = 6;
+ else if((tmp & 0x30) == 0x10)
+ sc->eeprom_addr_num = 8;
+ else
+ sc->eeprom_addr_num = 8;
+
+ /* read EEPROM version */
+
+ sc->eeprom_rev = rt2860_io_eeprom_read(sc, RT2860_EEPROM_VERSION);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+ "%s: EEPROM rev=0x%04x\n",
+ device_get_nameunit(sc->dev), sc->eeprom_rev);
+
+ /* read MAC address */
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_ADDRESS01);
+
+ sc->mac_addr[0] = (val & 0xff);
+ sc->mac_addr[1] = (val >> 8);
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_ADDRESS23);
+
+ sc->mac_addr[2] = (val & 0xff);
+ sc->mac_addr[3] = (val >> 8);
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_ADDRESS45);
+
+ sc->mac_addr[4] = (val & 0xff);
+ sc->mac_addr[5] = (val >> 8);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+ "%s: EEPROM mac address=%s\n",
+ device_get_nameunit(sc->dev), ether_sprintf(sc->mac_addr));
+
+ /* read RF information */
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_ANTENNA);
+ if (val == 0xffff)
+ {
+ printf("%s: invalid EEPROM antenna info\n",
+ device_get_nameunit(sc->dev));
+
+ sc->rf_rev = RT2860_EEPROM_RF_2820;
+ sc->ntxpath = 1;
+ sc->nrxpath = 2;
+ }
+ else
+ {
+ sc->rf_rev = (val >> 8) & 0xf;
+ sc->ntxpath = (val >> 4) & 0xf;
+ sc->nrxpath = (val & 0xf);
+ }
+
+ if ((sc->mac_rev != 0x28830300) && (sc->nrxpath > 2))
+ {
+ /* only 2 Rx streams for RT2860 series */
+
+ sc->nrxpath = 2;
+ }
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+ "%s: EEPROM RF rev=0x%04x, paths=%dT%dR\n",
+ device_get_nameunit(sc->dev), sc->rf_rev, sc->ntxpath, sc->nrxpath);
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_NIC_CONFIG);
+ if ((val & 0xff00) != 0xff00)
+ sc->patch_dac = (val >> 15) & 1;
+
+ sc->hw_radio_cntl = ((val & RT2860_EEPROM_HW_RADIO_CNTL) ? 1 : 0);
+ sc->tx_agc_cntl = ((val & RT2860_EEPROM_TX_AGC_CNTL) ? 1 : 0);
+ sc->ext_lna_2ghz = ((val & RT2860_EEPROM_EXT_LNA_2GHZ) ? 1 : 0);
+ sc->ext_lna_5ghz = ((val & RT2860_EEPROM_EXT_LNA_5GHZ) ? 1 : 0);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+ "%s: EEPROM NIC config: HW radio cntl=%d, Tx AGC cntl=%d, ext LNA gains=%d/%d\n",
+ device_get_nameunit(sc->dev),
+ sc->hw_radio_cntl, sc->tx_agc_cntl, sc->ext_lna_2ghz, sc->ext_lna_5ghz);
+
+ /* read country code */
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_COUNTRY);
+
+ sc->country_2ghz = (val >> 8) & 0xff;
+ sc->country_5ghz = (val & 0xff);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+ "%s: EEPROM country code=%d/%d\n",
+ device_get_nameunit(sc->dev), sc->country_2ghz, sc->country_5ghz);
+
+ /* read RF frequency offset */
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_RF_FREQ_OFF);
+
+ if ((val & 0xff) != 0xff)
+ {
+ sc->rf_freq_off = (val & 0xff);
+ }
+ else
+ {
+ printf("%s: invalid EEPROM RF freq offset\n",
+ device_get_nameunit(sc->dev));
+
+ sc->rf_freq_off = 0;
+ }
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+ "%s: EEPROM freq offset=0x%02x\n",
+ device_get_nameunit(sc->dev), sc->rf_freq_off);
+
+ /* read LEDs operating mode */
+
+ if (((val >> 8) & 0xff) != 0xff)
+ {
+ sc->led_cntl = ((val >> 8) & 0xff);
+ sc->led_off[0] = rt2860_io_eeprom_read(sc, RT2860_EEPROM_LED1_OFF);
+ sc->led_off[1] = rt2860_io_eeprom_read(sc, RT2860_EEPROM_LED2_OFF);
+ sc->led_off[2] = rt2860_io_eeprom_read(sc, RT2860_EEPROM_LED3_OFF);
+ }
+ else
+ {
+ printf("%s: invalid EEPROM LED settings\n",
+ device_get_nameunit(sc->dev));
+
+ sc->led_cntl = RT2860_EEPROM_LED_CNTL_DEFAULT;
+ sc->led_off[0] = RT2860_EEPROM_LED1_OFF_DEFAULT;
+ sc->led_off[1] = RT2860_EEPROM_LED2_OFF_DEFAULT;
+ sc->led_off[2] = RT2860_EEPROM_LED3_OFF_DEFAULT;
+ }
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+ "%s: EEPROM LED cntl=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n",
+ device_get_nameunit(sc->dev), sc->led_cntl,
+ sc->led_off[0], sc->led_off[1], sc->led_off[2]);
+
+ /* read RSSI offsets and LNA gains */
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_LNA_GAIN);
+ if ((sc->mac_rev & 0xffff0000) >= 0x30710000)
+ sc->lna_gain[0] = RT3090_DEF_LNA;
+ else /* channel group 0 */
+ sc->lna_gain[0] = val & 0xff;
+
+ sc->lna_gain[1] = (val >> 8) & 0xff;
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_RSSI_OFF_2GHZ_BASE);
+
+ sc->rssi_off_2ghz[0] = (val & 0xff);
+ sc->rssi_off_2ghz[1] = (val >> 8) & 0xff;
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_RSSI_OFF_2GHZ_BASE + 2);
+
+ if ((sc->mac_rev & 0xffff0000) >= 0x30710000) {
+ /*
+ * On RT3090 chips (limited to 2 Rx chains), this ROM
+ * field contains the Tx mixer gain for the 2GHz band.
+ */
+ if ((val & 0xff) != 0xff)
+ sc->txmixgain_2ghz = val & 0x7;
+ } else
+ sc->rssi_off_2ghz[2] = val & 0xff; /* Ant C */
+ sc->lna_gain[2] = (val >> 8) & 0xff;
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_RSSI_OFF_5GHZ_BASE);
+
+ sc->rssi_off_5ghz[0] = (val & 0xff);
+ sc->rssi_off_5ghz[1] = (val >> 8) & 0xff;
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_RSSI_OFF_5GHZ_BASE + 2);
+
+ sc->rssi_off_5ghz[2] = (val & 0xff);
+ sc->lna_gain[3] = (val >> 8) & 0xff;
+
+ for (i = 2; i < RT2860_SOFTC_LNA_GAIN_COUNT; i++)
+ {
+ if (sc->lna_gain[i] == 0x00 || sc->lna_gain[i] == (int8_t) 0xff)
+ {
+ printf("%s: invalid EEPROM LNA gain #%d: 0x%02x\n",
+ device_get_nameunit(sc->dev), i, sc->lna_gain[i]);
+
+ sc->lna_gain[i] = sc->lna_gain[1];
+ }
+ }
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+ "%s: EEPROM LNA gains=0x%02x/0x%02x/0x%02x/0x%02x\n",
+ device_get_nameunit(sc->dev),
+ sc->lna_gain[0], sc->lna_gain[1], sc->lna_gain[2], sc->lna_gain[3]);
+
+ for (i = 0; i < RT2860_SOFTC_RSSI_OFF_COUNT; i++)
+ {
+ if (sc->rssi_off_2ghz[i] < RT2860_EEPROM_RSSI_OFF_MIN ||
+ sc->rssi_off_2ghz[i] > RT2860_EEPROM_RSSI_OFF_MAX)
+ {
+ printf("%s: invalid EEPROM RSSI offset #%d (2GHz): 0x%02x\n",
+ device_get_nameunit(sc->dev), i, sc->rssi_off_2ghz[i]);
+
+ sc->rssi_off_2ghz[i] = 0;
+ }
+
+ if (sc->rssi_off_5ghz[i] < RT2860_EEPROM_RSSI_OFF_MIN ||
+ sc->rssi_off_5ghz[i] > RT2860_EEPROM_RSSI_OFF_MAX)
+ {
+ printf("%s: invalid EEPROM RSSI offset #%d (5GHz): 0x%02x\n",
+ device_get_nameunit(sc->dev), i, sc->rssi_off_5ghz[i]);
+
+ sc->rssi_off_5ghz[i] = 0;
+ }
+ }
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+ "%s: EEPROM RSSI offsets 2GHz=%d/%d/%d\n",
+ device_get_nameunit(sc->dev),
+ sc->rssi_off_2ghz[0], sc->rssi_off_2ghz[1], sc->rssi_off_2ghz[2]);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+ "%s: EEPROM RSSI offsets 5GHz=%d/%d/%d\n",
+ device_get_nameunit(sc->dev),
+ sc->rssi_off_5ghz[0], sc->rssi_off_5ghz[1], sc->rssi_off_5ghz[2]);
+
+ /* read Tx power settings for 2GHz channels */
+
+ for (i = 0; i < 14; i += 2)
+ {
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TXPOW1_2GHZ_BASE + i / 2);
+
+ sc->txpow1[i + 0] = (int8_t) (val & 0xff);
+ sc->txpow1[i + 1] = (int8_t) (val >> 8);
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TXPOW2_2GHZ_BASE + i / 2);
+
+ sc->txpow2[i + 0] = (int8_t) (val & 0xff);
+ sc->txpow2[i + 1] = (int8_t) (val >> 8);
+ }
+
+ /* read Tx power settings for 5GHz channels */
+
+ for (; i < RT2860_SOFTC_TXPOW_COUNT; i += 2)
+ {
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TXPOW1_5GHZ_BASE + i / 2);
+
+ sc->txpow1[i + 0] = (int8_t) (val & 0xff);
+ sc->txpow1[i + 1] = (int8_t) (val >> 8);
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TXPOW2_5GHZ_BASE + i / 2);
+
+ sc->txpow2[i + 0] = (int8_t) (val & 0xff);
+ sc->txpow2[i + 1] = (int8_t) (val >> 8);
+ }
+
+ /* fix broken Tx power settings */
+
+ for (i = 0; i < 14; i++)
+ {
+ if (sc->txpow1[i] < RT2860_EEPROM_TXPOW_2GHZ_MIN ||
+ sc->txpow1[i] > RT2860_EEPROM_TXPOW_2GHZ_MAX)
+ {
+ printf("%s: invalid EEPROM Tx power1 #%d (2GHz): 0x%02x\n",
+ device_get_nameunit(sc->dev), i, sc->txpow1[i]);
+
+ sc->txpow1[i] = RT2860_EEPROM_TXPOW_2GHZ_DEFAULT;
+ }
+
+ if (sc->txpow2[i] < RT2860_EEPROM_TXPOW_2GHZ_MIN ||
+ sc->txpow2[i] > RT2860_EEPROM_TXPOW_2GHZ_MAX)
+ {
+ printf("%s: invalid EEPROM Tx power2 #%d (2GHz): 0x%02x\n",
+ device_get_nameunit(sc->dev), i, sc->txpow2[i]);
+
+ sc->txpow2[i] = RT2860_EEPROM_TXPOW_2GHZ_DEFAULT;
+ }
+ }
+
+ for (; i < RT2860_SOFTC_TXPOW_COUNT; i++)
+ {
+ if (sc->txpow1[i] < RT2860_EEPROM_TXPOW_5GHZ_MIN ||
+ sc->txpow1[i] > RT2860_EEPROM_TXPOW_5GHZ_MAX)
+ {
+ printf("%s: invalid EEPROM Tx power1 #%d (5GHz): 0x%02x\n",
+ device_get_nameunit(sc->dev), i, sc->txpow1[i]);
+
+ sc->txpow1[i] = RT2860_EEPROM_TXPOW_5GHZ_DEFAULT;
+ }
+
+ if (sc->txpow2[i] < RT2860_EEPROM_TXPOW_5GHZ_MIN ||
+ sc->txpow2[i] > RT2860_EEPROM_TXPOW_5GHZ_MAX)
+ {
+ printf("%s: invalid EEPROM Tx power2 #%d (5GHz): 0x%02x\n",
+ device_get_nameunit(sc->dev), i, sc->txpow2[i]);
+
+ sc->txpow2[i] = RT2860_EEPROM_TXPOW_5GHZ_DEFAULT;
+ }
+ }
+
+ /* read Tx power per rate deltas */
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TXPOW_RATE_DELTA);
+
+ sc->txpow_rate_delta_2ghz = 0;
+ sc->txpow_rate_delta_5ghz = 0;
+
+ if ((val & 0xff) != 0xff)
+ {
+ if (val & 0x80)
+ sc->txpow_rate_delta_2ghz = (val & 0xf);
+
+ if (!(val & 0x40))
+ sc->txpow_rate_delta_2ghz = -sc->txpow_rate_delta_2ghz;
+ }
+
+ val >>= 8;
+
+ if ((val & 0xff) != 0xff)
+ {
+ if (val & 0x80)
+ sc->txpow_rate_delta_5ghz = (val & 0xf);
+
+ if (!(val & 0x40))
+ sc->txpow_rate_delta_5ghz = -sc->txpow_rate_delta_5ghz;
+ }
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+ "%s: EEPROM Tx power per rate deltas=%d(2MHz), %d(5MHz)\n",
+ device_get_nameunit(sc->dev),
+ sc->txpow_rate_delta_2ghz, sc->txpow_rate_delta_5ghz);
+
+ /* read Tx power per rate */
+
+ for (i = 0; i < RT2860_SOFTC_TXPOW_RATE_COUNT; i++)
+ {
+ rt2860_io_eeprom_read_multi(sc, RT2860_EEPROM_TXPOW_RATE_BASE + i * sizeof(uint32_t),
+ &tmp, sizeof(uint32_t));
+
+ sc->txpow_rate_20mhz[i] = tmp;
+ sc->txpow_rate_40mhz_2ghz[i] =
+ rt2860_read_eeprom_txpow_rate_add_delta(tmp, sc->txpow_rate_delta_2ghz);
+ sc->txpow_rate_40mhz_5ghz[i] =
+ rt2860_read_eeprom_txpow_rate_add_delta(tmp, sc->txpow_rate_delta_5ghz);
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+ "%s: EEPROM Tx power per rate #%d=0x%08x(20MHz), 0x%08x(40MHz/2GHz), 0x%08x(40MHz/5GHz)\n",
+ device_get_nameunit(sc->dev), i,
+ sc->txpow_rate_20mhz[i], sc->txpow_rate_40mhz_2ghz[i], sc->txpow_rate_40mhz_5ghz[i]);
+ }
+
+ if (sc->tx_agc_cntl)
+ sc->tx_agc_cntl_2ghz = sc->tx_agc_cntl_5ghz = 1;
+
+ /* read factory-calibrated samples for temperature compensation */
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_2GHZ_BASE);
+
+ sc->tssi_2ghz[0] = (val & 0xff); /* [-4] */
+ sc->tssi_2ghz[1] = (val >> 8); /* [-3] */
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_2GHZ_BASE + 2);
+
+ sc->tssi_2ghz[2] = (val & 0xff); /* [-2] */
+ sc->tssi_2ghz[3] = (val >> 8); /* [-1] */
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_2GHZ_BASE + 2 * 2);
+
+ sc->tssi_2ghz[4] = (val & 0xff); /* [0] */
+ sc->tssi_2ghz[5] = (val >> 8); /* [+1] */
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_2GHZ_BASE + 3 * 2);
+
+ sc->tssi_2ghz[6] = (val & 0xff); /* [+2] */
+ sc->tssi_2ghz[7] = (val >> 8); /* [+3] */
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_2GHZ_BASE + 4 * 2);
+
+ sc->tssi_2ghz[8] = (val & 0xff); /* [+4] */
+ sc->tssi_step_2ghz = (val >> 8);
+
+ if (sc->tssi_2ghz[4] == 0xff)
+ sc->tx_agc_cntl_2ghz = 0;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+ "%s: EEPROM TSSI 2GHz: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, "
+ "0x%02x, 0x%02x, step=%d\n",
+ device_get_nameunit(sc->dev),
+ sc->tssi_2ghz[0], sc->tssi_2ghz[1], sc->tssi_2ghz[2],
+ sc->tssi_2ghz[3], sc->tssi_2ghz[4], sc->tssi_2ghz[5],
+ sc->tssi_2ghz[6], sc->tssi_2ghz[7], sc->tssi_2ghz[8],
+ sc->tssi_step_2ghz);
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_5GHZ_BASE);
+
+ sc->tssi_5ghz[0] = (val & 0xff); /* [-4] */
+ sc->tssi_5ghz[1] = (val >> 8); /* [-3] */
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_5GHZ_BASE + 2);
+
+ sc->tssi_5ghz[2] = (val & 0xff); /* [-2] */
+ sc->tssi_5ghz[3] = (val >> 8); /* [-1] */
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_5GHZ_BASE + 2 * 2);
+
+ sc->tssi_5ghz[4] = (val & 0xff); /* [0] */
+ sc->tssi_5ghz[5] = (val >> 8); /* [+1] */
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_5GHZ_BASE + 3 * 2);
+
+ sc->tssi_5ghz[6] = (val & 0xff); /* [+2] */
+ sc->tssi_5ghz[7] = (val >> 8); /* [+3] */
+
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_TSSI_5GHZ_BASE + 4 * 2);
+
+ sc->tssi_5ghz[8] = (val & 0xff); /* [+4] */
+ sc->tssi_step_5ghz = (val >> 8);
+
+ if (sc->tssi_5ghz[4] == 0xff)
+ sc->tx_agc_cntl_5ghz = 0;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+ "%s: EEPROM TSSI 5GHz: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, "
+ "0x%02x, 0x%02x, step=%d\n",
+ device_get_nameunit(sc->dev),
+ sc->tssi_5ghz[0], sc->tssi_5ghz[1], sc->tssi_5ghz[2],
+ sc->tssi_5ghz[3], sc->tssi_5ghz[4], sc->tssi_5ghz[5],
+ sc->tssi_5ghz[6], sc->tssi_5ghz[7], sc->tssi_5ghz[8],
+ sc->tssi_step_5ghz);
+
+ /* read default BBP settings */
+
+ rt2860_io_eeprom_read_multi(sc, RT2860_EEPROM_BBP_BASE,
+ sc->bbp_eeprom, RT2860_SOFTC_BBP_EEPROM_COUNT * 2);
+
+ if ((sc->mac_rev & 0xffff0000) >= 0x30710000) {
+ /* read vendor RF settings */
+ rt2860_io_eeprom_read_multi(sc, RT3071_EEPROM_RF_BASE, sc->rf, 10 * 2);
+ }
+
+ /* read powersave level */
+ val = rt2860_io_eeprom_read(sc, RT2860_EEPROM_POWERSAVE_LEVEL);
+
+ sc->powersave_level = val & 0xff;
+
+ if ((sc->powersave_level & 0xff) == 0xff)
+ printf("%s: invalid EEPROM powersave level\n",
+ device_get_nameunit(sc->dev));
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_EEPROM,
+ "%s: EEPROM powersave level=0x%02x\n",
+ device_get_nameunit(sc->dev), sc->powersave_level);
+}
+
+/*
+ * rt2860_read_eeprom_txpow_rate_add_delta
+ */
+uint32_t rt2860_read_eeprom_txpow_rate_add_delta(uint32_t txpow_rate,
+ int8_t delta)
+{
+ int8_t b4;
+ int i;
+
+ for (i = 0; i < 8; i++)
+ {
+ b4 = txpow_rate & 0xf;
+ b4 += delta;
+
+ if (b4 < 0)
+ b4 = 0;
+ else if (b4 > 0xf)
+ b4 = 0xf;
+
+ txpow_rate = (txpow_rate >> 4) | (b4 << 28);
+ }
+
+ return txpow_rate;
+}
Index: sys/dev/rt2860/rt2860_reg.h
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_reg.h
@@ -0,0 +1,560 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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.
+ */
+
+#ifndef _RT2860_REG_H_
+#define _RT2860_REG_H_
+
+#define RT2860_REG_PCI_CFG 0x0000
+#define RT2860_REG_EEPROM_CSR 0x0004
+#define RT2860_REG_PCI_MCU_CSR 0x0008
+#define RT2860_REG_PCI_SYS_CSR 0x000c
+#define RT2860_REG_PCIE_JTAG 0x0010
+
+#define RT2860_REG_SCHDMA_INT_STATUS 0x0200
+#define RT2860_REG_SCHDMA_INT_MASK 0x0204
+#define RT2860_REG_SCHDMA_WPDMA_GLO_CFG 0x0208
+#define RT2860_REG_SCHDMA_WPDMA_RST_IDX 0x020c
+#define RT2860_REG_SCHDMA_DELAY_INT_CFG 0x0210
+#define RT2860_REG_SCHDMA_WMM_AIFSN_CFG 0x0214
+#define RT2860_REG_SCHDMA_WMM_CWMIN_CFG 0x0218
+#define RT2860_REG_SCHDMA_WMM_CWMAX_CFG 0x021c
+#define RT2860_REG_SCHDMA_WMM_TXOP0_CFG 0x0220
+#define RT2860_REG_SCHDMA_WMM_TXOP1_CFG 0x0224
+#define RT2860_REG_SCHDMA_GPIO_CTRL_CFG 0x0228
+#define RT2860_REG_SCHDMA_RX_BASE_PTR 0x0290
+#define RT2860_REG_SCHDMA_RX_MAX_CNT 0x0294
+#define RT2860_REG_SCHDMA_RX_CALC_IDX 0x0298
+#define RT2860_REG_SCHDMA_RX_DRX_IDX 0x029c
+#define RT2860_REG_SCHDMA_TX_BASE_PTR(qid) (0x0230 + (qid) * 16)
+#define RT2860_REG_SCHDMA_TX_MAX_CNT(qid) (0x0234 + (qid) * 16)
+#define RT2860_REG_SCHDMA_TX_CTX_IDX(qid) (0x0238 + (qid) * 16)
+#define RT2860_REG_SCHDMA_TX_DTX_IDX(qid) (0x023c + (qid) * 16)
+#define RT2860_REG_SCHDMA_US_CYC_CNT 0x02a4
+
+#define RT2860_REG_PBF_SYS_CTRL 0x0400
+#define RT2860_REG_PBF_HOST_CMD 0x0404
+#define RT2860_REG_PBF_CFG 0x0408
+#define RT2860_REG_PBF_MAX_PCNT 0x040c
+#define RT2860_REG_PBF_BUF_CTRL 0x0410
+#define RT2860_REG_PBF_MCU_INT_STA 0x0414
+#define RT2860_REG_PBF_MCU_INT_ENA 0x0418
+#define RT2860_REG_PBF_TX0Q_IO 0x041c
+#define RT2860_REG_PBF_TX1Q_IO 0x0420
+#define RT2860_REG_PBF_TX2Q_IO 0x0424
+#define RT2860_REG_PBF_RX0Q_IO 0x0428
+#define RT2860_REG_PBF_BCN_OFFSET0 0x042c
+#define RT2860_REG_PBF_BCN_OFFSET1 0x0430
+#define RT2860_REG_PBF_TXRXQ_STA 0x0434
+#define RT2860_REG_PBF_TXRXQ_PCNT 0x0438
+#define RT2860_REG_PBF_DBG 0x043c
+#define RT2860_REG_PBF_CAP_CTRL 0x0440
+
+#define RT2872_REG_RF_CSR_CFG 0x500
+#define RT2872_REG_RF_SETTING 0x504
+#define RT2872_REG_RF_TEST_CONTROL 0x508
+
+#define RT2860_REG_MAC_CSR0 0x1000
+#define RT2860_REG_SYS_CTRL 0x1004
+#define RT2860_REG_ADDR_DW0 0x1008
+#define RT2860_REG_ADDR_DW1 0x100c
+#define RT2860_REG_BSSID_DW0 0x1010
+#define RT2860_REG_BSSID_DW1 0x1014
+#define RT2860_REG_MAX_LEN_CFG 0x1018
+#define RT2860_REG_BBP_CSR_CFG 0x101c
+#define RT2860_REG_RF_CSR_CFG0 0x1020
+#define RT2860_REG_LED_CFG 0x102c
+#define RT2860_REG_AMPDU_MAX_LEN_20M1S 0x1030
+#define RT2860_REG_AMPDU_MAX_LEN_20M2S 0x1034
+#define RT2860_REG_AMPDU_MAX_LEN_40M1S 0x1038
+#define RT2860_REG_AMPDU_MAX_LEN_40M2S 0x103c
+#define RT2860_REG_AMPDU_BA_WINSIZE 0x1040
+
+#define RT2860_REG_XIFS_TIME_CFG 0x1100
+#define RT2860_REG_BKOFF_SLOT_CFG 0x1104
+#define RT2860_REG_NAV_TIME_CFG 0x1108
+#define RT2860_REG_CH_TIME_CFG 0x110c
+#define RT2860_REG_PBF_LIFE_TIMER 0x1110
+#define RT2860_REG_BCN_TIME_CFG 0x1114
+#define RT2860_REG_TBTT_SYNC_CFG 0x1118
+#define RT2860_REG_TSF_TIMER_DW0 0x111c
+#define RT2860_REG_TSF_TIMER_DW1 0x1120
+#define RT2860_REG_TBTT_TIMER 0x1124
+#define RT2860_REG_INT_TIMER 0x1128
+#define RT2860_REG_INT_TIMER_EN 0x112c
+#define RT2860_REG_CH_IDLE_STA 0x1130
+
+#define RT2860_REG_STATUS_CFG 0x1200
+#define RT2860_REG_PWR_PIN_CFG 0x1204
+#define RT2860_REG_AUTO_WAKEUP_CFG 0x1208
+
+#define RT2860_REG_TX_EDCA_AC_CFG(aci) (0x1300 + (aci) * 4)
+#define RT2860_REG_TX_EDCA_TID_AC_MAP 0x1310
+#define RT2860_REG_TX_PWR_CFG(ridx) (0x1314 + (ridx) * 4)
+#define RT2860_REG_TX_PIN_CFG 0x1328
+#define RT2860_REG_TX_BAND_CFG 0x132c
+#define RT2860_REG_TX_SW_CFG0 0x1330
+#define RT2860_REG_TX_SW_CFG1 0x1334
+#define RT2860_REG_TX_SW_CFG2 0x1338
+#define RT2860_REG_TX_TXOP_THRES_CFG 0x133c
+#define RT2860_REG_TX_TXOP_CTRL_CFG 0x1340
+#define RT2860_REG_TX_RTS_CFG 0x1344
+#define RT2860_REG_TX_TIMEOUT_CFG 0x1348
+#define RT2860_REG_TX_RTY_CFG 0x134c
+#define RT2860_REG_TX_LINK_CFG 0x1350
+#define RT2860_REG_TX_HT_FBK_CFG0 0x1354
+#define RT2860_REG_TX_HT_FBK_CFG1 0x1358
+#define RT2860_REG_TX_LG_FBK_CFG0 0x135c
+#define RT2860_REG_TX_LG_FBK_CFG1 0x1360
+#define RT2860_REG_TX_CCK_PROT_CFG 0x1364
+#define RT2860_REG_TX_OFDM_PROT_CFG 0x1368
+#define RT2860_REG_TX_MM20_PROT_CFG 0x136c
+#define RT2860_REG_TX_MM40_PROT_CFG 0x1370
+#define RT2860_REG_TX_GF20_PROT_CFG 0x1374
+#define RT2860_REG_TX_GF40_PROT_CFG 0x1378
+#define RT2860_REG_TX_EXP_CTS_TIME 0x137c
+#define RT2860_REG_TX_EXP_ACK_TIME 0x1380
+
+#define RT2860_REG_RX_FILTER_CFG 0x1400
+#define RT2860_REG_AUTO_RSP_CFG 0x1404
+#define RT2860_REG_LEGACY_BASIC_RATE 0x1408
+#define RT2860_REG_HT_BASIC_RATE 0x140c
+#define RT2860_REG_HT_CTRL_CFG 0x1410
+#define RT2860_REG_SIFS_COST_CFG 0x1414
+#define RT2860_REG_RX_PARSER_CFG 0x1418
+
+#define RT2860_REG_TX_SEC_CNT0 0x1500
+#define RT2860_REG_RX_SEC_CNT0 0x1504
+#define RT2860_REG_CCMP_FC_MUTE 0x1508
+
+#define RT2860_REG_HCCAPSMP_TXOP_HLDR_ADDR0 0x1600
+#define RT2860_REG_HCCAPSMP_TXOP_HLDR_ADDR1 0x1604
+#define RT2860_REG_HCCAPSMP_TXOP_HLDR_ET 0x1608
+#define RT2860_REG_HCCAPSMP_QOS_CFPOLL_RA_DW0 0x160c
+#define RT2860_REG_HCCAPSMP_QOS_CFPOLL_A1_DW1 0x1610
+#define RT2860_REG_HCCAPSMP_QOS_CFPOLL_QC 0x1614
+
+#define RT2860_REG_RX_STA_CNT0 0x1700
+#define RT2860_REG_RX_STA_CNT1 0x1704
+#define RT2860_REG_RX_STA_CNT2 0x1708
+#define RT2860_REG_TX_STA_CNT0 0x170c
+#define RT2860_REG_TX_STA_CNT1 0x1710
+#define RT2860_REG_TX_STA_CNT2 0x1714
+#define RT2860_REG_TX_STA_FIFO 0x1718
+#define RT2860_REG_TX_AGG_CNT 0x171c
+#define RT2860_REG_TX_AGG_CNT0 0x1720
+#define RT2860_REG_TX_AGG_CNT1 0x1724
+#define RT2860_REG_TX_AGG_CNT2 0x1728
+#define RT2860_REG_TX_AGG_CNT3 0x172c
+#define RT2860_REG_TX_AGG_CNT4 0x1730
+#define RT2860_REG_TX_AGG_CNT5 0x1734
+#define RT2860_REG_TX_AGG_CNT6 0x1738
+#define RT2860_REG_TX_AGG_CNT7 0x173c
+#define RT2860_REG_TXRX_MPDU_DEN_CNT 0x1740
+
+#define RT2860_REG_WCID(wcid) (0x1800 + (wcid) * 8)
+#define RT2860_REG_PKEY(wcid) (0x4000 + (wcid) * 32)
+#define RT2860_REG_IVEIV(wcid) (0x6000 + (wcid) * 8)
+#define RT2860_REG_WCID_ATTR(wcid) (0x6800 + (wcid) * 4)
+#define RT2860_REG_SKEY(vap, kidx) (0x6c00 + ((vap) * 4 + (kidx)) * 32)
+#define RT2860_REG_SKEY_MODE(vap) (0x7000 + ((vap) / 2) * 4)
+#define RT2860_REG_SKEY_MODE_0_7 0x7000
+
+#define RT2860_REG_MCU_UCODE_BASE 0x2000
+
+#define RT2860_REG_H2M_HOST_CMD 0x0404
+#define RT2860_REG_H2M_MAILBOX 0x7010
+#define RT2860_REG_H2M_MAILBOX_CID 0x7014
+#define RT2860_REG_H2M_MAILBOX_STATUS 0x701c
+#define RT2860_REG_H2M_MAILBOX_BBP_AGENT 0x7028
+
+#define RT2860_REG_BEACON_BASE(vap) (0x7800 + (vap) * 512)
+
+/* RT3070 registers */
+#define RT3070_RF_CSR_CFG 0x0500
+#define RT3070_EFUSE_CTRL 0x0580
+#define RT3070_EFUSE_DATA0 0x0590
+#define RT3070_EFUSE_DATA1 0x0594
+#define RT3070_EFUSE_DATA2 0x0598
+#define RT3070_EFUSE_DATA3 0x059c
+#define RT3090_OSC_CTRL 0x05a4
+#define RT3070_LDO_CFG0 0x05d4
+#define RT3070_GPIO_SWITCH 0x05dc
+
+#define RT3090_AUX_CTRL 0x010c
+#define RT3070_OPT_14 0x0114
+
+/* possible flags for register RF_CSR_CFG */
+#define RT3070_RF_KICK (1 << 17)
+#define RT3070_RF_WRITE (1 << 16)
+
+/* possible flags for register EFUSE_CTRL */
+#define RT3070_SEL_EFUSE (1 << 31)
+#define RT3070_EFSROM_KICK (1 << 30)
+#define RT3070_EFSROM_AIN_MASK 0x03ff0000
+#define RT3070_EFSROM_AIN_SHIFT 16
+#define RT3070_EFSROM_MODE_MASK 0x000000c0
+#define RT3070_EFUSE_AOUT_MASK 0x0000003f
+
+/* possible flags for RT3020 RF register 1 */
+#define RT3070_RF_BLOCK (1 << 0)
+#define RT3070_RX0_PD (1 << 2)
+#define RT3070_TX0_PD (1 << 3)
+#define RT3070_RX1_PD (1 << 4)
+#define RT3070_TX1_PD (1 << 5)
+#define RT3070_RX2_PD (1 << 6)
+#define RT3070_TX2_PD (1 << 7)
+
+/* possible flags for RT3020 RF register 1 */
+#define RT3070_RF_BLOCK (1 << 0)
+#define RT3070_RX0_PD (1 << 2)
+#define RT3070_TX0_PD (1 << 3)
+#define RT3070_RX1_PD (1 << 4)
+#define RT3070_TX1_PD (1 << 5)
+#define RT3070_RX2_PD (1 << 6)
+#define RT3070_TX2_PD (1 << 7)
+
+/* possible flags for RT3020 RF register 7 */
+#define RT3070_TUNE (1 << 0)
+
+/* possible flags for RT3020 RF register 15 */
+#define RT3070_TX_LO2 (1 << 3)
+
+/* possible flags for RT3020 RF register 17 */
+#define RT3070_TX_LO1 (1 << 3)
+
+/* possible flags for RT3020 RF register 20 */
+#define RT3070_RX_LO1 (1 << 3)
+
+/* possible flags for RT3020 RF register 21 */
+#define RT3070_RX_LO2 (1 << 3)
+#define RT3070_RX_CTB (1 << 7)
+
+/* possible flags for RT3020 RF register 22 */
+#define RT3070_BB_LOOPBACK (1 << 0)
+
+/* possible flags for RT3053 RF register 1 */
+#define RT3593_VCO (1 << 0)
+
+/* possible flags for RT3053 RF register 2 */
+#define RT3593_RESCAL (1 << 7)
+
+/* possible flags for RT3053 RF register 3 */
+#define RT3593_VCOCAL (1 << 7)
+
+/* possible flags for RT3053 RF register 6 */
+#define RT3593_VCO_IC (1 << 6)
+
+/* possible flags for RT3053 RF register 20 */
+#define RT3593_LDO_PLL_VC_MASK 0x0e
+#define RT3593_LDO_RF_VC_MASK 0xe0
+
+/* possible flags for RT3053 RF register 22 */
+#define RT3593_CP_IC_MASK 0xe0
+#define RT3593_CP_IC_SHIFT 5
+
+/* possible flags for RT3053 RF register 46 */
+#define RT3593_RX_CTB (1 << 5)
+
+#define RT3090_DEF_LNA 10
+
+
+#define RT2860_REG_RF_R1 0
+#define RT2860_REG_RF_R2 1
+#define RT2860_REG_RF_R3 2
+#define RT2860_REG_RF_R4 3
+
+/*
+ * RT2860_REG_EEPROM_CSR flags
+ */
+#define RT2860_REG_EERL (1 << 7)
+#define RT2860_REG_EEDO (1 << 3)
+#define RT2860_REG_EEDI (1 << 2)
+#define RT2860_REG_EECS (1 << 1)
+#define RT2860_REG_EESK (1 << 0)
+#define RT2860_REG_EEOP_READ 0x6
+
+/*
+ * RT2860_REG_SCHDMA_INT_STATUS
+ * RT2860_REG_SCHDMA_INT_MASK flags
+ */
+#define RT2860_REG_INT_TX_COHERENT (1 << 17)
+#define RT2860_REG_INT_RX_COHERENT (1 << 16)
+#define RT2860_REG_INT_GP_TIMER (1 << 15)
+#define RT2860_REG_INT_AUTO_WAKEUP (1 << 14)
+#define RT2860_REG_INT_FIFO_STA_FULL (1 << 13)
+#define RT2860_REG_INT_PRE_TBTT (1 << 12)
+#define RT2860_REG_INT_TBTT (1 << 11)
+#define RT2860_REG_INT_TXRX_COHERENT (1 << 10)
+#define RT2860_REG_INT_MCU_CMD (1 << 9)
+#define RT2860_REG_INT_TX_MGMT_DONE (1 << 8)
+#define RT2860_REG_INT_TX_HCCA_DONE (1 << 7)
+#define RT2860_REG_INT_TX_AC3_DONE (1 << 6)
+#define RT2860_REG_INT_TX_AC2_DONE (1 << 5)
+#define RT2860_REG_INT_TX_AC1_DONE (1 << 4)
+#define RT2860_REG_INT_TX_AC0_DONE (1 << 3)
+#define RT2860_REG_INT_RX_DONE (1 << 2)
+#define RT2860_REG_INT_TX_DELAY_DONE (1 << 1)
+#define RT2860_REG_INT_RX_DELAY_DONE (1 << 0)
+
+/*
+ * RT2860_REG_SCHDMA_WPDMA_GLO_CFG flags
+ */
+#define RT2860_REG_TX_WB_DDONE (1 << 6)
+#define RT2860_REG_RX_DMA_BUSY (1 << 3)
+#define RT2860_REG_RX_DMA_ENABLE (1 << 2)
+#define RT2860_REG_TX_DMA_BUSY (1 << 1)
+#define RT2860_REG_TX_DMA_ENABLE (1 << 0)
+#define RT2860_REG_WPDMA_BT_SIZE_SHIFT 4
+#define RT2860_REG_WPDMA_BT_SIZE16 0
+#define RT2860_REG_WPDMA_BT_SIZE32 1
+#define RT2860_REG_WPDMA_BT_SIZE64 2
+#define RT2860_REG_WPDMA_BT_SIZE128 3
+
+/*
+ * RT2860_REG_SCHDMA_WPDMA_RST_IDX flags
+ */
+#define RT2860_REG_RST_IDX_RX (1 << 16)
+#define RT2860_REG_RST_IDX_TX_MGMT (1 << 5)
+#define RT2860_REG_RST_IDX_TX_HCCA (1 << 4)
+#define RT2860_REG_RST_IDX_TX_AC3 (1 << 3)
+#define RT2860_REG_RST_IDX_TX_AC2 (1 << 2)
+#define RT2860_REG_RST_IDX_TX_AC1 (1 << 1)
+#define RT2860_REG_RST_IDX_TX_AC0 (1 << 0)
+
+/*
+ * RT2860_REG_SCHDMA_DELAY_INT_CFG flags
+ */
+#define RT2860_REG_INT_TX_DELAY_ENABLE (1 << 31)
+#define RT2860_REG_INT_TX_MAX_PINT_SHIFT 24
+#define RT2860_REG_INT_TX_MAX_PINT_MASK 0x7
+#define RT2860_REG_INT_TX_MAX_PTIME_SHIFT 16
+#define RT2860_REG_INT_TX_MAX_PTIME_MASK 0x8
+#define RT2860_REG_INT_RX_DELAY_ENABLE (1 << 15)
+#define RT2860_REG_INT_RX_MAX_PINT_SHIFT 8
+#define RT2860_REG_INT_RX_MAX_PINT_MASK 0x7
+#define RT2860_REG_INT_RX_MAX_PTIME_SHIFT 0
+#define RT2860_REG_INT_RX_MAX_PTIME_MASK 0x8
+
+/*
+ * RT2860_REG_PBF_SYS_CTRL flags
+ */
+#define RT2860_REG_HST_PM_SEL (1 << 16)
+#define RT2860_REG_MCU_READY (1 << 7)
+#define RT2860_REG_MCU_RESET (1 << 0)
+
+/*
+ * RT2860_REG_PBF_TXRXQ_PCNT flags
+ */
+#define RT2860_REG_RXQ_PCNT_SHIFT 24
+#define RT2860_REG_RXQ_PCNT_MASK 0xff
+#define RT2860_REG_TX2Q_PCNT_SHIFT 16
+#define RT2860_REG_TX2Q_PCNT_MASK 0xff
+#define RT2860_REG_TX1Q_PCNT_SHIFT 8
+#define RT2860_REG_TX1Q_PCNT_MASK 0xff
+#define RT2860_REG_TX0Q_PCNT_SHIFT 0
+#define RT2860_REG_TX0Q_PCNT_MASK 0xff
+
+/*
+ * RT2860_REG_SYS_CTRL flags
+ */
+#define RT2860_REG_RX_ENABLE (1 << 3)
+#define RT2860_REG_TX_ENABLE (1 << 2)
+#define RT2860_REG_BBP_HRST (1 << 1)
+#define RT2860_REG_MAC_SRST (1 << 0)
+
+/*
+ * RT2872_REG_RF_CSR_CFG flags
+ */
+#define RT2872_REG_RF_CSR_BUSY (1 << 17)
+#define RT2872_REG_RF_CSR_KICK (1 << 17)
+#define RT2872_REG_RF_CSR_WRITE (1 << 16)
+#define RT2872_REG_RF_ID_SHIFT 8
+#define RT2872_REG_RF_ID_MASK 0x1f
+#define RT2872_REG_RF_VAL_SHIFT 0
+#define RT2872_REG_RF_VAL_MASK 0xff
+
+/*
+ * RT2860_REG_BBP_CSR_CFG flags
+ */
+#define RT2860_REG_BBP_RW_MODE_PARALLEL (1 << 19)
+#define RT2860_REG_BBP_PAR_DUR (1 << 19)
+#define RT2860_REG_BBP_CSR_BUSY (1 << 17)
+#define RT2860_REG_BBP_CSR_KICK (1 << 17)
+#define RT2860_REG_BBP_CSR_READ (1 << 16)
+#define RT2860_REG_BBP_REG_SHIFT 8
+#define RT2860_REG_BBP_REG_MASK 0xff
+#define RT2860_REG_BBP_VAL_SHIFT 0
+#define RT2860_REG_BBP_VAL_MASK 0xff
+
+/*
+ * RT2860_REG_RF_CSR_CFG0 flags
+ */
+#define RT2860_REG_RF_BUSY (1 << 31)
+
+/*
+ * RT2860_REG_BCN_TIME_CFG flags
+ */
+#define RT2860_REG_BCN_TX_ENABLE (1 << 20)
+#define RT2860_REG_TBTT_TIMER_ENABLE (1 << 19)
+#define RT2860_REG_TSF_TIMER_ENABLE (1 << 16)
+#define RT2860_REG_TSF_SYNC_MODE_SHIFT 17
+#define RT2860_REG_TSF_SYNC_MODE_MASK 0x3
+#define RT2860_REG_TSF_SYNC_MODE_DISABLE 0
+#define RT2860_REG_TSF_SYNC_MODE_STA 1
+#define RT2860_REG_TSF_SYNC_MODE_IBSS 2
+#define RT2860_REG_TSF_SYNC_MODE_HOSTAP 3
+
+/*
+ * RT2860_REG_STATUS_CFG flags
+ */
+#define RT2860_REG_STATUS_RX_BUSY (1 << 1)
+#define RT2860_REG_STATUS_TX_BUSY (1 << 0)
+
+/*
+ * RT2860_REG_TX_PIN_CFG flags
+ */
+#define RT2860_REG_TRSW_ENABLE (1 << 18)
+#define RT2860_REG_RFTR_ENABLE (1 << 16)
+#define RT2860_REG_LNA_PE_G1_ENABLE (1 << 11)
+#define RT2860_REG_LNA_PE_A1_ENABLE (1 << 10)
+#define RT2860_REG_LNA_PE_G0_ENABLE (1 << 9)
+#define RT2860_REG_LNA_PE_A0_ENABLE (1 << 8)
+#define RT2860_REG_PA_PE_G1_ENABLE (1 << 3)
+#define RT2860_REG_PA_PE_A1_ENABLE (1 << 2)
+#define RT2860_REG_PA_PE_G0_ENABLE (1 << 1)
+#define RT2860_REG_PA_PE_A0_ENABLE (1 << 0)
+
+/*
+ * RT2860_REG_TX_BAND_CFG flags
+ */
+#define RT2860_REG_TX_BAND_BG (1 << 2)
+#define RT2860_REG_TX_BAND_A (1 << 1)
+#define RT2860_REG_TX_BAND_HT40_ABOVE (1 << 0)
+#define RT2860_REG_TX_BAND_HT40_BELOW (0 << 0)
+
+/*
+ * RT2860_REG_TX_RTS_CFG flags
+ */
+#define RT2860_REG_TX_RTS_THRESHOLD_SHIFT 8
+#define RT2860_REG_TX_RTS_THRESHOLD_MASK 0xffff
+
+/*
+ * RT2860_REG_TX_CCK_PROT_CFG
+ * RT2860_REG_TX_OFDM_PROT_CFG
+ * RT2860_REG_TX_MM20_PROT_CFG
+ * RT2860_REG_TX_MM40_PROT_CFG
+ * RT2860_REG_TX_GF20_PROT_CFG
+ * RT2860_REG_TX_GF40_PROT_CFG flags
+ */
+#define RT2860_REG_RTSTH_ENABLE (1 << 26)
+#define RT2860_REG_TXOP_ALLOW_GF40 (1 << 25)
+#define RT2860_REG_TXOP_ALLOW_GF20 (1 << 24)
+#define RT2860_REG_TXOP_ALLOW_MM40 (1 << 23)
+#define RT2860_REG_TXOP_ALLOW_MM20 (1 << 22)
+#define RT2860_REG_TXOP_ALLOW_OFDM (1 << 21)
+#define RT2860_REG_TXOP_ALLOW_CCK (1 << 20)
+#define RT2860_REG_TXOP_ALLOW_ALL (0x3f << 20)
+#define RT2860_REG_PROT_NAV_NONE (0 << 18)
+#define RT2860_REG_PROT_NAV_SHORT (1 << 18)
+#define RT2860_REG_PROT_NAV_LONG (2 << 18)
+#define RT2860_REG_PROT_CTRL_NONE (0 << 16)
+#define RT2860_REG_PROT_CTRL_RTS_CTS (1 << 16)
+#define RT2860_REG_PROT_CTRL_CTS (2 << 16)
+#define RT2860_REG_PROT_PHYMODE_SHIFT 14
+#define RT2860_REG_PROT_PHYMODE_MASK 0x3
+#define RT2860_REG_PROT_PHYMODE_CCK 0
+#define RT2860_REG_PROT_PHYMODE_OFDM 1
+#define RT2860_REG_PROT_MCS_SHIFT 0
+#define RT2860_REG_PROT_MCS_MASK 0x7f
+
+/*
+ * RT2860_REG_RX_FILTER_CFG flags
+ */
+#define RT2860_REG_RX_FILTER_DROP_CTRL_RSV (1 << 16)
+#define RT2860_REG_RX_FILTER_DROP_BAR (1 << 15)
+#define RT2860_REG_RX_FILTER_DROP_BA (1 << 14)
+#define RT2860_REG_RX_FILTER_DROP_PSPOLL (1 << 13)
+#define RT2860_REG_RX_FILTER_DROP_RTS (1 << 12)
+#define RT2860_REG_RX_FILTER_DROP_CTS (1 << 11)
+#define RT2860_REG_RX_FILTER_DROP_ACK (1 << 10)
+#define RT2860_REG_RX_FILTER_DROP_CFEND (1 << 9)
+#define RT2860_REG_RX_FILTER_DROP_CFACK (1 << 8)
+#define RT2860_REG_RX_FILTER_DROP_DUPL (1 << 7)
+#define RT2860_REG_RX_FILTER_DROP_BCAST (1 << 6)
+#define RT2860_REG_RX_FILTER_DROP_MCAST (1 << 5)
+#define RT2860_REG_RX_FILTER_DROP_VER_ERR (1 << 4)
+#define RT2860_REG_RX_FILTER_DROP_NOT_MYBSS (1 << 3)
+#define RT2860_REG_RX_FILTER_DROP_UC_NOME (1 << 2)
+#define RT2860_REG_RX_FILTER_DROP_PHY_ERR (1 << 1)
+#define RT2860_REG_RX_FILTER_DROP_CRC_ERR (1 << 0)
+
+/*
+ * RT2860_REG_AUTO_RSP_CFG flags
+ */
+#define RT2860_REG_CCK_SHORT_ENABLE (1 << 4)
+
+/*
+ * RT2860_REG_TX_STA_FIFO flags
+ */
+#define RT2860_REG_TX_STA_FIFO_MCS_SHIFT 16
+#define RT2860_REG_TX_STA_FIFO_MCS_MASK 0x7f
+#define RT2860_REG_TX_STA_FIFO_WCID_SHIFT 8
+#define RT2860_REG_TX_STA_FIFO_WCID_MASK 0xff
+#define RT2860_REG_TX_STA_FIFO_PID_SHIFT 1
+#define RT2860_REG_TX_STA_FIFO_PID_MASK 0xf
+#define RT2860_REG_TX_STA_FIFO_ACK_REQ (1 << 7)
+#define RT2860_REG_TX_STA_FIFO_AGG (1 << 6)
+#define RT2860_REG_TX_STA_FIFO_TX_OK (1 << 5)
+#define RT2860_REG_TX_STA_FIFO_VALID (1 << 0)
+
+/*
+ * RT2860_REG_WCID_ATTR flags
+ */
+#define RT2860_REG_VAP_SHIFT 4
+#define RT2860_REG_VAP_MASK 0x7
+#define RT2860_REG_CIPHER_MODE_SHIFT 1
+#define RT2860_REG_CIPHER_MODE_MASK 0x7
+#define RT2860_REG_CIPHER_MODE_NONE 0
+#define RT2860_REG_CIPHER_MODE_WEP40 1
+#define RT2860_REG_CIPHER_MODE_WEP104 2
+#define RT2860_REG_CIPHER_MODE_TKIP 3
+#define RT2860_REG_CIPHER_MODE_AES_CCMP 4
+#define RT2860_REG_CIPHER_MODE_CKIP40 5
+#define RT2860_REG_CIPHER_MODE_CKIP104 6
+#define RT2860_REG_CIPHER_MODE_CKIP128 7
+#define RT2860_REG_PKEY_ENABLE (1 << 0)
+
+/*
+ * RT2860_REG_H2M_MAILBOX flags
+ */
+#define RT2860_REG_H2M_BUSY (1 << 24)
+#define RT2860_REG_H2M_TOKEN_POWERSAVE 1
+#define RT2860_REG_H2M_TOKEN_RADIOOFF 2
+#define RT2860_REG_H2M_TOKEN_WAKEUP 3
+#define RT2860_REG_H2M_TOKEN_NO_INTR 0xff
+
+/*
+ * RT2860_REG_H2M_MAILBOX_CID flags
+ */
+#define RT2860_REG_H2M_CID0_SHIFT 0
+#define RT2860_REG_H2M_CID1_SHIFT 8
+#define RT2860_REG_H2M_CID2_SHIFT 16
+#define RT2860_REG_H2M_CID3_SHIFT 24
+#define RT2860_REG_H2M_CID_MASK 0xff
+
+#endif /* #ifndef _RT2860_REG_H_ */
Index: sys/dev/rt2860/rt2860_rf.h
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_rf.h
@@ -0,0 +1,49 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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.
+ */
+
+#ifndef _RT2860_RF_H_
+#define _RT2860_RF_H_
+
+#include <dev/rt2860/rt2860_softc.h>
+
+const char *rt2860_rf_name(int rf_rev);
+
+void rt2860_rf_select_chan_group(struct rt2860_softc *sc,
+ struct ieee80211_channel *c);
+
+void rt2860_rf_set_chan(struct rt2860_softc *sc,
+ struct ieee80211_channel *c);
+
+uint8_t rt3090_rf_read(struct rt2860_softc *sc, uint8_t reg);
+
+void rt3090_rf_write(struct rt2860_softc *sc, uint8_t reg, uint8_t val);
+
+void rt3090_set_chan(struct rt2860_softc *sc, u_int chan);
+
+int rt3090_rf_init(struct rt2860_softc *sc);
+
+void rt3090_set_rx_antenna(struct rt2860_softc *, int);
+
+void rt3090_rf_wakeup(struct rt2860_softc *sc);
+
+int rt3090_filter_calib(struct rt2860_softc *sc, uint8_t init, uint8_t target,
+ uint8_t *val);
+
+void rt3090_rf_setup(struct rt2860_softc *sc);
+
+#endif /* #ifndef _RT2860_RF_H_ */
Index: sys/dev/rt2860/rt2860_rf.c
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_rf.c
@@ -0,0 +1,1148 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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 <dev/rt2860/rt2860_rf.h>
+#include <dev/rt2860/rt2860_reg.h>
+#include <dev/rt2860/rt2860_eeprom.h>
+#include <dev/rt2860/rt2860_io.h>
+#include <dev/rt2860/rt2860_debug.h>
+
+static void rt2872_rf_set_chan(struct rt2860_softc *sc, struct ieee80211_channel *c);
+
+extern uint8_t rt3052_rf_default[];
+
+/*
+ * Static variables
+ */
+
+static const struct rt2860_rf_prog
+{
+ uint8_t chan;
+ uint32_t r1, r2, r3, r4;
+} rt2860_rf_2850[] =
+{
+ { 1, 0x98402ecc, 0x984c0786, 0x9816b455, 0x9800510b },
+ { 2, 0x98402ecc, 0x984c0786, 0x98168a55, 0x9800519f },
+ { 3, 0x98402ecc, 0x984c078a, 0x98168a55, 0x9800518b },
+ { 4, 0x98402ecc, 0x984c078a, 0x98168a55, 0x9800519f },
+ { 5, 0x98402ecc, 0x984c078e, 0x98168a55, 0x9800518b },
+ { 6, 0x98402ecc, 0x984c078e, 0x98168a55, 0x9800519f },
+ { 7, 0x98402ecc, 0x984c0792, 0x98168a55, 0x9800518b },
+ { 8, 0x98402ecc, 0x984c0792, 0x98168a55, 0x9800519f },
+ { 9, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800518b },
+ { 10, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800519f },
+ { 11, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800518b },
+ { 12, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800519f },
+ { 13, 0x98402ecc, 0x984c079e, 0x98168a55, 0x9800518b },
+ { 14, 0x98402ecc, 0x984c07a2, 0x98168a55, 0x98005193 },
+ { 36, 0x98402ecc, 0x984c099a, 0x98158a55, 0x980ed1a3 },
+ { 38, 0x98402ecc, 0x984c099e, 0x98158a55, 0x980ed193 },
+ { 40, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed183 },
+ { 44, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed1a3 },
+ { 46, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed18b },
+ { 48, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed19b },
+ { 52, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed193 },
+ { 54, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed1a3 },
+ { 56, 0x98402ec8, 0x984c068e, 0x98158a55, 0x980ed18b },
+ { 60, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed183 },
+ { 62, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed193 },
+ { 64, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed1a3 },
+ { 100, 0x98402ec8, 0x984c06b2, 0x98178a55, 0x980ed783 },
+ { 102, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed793 },
+ { 104, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed1a3 },
+ { 108, 0x98402ecc, 0x985c0a32, 0x98578a55, 0x980ed193 },
+ { 110, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed183 },
+ { 112, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed19b },
+ { 116, 0x98402ecc, 0x984c0a3a, 0x98178a55, 0x980ed1a3 },
+ { 118, 0x98402ecc, 0x984c0a3e, 0x98178a55, 0x980ed193 },
+ { 120, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed183 },
+ { 124, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed193 },
+ { 126, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed15b },
+ { 128, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed1a3 },
+ { 132, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed18b },
+ { 134, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed193 },
+ { 136, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed19b },
+ { 140, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed183 },
+ { 149, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed1a7 },
+ { 151, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed187 },
+ { 153, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed18f },
+ { 157, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed19f },
+ { 159, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed1a7 },
+ { 161, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed187 },
+ { 165, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed197 },
+ { 184, 0x95002ccc, 0x9500491e, 0x9509be55, 0x950c0a0b },
+ { 188, 0x95002ccc, 0x95004922, 0x9509be55, 0x950c0a13 },
+ { 192, 0x95002ccc, 0x95004926, 0x9509be55, 0x950c0a1b },
+ { 196, 0x95002ccc, 0x9500492a, 0x9509be55, 0x950c0a23 },
+ { 208, 0x95002ccc, 0x9500493a, 0x9509be55, 0x950c0a13 },
+ { 212, 0x95002ccc, 0x9500493e, 0x9509be55, 0x950c0a1b },
+ { 216, 0x95002ccc, 0x95004982, 0x9509be55, 0x950c0a23 },
+};
+
+static const struct rfprog {
+ uint8_t chan;
+ uint32_t r1, r2, r3, r4;
+} rt2860_rf2850[] = {
+ { 1, 0x100bb3, 0x1301e1, 0x05a014, 0x001402 },
+ { 2, 0x100bb3, 0x1301e1, 0x05a014, 0x001407 },
+ { 3, 0x100bb3, 0x1301e2, 0x05a014, 0x001402 },
+ { 4, 0x100bb3, 0x1301e2, 0x05a014, 0x001407 },
+ { 5, 0x100bb3, 0x1301e3, 0x05a014, 0x001402 },
+ { 6, 0x100bb3, 0x1301e3, 0x05a014, 0x001407 },
+ { 7, 0x100bb3, 0x1301e4, 0x05a014, 0x001402 },
+ { 8, 0x100bb3, 0x1301e4, 0x05a014, 0x001407 },
+ { 9, 0x100bb3, 0x1301e5, 0x05a014, 0x001402 },
+ { 10, 0x100bb3, 0x1301e5, 0x05a014, 0x001407 },
+ { 11, 0x100bb3, 0x1301e6, 0x05a014, 0x001402 },
+ { 12, 0x100bb3, 0x1301e6, 0x05a014, 0x001407 },
+ { 13, 0x100bb3, 0x1301e7, 0x05a014, 0x001402 },
+ { 14, 0x100bb3, 0x1301e8, 0x05a014, 0x001404 },
+ { 36, 0x100bb3, 0x130266, 0x056014, 0x001408 },
+ { 38, 0x100bb3, 0x130267, 0x056014, 0x001404 },
+ { 40, 0x100bb2, 0x1301a0, 0x056014, 0x001400 },
+ { 44, 0x100bb2, 0x1301a0, 0x056014, 0x001408 },
+ { 46, 0x100bb2, 0x1301a1, 0x056014, 0x001402 },
+ { 48, 0x100bb2, 0x1301a1, 0x056014, 0x001406 },
+ { 52, 0x100bb2, 0x1301a2, 0x056014, 0x001404 },
+ { 54, 0x100bb2, 0x1301a2, 0x056014, 0x001408 },
+ { 56, 0x100bb2, 0x1301a3, 0x056014, 0x001402 },
+ { 60, 0x100bb2, 0x1301a4, 0x056014, 0x001400 },
+ { 62, 0x100bb2, 0x1301a4, 0x056014, 0x001404 },
+ { 64, 0x100bb2, 0x1301a4, 0x056014, 0x001408 },
+ { 100, 0x100bb2, 0x1301ac, 0x05e014, 0x001400 },
+ { 102, 0x100bb2, 0x1701ac, 0x15e014, 0x001404 },
+ { 104, 0x100bb2, 0x1701ac, 0x15e014, 0x001408 },
+ { 108, 0x100bb3, 0x17028c, 0x15e014, 0x001404 },
+ { 110, 0x100bb3, 0x13028d, 0x05e014, 0x001400 },
+ { 112, 0x100bb3, 0x13028d, 0x05e014, 0x001406 },
+ { 116, 0x100bb3, 0x13028e, 0x05e014, 0x001408 },
+ { 118, 0x100bb3, 0x13028f, 0x05e014, 0x001404 },
+ { 120, 0x100bb1, 0x1300e0, 0x05e014, 0x001400 },
+ { 124, 0x100bb1, 0x1300e0, 0x05e014, 0x001404 },
+ { 126, 0x100bb1, 0x1300e0, 0x05e014, 0x001406 },
+ { 128, 0x100bb1, 0x1300e0, 0x05e014, 0x001408 },
+ { 132, 0x100bb1, 0x1300e1, 0x05e014, 0x001402 },
+ { 134, 0x100bb1, 0x1300e1, 0x05e014, 0x001404 },
+ { 136, 0x100bb1, 0x1300e1, 0x05e014, 0x001406 },
+ { 140, 0x100bb1, 0x1300e2, 0x05e014, 0x001400 },
+ { 149, 0x100bb1, 0x1300e2, 0x05e014, 0x001409 },
+ { 151, 0x100bb1, 0x1300e3, 0x05e014, 0x001401 },
+ { 153, 0x100bb1, 0x1300e3, 0x05e014, 0x001403 },
+ { 157, 0x100bb1, 0x1300e3, 0x05e014, 0x001407 },
+ { 159, 0x100bb1, 0x1300e3, 0x05e014, 0x001409 },
+ { 161, 0x100bb1, 0x1300e4, 0x05e014, 0x001401 },
+ { 165, 0x100bb1, 0x1300e4, 0x05e014, 0x001405 },
+ { 167, 0x100bb1, 0x1300f4, 0x05e014, 0x001407 },
+ { 169, 0x100bb1, 0x1300f4, 0x05e014, 0x001409 },
+ { 171, 0x100bb1, 0x1300f5, 0x05e014, 0x001401 },
+ { 173, 0x100bb1, 0x1300f5, 0x05e014, 0x001403 }
+};
+
+static const struct rt2860_rf_fi3020
+{
+ uint8_t channel, n, r, k;
+} rt2860_rf_fi3020[] =
+{
+ /* 802.11g */
+ {1, 241, 2, 2},
+ {2, 241, 2, 7},
+ {3, 242, 2, 2},
+ {4, 242, 2, 7},
+ {5, 243, 2, 2},
+ {6, 243, 2, 7},
+ {7, 244, 2, 2},
+ {8, 244, 2, 7},
+ {9, 245, 2, 2},
+ {10, 245, 2, 7},
+ {11, 246, 2, 2},
+ {12, 246, 2, 7},
+ {13, 247, 2, 2},
+ {14, 248, 2, 4},
+
+ /* 802.11 UNI / HyperLan 2 */
+ {36, 0x56, 0, 4},
+ {38, 0x56, 0, 6},
+ {40, 0x56, 0, 8},
+ {44, 0x57, 0, 0},
+ {46, 0x57, 0, 2},
+ {48, 0x57, 0, 4},
+ {52, 0x57, 0, 8},
+ {54, 0x57, 0, 10},
+ {56, 0x58, 0, 0},
+ {60, 0x58, 0, 4},
+ {62, 0x58, 0, 6},
+ {64, 0x58, 0, 8},
+
+ /* 802.11 HyperLan 2 */
+ {100, 0x5b, 0, 8},
+ {102, 0x5b, 0, 10},
+ {104, 0x5c, 0, 0},
+ {108, 0x5c, 0, 4},
+ {110, 0x5c, 0, 6},
+ {112, 0x5c, 0, 8},
+ {116, 0x5d, 0, 0},
+ {118, 0x5d, 0, 2},
+ {120, 0x5d, 0, 4},
+ {124, 0x5d, 0, 8},
+ {126, 0x5d, 0, 10},
+ {128, 0x5e, 0, 0},
+ {132, 0x5e, 0, 4},
+ {134, 0x5e, 0, 6},
+ {136, 0x5e, 0, 8},
+ {140, 0x5f, 0, 0},
+
+ /* 802.11 UNII */
+ {149, 0x5f, 0, 9},
+ {151, 0x5f, 0, 11},
+ {153, 0x60, 0, 1},
+ {157, 0x60, 0, 5},
+ {159, 0x60, 0, 7},
+ {161, 0x60, 0, 9},
+ {165, 0x61, 0, 1},
+ {167, 0x61, 0, 3},
+ {169, 0x61, 0, 5},
+ {171, 0x61, 0, 7},
+ {173, 0x61, 0, 9},
+};
+
+static const struct {
+ uint8_t reg;
+ uint8_t val;
+} rt3090_def_rf[] = {
+ { 4, 0x40 },
+ { 5, 0x03 },
+ { 6, 0x02 },
+ { 7, 0x70 },
+ { 9, 0x0f },
+ { 10, 0x41 },
+ { 11, 0x21 },
+ { 12, 0x7b },
+ { 14, 0x90 },
+ { 15, 0x58 },
+ { 16, 0xb3 },
+ { 17, 0x92 },
+ { 18, 0x2c },
+ { 19, 0x02 },
+ { 20, 0xba },
+ { 21, 0xdb },
+ { 24, 0x16 },
+ { 25, 0x01 },
+ { 29, 0x1f }
+};
+
+struct {
+ uint8_t n, r, k;
+} rt3090_freqs[] = {
+ { 0xf1, 2, 2 },
+ { 0xf1, 2, 7 },
+ { 0xf2, 2, 2 },
+ { 0xf2, 2, 7 },
+ { 0xf3, 2, 2 },
+ { 0xf3, 2, 7 },
+ { 0xf4, 2, 2 },
+ { 0xf4, 2, 7 },
+ { 0xf5, 2, 2 },
+ { 0xf5, 2, 7 },
+ { 0xf6, 2, 2 },
+ { 0xf6, 2, 7 },
+ { 0xf7, 2, 2 },
+ { 0xf8, 2, 4 },
+ { 0x56, 0, 4 },
+ { 0x56, 0, 6 },
+ { 0x56, 0, 8 },
+ { 0x57, 0, 0 },
+ { 0x57, 0, 2 },
+ { 0x57, 0, 4 },
+ { 0x57, 0, 8 },
+ { 0x57, 0, 10 },
+ { 0x58, 0, 0 },
+ { 0x58, 0, 4 },
+ { 0x58, 0, 6 },
+ { 0x58, 0, 8 },
+ { 0x5b, 0, 8 },
+ { 0x5b, 0, 10 },
+ { 0x5c, 0, 0 },
+ { 0x5c, 0, 4 },
+ { 0x5c, 0, 6 },
+ { 0x5c, 0, 8 },
+ { 0x5d, 0, 0 },
+ { 0x5d, 0, 2 },
+ { 0x5d, 0, 4 },
+ { 0x5d, 0, 8 },
+ { 0x5d, 0, 10 },
+ { 0x5e, 0, 0 },
+ { 0x5e, 0, 4 },
+ { 0x5e, 0, 6 },
+ { 0x5e, 0, 8 },
+ { 0x5f, 0, 0 },
+ { 0x5f, 0, 9 },
+ { 0x5f, 0, 11 },
+ { 0x60, 0, 1 },
+ { 0x60, 0, 5 },
+ { 0x60, 0, 7 },
+ { 0x60, 0, 9 },
+ { 0x61, 0, 1 },
+ { 0x61, 0, 3 },
+ { 0x61, 0, 5 },
+ { 0x61, 0, 7 },
+ { 0x61, 0, 9 }
+};
+
+
+
+uint8_t
+rt3090_rf_read(struct rt2860_softc *sc, uint8_t reg)
+{
+ uint32_t tmp;
+ int ntries;
+
+ for (ntries = 0; ntries < 100; ntries++) {
+ if (!(rt2860_io_mac_read(sc, RT3070_RF_CSR_CFG) & RT3070_RF_KICK))
+ break;
+ DELAY(1);
+ }
+ if (ntries == 100) {
+ device_printf(sc->dev, "could not read RF register\n");
+ return 0xff;
+ }
+ tmp = RT3070_RF_KICK | reg << 8;
+ rt2860_io_mac_write(sc, RT3070_RF_CSR_CFG, tmp);
+
+ for (ntries = 0; ntries < 100; ntries++) {
+ tmp = rt2860_io_mac_read(sc, RT3070_RF_CSR_CFG);
+ if (!(tmp & RT3070_RF_KICK))
+ break;
+ DELAY(1);
+ }
+ if (ntries == 100) {
+ device_printf(sc->dev, "could not read RF register\n");
+ return 0xff;
+ }
+ return tmp & 0xff;
+}
+
+void
+rt3090_rf_write(struct rt2860_softc *sc, uint8_t reg, uint8_t val)
+{
+ uint32_t tmp;
+ int ntries;
+
+ for (ntries = 0; ntries < 10; ntries++) {
+ if (!(rt2860_io_mac_read(sc, RT3070_RF_CSR_CFG) & RT3070_RF_KICK))
+ break;
+ DELAY(10);
+ }
+ if (ntries == 10) {
+ device_printf(sc->dev, "could not write to RF\n");
+ return;
+ }
+
+ tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val;
+ rt2860_io_mac_write(sc, RT3070_RF_CSR_CFG, tmp);
+}
+
+/*
+ * rt2860_rf_name
+ */
+const char *rt2860_rf_name(int rf_rev)
+{
+ switch (rf_rev)
+ {
+ case RT2860_EEPROM_RF_2820:
+ return "RT2820 2.4G 2T3R";
+
+ case RT2860_EEPROM_RF_2850:
+ return "RT2850 2.4G/5G 2T3R";
+
+ case RT2860_EEPROM_RF_2720:
+ return "RT2720 2.4G 1T2R";
+
+ case RT2860_EEPROM_RF_2750:
+ return "RT2750 2.4G/5G 1T2R";
+
+ case RT2860_EEPROM_RF_3020:
+ return "RT3020 2.4G 1T1R";
+
+ case RT2860_EEPROM_RF_2020:
+ return "RT2020 2.4G B/G";
+
+ case RT2860_EEPROM_RF_3021:
+ return "RT3021 2.4G 1T2R";
+
+ case RT2860_EEPROM_RF_3022:
+ return "RT3022 2.4G 2T2R";
+
+ case RT2860_EEPROM_RF_3052:
+ return "RT3052 2.4G/5G 2T2R";
+
+ case RT2860_EEPROM_RF_2853:
+ return "RT2853 2.4G.5G 3T3R";
+
+ case RT2860_EEPROM_RF_3320:
+ return "RT3320 2.4G 1T1R with PA";
+
+ case RT2860_EEPROM_RF_3322:
+ return "RT3322 2.4G 2T2R with PA";
+
+ case RT2860_EEPROM_RF_3053:
+ return "RT3053 2.4G/5G 3T3R";
+
+ default:
+ return "unknown";
+ }
+}
+
+/*
+ * rt2860_rf_select_chan_group
+ */
+void rt2860_rf_select_chan_group(struct rt2860_softc *sc,
+ struct ieee80211_channel *c)
+{
+ struct ieee80211com *ic;
+ int chan, group;
+ uint32_t tmp;
+
+ ic = &sc->sc_ic;
+
+ chan = ieee80211_chan2ieee(ic, c);
+ if (chan == 0 || chan == IEEE80211_CHAN_ANY)
+ return;
+
+ if (chan <= 14)
+ group = 0;
+ else if (chan <= 64)
+ group = 1;
+ else if (chan <= 128)
+ group = 2;
+ else
+ group = 3;
+
+ rt2860_io_bbp_write(sc, 62, 0x37 - sc->lna_gain[group]);
+ rt2860_io_bbp_write(sc, 63, 0x37 - sc->lna_gain[group]);
+ rt2860_io_bbp_write(sc, 64, 0x37 - sc->lna_gain[group]);
+ rt2860_io_bbp_write(sc, 86, 0x00);
+
+ if (group == 0)
+ {
+ if (sc->ext_lna_2ghz)
+ {
+ rt2860_io_bbp_write(sc, 82, 0x62);
+ rt2860_io_bbp_write(sc, 75, 0x46);
+ }
+ else
+ {
+ rt2860_io_bbp_write(sc, 82, 0x84);
+ rt2860_io_bbp_write(sc, 75, 0x50);
+ }
+ }
+ else
+ {
+ rt2860_io_bbp_write(sc, 82, 0xf2);
+
+ if (sc->ext_lna_5ghz)
+ rt2860_io_bbp_write(sc, 75, 0x46);
+ else
+ rt2860_io_bbp_write(sc, 75, 0x50);
+ }
+
+ if (group == 0)
+ {
+ tmp = 0x2e + sc->lna_gain[group];
+ }
+ else
+ {
+ if ((ic->ic_flags & IEEE80211_F_SCAN) || !IEEE80211_IS_CHAN_HT40(c))
+ tmp = 0x32 + sc->lna_gain[group] * 5 / 3;
+ else
+ tmp = 0x3a + sc->lna_gain[group] * 5 / 3;
+ }
+
+ rt2860_io_bbp_write(sc, 66, tmp);
+
+ tmp = RT2860_REG_RFTR_ENABLE |
+ RT2860_REG_TRSW_ENABLE |
+ RT2860_REG_LNA_PE_G1_ENABLE |
+ RT2860_REG_LNA_PE_A1_ENABLE |
+ RT2860_REG_LNA_PE_G0_ENABLE |
+ RT2860_REG_LNA_PE_A0_ENABLE;
+
+ if (group == 0)
+ tmp |= RT2860_REG_PA_PE_G1_ENABLE |
+ RT2860_REG_PA_PE_G0_ENABLE;
+ else
+ tmp |= RT2860_REG_PA_PE_A1_ENABLE |
+ RT2860_REG_PA_PE_A0_ENABLE;
+
+ if (sc->ntxpath == 1)
+ tmp &= ~(RT2860_REG_PA_PE_G1_ENABLE | RT2860_REG_PA_PE_A1_ENABLE);
+
+ if (sc->nrxpath == 1)
+ tmp &= ~(RT2860_REG_LNA_PE_G1_ENABLE | RT2860_REG_LNA_PE_A1_ENABLE);
+
+ rt2860_io_mac_write(sc, RT2860_REG_TX_PIN_CFG, tmp);
+
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_TX_BAND_CFG);
+
+ tmp &= ~(RT2860_REG_TX_BAND_BG | RT2860_REG_TX_BAND_A | RT2860_REG_TX_BAND_HT40_ABOVE);
+
+ if (group == 0)
+ tmp |= RT2860_REG_TX_BAND_BG;
+ else
+ tmp |= RT2860_REG_TX_BAND_A;
+
+ /* set central channel position */
+
+ if (IEEE80211_IS_CHAN_HT40U(c))
+ tmp |= RT2860_REG_TX_BAND_HT40_BELOW;
+ else if (IEEE80211_IS_CHAN_HT40D(c))
+ tmp |= RT2860_REG_TX_BAND_HT40_ABOVE;
+ else
+ tmp |= RT2860_REG_TX_BAND_HT40_BELOW;
+
+ rt2860_io_mac_write(sc, RT2860_REG_TX_BAND_CFG, tmp);
+
+ /* set bandwidth (20MHz or 40MHz) */
+
+ tmp = rt2860_io_bbp_read(sc, 4);
+
+ tmp &= ~0x18;
+
+ if (IEEE80211_IS_CHAN_HT40(c))
+ tmp |= 0x10;
+
+ rt2860_io_bbp_write(sc, 4, tmp);
+
+ /* set central channel position */
+
+ tmp = rt2860_io_bbp_read(sc, 3);
+
+ tmp &= ~0x20;
+
+ if (IEEE80211_IS_CHAN_HT40D(c))
+ tmp |= 0x20;
+
+ rt2860_io_bbp_write(sc, 3, tmp);
+
+// if (sc->mac_rev == 0x28600100)
+ if (sc->mac_rev == 0x28600102)
+ {
+ if (!IEEE80211_IS_CHAN_HT40(c))
+ {
+ rt2860_io_bbp_write(sc, 69, 0x16);
+ rt2860_io_bbp_write(sc, 70, 0x08);
+ rt2860_io_bbp_write(sc, 73, 0x12);
+ }
+ else
+ {
+ rt2860_io_bbp_write(sc, 69, 0x1a);
+ rt2860_io_bbp_write(sc, 70, 0x0a);
+ rt2860_io_bbp_write(sc, 73, 0x16);
+ }
+ }
+
+}
+
+void
+rt3090_set_chan(struct rt2860_softc *sc, u_int chan)
+{
+ int8_t txpow1, txpow2;
+ uint8_t rf;
+ int i;
+
+ KASSERT((chan >= 1 && chan <= 14), "RT3090 is 2GHz only"); /* RT3090 is 2GHz only */
+
+ /* find the settings for this channel (we know it exists) */
+ for (i = 0; rt2860_rf2850[i].chan != chan; i++);
+
+ /* use Tx power values from EEPROM */
+ txpow1 = sc->txpow1[i];
+ txpow2 = sc->txpow2[i];
+
+ rt3090_rf_write(sc, 2, rt3090_freqs[i].n);
+ rf = rt3090_rf_read(sc, 3);
+ rf = (rf & ~0x0f) | rt3090_freqs[i].k;
+ rt3090_rf_write(sc, 3, rf);
+ rf = rt3090_rf_read(sc, 6);
+ rf = (rf & ~0x03) | rt3090_freqs[i].r;
+ rt3090_rf_write(sc, 6, rf);
+
+ /* set Tx0 power */
+ rf = rt3090_rf_read(sc, 12);
+ rf = (rf & ~0x1f) | txpow1;
+ rt3090_rf_write(sc, 12, rf);
+
+ /* set Tx1 power */
+ rf = rt3090_rf_read(sc, 13);
+ rf = (rf & ~0x1f) | txpow2;
+ rt3090_rf_write(sc, 13, rf);
+
+ rf = rt3090_rf_read(sc, 1);
+ rf &= ~0xfc;
+ if (sc->ntxpath == 1)
+ rf |= RT3070_TX1_PD | RT3070_TX2_PD;
+ else if (sc->ntxpath == 2)
+ rf |= RT3070_TX2_PD;
+ if (sc->nrxpath == 1)
+ rf |= RT3070_RX1_PD | RT3070_RX2_PD;
+ else if (sc->nrxpath == 2)
+ rf |= RT3070_RX2_PD;
+ rt3090_rf_write(sc, 1, rf);
+
+ /* set RF offset */
+ rf = rt3090_rf_read(sc, 23);
+ rf = (rf & ~0x7f) | sc->rf_freq_off;
+ rt3090_rf_write(sc, 23, rf);
+
+ /* program RF filter */
+ rf = rt3090_rf_read(sc, 24); /* Tx */
+ rf = (rf & ~0x3f) | sc->rf24_20mhz;
+ rt3090_rf_write(sc, 24, rf);
+ rf = rt3090_rf_read(sc, 31); /* Rx */
+ rf = (rf & ~0x3f) | sc->rf24_20mhz;
+ rt3090_rf_write(sc, 31, rf);
+
+ /* enable RF tuning */
+ rf = rt3090_rf_read(sc, 7);
+ rt3090_rf_write(sc, 7, rf | RT3070_TUNE);
+}
+
+int
+rt3090_rf_init(struct rt2860_softc *sc)
+{
+ uint32_t tmp;
+ uint8_t rf, bbp;
+ int i;
+
+ rf = rt3090_rf_read(sc, 30);
+ /* toggle RF R30 bit 7 */
+ rt3090_rf_write(sc, 30, rf | 0x80);
+ DELAY(1000);
+ rt3090_rf_write(sc, 30, rf & ~0x80);
+
+ tmp = rt2860_io_mac_read(sc, RT3070_LDO_CFG0);
+ tmp &= ~0x1f000000;
+ if (sc->patch_dac && (sc->mac_rev & 0x0000ffff) < 0x0211)
+ tmp |= 0x0d000000; /* 1.35V */
+ else
+ tmp |= 0x01000000; /* 1.2V */
+ rt2860_io_mac_write(sc, RT3070_LDO_CFG0, tmp);
+
+ /* patch LNA_PE_G1 */
+ tmp = rt2860_io_mac_read(sc, RT3070_GPIO_SWITCH);
+ rt2860_io_mac_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20);
+
+ /* initialize RF registers to default value */
+ for (i = 0; i < (sizeof(rt3090_def_rf)/2); i++) {
+ rt3090_rf_write(sc, rt3090_def_rf[i].reg,
+ rt3090_def_rf[i].val);
+ }
+
+ /* select 20MHz bandwidth */
+ rt3090_rf_write(sc, 31, 0x14);
+
+ rf = rt3090_rf_read(sc, 6);
+ rt3090_rf_write(sc, 6, rf | 0x40);
+
+ if ((sc->mac_rev & 0xffff0000) != 0x35930000) {
+ /* calibrate filter for 20MHz bandwidth */
+ sc->rf24_20mhz = 0x1f; /* default value */
+ rt3090_filter_calib(sc, 0x07, 0x16, &sc->rf24_20mhz);
+
+ /* select 40MHz bandwidth */
+ bbp = rt2860_io_bbp_read(sc, 4);
+ rt2860_io_bbp_write(sc, 4, (bbp & ~0x08) | 0x10);
+ rf = rt3090_rf_read(sc, 31);
+ rt3090_rf_write(sc, 31, rf | 0x20);
+
+ /* calibrate filter for 40MHz bandwidth */
+ sc->rf24_40mhz = 0x2f; /* default value */
+ rt3090_filter_calib(sc, 0x27, 0x19, &sc->rf24_40mhz);
+
+ /* go back to 20MHz bandwidth */
+ bbp = rt2860_io_bbp_read(sc, 4);
+ rt2860_io_bbp_write(sc, 4, bbp & ~0x18);
+ }
+ if ((sc->mac_rev & 0x0000ffff) < 0x0211)
+ rt3090_rf_write(sc, 27, 0x03);
+
+ tmp = rt2860_io_mac_read(sc, RT3070_OPT_14);
+ rt2860_io_mac_write(sc, RT3070_OPT_14, tmp | 1);
+
+ if (sc->rf_rev == RT2860_EEPROM_RF_3020)
+ rt3090_set_rx_antenna(sc, 0);
+
+ bbp = rt2860_io_bbp_read(sc, 138);
+ if ((sc->mac_rev & 0xffff0000) == 0x35930000) {
+ if (sc->ntxpath == 1)
+ bbp |= 0x60; /* turn off DAC1 and DAC2 */
+ else if (sc->ntxpath == 2)
+ bbp |= 0x40; /* turn off DAC2 */
+ if (sc->nrxpath == 1)
+ bbp &= ~0x06; /* turn off ADC1 and ADC2 */
+ else if (sc->nrxpath == 2)
+ bbp &= ~0x04; /* turn off ADC2 */
+ } else {
+ if (sc->ntxpath == 1)
+ bbp |= 0x20; /* turn off DAC1 */
+ if (sc->nrxpath == 1)
+ bbp &= ~0x02; /* turn off ADC1 */
+ }
+ rt2860_io_bbp_write(sc, 138, bbp);
+
+ rf = rt3090_rf_read(sc, 1);
+ rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD);
+ rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD;
+ rt3090_rf_write(sc, 1, rf);
+
+ rf = rt3090_rf_read(sc, 15);
+ rt3090_rf_write(sc, 15, rf & ~RT3070_TX_LO2);
+
+ rf = rt3090_rf_read(sc, 17);
+ rf &= ~RT3070_TX_LO1;
+ if ((sc->mac_rev & 0x0000ffff) >= 0x0211 && !sc->ext_lna_2ghz)
+ rf |= 0x20; /* fix for long range Rx issue */
+ if (sc->txmixgain_2ghz >= 2)
+ rf = (rf & ~0x7) | sc->txmixgain_2ghz;
+ rt3090_rf_write(sc, 17, rf);
+
+ rf = rt3090_rf_read(sc, 20);
+ rt3090_rf_write(sc, 20, rf & ~RT3070_RX_LO1);
+
+ rf = rt3090_rf_read(sc, 21);
+ rt3090_rf_write(sc, 21, rf & ~RT3070_RX_LO2);
+
+ return 0;
+}
+
+void
+rt3090_set_rx_antenna(struct rt2860_softc *sc, int aux)
+{
+ uint32_t tmp;
+
+ if (aux) {
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_EEPROM_CSR);
+ rt2860_io_mac_write(sc, RT2860_REG_EEPROM_CSR, tmp & ~RT2860_REG_EESK);
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_GPIO_CTRL_CFG);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_GPIO_CTRL_CFG, (tmp & ~0x0808) | 0x08);
+ } else {
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_EEPROM_CSR);
+ rt2860_io_mac_write(sc, RT2860_REG_EEPROM_CSR, tmp | RT2860_REG_EESK);
+ tmp = rt2860_io_mac_read(sc, RT2860_REG_SCHDMA_GPIO_CTRL_CFG);
+ rt2860_io_mac_write(sc, RT2860_REG_SCHDMA_GPIO_CTRL_CFG, tmp & ~0x0808);
+ }
+}
+
+void
+rt3090_rf_wakeup(struct rt2860_softc *sc)
+{
+ uint32_t tmp;
+ uint8_t rf;
+
+ if ((sc->mac_rev & 0xffff0000) == 0x35930000) {
+ /* enable VCO */
+ rf = rt3090_rf_read(sc, 1);
+ rt3090_rf_write(sc, 1, rf | RT3593_VCO);
+
+ /* initiate VCO calibration */
+ rf = rt3090_rf_read(sc, 3);
+ rt3090_rf_write(sc, 3, rf | RT3593_VCOCAL);
+
+ /* enable VCO bias current control */
+ rf = rt3090_rf_read(sc, 6);
+ rt3090_rf_write(sc, 6, rf | RT3593_VCO_IC);
+
+ /* initiate res calibration */
+ rf = rt3090_rf_read(sc, 2);
+ rt3090_rf_write(sc, 2, rf | RT3593_RESCAL);
+
+ /* set reference current control to 0.33 mA */
+ rf = rt3090_rf_read(sc, 22);
+ rf &= ~RT3593_CP_IC_MASK;
+ rf |= 1 << RT3593_CP_IC_SHIFT;
+ rt3090_rf_write(sc, 22, rf);
+
+ /* enable RX CTB */
+ rf = rt3090_rf_read(sc, 46);
+ rt3090_rf_write(sc, 46, rf | RT3593_RX_CTB);
+
+ rf = rt3090_rf_read(sc, 20);
+ rf &= ~(RT3593_LDO_RF_VC_MASK | RT3593_LDO_PLL_VC_MASK);
+ rt3090_rf_write(sc, 20, rf);
+ } else {
+ /* enable RF block */
+ rf = rt3090_rf_read(sc, 1);
+ rt3090_rf_write(sc, 1, rf | RT3070_RF_BLOCK);
+
+ /* enable VCO bias current control */
+ rf = rt3090_rf_read(sc, 7);
+ rt3090_rf_write(sc, 7, rf | 0x30);
+
+ rf = rt3090_rf_read(sc, 9);
+ rt3090_rf_write(sc, 9, rf | 0x0e);
+
+ /* enable RX CTB */
+ rf = rt3090_rf_read(sc, 21);
+ rt3090_rf_write(sc, 21, rf | RT3070_RX_CTB);
+
+ /* fix Tx to Rx IQ glitch by raising RF voltage */
+ rf = rt3090_rf_read(sc, 27);
+ rf &= ~0x77;
+ if ((sc->mac_rev & 0x0000ffff) < 0x0211)
+ rf |= 0x03;
+ rt3090_rf_write(sc, 27, rf);
+ }
+ if (sc->patch_dac && (sc->mac_rev & 0x0000ffff) < 0x0211) {
+ tmp = rt2860_io_mac_read(sc, RT3070_LDO_CFG0);
+ tmp = (tmp & ~0x1f000000) | 0x0d000000;
+ rt2860_io_mac_write(sc, RT3070_LDO_CFG0, tmp);
+ }
+}
+
+int
+rt3090_filter_calib(struct rt2860_softc *sc, uint8_t init, uint8_t target,
+ uint8_t *val)
+{
+ uint8_t rf22, rf24;
+ uint8_t bbp55_pb, bbp55_sb, delta;
+ int ntries;
+
+ /* program filter */
+ rf24 = rt3090_rf_read(sc, 24);
+ rf24 = (rf24 & 0xc0) | init; /* initial filter value */
+ rt3090_rf_write(sc, 24, rf24);
+
+ /* enable baseband loopback mode */
+ rf22 = rt3090_rf_read(sc, 22);
+ rt3090_rf_write(sc, 22, rf22 | RT3070_BB_LOOPBACK);
+
+ /* set power and frequency of passband test tone */
+ rt2860_io_bbp_write(sc, 24, 0x00);
+ for (ntries = 0; ntries < 100; ntries++) {
+ /* transmit test tone */
+ rt2860_io_bbp_write(sc, 25, 0x90);
+ DELAY(1000);
+ /* read received power */
+ bbp55_pb = rt2860_io_bbp_read(sc, 55);
+ if (bbp55_pb != 0)
+ break;
+ }
+ if (ntries == 100)
+ return ETIMEDOUT;
+
+ /* set power and frequency of stopband test tone */
+ rt2860_io_bbp_write(sc, 24, 0x06);
+ for (ntries = 0; ntries < 100; ntries++) {
+ /* transmit test tone */
+ rt2860_io_bbp_write(sc, 25, 0x90);
+ DELAY(1000);
+ /* read received power */
+ bbp55_sb = rt2860_io_bbp_read(sc, 55);
+
+ delta = bbp55_pb - bbp55_sb;
+ if (delta > target)
+ break;
+
+ /* reprogram filter */
+ rf24++;
+ rt3090_rf_write(sc, 24, rf24);
+ }
+ if (ntries < 100) {
+ if (rf24 != init)
+ rf24--; /* backtrack */
+ *val = rf24;
+ rt3090_rf_write(sc, 24, rf24);
+ }
+
+ /* restore initial state */
+ rt2860_io_bbp_write(sc, 24, 0x00);
+
+ /* disable baseband loopback mode */
+ rf22 = rt3090_rf_read(sc, 22);
+ rt3090_rf_write(sc, 22, rf22 & ~RT3070_BB_LOOPBACK);
+
+ return 0;
+}
+
+void
+rt3090_rf_setup(struct rt2860_softc *sc)
+{
+ uint8_t bbp;
+ int i;
+
+ if ((sc->mac_rev & 0x0000ffff) >= 0x0211) {
+ /* enable DC filter */
+ rt2860_io_bbp_write(sc, 103, 0xc0);
+
+ /* improve power consumption */
+ bbp = rt2860_io_bbp_read(sc, 31);
+ rt2860_io_bbp_write(sc, 31, bbp & ~0x03);
+ }
+
+ rt2860_io_mac_write(sc, RT2860_REG_TX_SW_CFG1, 0);
+ if ((sc->mac_rev & 0x0000ffff) < 0x0211) {
+ rt2860_io_mac_write(sc, RT2860_REG_TX_SW_CFG2,
+ sc->patch_dac ? 0x2c : 0x0f);
+ } else
+ rt2860_io_mac_write(sc, RT2860_REG_TX_SW_CFG2, 0);
+
+ /* initialize RF registers from ROM */
+ for (i = 0; i < 10; i++) {
+ if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff)
+ continue;
+ rt3090_rf_write(sc, sc->rf[i].reg, sc->rf[i].val);
+ }
+}
+
+
+/*
+ * rt2860_rf_set_chan
+ */
+void rt2860_rf_set_chan(struct rt2860_softc *sc,
+ struct ieee80211_channel *c)
+{
+ struct ieee80211com *ic;
+ const struct rt2860_rf_prog *prog;
+ uint32_t r1, r2, r3, r4;
+ int8_t txpow1, txpow2;
+ int i, chan;
+
+ if (sc->mac_rev == 0x28720200) {
+ rt2872_rf_set_chan(sc, c);
+ return;
+ }
+
+ ic = &sc->sc_ic;
+ prog = rt2860_rf_2850;
+
+ /* get central channel position */
+
+ chan = ieee80211_chan2ieee(ic, c);
+
+ if ((sc->mac_rev & 0xffff0000) >= 0x30710000) {
+ rt3090_set_chan(sc, chan);
+ return;
+ }
+
+ if (IEEE80211_IS_CHAN_HT40U(c))
+ chan += 2;
+ else if (IEEE80211_IS_CHAN_HT40D(c))
+ chan -= 2;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_CHAN,
+ "%s: RF set channel: channel=%u, HT%s%s\n",
+ device_get_nameunit(sc->dev),
+ ieee80211_chan2ieee(ic, c),
+ !IEEE80211_IS_CHAN_HT(c) ? " disabled" :
+ IEEE80211_IS_CHAN_HT20(c) ? "20":
+ IEEE80211_IS_CHAN_HT40U(c) ? "40U" : "40D",
+ (ic->ic_flags & IEEE80211_F_SCAN) ? ", scanning" : "");
+
+ if (chan == 0 || chan == IEEE80211_CHAN_ANY)
+ return;
+
+ for (i = 0; prog[i].chan != chan; i++);
+
+ r1 = prog[i].r1;
+ r2 = prog[i].r2;
+ r3 = prog[i].r3;
+ r4 = prog[i].r4;
+
+ txpow1 = sc->txpow1[i];
+ txpow2 = sc->txpow2[i];
+
+ if (sc->ntxpath == 1)
+ r2 |= (1 << 14);
+
+ if (sc->nrxpath == 2)
+ r2 |= (1 << 6);
+ else if (sc->nrxpath == 1)
+ r2 |= (1 << 17) | (1 << 6);
+
+ if (IEEE80211_IS_CHAN_2GHZ(c))
+ {
+ r3 = (r3 & 0xffffc1ff) | (txpow1 << 9);
+ r4 = (r4 & ~0x001f87c0) | (sc->rf_freq_off << 15) |
+ (txpow2 << 6);
+ }
+ else
+ {
+ r3 = r3 & 0xffffc1ff;
+ r4 = (r4 & ~0x001f87c0) | (sc->rf_freq_off << 15);
+
+ if (txpow1 >= RT2860_EEPROM_TXPOW_5GHZ_MIN && txpow1 < 0)
+ {
+ txpow1 = (-RT2860_EEPROM_TXPOW_5GHZ_MIN + txpow1);
+ if (txpow1 > RT2860_EEPROM_TXPOW_5GHZ_MAX)
+ txpow1 = RT2860_EEPROM_TXPOW_5GHZ_MAX;
+
+ r3 |= (txpow1 << 10);
+ }
+ else
+ {
+ if (txpow1 > RT2860_EEPROM_TXPOW_5GHZ_MAX)
+ txpow1 = RT2860_EEPROM_TXPOW_5GHZ_MAX;
+
+ r3 |= (txpow1 << 10) | (1 << 9);
+ }
+
+ if (txpow2 >= RT2860_EEPROM_TXPOW_5GHZ_MIN && txpow2 < 0)
+ {
+ txpow2 = (-RT2860_EEPROM_TXPOW_5GHZ_MIN + txpow2);
+ if (txpow2 > RT2860_EEPROM_TXPOW_5GHZ_MAX)
+ txpow2 = RT2860_EEPROM_TXPOW_5GHZ_MAX;
+
+ r4 |= (txpow2 << 7);
+ }
+ else
+ {
+ if (txpow2 > RT2860_EEPROM_TXPOW_5GHZ_MAX)
+ txpow2 = RT2860_EEPROM_TXPOW_5GHZ_MAX;
+
+ r4 |= (txpow2 << 7) | (1 << 6);
+ }
+ }
+
+ if (!(ic->ic_flags & IEEE80211_F_SCAN) && IEEE80211_IS_CHAN_HT40(c))
+ r4 |= (1 << 21);
+
+ rt2860_io_rf_write(sc, RT2860_REG_RF_R1, r1);
+ rt2860_io_rf_write(sc, RT2860_REG_RF_R2, r2);
+ rt2860_io_rf_write(sc, RT2860_REG_RF_R3, r3 & ~(1 << 2));
+ rt2860_io_rf_write(sc, RT2860_REG_RF_R4, r4);
+
+ DELAY(200);
+
+ rt2860_io_rf_write(sc, RT2860_REG_RF_R1, r1);
+ rt2860_io_rf_write(sc, RT2860_REG_RF_R2, r2);
+ rt2860_io_rf_write(sc, RT2860_REG_RF_R3, r3 | (1 << 2));
+ rt2860_io_rf_write(sc, RT2860_REG_RF_R4, r4);
+
+ DELAY(200);
+
+ rt2860_io_rf_write(sc, RT2860_REG_RF_R1, r1);
+ rt2860_io_rf_write(sc, RT2860_REG_RF_R2, r2);
+ rt2860_io_rf_write(sc, RT2860_REG_RF_R3, r3 & ~(1 << 2));
+ rt2860_io_rf_write(sc, RT2860_REG_RF_R4, r4);
+
+ rt2860_rf_select_chan_group(sc, c);
+
+ DELAY(1000);
+}
+
+/*
+ * rt2872_rf_set_chan
+ */
+static void
+rt2872_rf_set_chan(struct rt2860_softc *sc,
+ struct ieee80211_channel *c)
+{
+ struct ieee80211com *ic;
+ const struct rt2860_rf_prog *prog;
+ uint32_t r1, r2, r3, r4;
+ uint32_t r6, r7, r12, r13, r23, r24;
+ int8_t txpow1, txpow2;
+ int i, chan;
+
+ ic = &sc->sc_ic;
+ prog = rt2860_rf_2850;
+
+ /* get central channel position */
+
+ chan = ieee80211_chan2ieee(ic, c);
+
+ if (IEEE80211_IS_CHAN_HT40U(c))
+ chan += 2;
+ else if (IEEE80211_IS_CHAN_HT40D(c))
+ chan -= 2;
+
+ RT2860_DPRINTF(sc, RT2860_DEBUG_CHAN,
+ "%s: RF set channel: channel=%u, HT%s%s\n",
+ device_get_nameunit(sc->dev),
+ ieee80211_chan2ieee(ic, c),
+ !IEEE80211_IS_CHAN_HT(c) ? " disabled" :
+ IEEE80211_IS_CHAN_HT20(c) ? "20":
+ IEEE80211_IS_CHAN_HT40U(c) ? "40U" : "40D",
+ (ic->ic_flags & IEEE80211_F_SCAN) ? ", scanning" : "");
+
+ if (chan == 0 || chan == IEEE80211_CHAN_ANY)
+ return;
+
+ for (i = 0; prog[i].chan != chan; i++);
+
+ r1 = prog[i].r1;
+ r2 = prog[i].r2;
+ r3 = prog[i].r3;
+ r4 = prog[i].r4;
+
+// txpow1 = sc->txpow1[i];
+// txpow2 = sc->txpow2[i];
+ txpow1 = 30;
+ txpow2 = 30;
+ r3 = 16;
+
+ for (i = 0; rt2860_rf_fi3020[i].channel != chan; i++);
+
+ /* Program channel parameters */
+ r2 = rt2860_rf_fi3020[i].n;
+ rt2860_io_rf_write(sc, 2 , r2 );
+ r3 = rt2860_rf_fi3020[i].k;
+ rt2860_io_rf_write(sc, 3 , r3 );
+
+ r6 = (rt3052_rf_default[6] & 0xFC) | (rt2860_rf_fi3020[i].r & 0x03);
+ rt2860_io_rf_write(sc, 6 , r6 );
+
+ /* Set Tx Power */
+ r12 = (rt3052_rf_default[12] & 0xE0) | (txpow1 & 0x1f);
+ rt2860_io_rf_write(sc, 12, r12);
+
+ /* Set Tx1 Power */
+ r13 = (rt3052_rf_default[13] & 0xE0) | (txpow2 & 0x1f);
+ rt2860_io_rf_write(sc, 13, r13);
+
+ /* Set RF offset */
+ r23 = (rt3052_rf_default[23] & 0x80) | (sc->rf_freq_off);
+ rt2860_io_rf_write(sc, 23, r23);
+
+ /* Set BW */
+ r24 = (rt3052_rf_default[24] & 0xDF);
+ if (!(ic->ic_flags & IEEE80211_F_SCAN) && IEEE80211_IS_CHAN_HT40(c))
+ r24 |= 0x20;
+ rt2860_io_rf_write(sc, 24, r24);
+
+ /* Enable RF tuning */
+ r7 = (rt3052_rf_default[7]) | 1;
+ rt2860_io_rf_write(sc, 7 , r7 );
+
+ /* Antenna */
+/*
+ r1 = (rt3052_rf_default[1] & 0xab) | ((sc->nrxpath == 1)?0x10:0) |
+ ((sc->ntxpath == 1)?0x20:0);
+ rt2860_io_rf_write(sc, 1 , r1 );
+*/
+ r1 = (rt3052_rf_default[1] & 0xab) | 0x10;
+ rt2860_io_rf_write(sc, 1 , r1 );
+ r1 = (r1 & 0x57) | 0x20;
+ rt2860_io_rf_write(sc, 1 , r1 );
+
+ DELAY(200);
+
+ rt2860_rf_select_chan_group(sc, c);
+
+ DELAY(1000);
+}
+
Index: sys/dev/rt2860/rt2860_rxdesc.h
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_rxdesc.h
@@ -0,0 +1,62 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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.
+ */
+
+#ifndef _RT2860_RXDESC_H_
+#define _RT2860_RXDESC_H_
+
+#define RT2860_RXDESC_SDL0_DDONE (1 << 15)
+
+#define RT2860_RXDESC_FLAGS_LAST_AMSDU (1 << 19)
+#define RT2860_RXDESC_FLAGS_CIPHER_ALG (1 << 18)
+#define RT2860_RXDESC_FLAGS_PLCP_RSSIL (1 << 17)
+#define RT2860_RXDESC_FLAGS_DECRYPTED (1 << 16)
+#define RT2860_RXDESC_FLAGS_AMPDU (1 << 15)
+#define RT2860_RXDESC_FLAGS_L2PAD (1 << 14)
+#define RT2860_RXDESC_FLAGS_RSSI (1 << 13)
+#define RT2860_RXDESC_FLAGS_HTC (1 << 12)
+#define RT2860_RXDESC_FLAGS_AMSDU (1 << 11)
+#define RT2860_RXDESC_FLAGS_CRC_ERR (1 << 8)
+#define RT2860_RXDESC_FLAGS_MYBSS (1 << 7)
+#define RT2860_RXDESC_FLAGS_BCAST (1 << 6)
+#define RT2860_RXDESC_FLAGS_MCAST (1 << 5)
+#define RT2860_RXDESC_FLAGS_U2M (1 << 4)
+#define RT2860_RXDESC_FLAGS_FRAG (1 << 3)
+#define RT2860_RXDESC_FLAGS_NULL_DATA (1 << 2)
+#define RT2860_RXDESC_FLAGS_DATA (1 << 1)
+#define RT2860_RXDESC_FLAGS_BA (1 << 0)
+
+#define RT2860_RXDESC_FLAGS_CIPHER_ERR_SHIFT 9
+#define RT2860_RXDESC_FLAGS_CIPHER_ERR_MASK 0x3
+#define RT2860_RXDESC_FLAGS_CIPHER_ERR_NONE 0
+#define RT2860_RXDESC_FLAGS_CIPHER_ERR_ICV 1
+#define RT2860_RXDESC_FLAGS_CIPHER_ERR_MIC 2
+#define RT2860_RXDESC_FLAGS_CIPHER_ERR_INVALID_KEY 3
+
+#define RT2860_RXDESC_FLAGS_PLCP_SIGNAL_SHIFT 20
+#define RT2860_RXDESC_FLAGS_PLCP_SIGNAL_MASK 0xfff
+
+struct rt2860_rxdesc
+{
+ uint32_t sdp0;
+ uint16_t sdl1;
+ uint16_t sdl0;
+ uint32_t sdp1;
+ uint32_t flags;
+} __packed;
+
+#endif /* #ifndef _RT2860_RXDESC_H_ */
Index: sys/dev/rt2860/rt2860_rxwi.h
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_rxwi.h
@@ -0,0 +1,79 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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.
+ */
+
+#ifndef _RT2860_RXWI_H_
+#define _RT2860_RXWI_H_
+
+#define RT2860_RXWI_KEYIDX_SHIFT 0
+#define RT2860_RXWI_KEYIDX_MASK 0x3
+
+#define RT2860_RXWI_BSSIDX_SHIFT 2
+#define RT2860_RXWI_BSSIDX_MASK 0x7
+
+#define RT2860_RXWI_UDF_SHIFT 5
+#define RT2860_RXWI_UDF_MASK 0x7
+
+#define RT2860_RXWI_SIZE_SHIFT 0
+#define RT2860_RXWI_SIZE_MASK 0xfff
+
+#define RT2860_RXWI_TID_SHIFT 12
+#define RT2860_RXWI_TID_MASK 0xf
+
+#define RT2860_RXWI_FRAG_SHIFT 0
+#define RT2860_RXWI_FRAG_MASK 0xf
+
+#define RT2860_RXWI_SEQ_SHIFT 4
+#define RT2860_RXWI_SEQ_MASK 0xfff
+
+#define RT2860_RXWI_MCS_SHIFT 0
+#define RT2860_RXWI_MCS_MASK 0x7f
+#define RT2860_RXWI_MCS_SHOTPRE (1 << 3)
+
+#define RT2860_RXWI_BW_SHIFT 7
+#define RT2860_RXWI_BW_MASK 0x1
+#define RT2860_RXWI_BW_20 0
+#define RT2860_RXWI_BW_40 1
+
+#define RT2860_RXWI_SHORTGI_SHIFT 0
+#define RT2860_RXWI_SHORTGI_MASK 0x1
+
+#define RT2860_RXWI_STBC_SHIFT 1
+#define RT2860_RXWI_STBC_MASK 0x3
+
+#define RT2860_RXWI_PHYMODE_SHIFT 6
+#define RT2860_RXWI_PHYMODE_MASK 0x3
+#define RT2860_RXWI_PHYMODE_CCK 0
+#define RT2860_RXWI_PHYMODE_OFDM 1
+#define RT2860_RXWI_PHYMODE_HT_MIXED 2
+#define RT2860_RXWI_PHYMODE_HT_GF 3
+
+struct rt2860_rxwi
+{
+ uint8_t wcid;
+ uint8_t udf_bssidx_keyidx;
+ uint16_t tid_size;
+ uint16_t seq_frag;
+ uint8_t bw_mcs;
+ uint8_t phymode_stbc_shortgi;
+ uint8_t rssi[3];
+ uint8_t reserved1;
+ uint8_t snr[2];
+ uint16_t reserved2;
+} __packed;
+
+#endif /* #ifndef _RT2860_RXWI_H_ */
Index: sys/dev/rt2860/rt2860_softc.h
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_softc.h
@@ -0,0 +1,437 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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.
+ */
+
+#ifndef _RT2860_SOFTC_H_
+#define _RT2860_SOFTC_H_
+
+#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/taskqueue.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.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_var.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_input.h>
+#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_regdomain.h>
+
+//#include "opt_rt2860.h"
+#define RT2860_DEBUG
+#define RT2860_HW_CRYPTO
+
+#include <dev/rt2860/rt2860_rxdesc.h>
+#include <dev/rt2860/rt2860_txdesc.h>
+#include <dev/rt2860/rt2860_txwi.h>
+#include <dev/rt2860/rt2860_amrr.h>
+
+#define RT_CHIPID_RT3050 0x3050
+#define RT_CHIPID_RT3052 0x3052
+
+#define RT2860_SOFTC_LOCK(sc) mtx_lock(&(sc)->lock)
+#define RT2860_SOFTC_UNLOCK(sc) \
+ mtx_unlock(&(sc)->lock)
+#define RT2860_SOFTC_ASSERT_LOCKED(sc) \
+ mtx_assert(&(sc)->lock, MA_OWNED)
+
+#define RT2860_SOFTC_TX_RING_LOCK(ring) mtx_lock(&(ring)->lock)
+#define RT2860_SOFTC_TX_RING_UNLOCK(ring) \
+ mtx_unlock(&(ring)->lock)
+#define RT2860_SOFTC_TX_RING_ASSERT_LOCKED(ring) \
+ mtx_assert(&(ring)->lock, MA_OWNED)
+
+#define RT2860_SOFTC_FLAGS_UCODE_LOADED (1 << 0)
+
+#define RT2860_SOFTC_LED_OFF_COUNT 3
+
+#define RT2860_SOFTC_RSSI_OFF_COUNT 3
+
+#define RT2860_SOFTC_LNA_GAIN_COUNT 4
+
+#define RT2860_SOFTC_TXPOW_COUNT 50
+
+#define RT2860_SOFTC_TXPOW_RATE_COUNT 5
+
+#define RT2860_SOFTC_TSSI_COUNT 9
+
+#define RT2860_SOFTC_BBP_EEPROM_COUNT 8
+
+#define RT2860_SOFTC_RSSI_COUNT 3
+
+#define RT2860_SOFTC_STAID_COUNT 64
+
+#define RT2860_SOFTC_TX_RING_COUNT 6
+
+#define RT2860_SOFTC_RX_RING_DATA_COUNT 128
+
+#define RT2860_SOFTC_MAX_SCATTER 10
+
+#define RT2860_SOFTC_TX_RING_DATA_COUNT 256
+#define RT2860_SOFTC_TX_RING_DESC_COUNT \
+ (RT2860_SOFTC_TX_RING_DATA_COUNT * RT2860_SOFTC_MAX_SCATTER)
+
+#define RT2860_SOFTC_RX_RADIOTAP_PRESENT \
+ ((1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \
+ (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | \
+ (1 << IEEE80211_RADIOTAP_ANTENNA) | \
+ (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) | \
+ (1 << IEEE80211_RADIOTAP_XCHANNEL))
+
+#define RT2860_SOFTC_TX_RADIOTAP_PRESENT \
+ ((1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_XCHANNEL))
+
+struct rt2860_softc_rx_data
+{
+ bus_dmamap_t dma_map;
+ struct mbuf *m;
+};
+
+struct rt2860_softc_rx_ring
+{
+ bus_dma_tag_t desc_dma_tag;
+ bus_dmamap_t desc_dma_map;
+ bus_addr_t desc_phys_addr;
+ struct rt2860_rxdesc *desc;
+ bus_dma_tag_t data_dma_tag;
+ bus_dmamap_t spare_dma_map;
+ struct rt2860_softc_rx_data data[RT2860_SOFTC_RX_RING_DATA_COUNT];
+ int cur;
+};
+
+struct rt2860_softc_tx_data
+{
+ bus_dmamap_t dma_map;
+ struct ieee80211_node *ni;
+ struct mbuf *m;
+};
+
+struct rt2860_softc_tx_ring
+{
+ struct mtx lock;
+ bus_dma_tag_t desc_dma_tag;
+ bus_dmamap_t desc_dma_map;
+ bus_addr_t desc_phys_addr;
+ struct rt2860_txdesc *desc;
+ int desc_queued;
+ int desc_cur;
+ int desc_next;
+ bus_dma_tag_t seg0_dma_tag;
+ bus_dmamap_t seg0_dma_map;
+ bus_addr_t seg0_phys_addr;
+ uint8_t *seg0;
+ bus_dma_tag_t data_dma_tag;
+ struct rt2860_softc_tx_data data[RT2860_SOFTC_TX_RING_DATA_COUNT];
+ int data_queued;
+ int data_cur;
+ int data_next;
+ int qid;
+};
+
+struct rt2860_softc_node
+{
+ struct ieee80211_node ni;
+
+ uint8_t staid;
+
+ uint8_t last_rssi[RT2860_SOFTC_RSSI_COUNT];
+ int8_t last_rssi_dbm[RT2860_SOFTC_RSSI_COUNT];
+};
+
+struct rt2860_softc_vap
+{
+ struct ieee80211vap vap;
+
+ struct ieee80211_beacon_offsets beacon_offsets;
+ struct mbuf *beacon_mbuf;
+ struct rt2860_txwi beacon_txwi;
+
+ struct rt2860_amrr amrr;
+
+ int (*newstate)(struct ieee80211vap *vap,
+ enum ieee80211_state nstate, int arg);
+};
+
+struct rt2860_softc_rx_radiotap_header
+{
+ struct ieee80211_radiotap_header ihdr;
+ uint8_t flags;
+ uint8_t rate;
+ int8_t dbm_antsignal;
+ int8_t dbm_antnoise;
+ uint8_t antenna;
+ uint8_t antsignal;
+ uint8_t pad[2];
+ uint32_t chan_flags;
+ uint16_t chan_freq;
+ uint8_t chan_ieee;
+ int8_t chan_maxpow;
+} __packed;
+
+struct rt2860_softc_tx_radiotap_header
+{
+ struct ieee80211_radiotap_header ihdr;
+ uint8_t flags;
+ uint8_t rate;
+ uint8_t pad[2];
+ uint32_t chan_flags;
+ uint16_t chan_freq;
+ uint8_t chan_ieee;
+ int8_t chan_maxpow;
+} __packed;
+
+struct rt2860_softc
+{
+ struct ieee80211com sc_ic;
+
+ struct mtx lock;
+
+ struct mbufq sc_snd;
+
+ uint32_t flags;
+ uint32_t sc_flags;
+#define RT2860_ENABLED (1 << 0)
+#define RT2860_ADVANCED_PS (1 << 1)
+#define RT2860_PCIE (1 << 2)
+#define RT2860_RUNNING (1 << 3)
+
+ device_t dev;
+
+ int pid;
+
+ int mem_rid;
+ struct resource *mem;
+
+ int irq_rid;
+ struct resource *irq;
+ void *irqh;
+
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+
+ int nvaps;
+ int napvaps;
+ int nadhocvaps;
+ int nstavaps;
+ int nwdsvaps;
+
+ void (*node_cleanup)(struct ieee80211_node *ni);
+
+ int (*recv_action)(struct ieee80211_node *ni,
+ const struct ieee80211_frame *wh,
+ const uint8_t *frm, const uint8_t *efrm);
+
+ int (*send_action)(struct ieee80211_node *ni,
+ int cat, int act, void *sa);
+
+ int (*addba_response)(struct ieee80211_node *ni,
+ struct ieee80211_tx_ampdu *tap,
+ int status, int baparamset, int batimeout);
+
+ void (*addba_stop)(struct ieee80211_node *ni,
+ struct ieee80211_tx_ampdu *tap);
+
+ int (*ampdu_rx_start)(struct ieee80211_node *ni,
+ struct ieee80211_rx_ampdu *rap,
+ int baparamset, int batimeout, int baseqctl);
+
+ void (*ampdu_rx_stop)(struct ieee80211_node *ni,
+ struct ieee80211_rx_ampdu *rap);
+
+ struct rt2860_amrr_node amrr_node[RT2860_SOFTC_STAID_COUNT];
+
+ uint32_t mac_rev;
+ uint8_t eeprom_addr_num;
+ uint16_t eeprom_rev;
+ uint8_t rf_rev;
+
+ uint8_t mac_addr[IEEE80211_ADDR_LEN];
+
+ uint8_t ntxpath;
+ uint8_t nrxpath;
+
+ int hw_radio_cntl;
+ int tx_agc_cntl;
+ int ext_lna_2ghz;
+ int ext_lna_5ghz;
+
+ uint8_t country_2ghz;
+ uint8_t country_5ghz;
+
+ uint8_t rf_freq_off;
+
+ uint8_t led_cntl;
+ uint16_t led_off[RT2860_SOFTC_LED_OFF_COUNT];
+
+ int8_t rssi_off_2ghz[RT2860_SOFTC_RSSI_OFF_COUNT];
+ int8_t rssi_off_5ghz[RT2860_SOFTC_RSSI_OFF_COUNT];
+
+ int8_t lna_gain[RT2860_SOFTC_LNA_GAIN_COUNT];
+
+ int8_t txpow1[RT2860_SOFTC_TXPOW_COUNT];
+ int8_t txpow2[RT2860_SOFTC_TXPOW_COUNT];
+
+ int8_t txpow_rate_delta_2ghz;
+ int8_t txpow_rate_delta_5ghz;
+ uint32_t txpow_rate_20mhz[RT2860_SOFTC_TXPOW_RATE_COUNT];
+ uint32_t txpow_rate_40mhz_2ghz[RT2860_SOFTC_TXPOW_RATE_COUNT];
+ uint32_t txpow_rate_40mhz_5ghz[RT2860_SOFTC_TXPOW_RATE_COUNT];
+
+ int tx_agc_cntl_2ghz;
+ int tx_agc_cntl_5ghz;
+
+ uint8_t tssi_2ghz[RT2860_SOFTC_TSSI_COUNT];
+ uint8_t tssi_step_2ghz;
+ uint8_t tssi_5ghz[RT2860_SOFTC_TSSI_COUNT];
+ uint8_t tssi_step_5ghz;
+
+ struct
+ {
+ uint8_t val;
+ uint8_t reg;
+ } __packed bbp_eeprom[RT2860_SOFTC_BBP_EEPROM_COUNT], rf[10];
+
+ uint16_t powersave_level;
+
+ uint8_t staid_mask[RT2860_SOFTC_STAID_COUNT / NBBY];
+
+ uint32_t intr_enable_mask;
+ uint32_t intr_disable_mask;
+ uint32_t intr_pending_mask;
+
+ struct task rx_done_task;
+ int rx_process_limit;
+
+ struct task tx_done_task;
+
+ struct task fifo_sta_full_task;
+
+ struct task periodic_task;
+ struct callout periodic_ch;
+ unsigned long periodic_round;
+
+ struct taskqueue *taskqueue;
+
+ struct rt2860_softc_rx_ring rx_ring;
+
+ struct rt2860_softc_tx_ring tx_ring[RT2860_SOFTC_TX_RING_COUNT];
+ int tx_ring_mgtqid;
+
+ struct callout tx_watchdog_ch;
+ int tx_timer;
+
+ struct rt2860_softc_rx_radiotap_header rxtap;
+ struct rt2860_softc_tx_radiotap_header txtap;
+
+ /* statistic counters */
+
+ int interrupts;
+ int tx_coherent_interrupts;
+ int rx_coherent_interrupts;
+ int txrx_coherent_interrupts;
+ int fifo_sta_full_interrupts;
+ int rx_interrupts;
+ int rx_delay_interrupts;
+ int tx_interrupts[RT2860_SOFTC_TX_RING_COUNT];
+ int tx_delay_interrupts;
+ int pre_tbtt_interrupts;
+ int tbtt_interrupts;
+ int mcu_cmd_interrupts;
+ int auto_wakeup_interrupts;
+ int gp_timer_interrupts;
+
+ int tx_data_queue_full[RT2860_SOFTC_TX_RING_COUNT];
+
+ int tx_watchdog_timeouts;
+
+ int tx_defrag_packets;
+
+ int no_tx_desc_avail;
+
+ int rx_mbuf_alloc_errors;
+ int rx_mbuf_dmamap_errors;
+
+ int tx_queue_not_empty[2];
+
+ int tx_beacons;
+ int tx_noretryok;
+ int tx_retryok;
+ int tx_failed;
+ int tx_underflows;
+ int tx_zerolen;
+ int tx_nonagg;
+ int tx_agg;
+ int tx_ampdu;
+ int tx_mpdu_zero_density;
+ int tx_ampdu_sessions;
+
+ int rx_packets;
+ int rx_ampdu;
+ int rx_ampdu_retries;
+ int rx_mpdu_zero_density;
+ int rx_ampdu_sessions;
+ int rx_amsdu;
+ int rx_crc_errors;
+ int rx_phy_errors;
+ int rx_false_ccas;
+ int rx_plcp_errors;
+ int rx_dup_packets;
+ int rx_fifo_overflows;
+ int rx_cipher_no_errors;
+ int rx_cipher_icv_errors;
+ int rx_cipher_mic_errors;
+ int rx_cipher_invalid_key_errors;
+
+ int tx_stbc;
+
+ uint8_t rf24_20mhz;
+ uint8_t rf24_40mhz;
+ uint8_t patch_dac;
+ uint8_t txmixgain_2ghz;
+ uint8_t txmixgain_5ghz;
+
+#ifdef RT2860_DEBUG
+ int debug;
+#endif
+};
+
+#endif /* #ifndef _RT2860_SOFTC_H_ */
Index: sys/dev/rt2860/rt2860_txdesc.h
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_txdesc.h
@@ -0,0 +1,48 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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.
+ */
+
+#ifndef _RT2860_TXDESC_H_
+#define _RT2860_TXDESC_H_
+
+#define RT2860_TXDESC_SDL1_BURST (1 << 15)
+#define RT2860_TXDESC_SDL1_LASTSEG (1 << 14)
+
+#define RT2860_TXDESC_SDL0_DDONE (1 << 15)
+#define RT2860_TXDESC_SDL0_LASTSEG (1 << 14)
+
+#define RT2860_TXDESC_FLAGS_SHIFT 0
+#define RT2860_TXDESC_FLAGS_MASK 0xf9
+#define RT2860_TXDESC_FLAGS_WI_VALID (1 << 0)
+
+#define RT2860_TXDESC_QSEL_SHIFT 1
+#define RT2860_TXDESC_QSEL_MASK 0x3
+#define RT2860_TXDESC_QSEL_MGMT 0
+#define RT2860_TXDESC_QSEL_HCCA 1
+#define RT2860_TXDESC_QSEL_EDCA 2
+
+struct rt2860_txdesc
+{
+ uint32_t sdp0;
+ uint16_t sdl1;
+ uint16_t sdl0;
+ uint32_t sdp1;
+ uint8_t reserved[3];
+ uint8_t qsel_flags;
+} __packed;
+
+#endif /* #ifndef _RT2860_TXDESC_H_ */
Index: sys/dev/rt2860/rt2860_txwi.h
===================================================================
--- /dev/null
+++ sys/dev/rt2860/rt2860_txwi.h
@@ -0,0 +1,92 @@
+
+/*-
+ * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
+ * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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.
+ */
+
+#ifndef _RT2860_TXWI_H_
+#define _RT2860_TXWI_H_
+
+#define RT2860_TXWI_FLAGS_SHIFT 0
+#define RT2860_TXWI_FLAGS_MASK 0x1f
+#define RT2860_TXWI_FLAGS_AMPDU (1 << 4)
+#define RT2860_TXWI_FLAGS_TS (1 << 3)
+#define RT2860_TXWI_FLAGS_CFACK (1 << 2)
+#define RT2860_TXWI_FLAGS_MIMOPS (1 << 1)
+#define RT2860_TXWI_FLAGS_FRAG (1 << 0)
+
+#define RT2860_TXWI_MPDU_DENSITY_SHIFT 5
+#define RT2860_TXWI_MPDU_DENSITY_MASK 0x7
+
+#define RT2860_TXWI_TXOP_SHIFT 0
+#define RT2860_TXWI_TXOP_MASK 0x3
+#define RT2860_TXWI_TXOP_HT 0
+#define RT2860_TXWI_TXOP_PIFS 1
+#define RT2860_TXWI_TXOP_SIFS 2
+#define RT2860_TXWI_TXOP_BACKOFF 3
+
+#define RT2860_TXWI_MCS_SHIFT 0
+#define RT2860_TXWI_MCS_MASK 0x7f
+#define RT2860_TXWI_MCS_SHOTPRE (1 << 3)
+
+#define RT2860_TXWI_BW_SHIFT 7
+#define RT2860_TXWI_BW_MASK 0x1
+#define RT2860_TXWI_BW_20 0
+#define RT2860_TXWI_BW_40 1
+
+#define RT2860_TXWI_SHORTGI_SHIFT 0
+#define RT2860_TXWI_SHORTGI_MASK 0x1
+
+#define RT2860_TXWI_STBC_SHIFT 1
+#define RT2860_TXWI_STBC_MASK 0x3
+
+#define RT2860_TXWI_IFS_SHIFT 3
+#define RT2860_TXWI_IFS_MASK 0x1
+
+#define RT2860_TXWI_PHYMODE_SHIFT 6
+#define RT2860_TXWI_PHYMODE_MASK 0x3
+#define RT2860_TXWI_PHYMODE_CCK 0
+#define RT2860_TXWI_PHYMODE_OFDM 1
+#define RT2860_TXWI_PHYMODE_HT_MIXED 2
+#define RT2860_TXWI_PHYMODE_HT_GF 3
+
+#define RT2860_TXWI_XFLAGS_SHIFT 0
+#define RT2860_TXWI_XFLAGS_MASK 0x3
+#define RT2860_TXWI_XFLAGS_NSEQ (1 << 1)
+#define RT2860_TXWI_XFLAGS_ACK (1 << 0)
+
+#define RT2860_TXWI_BAWIN_SIZE_SHIFT 2
+#define RT2860_TXWI_BAWIN_SIZE_MASK 0x3f
+
+#define RT2860_TXWI_MPDU_LEN_SHIFT 0
+#define RT2860_TXWI_MPDU_LEN_MASK 0xfff
+
+#define RT2860_TXWI_PID_SHIFT 12
+#define RT2860_TXWI_PID_MASK 0xf
+
+struct rt2860_txwi
+{
+ uint8_t mpdu_density_flags;
+ uint8_t txop;
+ uint8_t bw_mcs;
+ uint8_t phymode_ifs_stbc_shortgi;
+ uint8_t bawin_size_xflags;
+ uint8_t wcid;
+ uint16_t pid_mpdu_len;
+ uint32_t iv;
+ uint32_t eiv;
+} __packed;
+
+#endif /* #ifndef _RT2860_TXWI_H_ */

File Metadata

Mime Type
text/plain
Expires
Thu, Feb 26, 7:10 AM (5 h, 2 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29002145
Default Alt Text
D15943.id.diff (320 KB)

Event Timeline