diff options
author | thompsa <thompsa@FreeBSD.org> | 2010-05-13 00:19:03 +0000 |
---|---|---|
committer | thompsa <thompsa@FreeBSD.org> | 2010-05-13 00:19:03 +0000 |
commit | c260948bc7bd3fe9d1a27d8be8bddc7e5261f980 (patch) | |
tree | cc3a880dc85be5ec7798aebfdd3945963f8efac6 /sys/dev/usb/wlan | |
parent | d57aea636907a33a4d849915b2c88264122fbdcf (diff) | |
download | FreeBSD-src-c260948bc7bd3fe9d1a27d8be8bddc7e5261f980.zip FreeBSD-src-c260948bc7bd3fe9d1a27d8be8bddc7e5261f980.tar.gz |
Sync run(4) driver from author's site.
Submitted by: Akinori Furukoshi
Obtained from: git://gitorious.org/run/run.git
Diffstat (limited to 'sys/dev/usb/wlan')
-rw-r--r-- | sys/dev/usb/wlan/if_run.c | 1151 | ||||
-rw-r--r-- | sys/dev/usb/wlan/if_runreg.h | 22 | ||||
-rw-r--r-- | sys/dev/usb/wlan/if_runvar.h | 61 |
3 files changed, 789 insertions, 445 deletions
diff --git a/sys/dev/usb/wlan/if_run.c b/sys/dev/usb/wlan/if_run.c index c798c32..c570664 100644 --- a/sys/dev/usb/wlan/if_run.c +++ b/sys/dev/usb/wlan/if_run.c @@ -1,5 +1,3 @@ -/* $FreeBSD$ */ - /*- * Copyright (c) 2008,2010 Damien Bergamini <damien.bergamini@free.fr> * ported to FreeBSD by Akinori Furukoshi <moonlightakkiy@yahoo.ca> @@ -39,7 +37,6 @@ __FBSDID("$FreeBSD$"); #include <sys/module.h> #include <sys/bus.h> #include <sys/endian.h> -#include <sys/systm.h> #include <sys/linker.h> #include <sys/firmware.h> #include <sys/kdb.h> @@ -74,7 +71,7 @@ __FBSDID("$FreeBSD$"); #define USB_DEBUG_VAR run_debug #include <dev/usb/usb_debug.h> -#include "if_runreg.h" /* shared with ral(4) */ +#include "if_runreg.h" #include "if_runvar.h" #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) @@ -93,6 +90,12 @@ SYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RW, &run_debug, 0, #define IEEE80211_HAS_ADDR4(wh) \ (((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) +/* + * Because of LOR in run_key_delete(), use atomic instead. + * '& RUN_CMDQ_MASQ' is to loop cmdq[]. + */ +#define RUN_CMDQ_GET(c) (atomic_fetchadd_32((c), 1) & RUN_CMDQ_MASQ) + static const struct usb_device_id run_devs[] = { { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT2770) }, { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT2870) }, @@ -312,6 +315,7 @@ static struct ieee80211vap *run_vap_create(struct ieee80211com *, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]); static void run_vap_delete(struct ieee80211vap *); +static void run_cmdq_cb(void *, int); static void run_setup_tx_list(struct run_softc *, struct run_endpoint_queue *); static void run_unsetup_tx_list(struct run_softc *, @@ -342,23 +346,24 @@ static struct ieee80211_node *run_node_alloc(struct ieee80211vap *, static int run_media_change(struct ifnet *); static int run_newstate(struct ieee80211vap *, enum ieee80211_state, int); static int run_wme_update(struct ieee80211com *); -static void run_wme_update_cb(void *, int); +static void run_wme_update_cb(void *); static void run_key_update_begin(struct ieee80211vap *); static void run_key_update_end(struct ieee80211vap *); -static int run_key_set(struct ieee80211vap *, const struct ieee80211_key *, +static void run_key_set_cb(void *); +static int run_key_set(struct ieee80211vap *, struct ieee80211_key *, const uint8_t mac[IEEE80211_ADDR_LEN]); -static int run_key_delete(struct ieee80211vap *, - const struct ieee80211_key *); -static void run_ratectl_start(struct run_softc *, struct ieee80211_node *); +static void run_key_delete_cb(void *); +static int run_key_delete(struct ieee80211vap *, struct ieee80211_key *); static void run_ratectl_to(void *); static void run_ratectl_cb(void *, int); +static void run_drain_fifo(void *); static void run_iter_func(void *, struct ieee80211_node *); +static void run_newassoc_cb(void *); static void run_newassoc(struct ieee80211_node *, int); static void run_rx_frame(struct run_softc *, struct mbuf *, uint32_t); static void run_tx_free(struct run_endpoint_queue *pq, struct run_tx_data *, int); -static void run_set_tx_desc(struct run_softc *, struct run_tx_data *, - uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t); +static void run_set_tx_desc(struct run_softc *, struct run_tx_data *); static int run_tx(struct run_softc *, struct mbuf *, struct ieee80211_node *); static int run_tx_mgt(struct run_softc *, struct mbuf *, @@ -382,11 +387,10 @@ static int run_set_chan(struct run_softc *, struct ieee80211_channel *); static void run_set_channel(struct ieee80211com *); static void run_scan_start(struct ieee80211com *); static void run_scan_end(struct ieee80211com *); -static uint8_t run_rate2mcs(uint8_t); static void run_update_beacon(struct ieee80211vap *, int); -static void run_update_beacon_locked(struct ieee80211vap *, int); +static void run_update_beacon_cb(void *); static void run_updateprot(struct ieee80211com *); -static void run_usb_timeout_cb(void *, int); +static void run_usb_timeout_cb(void *); static void run_reset_livelock(struct run_softc *); static void run_enable_tsf_sync(struct run_softc *); static void run_enable_mrr(struct run_softc *); @@ -396,6 +400,7 @@ static void run_set_leds(struct run_softc *, uint16_t); static void run_set_bssid(struct run_softc *, const uint8_t *); static void run_set_macaddr(struct run_softc *, const uint8_t *); static void run_updateslot(struct ifnet *); +static void run_update_mcast(struct ifnet *); static int8_t run_rssi2dbm(struct run_softc *, uint8_t, uint8_t); static void run_update_promisc_locked(struct ifnet *); static void run_update_promisc(struct ifnet *); @@ -411,7 +416,7 @@ static void run_stop(void *); static void run_delay(struct run_softc *, unsigned int); static const struct { - uint32_t reg; + uint16_t reg; uint32_t val; } rt2870_def_mac[] = { RT2870_DEF_MAC @@ -551,6 +556,7 @@ run_attach(device_t self) MTX_NETWORK_LOCK, MTX_DEF); iface_index = RT2860_IFACE_INDEX; + error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx); if (error) { @@ -616,15 +622,15 @@ run_attach(device_t self) ic->ic_ifp = ifp; ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ -#if 0 - ic->ic_state = IEEE80211_S_INIT; -#endif + /* set device capabilities */ ic->ic_caps = IEEE80211_C_STA | /* station mode supported */ IEEE80211_C_MONITOR | /* monitor mode supported */ IEEE80211_C_IBSS | IEEE80211_C_HOSTAP | + IEEE80211_C_WDS | /* 4-address traffic works */ + IEEE80211_C_MBSS | IEEE80211_C_SHPREAMBLE | /* short preamble supported */ IEEE80211_C_SHSLOT | /* short slot time supported */ IEEE80211_C_WME | /* WME */ @@ -671,6 +677,7 @@ run_attach(device_t self) ic->ic_node_alloc = run_node_alloc; ic->ic_newassoc = run_newassoc; //ic->ic_updateslot = run_updateslot; + ic->ic_update_mcast = run_update_mcast; ic->ic_wme.wme_update = run_wme_update; ic->ic_raw_xmit = run_raw_xmit; ic->ic_update_promisc = run_update_promisc; @@ -684,6 +691,10 @@ run_attach(device_t self) &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), RUN_RX_RADIOTAP_PRESENT); + TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc); + TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc); + callout_init((struct callout *)&sc->ratectl_ch, 1); + if (bootverbose) ieee80211_announce(ic); @@ -713,6 +724,10 @@ run_detach(device_t self) if (ifp) { ic = ifp->if_l2com; + /* drain tasks */ + usb_callout_drain(&sc->ratectl_ch); + ieee80211_draintask(ic, &sc->cmdq_task); + ieee80211_draintask(ic, &sc->ratectl_task); ieee80211_ifdetach(ic); if_free(ifp); } @@ -728,41 +743,92 @@ run_vap_create(struct ieee80211com *ic, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { - struct run_softc *sc = ic->ic_ifp->if_softc; + struct ifnet *ifp = ic->ic_ifp; + struct run_softc *sc = ifp->if_softc; struct run_vap *rvp; struct ieee80211vap *vap; + int i; - if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ + if(sc->rvp_cnt >= RUN_VAP_MAX){ + if_printf(ifp, "number of VAPs maxed out\n"); return NULL; - sc->sc_rvp = rvp = (struct run_vap *) malloc(sizeof(struct run_vap), + } + + switch (opmode) { + case IEEE80211_M_STA: + /* enable s/w bmiss handling for sta mode */ + flags |= IEEE80211_CLONE_NOBEACONS; + /* fall though */ + case IEEE80211_M_IBSS: + case IEEE80211_M_MONITOR: + case IEEE80211_M_HOSTAP: + case IEEE80211_M_MBSS: + /* other than WDS vaps, only one at a time */ + if (!TAILQ_EMPTY(&ic->ic_vaps)) + return NULL; + break; + case IEEE80211_M_WDS: + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next){ + if(vap->iv_opmode != IEEE80211_M_HOSTAP) + continue; + /* WDS vap's always share the local mac address. */ + flags &= ~IEEE80211_CLONE_BSSID; + break; + } + if(vap == NULL){ + if_printf(ifp, "wds only supported in ap mode\n"); + return NULL; + } + break; + default: + if_printf(ifp, "unknown opmode %d\n", opmode); + return NULL; + } + + rvp = (struct run_vap *) malloc(sizeof(struct run_vap), M_80211_VAP, M_NOWAIT | M_ZERO); if (rvp == NULL) return NULL; vap = &rvp->vap; - /* enable s/w bmiss handling for sta mode */ - ieee80211_vap_setup(ic, vap, name, unit, opmode, - flags | IEEE80211_CLONE_NOBEACONS, bssid, mac); + ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); vap->iv_key_update_begin = run_key_update_begin; vap->iv_key_update_end = run_key_update_end; - vap->iv_key_delete = run_key_delete; - vap->iv_key_set = run_key_set; vap->iv_update_beacon = run_update_beacon; + vap->iv_max_aid = RT2870_WCID_MAX; + /* + * To delete the right key from h/w, we need wcid. + * Luckily, there is unused space in ieee80211_key{}, wk_pad, + * and matching wcid will be written into there. So, cast + * some spells to remove 'const' from ieee80211_key{} + */ + vap->iv_key_delete = (void *)run_key_delete; + vap->iv_key_set = (void *)run_key_set; /* override state transition machine */ rvp->newstate = vap->iv_newstate; vap->iv_newstate = run_newstate; - TASK_INIT(&rvp->ratectl_task, 0, run_ratectl_cb, rvp); - TASK_INIT(&sc->wme_task, 0, run_wme_update_cb, ic); - TASK_INIT(&sc->usb_timeout_task, 0, run_usb_timeout_cb, sc); - callout_init((struct callout *)&rvp->ratectl_ch, 1); ieee80211_ratectl_init(vap); ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */); /* complete setup */ ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status); - ic->ic_opmode = opmode; + + /* make sure id is always unique */ + for(i = 0; i < RUN_VAP_MAX; i++){ + if((sc->rvp_bmap & 1 << i) == 0){ + sc->rvp_bmap |= 1 << i; + rvp->rvp_id = i; + break; + } + } + if(sc->rvp_cnt++ == 0) + ic->ic_opmode = opmode; + + DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n", + rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt); + return vap; } @@ -773,6 +839,7 @@ run_vap_delete(struct ieee80211vap *vap) struct ifnet *ifp; struct ieee80211com *ic; struct run_softc *sc; + uint8_t rvp_id; if(vap == NULL) return; @@ -783,19 +850,59 @@ run_vap_delete(struct ieee80211vap *vap) sc = ifp->if_softc; RUN_LOCK(sc); - sc->sc_rvp->ratectl_run = RUN_RATECTL_OFF; - RUN_UNLOCK(sc); - /* drain them all */ - usb_callout_drain(&sc->sc_rvp->ratectl_ch); - ieee80211_draintask(ic, &sc->sc_rvp->ratectl_task); - ieee80211_draintask(ic, &sc->wme_task); - ieee80211_draintask(ic, &sc->usb_timeout_task); + rvp_id = rvp->rvp_id; + sc->ratectl_run &= ~(1 << rvp_id); + sc->rvp_bmap &= ~(1 << rvp_id); + run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128); + run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512); + --sc->rvp_cnt; + + DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n", + vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt); + + RUN_UNLOCK(sc); ieee80211_ratectl_deinit(vap); ieee80211_vap_detach(vap); free(rvp, M_80211_VAP); - sc->sc_rvp = NULL; +} + +/* + * There are numbers of functions need to be called in context thread. + * Rather than creating taskqueue event for each of those functions, + * here is all-for-one taskqueue callback function. This function + * gurantees deferred functions are executed in the same order they + * were enqueued. + * '& RUN_CMDQ_MASQ' is to loop cmdq[]. + */ +static void +run_cmdq_cb(void *arg, int pending) +{ + struct run_softc *sc = arg; + uint8_t i; + + /* call cmdq[].func locked */ + RUN_LOCK(sc); + for(i = sc->cmdq_exec; sc->cmdq[i].func && pending; + i = sc->cmdq_exec, pending--){ + DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending); + if(sc->cmdq_run == RUN_CMDQ_GO){ + /* + * If arg0 is NULL, callback func needs more + * than one arg. So, pass ptr to cmdq struct. + */ + if(sc->cmdq[i].arg0) + sc->cmdq[i].func(sc->cmdq[i].arg0); + else + sc->cmdq[i].func(&sc->cmdq[i]); + } + sc->cmdq[i].arg0 = NULL; + sc->cmdq[i].func = NULL; + sc->cmdq_exec++; + sc->cmdq_exec &= RUN_CMDQ_MASQ; + } + RUN_UNLOCK(sc); } static void @@ -1415,6 +1522,7 @@ run_read_eeprom(struct run_softc *sc) DPRINTF("EEPROM RF rev=0x%02x chains=%dT%dR\n", sc->rf_rev, sc->ntxchains, sc->nrxchains); + /* check if RF supports automatic Tx access gain control */ run_srom_read(sc, RT2860_EEPROM_CONFIG, &val); DPRINTF("EEPROM CFG 0x%04x\n", val); /* check if driver should patch the DAC issue */ @@ -1489,10 +1597,10 @@ run_read_eeprom(struct run_softc *sc) for (ridx = 0; ridx < 5; ridx++) { uint32_t reg; - run_srom_read(sc, RT2860_EEPROM_RPWR + ridx, &val); - reg = (uint32_t)val << 16; - run_srom_read(sc, RT2860_EEPROM_RPWR + ridx + 1, &val); - reg |= val; + run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val); + reg = val; + run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val); + reg |= (uint32_t)val << 16; sc->txpow20mhz[ridx] = reg; sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz); @@ -1575,19 +1683,21 @@ run_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) static int run_media_change(struct ifnet *ifp) { + struct ieee80211vap *vap = ifp->if_softc; + struct ieee80211com *ic = vap->iv_ic; const struct ieee80211_txparam *tp; - struct run_softc *sc = ifp->if_softc; - struct ieee80211com *ic = sc->sc_ifp->if_l2com; - struct ieee80211vap *vap = &sc->sc_rvp->vap; + struct run_softc *sc = ic->ic_ifp->if_softc; + struct run_node *rn = (void *)vap->iv_bss; uint8_t rate, ridx; int error; RUN_LOCK(sc); error = ieee80211_media_change(ifp); - if (error != ENETRESET) + if (error != ENETRESET){ RUN_UNLOCK(sc); return error; + } tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { @@ -1596,13 +1706,16 @@ run_media_change(struct ifnet *ifp) for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) if (rt2860_rates[ridx].rate == rate) break; - sc->fixed_ridx = ridx; + rn->fix_ridx = ridx; + DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx); } +#if 0 if ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)){ run_init_locked(sc); } +#endif RUN_UNLOCK(sc); @@ -1618,8 +1731,11 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) struct run_vap *rvp = RUN_VAP(vap); enum ieee80211_state ostate; struct ieee80211_node *ni; + uint32_t sta[3]; uint32_t tmp; - uint8_t wcid; + uint8_t ratectl; + uint8_t restart_ratectl = 0; + uint8_t bid = 1 << rvp->rvp_id; ostate = vap->iv_state; DPRINTF("%s -> %s\n", @@ -1629,8 +1745,9 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) IEEE80211_UNLOCK(ic); RUN_LOCK(sc); - sc->sc_rvp->ratectl_run = RUN_RATECTL_OFF; - usb_callout_stop(&rvp->ratectl_ch); + ratectl = sc->ratectl_run; /* remember current state */ + sc->ratectl_run = RUN_RATECTL_OFF; + usb_callout_stop(&sc->ratectl_ch); if (ostate == IEEE80211_S_RUN) { /* turn link LED off */ @@ -1639,8 +1756,16 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) switch (nstate) { case IEEE80211_S_INIT: - if (ostate == IEEE80211_S_RUN) { - /* abort TSF synchronization */ + restart_ratectl = 1; + + if (ostate != IEEE80211_S_RUN) + break; + + ratectl &= ~bid; + sc->runbmap &= ~bid; + + /* abort TSF synchronization if there is no vap running */ + if(--sc->running == 0){ run_read(sc, RT2860_BCN_TIME_CFG, &tmp); run_write(sc, RT2860_BCN_TIME_CFG, tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | @@ -1648,8 +1773,42 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) } break; + case IEEE80211_S_RUN: ni = vap->iv_bss; + if(!(sc->runbmap & bid)){ + if(sc->running++) + restart_ratectl = 1; + sc->runbmap |= bid; + } + + switch(vap->iv_opmode){ + case IEEE80211_M_HOSTAP: + case IEEE80211_M_MBSS: + sc->ap_running |= bid; + ic->ic_opmode = vap->iv_opmode; + run_update_beacon_cb(vap); + break; + case IEEE80211_M_IBSS: + sc->adhoc_running |= bid; + if(!sc->ap_running) + ic->ic_opmode = vap->iv_opmode; + run_update_beacon_cb(vap); + break; + case IEEE80211_M_STA: + sc->sta_running |= bid; + if(!sc->ap_running && !sc->adhoc_running) + ic->ic_opmode = vap->iv_opmode; + + /* read statistic counters (clear on read) */ + run_read_region_1(sc, RT2860_TX_STA_CNT0, + (uint8_t *)sta, sizeof sta); + + break; + default: + ic->ic_opmode = vap->iv_opmode; + break; + } if (vap->iv_opmode != IEEE80211_M_MONITOR) { run_updateslot(ic->ic_ifp); @@ -1658,31 +1817,17 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) run_set_basicrates(sc); IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); run_set_bssid(sc, ni->ni_bssid); - } - - if (vap->iv_opmode == IEEE80211_M_STA) { - /* add BSS entry to the WCID table */ - wcid = RUN_AID2WCID(ni->ni_associd); - run_write_region_1(sc, RT2860_WCID_ENTRY(wcid), - ni->ni_macaddr, IEEE80211_ADDR_LEN); - } - - if (vap->iv_opmode == IEEE80211_M_HOSTAP || - vap->iv_opmode == IEEE80211_M_IBSS) - run_update_beacon_locked(vap, 0); - - if (vap->iv_opmode != IEEE80211_M_MONITOR) { run_enable_tsf_sync(sc); - } /* else tsf */ - /* enable automatic rate adaptation */ - tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; - if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) - run_ratectl_start(sc, ni); + /* enable automatic rate adaptation */ + tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; + if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) + ratectl |= bid; + } /* turn link LED on */ run_set_leds(sc, RT2860_LED_RADIO | - (IEEE80211_IS_CHAN_2GHZ(vap->iv_bss->ni_chan) ? + (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ)); break; @@ -1691,34 +1836,26 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) break; } + /* restart amrr for running VAPs */ + if((sc->ratectl_run = ratectl) && restart_ratectl) + usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); + RUN_UNLOCK(sc); IEEE80211_LOCK(ic); return(rvp->newstate(vap, nstate, arg)); } -/* another taskqueue, so usbd_do_request() can go sleep */ -static int -run_wme_update(struct ieee80211com *ic) -{ - struct run_softc *sc = ic->ic_ifp->if_softc; - - ieee80211_runtask(ic, &sc->wme_task); - - /* return whatever, upper layer desn't care anyway */ - return 0; -} - /* ARGSUSED */ static void -run_wme_update_cb(void *arg, int pending) +run_wme_update_cb(void *arg) { struct ieee80211com *ic = arg; struct run_softc *sc = ic->ic_ifp->if_softc; struct ieee80211_wme_state *wmesp = &ic->ic_wme; int aci, error = 0; - RUN_LOCK(sc); + RUN_LOCK_ASSERT(sc, MA_OWNED); /* update MAC TX configuration registers */ for (aci = 0; aci < WME_NUM_AC; aci++) { @@ -1761,19 +1898,39 @@ err: if(error) DPRINTF("WME update failed\n"); - RUN_UNLOCK(sc); return; } +static int +run_wme_update(struct ieee80211com *ic) +{ + struct run_softc *sc = ic->ic_ifp->if_softc; + + /* sometime called wothout lock */ + if(mtx_owned(&ic->ic_comlock.mtx)){ + uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); + DPRINTF("cmdq_store=%d\n", i); + sc->cmdq[i].func = run_wme_update_cb; + sc->cmdq[i].arg0 = ic; + ieee80211_runtask(ic, &sc->cmdq_task); + return (0); + } + + RUN_LOCK(sc); + run_wme_update_cb(ic); + RUN_UNLOCK(sc); + + /* return whatever, upper layer desn't care anyway */ + return (0); +} + static void run_key_update_begin(struct ieee80211vap *vap) { /* - * Because run_key_delete() needs special attention - * on lock related operation, lock handling is being done - * differently in run_key_set and _delete. - * - * So, we don't use key_update_begin and _end. + * To avoid out-of-order events, both run_key_set() and + * _delete() are deferred and handled by run_cmdq_cb(). + * So, there is nothing we need to do here. */ } @@ -1783,37 +1940,31 @@ run_key_update_end(struct ieee80211vap *vap) /* null */ } -/* - * return 0 on error - */ -static int -run_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, - const uint8_t mac[IEEE80211_ADDR_LEN]) +static void +run_key_set_cb(void *arg) { + struct run_cmdq *cmdq = arg; + struct ieee80211vap *vap = cmdq->arg1; + struct ieee80211_key *k = cmdq->k; struct ieee80211com *ic = vap->iv_ic; - struct ifnet *ifp = ic->ic_ifp; - struct run_softc *sc = ifp->if_softc; + struct run_softc *sc = ic->ic_ifp->if_softc; struct ieee80211_node *ni; uint32_t attr; uint16_t base, associd; uint8_t mode, wcid, txmic, rxmic, iv[8]; - int error = 0; - RUN_LOCK(sc); + RUN_LOCK_ASSERT(sc, MA_OWNED); if(vap->iv_opmode == IEEE80211_M_HOSTAP){ - ni = ieee80211_find_vap_node(&ic->ic_sta, vap, mac); - associd = (ni != NULL) ? ni->ni_associd : 0; - if(ni != NULL) - ieee80211_free_node(ni); + ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac); txmic = 24; rxmic = 16; } else { ni = vap->iv_bss; - associd = (ni != NULL) ? ni->ni_associd : 0; txmic = 16; rxmic = 24; } + associd = (ni != NULL) ? ni->ni_associd : 0; /* map net80211 cipher to RT2860 security mode */ switch (k->wk_cipher->ic_cipher) { @@ -1831,16 +1982,18 @@ run_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, break; default: DPRINTF("undefined case\n"); - goto fail; + return; } - DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s\n", + DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n", associd, k->wk_keyix, mode, - (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise"); + (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise", + (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off", + (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off"); if (k->wk_flags & IEEE80211_KEY_GROUP) { wcid = 0; /* NB: update WCID0 for group keys */ - base = RT2860_SKEY(0, k->wk_keyix); + base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix); } else { wcid = RUN_AID2WCID(associd); base = RT2860_PKEY(wcid); @@ -1848,15 +2001,15 @@ run_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) { if(run_write_region_1(sc, base, k->wk_key, 16)) - goto fail; + return; if(run_write_region_1(sc, base + 16, &k->wk_key[txmic], 8)) /* wk_txmic */ - goto fail; + return; if(run_write_region_1(sc, base + 24, &k->wk_key[rxmic], 8)) /* wk_rxmic */ - goto fail; + return; } else { /* roundup len to 16-bit: XXX fix write_region_1() instead */ if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1)) - goto fail; + return; } if (!(k->wk_flags & IEEE80211_KEY_GROUP) || @@ -1864,7 +2017,7 @@ run_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, /* set initial packet number in IV+EIV */ if (k->wk_cipher == IEEE80211_CIPHER_WEP){ memset(iv, 0, sizeof iv); - iv[3] = sc->sc_rvp->vap.iv_def_txkey << 6; + iv[3] = vap->iv_def_txkey << 6; } else { if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) { iv[0] = k->wk_keytsc >> 8; @@ -1882,111 +2035,134 @@ run_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, iv[7] = k->wk_keytsc >> 40; } if(run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8)) - goto fail; + return; } if (k->wk_flags & IEEE80211_KEY_GROUP) { /* install group key */ if(run_read(sc, RT2860_SKEY_MODE_0_7, &attr)) - goto fail; + return; attr &= ~(0xf << (k->wk_keyix * 4)); attr |= mode << (k->wk_keyix * 4); if(run_write(sc, RT2860_SKEY_MODE_0_7, attr)) - goto fail; + return; } else { /* install pairwise key */ if(run_read(sc, RT2860_WCID_ATTR(wcid), &attr)) - goto fail; + return; attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN; if(run_write(sc, RT2860_WCID_ATTR(wcid), attr)) - goto fail; + return; } /* TODO create a pass-thru key entry? */ -fail: - RUN_UNLOCK(sc); - return (error? 0 : 1); + /* need wcid to delete the right key later */ + k->wk_pad = wcid; } /* + * Don't have to be deferred, but in order to keep order of + * execution, i.e. with run_key_delete(), defer this and let + * run_cmdq_cb() maintain the order. + * * return 0 on error */ static int -run_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) +run_key_set(struct ieee80211vap *vap, struct ieee80211_key *k, + const uint8_t mac[IEEE80211_ADDR_LEN]) { struct ieee80211com *ic = vap->iv_ic; struct run_softc *sc = ic->ic_ifp->if_softc; - struct ieee80211_node *ni = vap->iv_bss; - struct ieee80211_node_table *nt = &ic->ic_sta; + uint32_t i; + + i = RUN_CMDQ_GET(&sc->cmdq_store); + DPRINTF("cmdq_store=%d\n", i); + sc->cmdq[i].func = run_key_set_cb; + sc->cmdq[i].arg0 = NULL; + sc->cmdq[i].arg1 = vap; + sc->cmdq[i].k = k; + IEEE80211_ADDR_COPY(sc->cmdq[i].mac, mac); + ieee80211_runtask(ic, &sc->cmdq_task); + + return(1); +} + +/* + * If wlan is destroyed without being brought down i.e. without + * wlan down or wpa_cli terminate, this function is called after + * vap is gone. Don't refer it. + */ +static void +run_key_delete_cb(void *arg) +{ + struct run_cmdq *cmdq = arg; + struct run_softc *sc = cmdq->arg1; + struct ieee80211_key *k = &cmdq->key; uint32_t attr; uint8_t wcid; - int error = 0; - uint8_t nislocked, cislocked; - if((nislocked = IEEE80211_NODE_IS_LOCKED(nt))) - IEEE80211_NODE_UNLOCK(nt); - if((cislocked = mtx_owned(&ic->ic_comlock.mtx))) - IEEE80211_UNLOCK(ic); - RUN_LOCK(sc); + RUN_LOCK_ASSERT(sc, MA_OWNED); if (k->wk_flags & IEEE80211_KEY_GROUP) { /* remove group key */ - if(run_read(sc, RT2860_SKEY_MODE_0_7, &attr)) - goto fail; + DPRINTF("removing group key\n"); + run_read(sc, RT2860_SKEY_MODE_0_7, &attr); attr &= ~(0xf << (k->wk_keyix * 4)); - if(run_write(sc, RT2860_SKEY_MODE_0_7, attr)) - goto fail; + run_write(sc, RT2860_SKEY_MODE_0_7, attr); } else { /* remove pairwise key */ - wcid = RUN_AID2WCID((ni != NULL) ? ni->ni_associd : 0); - if(run_read(sc, RT2860_WCID_ATTR(wcid), &attr)) - goto fail; + DPRINTF("removing key for wcid %x\n", k->wk_pad); + /* matching wcid was written to wk_pad in run_key_set() */ + wcid = k->wk_pad; + run_read(sc, RT2860_WCID_ATTR(wcid), &attr); attr &= ~0xf; - if(run_write(sc, RT2860_WCID_ATTR(wcid), attr)) - goto fail; + run_write(sc, RT2860_WCID_ATTR(wcid), attr); + run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8); } -fail: - RUN_UNLOCK(sc); - if(cislocked) - IEEE80211_LOCK(ic); - if(nislocked) - IEEE80211_NODE_LOCK(nt); - - return (error? 0 : 1); + k->wk_pad = 0; } -static void -run_ratectl_start(struct run_softc *sc, struct ieee80211_node *ni) +/* + * return 0 on error + */ +static int +run_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k) { - struct ieee80211vap *vap = ni->ni_vap; - struct run_vap *rvp = RUN_VAP(vap); - uint32_t sta[3]; - - RUN_LOCK_ASSERT(sc, MA_OWNED); - - /* read statistic counters (clear on read) and update AMRR state */ - run_read_region_1(sc, RT2860_TX_STA_CNT0, - (uint8_t *)sta, sizeof sta); - - ieee80211_ratectl_node_init(ni); + struct ieee80211com *ic = vap->iv_ic; + struct run_softc *sc = ic->ic_ifp->if_softc; + struct ieee80211_key *k0; + uint32_t i; - /* start at lowest available bit-rate, AMRR will raise */ - ni->ni_txrate = 2; + /* + * When called back, key might be gone. So, make a copy + * of some values need to delete keys before deferring. + * But, because of LOR with node lock, cannot use lock here. + * So, use atomic instead. + */ + i = RUN_CMDQ_GET(&sc->cmdq_store); + DPRINTF("cmdq_store=%d\n", i); + sc->cmdq[i].func = run_key_delete_cb; + sc->cmdq[i].arg0 = NULL; + sc->cmdq[i].arg1 = sc; + k0 = &sc->cmdq[i].key; + k0->wk_flags = k->wk_flags; + k0->wk_keyix = k->wk_keyix; + /* matching wcid was written to wk_pad in run_key_set() */ + k0->wk_pad = k->wk_pad; + ieee80211_runtask(ic, &sc->cmdq_task); + return (1); /* return fake success */ - /* start calibration timer */ - rvp->ratectl_run = RUN_RATECTL_ON; - usb_callout_reset(&rvp->ratectl_ch, hz, run_ratectl_to, rvp); } static void run_ratectl_to(void *arg) { - struct run_vap *rvp = arg; + struct run_softc *sc = arg; /* do it in a process context, so it can go sleep */ - ieee80211_runtask(rvp->vap.iv_ic, &rvp->ratectl_task); + ieee80211_runtask(sc->sc_ifp->if_l2com, &sc->ratectl_task); /* next timeout will be rescheduled in the callback task */ } @@ -1994,13 +2170,15 @@ run_ratectl_to(void *arg) static void run_ratectl_cb(void *arg, int pending) { - struct run_vap *rvp = arg; - struct ieee80211vap *vap = &rvp->vap; - struct ieee80211com *ic = vap->iv_ic; - struct run_softc *sc = ic->ic_ifp->if_softc; + struct run_softc *sc = arg; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - if (ic->ic_opmode == IEEE80211_M_STA) - run_iter_func(rvp, vap->iv_bss); + if(vap == NULL) + return; + + if(sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA) + run_iter_func(sc, vap->iv_bss); else { /* * run_reset_livelock() doesn't do anything with AMRR, @@ -2011,77 +2189,95 @@ run_ratectl_cb(void *arg, int pending) */ RUN_LOCK(sc); run_reset_livelock(sc); + /* just in case, there are some stats to drain */ + run_drain_fifo(sc); RUN_UNLOCK(sc); - ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, rvp); + ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc); } - if(rvp->ratectl_run == RUN_RATECTL_ON) - usb_callout_reset(&rvp->ratectl_ch, hz, run_ratectl_to, rvp); + if(sc->ratectl_run != RUN_RATECTL_OFF) + usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); } - static void -run_iter_func(void *arg, struct ieee80211_node *ni) +run_drain_fifo(void *arg) { - struct run_vap *rvp = arg; - struct ieee80211com *ic = rvp->vap.iv_ic; - struct ifnet *ifp = ic->ic_ifp; - struct run_softc *sc = ifp->if_softc; - struct ieee80211_node_table *nt = &ic->ic_sta; - uint32_t sta[3], stat; - int error; + struct run_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211_node *ni = sc->sc_ni[0]; /* make compiler happy */ + uint32_t stat; + int retrycnt = 0; uint8_t wcid, mcs, pid; - struct ieee80211vap *vap = ni->ni_vap; - int txcnt = 0, success = 0, retrycnt = 0; - - if(ic->ic_opmode != IEEE80211_M_STA) - IEEE80211_NODE_ITERATE_UNLOCK(nt); - RUN_LOCK(sc); + RUN_LOCK_ASSERT(sc, MA_OWNED); - if(ic->ic_opmode != IEEE80211_M_STA){ + for (;;) { /* drain Tx status FIFO (maxsize = 16) */ run_read(sc, RT2860_TX_STAT_FIFO, &stat); - while (stat & RT2860_TXQ_VLD) { - DPRINTFN(4, "tx stat 0x%08x\n", stat); + DPRINTFN(4, "tx stat 0x%08x\n", stat); + if(!(stat & RT2860_TXQ_VLD)) + break; - wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff; + wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff; - /* if no ACK was requested, no feedback is available */ - if (!(stat & RT2860_TXQ_ACKREQ) || wcid == 0xff) - continue; + /* if no ACK was requested, no feedback is available */ + if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX || + wcid == 0) + continue; - /* update per-STA AMRR stats */ - if (stat & RT2860_TXQ_OK) { - /* - * Check if there were retries, ie if the Tx - * success rate is different from the requested - * rate. Note that it works only because we do - * not allow rate fallback from OFDM to CCK. - */ - mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f; - pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf; - if (mcs + 1 != pid) - retrycnt = 1; - ieee80211_ratectl_tx_complete(vap, ni, - IEEE80211_RATECTL_TX_SUCCESS, - &retrycnt, NULL); - } else { + ni = sc->sc_ni[wcid]; + if(ni->ni_rctls == NULL) + continue; + + /* update per-STA AMRR stats */ + if (stat & RT2860_TXQ_OK) { + /* + * Check if there were retries, ie if the Tx + * success rate is different from the requested + * rate. Note that it works only because we do + * not allow rate fallback from OFDM to CCK. + */ + mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f; + pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf; + if (mcs + 1 != pid) retrycnt = 1; - ieee80211_ratectl_tx_complete(vap, ni, - IEEE80211_RATECTL_TX_SUCCESS, - &retrycnt, NULL); - ifp->if_oerrors++; - } - run_read_region_1(sc, RT2860_TX_STAT_FIFO, - (uint8_t *)&stat, sizeof stat); + ieee80211_ratectl_tx_complete(ni->ni_vap, ni, + IEEE80211_RATECTL_TX_SUCCESS, + &retrycnt, NULL); + } else { + retrycnt = 1; + ieee80211_ratectl_tx_complete(ni->ni_vap, ni, + IEEE80211_RATECTL_TX_FAILURE, + &retrycnt, NULL); + ifp->if_oerrors++; } - } else { + } + DPRINTFN(3, "count=%d\n", sc->fifo_cnt); + + sc->fifo_cnt = 0; +} + +static void +run_iter_func(void *arg, struct ieee80211_node *ni) +{ + struct run_softc *sc = arg; + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = ni->ni_ic; + struct ifnet *ifp = ic->ic_ifp; + struct run_node *rn = (void *)ni; + uint32_t sta[3]; + int txcnt = 0, success = 0, retrycnt = 0; + int error; + + if(sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS || + vap->iv_opmode == IEEE80211_M_STA)){ + RUN_LOCK(sc); + /* read statistic counters (clear on read) and update AMRR state */ error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta, sizeof sta); if (error != 0) - goto skip; + return; DPRINTFN(3, "retrycnt=%d txcnt=%d failcnt=%d\n", le32toh(sta[1]) >> 16, le32toh(sta[1]) & 0xffff, @@ -2101,17 +2297,29 @@ run_iter_func(void *arg, struct ieee80211_node *ni) success = (le32toh(sta[1]) >> 16) + (le32toh(sta[1]) & 0xffff); + ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt); + + RUN_UNLOCK(sc); } - ieee80211_ratectl_rate(ni, NULL, 0); + rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0); + DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx); +} -skip:; - RUN_UNLOCK(sc); +static void +run_newassoc_cb(void *arg) +{ + struct run_cmdq *cmdq = arg; + struct ieee80211_node *ni = cmdq->arg1; + struct run_softc *sc = ni->ni_vap->iv_ic->ic_ifp->if_softc; + uint8_t wcid = cmdq->wcid; - if(ic->ic_opmode != IEEE80211_M_STA) - IEEE80211_NODE_ITERATE_LOCK(nt); + RUN_LOCK_ASSERT(sc, MA_OWNED); + + run_write_region_1(sc, RT2860_WCID_ENTRY(wcid), + ni->ni_macaddr, IEEE80211_ADDR_LEN); } static void @@ -2119,11 +2327,40 @@ run_newassoc(struct ieee80211_node *ni, int isnew) { struct run_node *rn = (void *)ni; struct ieee80211_rateset *rs = &ni->ni_rates; + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = vap->iv_ic; + struct run_softc *sc = ic->ic_ifp->if_softc; uint8_t rate; - int ridx, i, j; + uint8_t ridx; + uint8_t wcid = RUN_AID2WCID(ni->ni_associd); + int i, j; + + if(wcid > RT2870_WCID_MAX){ + device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid); + return; + } - DPRINTF("new assoc isnew=%d addr=%s\n", - isnew, ether_sprintf(ni->ni_macaddr)); + /* only interested in true associations */ + if (isnew && ni->ni_associd != 0){ + + /* + * This function could is called though timeout function. + * Need to defer. + */ + uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store); + DPRINTF("cmdq_store=%d\n", cnt); + sc->cmdq[cnt].func = run_newassoc_cb; + sc->cmdq[cnt].arg0 = NULL; + sc->cmdq[cnt].arg1 = ni; + sc->cmdq[cnt].wcid = wcid; + ieee80211_runtask(ic, &sc->cmdq_task); + } + + DPRINTF("new assoc isnew=%d associd=%x addr=%s\n", + isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr)); + + ieee80211_ratectl_node_init(ni); + sc->sc_ni[wcid] = ni; for (i = 0; i < rs->rs_nrates; i++) { rate = rs->rs_rates[i] & IEEE80211_RATE_VAL; @@ -2148,6 +2385,14 @@ run_newassoc(struct ieee80211_node *ni, int isnew) DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n", rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]); } + rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate; + for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) + if (rt2860_rates[ridx].rate == rate) + break; + rn->mgt_ridx = ridx; + DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx); + + usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); } /* @@ -2172,7 +2417,6 @@ static void run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) { struct ifnet *ifp = sc->sc_ifp; - struct ieee80211vap *vap = &sc->sc_rvp->vap; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_frame *wh; struct ieee80211_node *ni; @@ -2217,9 +2461,13 @@ run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) len += 2; } + ni = ieee80211_find_rxnode(ic, + mtod(m, struct ieee80211_frame_min *)); + if (__predict_false(flags & RT2860_RX_MICERR)) { /* report MIC failures to net80211 for TKIP */ - ieee80211_notify_michael_failure(vap, wh, rxwi->keyidx); + if(ni != NULL) + ieee80211_notify_michael_failure(ni->ni_vap, wh, rxwi->keyidx); m_freem(m); ifp->if_ierrors++; DPRINTF("MIC error. Someone is lying.\n"); @@ -2233,8 +2481,6 @@ run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = len; - ni = ieee80211_find_rxnode(ic, - mtod(m, struct ieee80211_frame_min *)); if (ni != NULL) { (void)ieee80211_input(ni, m, rssi, nf); ieee80211_free_node(ni); @@ -2431,6 +2677,7 @@ run_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, unsigned int ind { struct run_softc *sc = usbd_xfer_softc(xfer); struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct run_tx_data *data; struct ieee80211vap *vap = NULL; struct usb_page_cache *pc; @@ -2486,20 +2733,22 @@ tr_setup: vap = data->ni->ni_vap; if (ieee80211_radiotap_active_vap(vap)) { struct run_tx_radiotap_header *tap = &sc->sc_txtap; + struct rt2860_txwi *txwi = + (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd)); tap->wt_flags = 0; tap->wt_rate = rt2860_rates[data->ridx].rate; tap->wt_chan_freq = htole16(vap->iv_bss->ni_chan->ic_freq); tap->wt_chan_flags = htole16(vap->iv_bss->ni_chan->ic_flags); tap->wt_hwqueue = index; - if (data->mcs & RT2860_PHY_SHPRE) + if (le16toh(txwi->phy) & RT2860_PHY_SHPRE) tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; ieee80211_radiotap_tx(vap, m); } /* align end on a 4-bytes boundary */ - len = (size + m->m_pkthdr.len + 3) & ~3; + len = (size + IEEE80211_CRC_LEN + m->m_pkthdr.len + 3) & ~3; DPRINTFN(11, "sending frame len=%u xferlen=%u @ index %d\n", m->m_pkthdr.len, len, index); @@ -2524,14 +2773,22 @@ tr_setup: ifp->if_oerrors++; if (data != NULL) { + if(data->ni != NULL) + vap = data->ni->ni_vap; run_tx_free(pq, data, error); usbd_xfer_set_priv(xfer, NULL); } + if(vap == NULL) + vap = TAILQ_FIRST(&ic->ic_vaps); if (error != USB_ERR_CANCELLED) { if (error == USB_ERR_TIMEOUT) { device_printf(sc->sc_dev, "device timeout\n"); - ieee80211_runtask(ifp->if_l2com, &sc->usb_timeout_task); + uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); + DPRINTF("cmdq_store=%d\n", i); + sc->cmdq[i].func = run_usb_timeout_cb; + sc->cmdq[i].arg0 = vap; + ieee80211_runtask(ic, &sc->cmdq_task); } /* @@ -2583,22 +2840,21 @@ run_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error) } static void -run_set_tx_desc(struct run_softc *sc, struct run_tx_data *data, - uint8_t wflags, uint8_t xflags, uint8_t opflags, uint8_t dflags, - uint8_t type, uint8_t pad) +run_set_tx_desc(struct run_softc *sc, struct run_tx_data *data) { struct mbuf *m = data->m; struct ieee80211com *ic = sc->sc_ifp->if_l2com; - struct ieee80211vap *vap = &sc->sc_rvp->vap; + struct ieee80211vap *vap = data->ni->ni_vap; struct ieee80211_frame *wh; struct rt2870_txd *txd; struct rt2860_txwi *txwi; - int xferlen; - uint8_t mcs; + uint16_t xferlen; + uint16_t mcs; uint8_t ridx = data->ridx; + uint8_t pad; /* get MCS code from rate index */ - data->mcs = mcs = rt2860_rates[ridx].mcs; + mcs = rt2860_rates[ridx].mcs; xferlen = sizeof(*txwi) + m->m_pkthdr.len; @@ -2606,15 +2862,21 @@ run_set_tx_desc(struct run_softc *sc, struct run_tx_data *data, xferlen = (xferlen + 3) & ~3; txd = (struct rt2870_txd *)&data->desc; - txd->flags = dflags; txd->len = htole16(xferlen); + wh = mtod(m, struct ieee80211_frame *); + + /* + * Ether both are true or both are false, the header + * are nicely aligned to 32-bit. So, no L2 padding. + */ + if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh)) + pad = 0; + else + pad = 2; + /* setup TX Wireless Information */ txwi = (struct rt2860_txwi *)(txd + 1); - txwi->flags = wflags; - txwi->xflags = xflags; - txwi->wcid = (type == IEEE80211_FC0_TYPE_DATA) ? - RUN_AID2WCID(data->ni->ni_associd) : 0xff; txwi->len = htole16(m->m_pkthdr.len - pad); if (rt2860_rates[ridx].phy == IEEE80211_T_DS) { txwi->phy = htole16(RT2860_PHY_CCK); @@ -2625,16 +2887,14 @@ run_set_tx_desc(struct run_softc *sc, struct run_tx_data *data, txwi->phy = htole16(RT2860_PHY_OFDM); txwi->phy |= htole16(mcs); - wh = mtod(m, struct ieee80211_frame *); - /* check if RTS/CTS or CTS-to-self protection is required */ if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold || ((ic->ic_flags & IEEE80211_F_USEPROT) && rt2860_rates[ridx].phy == IEEE80211_T_OFDM))) - txwi->txop = RT2860_TX_TXOP_HT | opflags; + txwi->txop |= RT2860_TX_TXOP_HT; else - txwi->txop = RT2860_TX_TXOP_BACKOFF | opflags; + txwi->txop |= RT2860_TX_TXOP_BACKOFF; } /* This function must be called locked */ @@ -2642,21 +2902,24 @@ static int run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { struct ieee80211com *ic = sc->sc_ifp->if_l2com; - struct ieee80211vap *vap = &sc->sc_rvp->vap; + struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_frame *wh; + struct ieee80211_channel *chan; const struct ieee80211_txparam *tp; + struct run_node *rn = (void *)ni; struct run_tx_data *data; + struct rt2870_txd *txd; + struct rt2860_txwi *txwi; uint16_t qos; uint16_t dur; + uint16_t qid; uint8_t type; uint8_t tid; - uint8_t qid; + uint8_t ridx; + uint8_t ctl_ridx; uint8_t qflags; - uint8_t pad; uint8_t xflags = 0; int hasqos; - int ridx; - int ctl_ridx; RUN_LOCK_ASSERT(sc, MA_OWNED); @@ -2681,19 +2944,18 @@ run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) qos = le16toh(*(const uint16_t *)frm); tid = qos & IEEE80211_QOS_TID; qid = TID_TO_WME_AC(tid); - pad = 2; } else { qos = 0; tid = 0; qid = WME_AC_BE; - pad = 0; } qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA; DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n", qos, qid, tid, qflags); - tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; + chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan; + tp = &vap->iv_txparms[ieee80211_chan2mode(chan)]; /* pickup a rate index */ if (IEEE80211_IS_MULTICAST(wh->i_addr1) || @@ -2701,25 +2963,22 @@ run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; ctl_ridx = rt2860_rates[ridx].ctl_ridx; - } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { - ridx = sc->fixed_ridx; - ctl_ridx = rt2860_rates[ridx].ctl_ridx; } else { - for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++){ - if (rt2860_rates[ridx].rate == ni->ni_txrate) - break; - } + if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) + ridx = rn->fix_ridx; + else + ridx = rn->amrr_ridx; ctl_ridx = rt2860_rates[ridx].ctl_ridx; } if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) != IEEE80211_QOS_ACKPOLICY_NOACK)) { - xflags |= RT2860_TX_ACK; + xflags = RT2860_TX_ACK; if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) - dur = rt2860_rates[ridx].sp_ack_dur; + dur = rt2860_rates[ctl_ridx].sp_ack_dur; else - dur = rt2860_rates[ridx].lp_ack_dur; + dur = rt2860_rates[ctl_ridx].lp_ack_dur; *(uint16_t *)wh->i_dur = htole16(dur); } @@ -2733,11 +2992,64 @@ run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next); sc->sc_epq[qid].tx_nfree--; + txd = (struct rt2870_txd *)&data->desc; + txd->flags = qflags; + txwi = (struct rt2860_txwi *)(txd + 1); + txwi->xflags = xflags; + txwi->wcid = (type == IEEE80211_FC0_TYPE_DATA) ? + RUN_AID2WCID(ni->ni_associd) : 0xff; + /* clear leftover garbage bits */ + txwi->flags = 0; + txwi->txop = 0; + data->m = m; data->ni = ni; data->ridx = ridx; - run_set_tx_desc(sc, data, 0, xflags, 0, qflags, type, pad); + run_set_tx_desc(sc, data); + + /* + * The chip keeps track of 2 kind of Tx stats, + * * TX_STAT_FIFO, for per WCID stats, and + * * TX_STA_CNT0 for all-TX-in-one stats. + * + * To use FIFO stats, we need to store MCS into the driver-private + * PacketID field. So that, we can tell whose stats when we read them. + * We add 1 to the MCS because setting the PacketID field to 0 means + * that we don't want feedback in TX_STAT_FIFO. + * And, that's what we want for STA mode, since TX_STA_CNT0 does the job. + * + * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx(). + */ + if(sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP || + vap->iv_opmode == IEEE80211_M_MBSS){ + uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf; + txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT); + + /* + * Unlike PCI based devices, we don't get any interrupt from + * USB devices, so we simulate FIFO-is-full interrupt here. + * Ralink recomends to drain FIFO stats every 100 ms, but 16 slots + * quickly get fulled. To prevent overflow, increment a counter on + * every FIFO stat request, so we know how many slots are left. + * We do this only in HOSTAP or multiple vap mode since FIFO stats + * are used only in those modes. + * We just drain stats. AMRR gets updated every 1 sec by + * run_ratectl_cb() via callout. + * Call it early. Otherwise overflow. + */ + if(sc->fifo_cnt++ == 10){ + /* + * With multiple vaps or if_bridge, if_start() is called + * with a non-sleepable lock, tcpinp. So, need to defer. + */ + uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); + DPRINTFN(6, "cmdq_store=%d\n", i); + sc->cmdq[i].func = run_drain_fifo; + sc->cmdq[i].arg0 = sc; + ieee80211_runtask(ic, &sc->cmdq_task); + } + } STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next); @@ -2753,36 +3065,36 @@ run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) static int run_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { - const struct ieee80211_txparam *tp; struct ifnet *ifp = sc->sc_ifp; - struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ifp->if_l2com; + struct run_node *rn = (void *)ni; struct run_tx_data *data; struct ieee80211_frame *wh; - int ridx; + struct rt2870_txd *txd; + struct rt2860_txwi *txwi; uint16_t dur; + uint8_t ridx = rn->mgt_ridx; uint8_t type; uint8_t xflags = 0; + uint8_t wflags = 0; RUN_LOCK_ASSERT(sc, MA_OWNED); wh = mtod(m, struct ieee80211_frame *); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; - tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; - if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { + /* tell hardware to add timestamp for probe responses */ + if ((wh->i_fc[0] & + (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == + (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) + wflags |= RT2860_TX_TS; + else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { xflags |= RT2860_TX_ACK; - dur = ieee80211_ack_duration(ic->ic_rt, tp->mgmtrate, + dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); *(uint16_t *)wh->i_dur = htole16(dur); - - /* tell hardware to add timestamp for probe responses */ - if ((wh->i_fc[0] & - (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == - (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) - xflags |= RT2860_TX_TS; } if (sc->sc_epq[0].tx_nfree == 0) { @@ -2794,19 +3106,23 @@ run_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); sc->sc_epq[0].tx_nfree--; + txd = (struct rt2870_txd *)&data->desc; + txd->flags = RT2860_TX_QSEL_EDCA; + txwi = (struct rt2860_txwi *)(txd + 1); + txwi->wcid = 0xff; + txwi->flags = wflags; + txwi->xflags = xflags; + txwi->txop = 0; /* clear leftover garbage bits */ + data->m = m; data->ni = ni; - for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) - if (rt2860_rates[ridx].rate == tp->mgmtrate) - break; data->ridx = ridx; - run_set_tx_desc(sc, data, 0, xflags, 0, RT2860_TX_QSEL_MGMT, - wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, 0); + run_set_tx_desc(sc, data); DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len + (int)(sizeof (struct rt2870_txd) + sizeof (struct rt2860_rxwi)), - tp->mgmtrate); + rt2860_rates[ridx].rate); STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); @@ -2822,6 +3138,8 @@ run_sendprot(struct run_softc *sc, struct ieee80211com *ic = ni->ni_ic; struct ieee80211_frame *wh; struct run_tx_data *data; + struct rt2870_txd *txd; + struct rt2860_txwi *txwi; struct mbuf *mprot; int ridx; int protrate; @@ -2830,8 +3148,8 @@ run_sendprot(struct run_softc *sc, int isshort; uint16_t dur; uint8_t type; - uint8_t wflags; - uint8_t txflags = 0; + uint8_t wflags = 0; + uint8_t xflags = 0; RUN_LOCK_ASSERT(sc, MA_OWNED); @@ -2860,7 +3178,7 @@ run_sendprot(struct run_softc *sc, if (prot == IEEE80211_PROT_RTSCTS) { /* NB: CTS is the same size as an ACK */ dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); - txflags |= RT2860_TX_ACK; + xflags |= RT2860_TX_ACK; mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); } else { mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); @@ -2875,6 +3193,14 @@ run_sendprot(struct run_softc *sc, STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); sc->sc_epq[0].tx_nfree--; + txd = (struct rt2870_txd *)&data->desc; + txd->flags = RT2860_TX_QSEL_EDCA; + txwi = (struct rt2860_txwi *)(txd + 1); + txwi->wcid = 0xff; + txwi->flags = wflags; + txwi->xflags = xflags; + txwi->txop = 0; /* clear leftover garbage bits */ + data->m = mprot; data->ni = ieee80211_ref_node(ni); @@ -2883,8 +3209,7 @@ run_sendprot(struct run_softc *sc, break; data->ridx = ridx; - run_set_tx_desc(sc, data, wflags, txflags, 0, - RT2860_TX_QSEL_EDCA, type, 0); + run_set_tx_desc(sc, data); DPRINTFN(1, "sending prot len=%u rate=%u\n", m->m_pkthdr.len, rate); @@ -2903,11 +3228,13 @@ run_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, struct ieee80211com *ic = ni->ni_ic; struct ieee80211_frame *wh; struct run_tx_data *data; + struct rt2870_txd *txd; + struct rt2860_txwi *txwi; uint8_t type; - uint8_t opflags; - uint8_t txflags; - int ridx; - int rate; + uint8_t ridx; + uint8_t rate; + uint8_t opflags = 0; + uint8_t xflags = 0; int error; RUN_LOCK_ASSERT(sc, MA_OWNED); @@ -2923,10 +3250,8 @@ run_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, return (EINVAL); } - opflags = 0; - txflags = 0; if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) - txflags |= RT2860_TX_ACK; + xflags |= RT2860_TX_ACK; if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { error = run_sendprot(sc, m, ni, params->ibp_flags & IEEE80211_BPF_RTS ? @@ -2949,6 +3274,14 @@ run_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); sc->sc_epq[0].tx_nfree--; + txd = (struct rt2870_txd *)&data->desc; + txd->flags = RT2860_TX_QSEL_EDCA; + txwi = (struct rt2860_txwi *)(txd + 1); + txwi->wcid = 0xff; + txwi->xflags = xflags; + txwi->txop = opflags; + txwi->flags = 0; /* clear leftover garbage bits */ + data->m = m; data->ni = ni; for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) @@ -2956,8 +3289,7 @@ run_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, break; data->ridx = ridx; - run_set_tx_desc(sc, data, 0, txflags, opflags, - RT2860_TX_QSEL_EDCA, type, 0); + run_set_tx_desc(sc, data); DPRINTFN(10, "sending raw frame len=%u rate=%u\n", m->m_pkthdr.len, rate); @@ -2975,14 +3307,14 @@ run_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, { struct ifnet *ifp = ni->ni_ic->ic_ifp; struct run_softc *sc = ifp->if_softc; - int error; - + int error = 0; + RUN_LOCK(sc); /* prevent management frames from being sent if we're not ready */ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { error = ENETDOWN; - goto bad; + goto done; } if (params == NULL) { @@ -2990,28 +3322,27 @@ run_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, if ((error = run_tx_mgt(sc, m, ni)) != 0){ ifp->if_oerrors++; DPRINTF("mgt tx failed\n"); - goto bad; + goto done; } } else { /* tx raw packet with param */ if ((error = run_tx_param(sc, m, ni, params)) != 0){ ifp->if_oerrors++; DPRINTF("tx with param failed\n"); - goto bad; + goto done; } } ifp->if_opackets++; +done: RUN_UNLOCK(sc); - return (0); - -bad: - RUN_UNLOCK(sc); - if(m != NULL) - m_freem(m); - ieee80211_free_node(ni); + if(error != 0){ + if(m != NULL) + m_freem(m); + ieee80211_free_node(ni); + } return (error); } @@ -3053,24 +3384,27 @@ run_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) struct run_softc *sc = ifp->if_softc; struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ifreq *ifr = (struct ifreq *) data; - int error = 0, startall = 0; + int startall = 0; + int error = 0; switch (cmd) { case SIOCSIFFLAGS: RUN_LOCK(sc); if (ifp->if_flags & IFF_UP) { if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)){ - run_init_locked(sc); startall = 1; + run_init_locked(sc); } else run_update_promisc_locked(ifp); } else { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - run_stop(sc); + if(ifp->if_drv_flags & IFF_DRV_RUNNING && + (ic->ic_nrunning == 0 || sc->rvp_cnt <= 1)){ + run_stop(sc); + } } RUN_UNLOCK(sc); if(startall) - ieee80211_start_all(ic); + ieee80211_start_all(ic); break; case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); @@ -3138,19 +3472,17 @@ run_select_chan_group(struct run_softc *sc, int group) run_write(sc, RT2860_TX_BAND_CFG, tmp); /* enable appropriate Power Amplifiers and Low Noise Amplifiers */ - tmp = RT2860_RFTR_EN | RT2860_TRSW_EN; + tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN; + if (sc->nrxchains > 1) + tmp |= RT2860_LNA_PE1_EN; if (group == 0) { /* 2GHz */ - tmp |= RT2860_PA_PE_G0_EN | RT2860_LNA_PE_G0_EN; + tmp |= RT2860_PA_PE_G0_EN; if (sc->ntxchains > 1) tmp |= RT2860_PA_PE_G1_EN; - if (sc->nrxchains > 1) - tmp |= RT2860_LNA_PE_G1_EN; } else { /* 5GHz */ - tmp |= RT2860_PA_PE_A0_EN | RT2860_LNA_PE_A0_EN; + tmp |= RT2860_PA_PE_A0_EN; if (sc->ntxchains > 1) tmp |= RT2860_PA_PE_A1_EN; - if (sc->nrxchains > 1) - tmp |= RT2860_LNA_PE_A1_EN; } if (sc->mac_ver == 0x3572) { run_rt3070_rf_write(sc, 8, 0x00); @@ -3198,13 +3530,13 @@ run_rt2870_set_chan(struct run_softc *sc, uint32_t chan) txpow2 = sc->txpow2[i]; if (chan > 14) { if (txpow1 >= 0) - txpow1 = txpow1 << 1; + txpow1 = txpow1 << 1 | 1; else - txpow1 = (7 + txpow1) << 1 | 1; + txpow1 = (7 + txpow1) << 1; if (txpow2 >= 0) - txpow2 = txpow2 << 1; + txpow2 = txpow2 << 1 | 1; else - txpow2 = (7 + txpow2) << 1 | 1; + txpow2 = (7 + txpow2) << 1; } r3 = rfprog[i].r3 | txpow1 << 7; r4 = rfprog[i].r4 | sc->freq << 13 | txpow2 << 4; @@ -3541,36 +3873,38 @@ run_scan_end(struct ieee80211com *ic) return; } -static uint8_t -run_rate2mcs(uint8_t rate) +/* + * Could be called from ieee80211_node_timeout() + * (non-sleepable thread) + */ +static void +run_update_beacon(struct ieee80211vap *vap, int item) { - 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; /* shouldn't get here */ + struct ieee80211com *ic = vap->iv_ic; + struct run_softc *sc = ic->ic_ifp->if_softc; + uint32_t i; + + i = RUN_CMDQ_GET(&sc->cmdq_store); + DPRINTF("cmdq_store=%d\n", i); + sc->cmdq[i].func = run_update_beacon_cb; + sc->cmdq[i].arg0 = vap; + ieee80211_runtask(ic, &sc->cmdq_task); + + return; } static void -run_update_beacon_locked(struct ieee80211vap *vap, int item) +run_update_beacon_cb(void *arg) { + struct ieee80211vap *vap = arg; struct ieee80211com *ic = vap->iv_ic; struct run_softc *sc = ic->ic_ifp->if_softc; struct rt2860_txwi txwi; struct mbuf *m; - int rate; + uint8_t ridx; + + if(vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC) + return; if ((m = ieee80211_beacon_alloc(vap->iv_bss, &RUN_VAP(vap)->bo)) == NULL) return; @@ -3579,16 +3913,17 @@ run_update_beacon_locked(struct ieee80211vap *vap, int item) txwi.wcid = 0xff; txwi.len = htole16(m->m_pkthdr.len); /* send beacons at the lowest available rate */ - rate = (ic->ic_curmode == IEEE80211_MODE_11A) ? 12 : 2; - txwi.phy = htole16(run_rate2mcs(rate)); - if (rate == 12) + ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? + RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; + txwi.phy = htole16(rt2860_rates[ridx].mcs); + if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM) txwi.phy |= htole16(RT2860_PHY_OFDM); txwi.txop = RT2860_TX_TXOP_HT; txwi.flags = RT2860_TX_TS; - run_write_region_1(sc, RT2860_BCN_BASE(0), - (u_int8_t *)&txwi, sizeof txwi); - run_write_region_1(sc, RT2860_BCN_BASE(0) + sizeof txwi, + run_write_region_1(sc, RT2860_BCN_BASE(RUN_VAP(vap)->rvp_id), + (uint8_t *)&txwi, sizeof txwi); + run_write_region_1(sc, RT2860_BCN_BASE(RUN_VAP(vap)->rvp_id) + sizeof txwi, mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1); /* roundup len */ m_freem(m); @@ -3597,21 +3932,6 @@ run_update_beacon_locked(struct ieee80211vap *vap, int item) } static void -run_update_beacon(struct ieee80211vap *vap, int item) -{ - struct ieee80211com *ic = vap->iv_ic; - struct run_softc *sc = ic->ic_ifp->if_softc; - - IEEE80211_UNLOCK(ic); - RUN_LOCK(sc); - run_update_beacon_locked(vap, item); - RUN_UNLOCK(sc); - IEEE80211_LOCK(ic); - - return; -} - -static void run_updateprot(struct ieee80211com *ic) { struct run_softc *sc = ic->ic_ifp->if_softc; @@ -3635,12 +3955,12 @@ run_updateprot(struct ieee80211com *ic) } static void -run_usb_timeout_cb(void *arg, int pending) +run_usb_timeout_cb(void *arg) { - struct run_softc *sc = arg; - struct ieee80211vap *vap = &sc->sc_rvp->vap; + struct ieee80211vap *vap = arg; + struct run_softc *sc = vap->iv_ic->ic_ifp->if_softc; - RUN_LOCK(sc); + RUN_LOCK_ASSERT(sc, MA_OWNED); if(vap->iv_state == IEEE80211_S_RUN && vap->iv_opmode != IEEE80211_M_STA) @@ -3651,8 +3971,6 @@ run_usb_timeout_cb(void *arg, int pending) ieee80211_cancel_scan(vap); } else DPRINTF("timeout by unknown cause\n"); - - RUN_UNLOCK(sc); } static void @@ -3660,12 +3978,15 @@ run_reset_livelock(struct run_softc *sc) { uint32_t tmp; + RUN_LOCK_ASSERT(sc, MA_OWNED); + /* * In IBSS or HostAP modes (when the hardware sends beacons), the MAC * can run into a livelock and start sending CTS-to-self frames like * crazy if protection is enabled. Reset MAC/BBP for a while */ run_read(sc, RT2860_DEBUG, &tmp); + DPRINTFN(3, "debug reg %08x\n", tmp); if((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))){ DPRINTF("CTS-to-self livelock detected\n"); run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST); @@ -3709,35 +4030,39 @@ run_update_promisc(struct ifnet *ifp) static void run_enable_tsf_sync(struct run_softc *sc) { - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); uint32_t tmp; + DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id, ic->ic_opmode); + run_read(sc, RT2860_BCN_TIME_CFG, &tmp); tmp &= ~0x1fffff; tmp |= vap->iv_bss->ni_intval * 16; tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN; - if (vap->iv_opmode == IEEE80211_M_STA) { + if (ic->ic_opmode == IEEE80211_M_STA) { /* * Local TSF is always updated with remote TSF on beacon * reception. */ tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT; - } else if (vap->iv_opmode == IEEE80211_M_IBSS) { + } else if (ic->ic_opmode == IEEE80211_M_IBSS) { tmp |= RT2860_BCN_TX_EN; /* * Local TSF is updated with remote TSF on beacon reception * only if the remote TSF is greater than local TSF. */ tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT; - } else if (vap->iv_opmode == IEEE80211_M_HOSTAP) { + } else if (ic->ic_opmode == IEEE80211_M_HOSTAP || + ic->ic_opmode == IEEE80211_M_MBSS) { tmp |= RT2860_BCN_TX_EN; /* SYNC with nobody */ tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT; - } else + } else { DPRINTF("Enabling TSF failed. undefined opmode\n"); + return; + } run_write(sc, RT2860_BCN_TIME_CFG, tmp); } @@ -3833,6 +4158,13 @@ run_updateslot(struct ifnet *ifp) run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp); } +static void +run_update_mcast(struct ifnet *ifp) +{ + /* h/w filter supports getting everything or nothing */ + ifp->if_flags |= IFF_ALLMULTI; +} + static int8_t run_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain) { @@ -3942,23 +4274,18 @@ run_rt3070_rf_init(struct run_softc *sc) /* patch LNA_PE_G1 */ run_read(sc, RT3070_GPIO_SWITCH, &tmp); run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20); + } else if(sc->mac_ver == 0x3572){ run_rt3070_rf_read(sc, 6, &rf); run_rt3070_rf_write(sc, 6, rf | 0x40); - if (sc->mac_rev < 0x0211){ - /* increase voltage from 1.2V to 1.35V */ - run_read(sc, RT3070_LDO_CFG0, &tmp); - tmp = (tmp & ~0x0f000000) | 0x0d000000; - run_write(sc, RT3070_LDO_CFG0, tmp); - } else { - /* increase voltage from 1.2V to 1.35V */ - run_read(sc, RT3070_LDO_CFG0, &tmp); - tmp = (tmp & ~0x1f000000) | 0x0d000000; - run_write(sc, RT3070_LDO_CFG0, tmp); + /* increase voltage from 1.2V to 1.35V */ + run_read(sc, RT3070_LDO_CFG0, &tmp); + tmp = (tmp & ~0x1f000000) | 0x0d000000; + run_write(sc, RT3070_LDO_CFG0, tmp); + if (sc->mac_rev < 0x0211 || !sc->patch_dac){ run_delay(sc, 1); /* wait for 1msec */ - /* decrease voltage back to 1.2V */ tmp = (tmp & ~0x1f000000) | 0x01000000; run_write(sc, RT3070_LDO_CFG0, tmp); @@ -4240,6 +4567,9 @@ run_init_locked(struct run_softc *sc) int ridx; int ntries; + if(ic->ic_nrunning > 1) + return; + run_stop(sc); for (ntries = 0; ntries < 100; ntries++) { @@ -4353,7 +4683,7 @@ run_init_locked(struct run_softc *sc) run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96); /* write vendor-specific BBP values (from EEPROM) */ - for (i = 0; i < 8; i++) { + for (i = 0; i < 10; i++) { if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff) continue; run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val); @@ -4400,6 +4730,7 @@ run_init_locked(struct run_softc *sc) ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; ifp->if_drv_flags |= IFF_DRV_RUNNING; + sc->cmdq_run = RUN_CMDQ_GO; for(i = 0; i != RUN_N_XFER; i++) usbd_xfer_set_stall(sc->sc_xfer[i]); @@ -4427,7 +4758,7 @@ run_init(void *arg) RUN_UNLOCK(sc); if (ifp->if_drv_flags & IFF_DRV_RUNNING) - ieee80211_start_all(ic); + ieee80211_start_all(ic); } static void @@ -4435,24 +4766,20 @@ run_stop(void *arg) { struct run_softc *sc = (struct run_softc *)arg; struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; int i; int ntries; RUN_LOCK_ASSERT(sc, MA_OWNED); - if(sc->sc_rvp != NULL){ - sc->sc_rvp->ratectl_run = RUN_RATECTL_OFF; - if (ic->ic_flags & IEEE80211_F_SCAN) - ieee80211_cancel_scan(&sc->sc_rvp->vap); - } - if (ifp->if_drv_flags & IFF_DRV_RUNNING) run_set_leds(sc, 0); /* turn all LEDs off */ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + sc->ratectl_run = RUN_RATECTL_OFF; + sc->cmdq_run = RUN_CMDQ_ABORT; + RUN_UNLOCK(sc); for(i = 0; i < RUN_N_XFER; i++) diff --git a/sys/dev/usb/wlan/if_runreg.h b/sys/dev/usb/wlan/if_runreg.h index f872fad..33f3b94 100644 --- a/sys/dev/usb/wlan/if_runreg.h +++ b/sys/dev/usb/wlan/if_runreg.h @@ -517,8 +517,10 @@ #define RT2860_LNA_PE_A0_POL (1 << 12) #define RT2860_LNA_PE_G1_EN (1 << 11) #define RT2860_LNA_PE_A1_EN (1 << 10) +#define RT2860_LNA_PE1_EN (RT2860_LNA_PE_A1_EN | RT2860_LNA_PE_G1_EN) #define RT2860_LNA_PE_G0_EN (1 << 9) #define RT2860_LNA_PE_A0_EN (1 << 8) +#define RT2860_LNA_PE0_EN (RT2860_LNA_PE_A0_EN | RT2860_LNA_PE_G0_EN) #define RT2860_PA_PE_G1_POL (1 << 7) #define RT2860_PA_PE_A1_POL (1 << 6) #define RT2860_PA_PE_G0_POL (1 << 5) @@ -896,7 +898,7 @@ struct rt2860_rxwi { #define RT2860_RIDX_CCK1 0 #define RT2860_RIDX_CCK11 3 #define RT2860_RIDX_OFDM6 4 -#define RT2860_RIDX_MAX 11 +#define RT2860_RIDX_MAX 12 static const struct rt2860_rate { uint8_t rate; uint8_t mcs; @@ -1097,24 +1099,6 @@ static const struct rt2860_rate { { 171, 0x100bb1, 0x1300f5, 0x05e014, 0x001401 }, \ { 173, 0x100bb1, 0x1300f5, 0x05e014, 0x001403 } -#if 0 -#define RT3070_RF3020 \ - { 241, 2, 2 }, \ - { 241, 2, 7 }, \ - { 242, 2, 2 }, \ - { 242, 2, 7 }, \ - { 243, 2, 2 }, \ - { 243, 2, 7 }, \ - { 244, 2, 2 }, \ - { 244, 2, 7 }, \ - { 245, 2, 2 }, \ - { 245, 2, 7 }, \ - { 246, 2, 2 }, \ - { 246, 2, 7 }, \ - { 247, 2, 2 }, \ - { 248, 2, 4 } -#endif - #define RT3070_RF3052 \ { 0xf1, 2, 2 }, \ { 0xf1, 2, 7 }, \ diff --git a/sys/dev/usb/wlan/if_runvar.h b/sys/dev/usb/wlan/if_runvar.h index a7f8f1f..7349eaf 100644 --- a/sys/dev/usb/wlan/if_runvar.h +++ b/sys/dev/usb/wlan/if_runvar.h @@ -44,16 +44,18 @@ #define RUN_TX_RING_COUNT 32 #define RUN_RX_RING_COUNT 1 -#define RT2870_WCID_MAX 253 +#define RT2870_WCID_MAX 64 #define RUN_AID2WCID(aid) ((aid) & 0xff) +#define RUN_VAP_MAX 8 + struct run_rx_radiotap_header { struct ieee80211_radiotap_header wr_ihdr; uint8_t wr_flags; uint8_t wr_rate; uint16_t wr_chan_freq; uint16_t wr_chan_flags; - uint8_t wr_dbm_antsignal; + int8_t wr_dbm_antsignal; uint8_t wr_antenna; uint8_t wr_antsignal; } __packed; @@ -93,8 +95,7 @@ struct run_tx_data { uint32_t align[0]; /* dummy field */ uint8_t desc[sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi)]; - int ridx; - uint8_t mcs; + uint8_t ridx; }; STAILQ_HEAD(run_tx_data_head, run_tx_data); @@ -102,19 +103,29 @@ struct run_node { struct ieee80211_node ni; uint8_t ridx[IEEE80211_RATE_MAXSIZE]; uint8_t ctl_ridx[IEEE80211_RATE_MAXSIZE]; + uint8_t amrr_ridx; + uint8_t mgt_ridx; + uint8_t fix_ridx; +}; + +struct run_cmdq { + void *arg0; + void *arg1; + void (*func)(void *); + struct ieee80211_key *k; + struct ieee80211_key key; + uint8_t mac[IEEE80211_ADDR_LEN]; + uint8_t wcid; }; struct run_vap { struct ieee80211vap vap; struct ieee80211_beacon_offsets bo; - struct usb_callout ratectl_ch; - struct task ratectl_task; - uint8_t ratectl_run; -#define RUN_RATECTL_ON 1 -#define RUN_RATECTL_OFF 0 int (*newstate)(struct ieee80211vap *, enum ieee80211_state, int); + + uint8_t rvp_id; }; #define RUN_VAP(vap) ((struct run_vap *)(vap)) @@ -148,7 +159,7 @@ struct run_softc { device_t sc_dev; struct usb_device *sc_udev; struct ifnet *sc_ifp; - struct run_vap *sc_rvp; + struct ieee80211_node *sc_ni[RT2870_WCID_MAX + 1]; int (*sc_srom_read)(struct run_softc *, uint16_t, uint16_t *); @@ -159,7 +170,6 @@ struct run_softc { uint8_t freq; uint8_t ntxchains; uint8_t nrxchains; - int fixed_ridx; uint8_t bbp25; uint8_t bbp26; @@ -182,7 +192,7 @@ struct run_softc { struct { uint8_t reg; uint8_t val; - } bbp[8], rf[10]; + } bbp[10], rf[10]; uint8_t leds; uint16_t led[3]; uint32_t txpow20mhz[5]; @@ -195,13 +205,36 @@ struct run_softc { struct run_endpoint_queue sc_epq[RUN_EP_QUEUES]; - struct task wme_task; - struct task usb_timeout_task; + struct task ratectl_task; + struct usb_callout ratectl_ch; + uint8_t ratectl_run; +#define RUN_RATECTL_OFF 0 + +/* need to be power of 2, otherwise RUN_CMDQ_GET fails */ +#define RUN_CMDQ_MAX 16 +#define RUN_CMDQ_MASQ (RUN_CMDQ_MAX - 1) + struct run_cmdq cmdq[RUN_CMDQ_MAX]; + struct task cmdq_task; + uint32_t cmdq_store; + uint8_t cmdq_exec; + uint8_t cmdq_run; +#define RUN_CMDQ_ABORT 0 +#define RUN_CMDQ_GO 1 struct usb_xfer *sc_xfer[RUN_N_XFER]; struct mbuf *rx_m; + uint8_t fifo_cnt; + + uint8_t running; + uint8_t runbmap; + uint8_t ap_running; + uint8_t adhoc_running; + uint8_t sta_running; + uint8_t rvp_cnt; + uint8_t rvp_bmap; + union { struct run_rx_radiotap_header th; uint8_t pad[64]; |