Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ral/rt2560.c
Show First 20 Lines • Show All 121 Lines • ▼ Show 20 Lines | static void rt2560_setup_tx_desc(struct rt2560_softc *, | ||||
struct rt2560_tx_desc *, uint32_t, int, int, int, | struct rt2560_tx_desc *, uint32_t, int, int, int, | ||||
bus_addr_t); | bus_addr_t); | ||||
static int rt2560_tx_bcn(struct rt2560_softc *, struct mbuf *, | static int rt2560_tx_bcn(struct rt2560_softc *, struct mbuf *, | ||||
struct ieee80211_node *); | struct ieee80211_node *); | ||||
static int rt2560_tx_mgt(struct rt2560_softc *, struct mbuf *, | static int rt2560_tx_mgt(struct rt2560_softc *, struct mbuf *, | ||||
struct ieee80211_node *); | struct ieee80211_node *); | ||||
static int rt2560_tx_data(struct rt2560_softc *, struct mbuf *, | static int rt2560_tx_data(struct rt2560_softc *, struct mbuf *, | ||||
struct ieee80211_node *); | struct ieee80211_node *); | ||||
static void rt2560_start_locked(struct ifnet *); | static int rt2560_transmit(struct ieee80211com *, struct mbuf *); | ||||
static void rt2560_start(struct ifnet *); | static void rt2560_start(struct rt2560_softc *); | ||||
static void rt2560_watchdog(void *); | static void rt2560_watchdog(void *); | ||||
static int rt2560_ioctl(struct ifnet *, u_long, caddr_t); | static void rt2560_parent(struct ieee80211com *); | ||||
static void rt2560_bbp_write(struct rt2560_softc *, uint8_t, | static void rt2560_bbp_write(struct rt2560_softc *, uint8_t, | ||||
uint8_t); | uint8_t); | ||||
static uint8_t rt2560_bbp_read(struct rt2560_softc *, uint8_t); | static uint8_t rt2560_bbp_read(struct rt2560_softc *, uint8_t); | ||||
static void rt2560_rf_write(struct rt2560_softc *, uint8_t, | static void rt2560_rf_write(struct rt2560_softc *, uint8_t, | ||||
uint32_t); | uint32_t); | ||||
static void rt2560_set_chan(struct rt2560_softc *, | static void rt2560_set_chan(struct rt2560_softc *, | ||||
struct ieee80211_channel *); | struct ieee80211_channel *); | ||||
#if 0 | #if 0 | ||||
static void rt2560_disable_rf_tune(struct rt2560_softc *); | static void rt2560_disable_rf_tune(struct rt2560_softc *); | ||||
#endif | #endif | ||||
static void rt2560_enable_tsf_sync(struct rt2560_softc *); | static void rt2560_enable_tsf_sync(struct rt2560_softc *); | ||||
static void rt2560_enable_tsf(struct rt2560_softc *); | static void rt2560_enable_tsf(struct rt2560_softc *); | ||||
static void rt2560_update_plcp(struct rt2560_softc *); | static void rt2560_update_plcp(struct rt2560_softc *); | ||||
static void rt2560_update_slot(struct ieee80211com *); | static void rt2560_update_slot(struct ieee80211com *); | ||||
static void rt2560_set_basicrates(struct rt2560_softc *, | static void rt2560_set_basicrates(struct rt2560_softc *, | ||||
const struct ieee80211_rateset *); | const struct ieee80211_rateset *); | ||||
static void rt2560_update_led(struct rt2560_softc *, int, int); | static void rt2560_update_led(struct rt2560_softc *, int, int); | ||||
static void rt2560_set_bssid(struct rt2560_softc *, const uint8_t *); | static void rt2560_set_bssid(struct rt2560_softc *, const uint8_t *); | ||||
static void rt2560_set_macaddr(struct rt2560_softc *, uint8_t *); | static void rt2560_set_macaddr(struct rt2560_softc *, | ||||
const uint8_t *); | |||||
static void rt2560_get_macaddr(struct rt2560_softc *, uint8_t *); | static void rt2560_get_macaddr(struct rt2560_softc *, uint8_t *); | ||||
static void rt2560_update_promisc(struct ieee80211com *); | static void rt2560_update_promisc(struct ieee80211com *); | ||||
static const char *rt2560_get_rf(int); | static const char *rt2560_get_rf(int); | ||||
static void rt2560_read_config(struct rt2560_softc *); | static void rt2560_read_config(struct rt2560_softc *); | ||||
static int rt2560_bbp_init(struct rt2560_softc *); | static int rt2560_bbp_init(struct rt2560_softc *); | ||||
static void rt2560_set_txantenna(struct rt2560_softc *, int); | static void rt2560_set_txantenna(struct rt2560_softc *, int); | ||||
static void rt2560_set_rxantenna(struct rt2560_softc *, int); | static void rt2560_set_rxantenna(struct rt2560_softc *, int); | ||||
static void rt2560_init_locked(struct rt2560_softc *); | static void rt2560_init_locked(struct rt2560_softc *); | ||||
Show All 31 Lines | |||||
} rt2560_rf5222[] = { | } rt2560_rf5222[] = { | ||||
RT2560_RF5222 | RT2560_RF5222 | ||||
}; | }; | ||||
int | int | ||||
rt2560_attach(device_t dev, int id) | rt2560_attach(device_t dev, int id) | ||||
{ | { | ||||
struct rt2560_softc *sc = device_get_softc(dev); | struct rt2560_softc *sc = device_get_softc(dev); | ||||
struct ieee80211com *ic; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ifnet *ifp; | |||||
int error; | |||||
uint8_t bands; | uint8_t bands; | ||||
uint8_t macaddr[IEEE80211_ADDR_LEN]; | int error; | ||||
sc->sc_dev = dev; | sc->sc_dev = dev; | ||||
mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, | mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, | ||||
MTX_DEF | MTX_RECURSE); | MTX_DEF | MTX_RECURSE); | ||||
callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0); | callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0); | ||||
mbufq_init(&sc->sc_snd, ifqmaxlen); | |||||
/* retrieve RT2560 rev. no */ | /* retrieve RT2560 rev. no */ | ||||
sc->asic_rev = RAL_READ(sc, RT2560_CSR0); | sc->asic_rev = RAL_READ(sc, RT2560_CSR0); | ||||
/* retrieve RF rev. no and various other things from EEPROM */ | /* retrieve RF rev. no and various other things from EEPROM */ | ||||
rt2560_read_config(sc); | rt2560_read_config(sc); | ||||
device_printf(dev, "MAC/BBP RT2560 (rev 0x%02x), RF %s\n", | device_printf(dev, "MAC/BBP RT2560 (rev 0x%02x), RF %s\n", | ||||
Show All 27 Lines | rt2560_attach(device_t dev, int id) | ||||
} | } | ||||
error = rt2560_alloc_rx_ring(sc, &sc->rxq, RT2560_RX_RING_COUNT); | error = rt2560_alloc_rx_ring(sc, &sc->rxq, RT2560_RX_RING_COUNT); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(sc->sc_dev, "could not allocate Rx ring\n"); | device_printf(sc->sc_dev, "could not allocate Rx ring\n"); | ||||
goto fail5; | goto fail5; | ||||
} | } | ||||
ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); | |||||
if (ifp == NULL) { | |||||
device_printf(sc->sc_dev, "can not if_alloc()\n"); | |||||
goto fail6; | |||||
} | |||||
ic = ifp->if_l2com; | |||||
/* retrieve MAC address */ | /* retrieve MAC address */ | ||||
rt2560_get_macaddr(sc, macaddr); | rt2560_get_macaddr(sc, ic->ic_macaddr); | ||||
ifp->if_softc = sc; | |||||
if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | |||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |||||
ifp->if_init = rt2560_init; | |||||
ifp->if_ioctl = rt2560_ioctl; | |||||
ifp->if_start = rt2560_start; | |||||
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); | |||||
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; | |||||
IFQ_SET_READY(&ifp->if_snd); | |||||
ic->ic_ifp = ifp; | |||||
ic->ic_softc = sc; | ic->ic_softc = sc; | ||||
ic->ic_name = device_get_nameunit(dev); | ic->ic_name = device_get_nameunit(dev); | ||||
ic->ic_opmode = IEEE80211_M_STA; | ic->ic_opmode = IEEE80211_M_STA; | ||||
ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ | ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ | ||||
/* set device capabilities */ | /* set device capabilities */ | ||||
ic->ic_caps = | ic->ic_caps = | ||||
IEEE80211_C_STA /* station mode */ | IEEE80211_C_STA /* station mode */ | ||||
Show All 14 Lines | #endif | ||||
bands = 0; | bands = 0; | ||||
setbit(&bands, IEEE80211_MODE_11B); | setbit(&bands, IEEE80211_MODE_11B); | ||||
setbit(&bands, IEEE80211_MODE_11G); | setbit(&bands, IEEE80211_MODE_11G); | ||||
if (sc->rf_rev == RT2560_RF_5222) | if (sc->rf_rev == RT2560_RF_5222) | ||||
setbit(&bands, IEEE80211_MODE_11A); | setbit(&bands, IEEE80211_MODE_11A); | ||||
ieee80211_init_channels(ic, NULL, &bands); | ieee80211_init_channels(ic, NULL, &bands); | ||||
ieee80211_ifattach(ic, macaddr); | ieee80211_ifattach(ic); | ||||
ic->ic_raw_xmit = rt2560_raw_xmit; | ic->ic_raw_xmit = rt2560_raw_xmit; | ||||
ic->ic_updateslot = rt2560_update_slot; | ic->ic_updateslot = rt2560_update_slot; | ||||
ic->ic_update_promisc = rt2560_update_promisc; | ic->ic_update_promisc = rt2560_update_promisc; | ||||
ic->ic_scan_start = rt2560_scan_start; | ic->ic_scan_start = rt2560_scan_start; | ||||
ic->ic_scan_end = rt2560_scan_end; | ic->ic_scan_end = rt2560_scan_end; | ||||
ic->ic_set_channel = rt2560_set_channel; | ic->ic_set_channel = rt2560_set_channel; | ||||
ic->ic_vap_create = rt2560_vap_create; | ic->ic_vap_create = rt2560_vap_create; | ||||
ic->ic_vap_delete = rt2560_vap_delete; | ic->ic_vap_delete = rt2560_vap_delete; | ||||
ic->ic_parent = rt2560_parent; | |||||
ic->ic_transmit = rt2560_transmit; | |||||
ieee80211_radiotap_attach(ic, | ieee80211_radiotap_attach(ic, | ||||
&sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), | &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), | ||||
RT2560_TX_RADIOTAP_PRESENT, | RT2560_TX_RADIOTAP_PRESENT, | ||||
&sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), | &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), | ||||
RT2560_RX_RADIOTAP_PRESENT); | RT2560_RX_RADIOTAP_PRESENT); | ||||
/* | /* | ||||
Show All 12 Lines | SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), | ||||
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, | SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, | ||||
"rxantenna", CTLFLAG_RW, &sc->rx_ant, 0, "rx antenna (0=auto)"); | "rxantenna", CTLFLAG_RW, &sc->rx_ant, 0, "rx antenna (0=auto)"); | ||||
if (bootverbose) | if (bootverbose) | ||||
ieee80211_announce(ic); | ieee80211_announce(ic); | ||||
return 0; | return 0; | ||||
fail6: rt2560_free_rx_ring(sc, &sc->rxq); | |||||
fail5: rt2560_free_tx_ring(sc, &sc->bcnq); | fail5: rt2560_free_tx_ring(sc, &sc->bcnq); | ||||
fail4: rt2560_free_tx_ring(sc, &sc->prioq); | fail4: rt2560_free_tx_ring(sc, &sc->prioq); | ||||
fail3: rt2560_free_tx_ring(sc, &sc->atimq); | fail3: rt2560_free_tx_ring(sc, &sc->atimq); | ||||
fail2: rt2560_free_tx_ring(sc, &sc->txq); | fail2: rt2560_free_tx_ring(sc, &sc->txq); | ||||
fail1: mtx_destroy(&sc->sc_mtx); | fail1: mtx_destroy(&sc->sc_mtx); | ||||
return ENXIO; | return ENXIO; | ||||
} | } | ||||
int | int | ||||
rt2560_detach(void *xsc) | rt2560_detach(void *xsc) | ||||
{ | { | ||||
struct rt2560_softc *sc = xsc; | struct rt2560_softc *sc = xsc; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
rt2560_stop(sc); | rt2560_stop(sc); | ||||
ieee80211_ifdetach(ic); | ieee80211_ifdetach(ic); | ||||
mbufq_drain(&sc->sc_snd); | |||||
rt2560_free_tx_ring(sc, &sc->txq); | rt2560_free_tx_ring(sc, &sc->txq); | ||||
rt2560_free_tx_ring(sc, &sc->atimq); | rt2560_free_tx_ring(sc, &sc->atimq); | ||||
rt2560_free_tx_ring(sc, &sc->prioq); | rt2560_free_tx_ring(sc, &sc->prioq); | ||||
rt2560_free_tx_ring(sc, &sc->bcnq); | rt2560_free_tx_ring(sc, &sc->bcnq); | ||||
rt2560_free_rx_ring(sc, &sc->rxq); | rt2560_free_rx_ring(sc, &sc->rxq); | ||||
if_free(ifp); | |||||
mtx_destroy(&sc->sc_mtx); | mtx_destroy(&sc->sc_mtx); | ||||
return 0; | return 0; | ||||
} | } | ||||
static struct ieee80211vap * | static struct ieee80211vap * | ||||
rt2560_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, | rt2560_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, | ||||
enum ieee80211_opmode opmode, int flags, | enum ieee80211_opmode opmode, int flags, | ||||
const uint8_t bssid[IEEE80211_ADDR_LEN], | const uint8_t bssid[IEEE80211_ADDR_LEN], | ||||
const uint8_t mac[IEEE80211_ADDR_LEN]) | const uint8_t mac[IEEE80211_ADDR_LEN]) | ||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | struct rt2560_softc *sc = ic->ic_softc; | ||||
struct rt2560_vap *rvp; | struct rt2560_vap *rvp; | ||||
struct ieee80211vap *vap; | struct ieee80211vap *vap; | ||||
switch (opmode) { | switch (opmode) { | ||||
case IEEE80211_M_STA: | case IEEE80211_M_STA: | ||||
case IEEE80211_M_IBSS: | case IEEE80211_M_IBSS: | ||||
case IEEE80211_M_AHDEMO: | case IEEE80211_M_AHDEMO: | ||||
case IEEE80211_M_MONITOR: | case IEEE80211_M_MONITOR: | ||||
case IEEE80211_M_HOSTAP: | case IEEE80211_M_HOSTAP: | ||||
case IEEE80211_M_MBSS: | case IEEE80211_M_MBSS: | ||||
/* XXXRP: TBD */ | /* XXXRP: TBD */ | ||||
if (!TAILQ_EMPTY(&ic->ic_vaps)) { | if (!TAILQ_EMPTY(&ic->ic_vaps)) { | ||||
if_printf(ifp, "only 1 vap supported\n"); | device_printf(sc->sc_dev, "only 1 vap supported\n"); | ||||
return NULL; | return NULL; | ||||
} | } | ||||
if (opmode == IEEE80211_M_STA) | if (opmode == IEEE80211_M_STA) | ||||
flags |= IEEE80211_CLONE_NOBEACONS; | flags |= IEEE80211_CLONE_NOBEACONS; | ||||
break; | break; | ||||
case IEEE80211_M_WDS: | case IEEE80211_M_WDS: | ||||
if (TAILQ_EMPTY(&ic->ic_vaps) || | if (TAILQ_EMPTY(&ic->ic_vaps) || | ||||
ic->ic_opmode != IEEE80211_M_HOSTAP) { | ic->ic_opmode != IEEE80211_M_HOSTAP) { | ||||
if_printf(ifp, "wds only supported in ap mode\n"); | device_printf(sc->sc_dev, | ||||
"wds only supported in ap mode\n"); | |||||
return NULL; | return NULL; | ||||
} | } | ||||
/* | /* | ||||
* Silently remove any request for a unique | * Silently remove any request for a unique | ||||
* bssid; WDS vap's always share the local | * bssid; WDS vap's always share the local | ||||
* mac address. | * mac address. | ||||
*/ | */ | ||||
flags &= ~IEEE80211_CLONE_BSSID; | flags &= ~IEEE80211_CLONE_BSSID; | ||||
break; | break; | ||||
default: | default: | ||||
if_printf(ifp, "unknown opmode %d\n", opmode); | device_printf(sc->sc_dev, "unknown opmode %d\n", opmode); | ||||
return NULL; | return NULL; | ||||
} | } | ||||
rvp = (struct rt2560_vap *) malloc(sizeof(struct rt2560_vap), | rvp = malloc(sizeof(struct rt2560_vap), M_80211_VAP, M_WAITOK | M_ZERO); | ||||
M_80211_VAP, M_NOWAIT | M_ZERO); | |||||
if (rvp == NULL) | |||||
return NULL; | |||||
vap = &rvp->ral_vap; | vap = &rvp->ral_vap; | ||||
ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); | ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); | ||||
/* override state transition machine */ | /* override state transition machine */ | ||||
rvp->ral_newstate = vap->iv_newstate; | rvp->ral_newstate = vap->iv_newstate; | ||||
vap->iv_newstate = rt2560_newstate; | vap->iv_newstate = rt2560_newstate; | ||||
vap->iv_update_beacon = rt2560_beacon_update; | vap->iv_update_beacon = rt2560_beacon_update; | ||||
ieee80211_ratectl_init(vap); | ieee80211_ratectl_init(vap); | ||||
/* complete setup */ | /* complete setup */ | ||||
ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); | ieee80211_vap_attach(vap, ieee80211_media_change, | ||||
ieee80211_media_status, mac); | |||||
if (TAILQ_FIRST(&ic->ic_vaps) == vap) | if (TAILQ_FIRST(&ic->ic_vaps) == vap) | ||||
ic->ic_opmode = opmode; | ic->ic_opmode = opmode; | ||||
return vap; | return vap; | ||||
} | } | ||||
static void | static void | ||||
rt2560_vap_delete(struct ieee80211vap *vap) | rt2560_vap_delete(struct ieee80211vap *vap) | ||||
{ | { | ||||
struct rt2560_vap *rvp = RT2560_VAP(vap); | struct rt2560_vap *rvp = RT2560_VAP(vap); | ||||
ieee80211_ratectl_deinit(vap); | ieee80211_ratectl_deinit(vap); | ||||
ieee80211_vap_detach(vap); | ieee80211_vap_detach(vap); | ||||
free(rvp, M_80211_VAP); | free(rvp, M_80211_VAP); | ||||
} | } | ||||
void | void | ||||
rt2560_resume(void *xsc) | rt2560_resume(void *xsc) | ||||
{ | { | ||||
struct rt2560_softc *sc = xsc; | struct rt2560_softc *sc = xsc; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
if (ifp->if_flags & IFF_UP) | if (sc->sc_ic.ic_nrunning > 0) | ||||
rt2560_init(sc); | rt2560_init(sc); | ||||
} | } | ||||
static void | static void | ||||
rt2560_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) | rt2560_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) | ||||
{ | { | ||||
if (error != 0) | if (error != 0) | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 293 Lines • ▼ Show 20 Lines | rt2560_free_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) | ||||
if (ring->data_dmat != NULL) | if (ring->data_dmat != NULL) | ||||
bus_dma_tag_destroy(ring->data_dmat); | bus_dma_tag_destroy(ring->data_dmat); | ||||
} | } | ||||
static int | static int | ||||
rt2560_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) | rt2560_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) | ||||
{ | { | ||||
struct rt2560_vap *rvp = RT2560_VAP(vap); | struct rt2560_vap *rvp = RT2560_VAP(vap); | ||||
struct ifnet *ifp = vap->iv_ic->ic_ifp; | struct rt2560_softc *sc = vap->iv_ic->ic_softc; | ||||
struct rt2560_softc *sc = ifp->if_softc; | |||||
int error; | int error; | ||||
if (nstate == IEEE80211_S_INIT && vap->iv_state == IEEE80211_S_RUN) { | if (nstate == IEEE80211_S_INIT && vap->iv_state == IEEE80211_S_RUN) { | ||||
/* abort TSF synchronization */ | /* abort TSF synchronization */ | ||||
RAL_WRITE(sc, RT2560_CSR14, 0); | RAL_WRITE(sc, RT2560_CSR14, 0); | ||||
/* turn association led off */ | /* turn association led off */ | ||||
rt2560_update_led(sc, 0, 0); | rt2560_update_led(sc, 0, 0); | ||||
Show All 11 Lines | if (vap->iv_opmode != IEEE80211_M_MONITOR) { | ||||
rt2560_set_bssid(sc, ni->ni_bssid); | rt2560_set_bssid(sc, ni->ni_bssid); | ||||
} | } | ||||
if (vap->iv_opmode == IEEE80211_M_HOSTAP || | if (vap->iv_opmode == IEEE80211_M_HOSTAP || | ||||
vap->iv_opmode == IEEE80211_M_IBSS || | vap->iv_opmode == IEEE80211_M_IBSS || | ||||
vap->iv_opmode == IEEE80211_M_MBSS) { | vap->iv_opmode == IEEE80211_M_MBSS) { | ||||
m = ieee80211_beacon_alloc(ni, &rvp->ral_bo); | m = ieee80211_beacon_alloc(ni, &rvp->ral_bo); | ||||
if (m == NULL) { | if (m == NULL) { | ||||
if_printf(ifp, "could not allocate beacon\n"); | device_printf(sc->sc_dev, | ||||
"could not allocate beacon\n"); | |||||
return ENOBUFS; | return ENOBUFS; | ||||
} | } | ||||
ieee80211_ref_node(ni); | ieee80211_ref_node(ni); | ||||
error = rt2560_tx_bcn(sc, m, ni); | error = rt2560_tx_bcn(sc, m, ni); | ||||
if (error != 0) | if (error != 0) | ||||
return error; | return error; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 117 Lines • ▼ Show 20 Lines | rt2560_encryption_intr(struct rt2560_softc *sc) | ||||
/* kick Tx */ | /* kick Tx */ | ||||
RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_TX); | RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_TX); | ||||
} | } | ||||
static void | static void | ||||
rt2560_tx_intr(struct rt2560_softc *sc) | rt2560_tx_intr(struct rt2560_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct rt2560_tx_desc *desc; | struct rt2560_tx_desc *desc; | ||||
struct rt2560_tx_data *data; | struct rt2560_tx_data *data; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
uint32_t flags; | |||||
int retrycnt; | |||||
struct ieee80211vap *vap; | struct ieee80211vap *vap; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
uint32_t flags; | |||||
int retrycnt, status; | |||||
bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, | bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, | ||||
BUS_DMASYNC_POSTREAD); | BUS_DMASYNC_POSTREAD); | ||||
for (;;) { | for (;;) { | ||||
desc = &sc->txq.desc[sc->txq.next]; | desc = &sc->txq.desc[sc->txq.next]; | ||||
data = &sc->txq.data[sc->txq.next]; | data = &sc->txq.data[sc->txq.next]; | ||||
Show All 11 Lines | for (;;) { | ||||
case RT2560_TX_SUCCESS: | case RT2560_TX_SUCCESS: | ||||
retrycnt = 0; | retrycnt = 0; | ||||
DPRINTFN(sc, 10, "%s\n", "data frame sent successfully"); | DPRINTFN(sc, 10, "%s\n", "data frame sent successfully"); | ||||
if (data->rix != IEEE80211_FIXED_RATE_NONE) | if (data->rix != IEEE80211_FIXED_RATE_NONE) | ||||
ieee80211_ratectl_tx_complete(vap, ni, | ieee80211_ratectl_tx_complete(vap, ni, | ||||
IEEE80211_RATECTL_TX_SUCCESS, | IEEE80211_RATECTL_TX_SUCCESS, | ||||
&retrycnt, NULL); | &retrycnt, NULL); | ||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | status = 0; | ||||
break; | break; | ||||
case RT2560_TX_SUCCESS_RETRY: | case RT2560_TX_SUCCESS_RETRY: | ||||
retrycnt = RT2560_TX_RETRYCNT(flags); | retrycnt = RT2560_TX_RETRYCNT(flags); | ||||
DPRINTFN(sc, 9, "data frame sent after %u retries\n", | DPRINTFN(sc, 9, "data frame sent after %u retries\n", | ||||
retrycnt); | retrycnt); | ||||
if (data->rix != IEEE80211_FIXED_RATE_NONE) | if (data->rix != IEEE80211_FIXED_RATE_NONE) | ||||
ieee80211_ratectl_tx_complete(vap, ni, | ieee80211_ratectl_tx_complete(vap, ni, | ||||
IEEE80211_RATECTL_TX_SUCCESS, | IEEE80211_RATECTL_TX_SUCCESS, | ||||
&retrycnt, NULL); | &retrycnt, NULL); | ||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | status = 0; | ||||
break; | break; | ||||
case RT2560_TX_FAIL_RETRY: | case RT2560_TX_FAIL_RETRY: | ||||
retrycnt = RT2560_TX_RETRYCNT(flags); | retrycnt = RT2560_TX_RETRYCNT(flags); | ||||
DPRINTFN(sc, 9, "data frame failed after %d retries\n", | DPRINTFN(sc, 9, "data frame failed after %d retries\n", | ||||
retrycnt); | retrycnt); | ||||
if (data->rix != IEEE80211_FIXED_RATE_NONE) | if (data->rix != IEEE80211_FIXED_RATE_NONE) | ||||
ieee80211_ratectl_tx_complete(vap, ni, | ieee80211_ratectl_tx_complete(vap, ni, | ||||
IEEE80211_RATECTL_TX_FAILURE, | IEEE80211_RATECTL_TX_FAILURE, | ||||
&retrycnt, NULL); | &retrycnt, NULL); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | status = 1; | ||||
break; | break; | ||||
case RT2560_TX_FAIL_INVALID: | case RT2560_TX_FAIL_INVALID: | ||||
case RT2560_TX_FAIL_OTHER: | case RT2560_TX_FAIL_OTHER: | ||||
default: | default: | ||||
device_printf(sc->sc_dev, "sending data frame failed " | device_printf(sc->sc_dev, "sending data frame failed " | ||||
"0x%08x\n", flags); | "0x%08x\n", flags); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | status = 1; | ||||
} | } | ||||
bus_dmamap_sync(sc->txq.data_dmat, data->map, | bus_dmamap_sync(sc->txq.data_dmat, data->map, | ||||
BUS_DMASYNC_POSTWRITE); | BUS_DMASYNC_POSTWRITE); | ||||
bus_dmamap_unload(sc->txq.data_dmat, data->map); | bus_dmamap_unload(sc->txq.data_dmat, data->map); | ||||
m_freem(m); | |||||
data->m = NULL; | ieee80211_tx_complete(ni, m, status); | ||||
ieee80211_free_node(data->ni); | |||||
data->ni = NULL; | data->ni = NULL; | ||||
data->m = NULL; | |||||
/* descriptor is no longer valid */ | /* descriptor is no longer valid */ | ||||
desc->flags &= ~htole32(RT2560_TX_VALID); | desc->flags &= ~htole32(RT2560_TX_VALID); | ||||
DPRINTFN(sc, 15, "tx done idx=%u\n", sc->txq.next); | DPRINTFN(sc, 15, "tx done idx=%u\n", sc->txq.next); | ||||
sc->txq.queued--; | sc->txq.queued--; | ||||
sc->txq.next = (sc->txq.next + 1) % RT2560_TX_RING_COUNT; | sc->txq.next = (sc->txq.next + 1) % RT2560_TX_RING_COUNT; | ||||
} | } | ||||
bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, | bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, | ||||
BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREWRITE); | ||||
if (sc->prioq.queued == 0 && sc->txq.queued == 0) | if (sc->prioq.queued == 0 && sc->txq.queued == 0) | ||||
sc->sc_tx_timer = 0; | sc->sc_tx_timer = 0; | ||||
if (sc->txq.queued < RT2560_TX_RING_COUNT - 1) { | if (sc->txq.queued < RT2560_TX_RING_COUNT - 1) | ||||
sc->sc_flags &= ~RT2560_F_DATA_OACTIVE; | rt2560_start(sc); | ||||
if ((sc->sc_flags & | |||||
(RT2560_F_DATA_OACTIVE | RT2560_F_PRIO_OACTIVE)) == 0) | |||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
rt2560_start_locked(ifp); | |||||
} | } | ||||
} | |||||
static void | static void | ||||
rt2560_prio_intr(struct rt2560_softc *sc) | rt2560_prio_intr(struct rt2560_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct rt2560_tx_desc *desc; | struct rt2560_tx_desc *desc; | ||||
struct rt2560_tx_data *data; | struct rt2560_tx_data *data; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
int flags; | int flags; | ||||
bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, | bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, | ||||
BUS_DMASYNC_POSTREAD); | BUS_DMASYNC_POSTREAD); | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | rt2560_prio_intr(struct rt2560_softc *sc) | ||||
} | } | ||||
bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, | bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, | ||||
BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREWRITE); | ||||
if (sc->prioq.queued == 0 && sc->txq.queued == 0) | if (sc->prioq.queued == 0 && sc->txq.queued == 0) | ||||
sc->sc_tx_timer = 0; | sc->sc_tx_timer = 0; | ||||
if (sc->prioq.queued < RT2560_PRIO_RING_COUNT) { | if (sc->prioq.queued < RT2560_PRIO_RING_COUNT) | ||||
sc->sc_flags &= ~RT2560_F_PRIO_OACTIVE; | rt2560_start(sc); | ||||
if ((sc->sc_flags & | |||||
(RT2560_F_DATA_OACTIVE | RT2560_F_PRIO_OACTIVE)) == 0) | |||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
rt2560_start_locked(ifp); | |||||
} | } | ||||
} | |||||
/* | /* | ||||
* Some frames were processed by the hardware cipher engine and are ready for | * Some frames were processed by the hardware cipher engine and are ready for | ||||
* handoff to the IEEE802.11 layer. | * handoff to the IEEE802.11 layer. | ||||
*/ | */ | ||||
static void | static void | ||||
rt2560_decryption_intr(struct rt2560_softc *sc) | rt2560_decryption_intr(struct rt2560_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct rt2560_rx_desc *desc; | struct rt2560_rx_desc *desc; | ||||
struct rt2560_rx_data *data; | struct rt2560_rx_data *data; | ||||
bus_addr_t physaddr; | bus_addr_t physaddr; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct mbuf *mnew, *m; | struct mbuf *mnew, *m; | ||||
int hw, error; | int hw, error; | ||||
int8_t rssi, nf; | int8_t rssi, nf; | ||||
Show All 9 Lines | for (; sc->rxq.cur_decrypt != hw;) { | ||||
desc = &sc->rxq.desc[sc->rxq.cur_decrypt]; | desc = &sc->rxq.desc[sc->rxq.cur_decrypt]; | ||||
data = &sc->rxq.data[sc->rxq.cur_decrypt]; | data = &sc->rxq.data[sc->rxq.cur_decrypt]; | ||||
if ((le32toh(desc->flags) & RT2560_RX_BUSY) || | if ((le32toh(desc->flags) & RT2560_RX_BUSY) || | ||||
(le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY)) | (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY)) | ||||
break; | break; | ||||
if (data->drop) { | if (data->drop) { | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
goto skip; | goto skip; | ||||
} | } | ||||
if ((le32toh(desc->flags) & RT2560_RX_CIPHER_MASK) != 0 && | if ((le32toh(desc->flags) & RT2560_RX_CIPHER_MASK) != 0 && | ||||
(le32toh(desc->flags) & RT2560_RX_ICV_ERROR)) { | (le32toh(desc->flags) & RT2560_RX_ICV_ERROR)) { | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
goto skip; | goto skip; | ||||
} | } | ||||
/* | /* | ||||
* Try to allocate a new mbuf for this ring element and load it | * Try to allocate a new mbuf for this ring element and load it | ||||
* before processing the current mbuf. If the ring element | * before processing the current mbuf. If the ring element | ||||
* cannot be loaded, drop the received packet and reuse the old | * cannot be loaded, drop the received packet and reuse the old | ||||
* mbuf. In the unlikely case that the old mbuf can't be | * mbuf. In the unlikely case that the old mbuf can't be | ||||
* reloaded either, explicitly panic. | * reloaded either, explicitly panic. | ||||
*/ | */ | ||||
mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); | mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); | ||||
if (mnew == NULL) { | if (mnew == NULL) { | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
goto skip; | goto skip; | ||||
} | } | ||||
bus_dmamap_sync(sc->rxq.data_dmat, data->map, | bus_dmamap_sync(sc->rxq.data_dmat, data->map, | ||||
BUS_DMASYNC_POSTREAD); | BUS_DMASYNC_POSTREAD); | ||||
bus_dmamap_unload(sc->rxq.data_dmat, data->map); | bus_dmamap_unload(sc->rxq.data_dmat, data->map); | ||||
error = bus_dmamap_load(sc->rxq.data_dmat, data->map, | error = bus_dmamap_load(sc->rxq.data_dmat, data->map, | ||||
mtod(mnew, void *), MCLBYTES, rt2560_dma_map_addr, | mtod(mnew, void *), MCLBYTES, rt2560_dma_map_addr, | ||||
&physaddr, 0); | &physaddr, 0); | ||||
if (error != 0) { | if (error != 0) { | ||||
m_freem(mnew); | m_freem(mnew); | ||||
/* try to reload the old mbuf */ | /* try to reload the old mbuf */ | ||||
error = bus_dmamap_load(sc->rxq.data_dmat, data->map, | error = bus_dmamap_load(sc->rxq.data_dmat, data->map, | ||||
mtod(data->m, void *), MCLBYTES, | mtod(data->m, void *), MCLBYTES, | ||||
rt2560_dma_map_addr, &physaddr, 0); | rt2560_dma_map_addr, &physaddr, 0); | ||||
if (error != 0) { | if (error != 0) { | ||||
/* very unlikely that it will fail... */ | /* very unlikely that it will fail... */ | ||||
panic("%s: could not load old rx mbuf", | panic("%s: could not load old rx mbuf", | ||||
device_get_name(sc->sc_dev)); | device_get_name(sc->sc_dev)); | ||||
} | } | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
goto skip; | goto skip; | ||||
} | } | ||||
/* | /* | ||||
* New mbuf successfully loaded, update Rx ring and continue | * New mbuf successfully loaded, update Rx ring and continue | ||||
* processing. | * processing. | ||||
*/ | */ | ||||
m = data->m; | m = data->m; | ||||
data->m = mnew; | data->m = mnew; | ||||
desc->physaddr = htole32(physaddr); | desc->physaddr = htole32(physaddr); | ||||
/* finalize mbuf */ | /* finalize mbuf */ | ||||
m->m_pkthdr.rcvif = ifp; | |||||
m->m_pkthdr.len = m->m_len = | m->m_pkthdr.len = m->m_len = | ||||
(le32toh(desc->flags) >> 16) & 0xfff; | (le32toh(desc->flags) >> 16) & 0xfff; | ||||
rssi = RT2560_RSSI(sc, desc->rssi); | rssi = RT2560_RSSI(sc, desc->rssi); | ||||
nf = RT2560_NOISE_FLOOR; | nf = RT2560_NOISE_FLOOR; | ||||
if (ieee80211_radiotap_active(ic)) { | if (ieee80211_radiotap_active(ic)) { | ||||
struct rt2560_rx_radiotap_header *tap = &sc->sc_rxtap; | struct rt2560_rx_radiotap_header *tap = &sc->sc_rxtap; | ||||
uint32_t tsf_lo, tsf_hi; | uint32_t tsf_lo, tsf_hi; | ||||
▲ Show 20 Lines • Show All 103 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* This function is called periodically in IBSS mode when a new beacon must be | * This function is called periodically in IBSS mode when a new beacon must be | ||||
* sent out. | * sent out. | ||||
*/ | */ | ||||
static void | static void | ||||
rt2560_beacon_expire(struct rt2560_softc *sc) | rt2560_beacon_expire(struct rt2560_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
struct rt2560_vap *rvp = RT2560_VAP(vap); | struct rt2560_vap *rvp = RT2560_VAP(vap); | ||||
struct rt2560_tx_data *data; | struct rt2560_tx_data *data; | ||||
if (ic->ic_opmode != IEEE80211_M_IBSS && | if (ic->ic_opmode != IEEE80211_M_IBSS && | ||||
ic->ic_opmode != IEEE80211_M_HOSTAP && | ic->ic_opmode != IEEE80211_M_HOSTAP && | ||||
ic->ic_opmode != IEEE80211_M_MBSS) | ic->ic_opmode != IEEE80211_M_MBSS) | ||||
return; | return; | ||||
Show All 24 Lines | |||||
{ | { | ||||
DPRINTFN(sc, 2, "%s", "wakeup expired\n"); | DPRINTFN(sc, 2, "%s", "wakeup expired\n"); | ||||
} | } | ||||
void | void | ||||
rt2560_intr(void *arg) | rt2560_intr(void *arg) | ||||
{ | { | ||||
struct rt2560_softc *sc = arg; | struct rt2560_softc *sc = arg; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
uint32_t r; | uint32_t r; | ||||
RAL_LOCK(sc); | RAL_LOCK(sc); | ||||
/* disable interrupts */ | /* disable interrupts */ | ||||
RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); | RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); | ||||
/* don't re-enable interrupts if we're shutting down */ | /* don't re-enable interrupts if we're shutting down */ | ||||
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { | if (!(sc->sc_flags & RT2560_F_RUNNING)) { | ||||
RAL_UNLOCK(sc); | RAL_UNLOCK(sc); | ||||
return; | return; | ||||
} | } | ||||
r = RAL_READ(sc, RT2560_CSR7); | r = RAL_READ(sc, RT2560_CSR7); | ||||
RAL_WRITE(sc, RT2560_CSR7, r); | RAL_WRITE(sc, RT2560_CSR7, r); | ||||
if (r & RT2560_BEACON_EXPIRE) | if (r & RT2560_BEACON_EXPIRE) | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | rt2560_plcp_signal(int rate) | ||||
} | } | ||||
return 0xff; /* XXX unsupported/unknown rate */ | return 0xff; /* XXX unsupported/unknown rate */ | ||||
} | } | ||||
static void | static void | ||||
rt2560_setup_tx_desc(struct rt2560_softc *sc, struct rt2560_tx_desc *desc, | rt2560_setup_tx_desc(struct rt2560_softc *sc, struct rt2560_tx_desc *desc, | ||||
uint32_t flags, int len, int rate, int encrypt, bus_addr_t physaddr) | uint32_t flags, int len, int rate, int encrypt, bus_addr_t physaddr) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
uint16_t plcp_length; | uint16_t plcp_length; | ||||
int remainder; | int remainder; | ||||
desc->flags = htole32(flags); | desc->flags = htole32(flags); | ||||
desc->flags |= htole32(len << 16); | desc->flags |= htole32(len << 16); | ||||
desc->physaddr = htole32(physaddr); | desc->physaddr = htole32(physaddr); | ||||
desc->wme = htole16( | desc->wme = htole16( | ||||
▲ Show 20 Lines • Show All 458 Lines • ▼ Show 20 Lines | rt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0, | ||||
/* kick encrypt */ | /* kick encrypt */ | ||||
sc->txq.queued++; | sc->txq.queued++; | ||||
sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; | sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT; | ||||
RAL_WRITE(sc, RT2560_SECCSR1, RT2560_KICK_ENCRYPT); | RAL_WRITE(sc, RT2560_SECCSR1, RT2560_KICK_ENCRYPT); | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | |||||
rt2560_transmit(struct ieee80211com *ic, struct mbuf *m) | |||||
{ | |||||
struct rt2560_softc *sc = ic->ic_softc; | |||||
int error; | |||||
RAL_LOCK(sc); | |||||
if ((sc->sc_flags & RT2560_F_RUNNING) == 0) { | |||||
RAL_UNLOCK(sc); | |||||
return (ENXIO); | |||||
} | |||||
error = mbufq_enqueue(&sc->sc_snd, m); | |||||
if (error) { | |||||
RAL_UNLOCK(sc); | |||||
return (error); | |||||
} | |||||
rt2560_start(sc); | |||||
RAL_UNLOCK(sc); | |||||
return (0); | |||||
} | |||||
static void | static void | ||||
rt2560_start_locked(struct ifnet *ifp) | rt2560_start(struct rt2560_softc *sc) | ||||
{ | { | ||||
struct rt2560_softc *sc = ifp->if_softc; | |||||
struct mbuf *m; | |||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct mbuf *m; | |||||
RAL_LOCK_ASSERT(sc); | RAL_LOCK_ASSERT(sc); | ||||
for (;;) { | while (sc->txq.queued < RT2560_TX_RING_COUNT - 1 && | ||||
IFQ_DRV_DEQUEUE(&ifp->if_snd, m); | (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { | ||||
if (m == NULL) | |||||
break; | |||||
if (sc->txq.queued >= RT2560_TX_RING_COUNT - 1) { | |||||
IFQ_DRV_PREPEND(&ifp->if_snd, m); | |||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | |||||
sc->sc_flags |= RT2560_F_DATA_OACTIVE; | |||||
break; | |||||
} | |||||
ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; | ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; | ||||
if (rt2560_tx_data(sc, m, ni) != 0) { | if (rt2560_tx_data(sc, m, ni) != 0) { | ||||
if_inc_counter(ni->ni_vap->iv_ifp, | |||||
IFCOUNTER_OERRORS, 1); | |||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
break; | break; | ||||
} | } | ||||
sc->sc_tx_timer = 5; | sc->sc_tx_timer = 5; | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
rt2560_start(struct ifnet *ifp) | |||||
{ | |||||
struct rt2560_softc *sc = ifp->if_softc; | |||||
RAL_LOCK(sc); | |||||
rt2560_start_locked(ifp); | |||||
RAL_UNLOCK(sc); | |||||
} | |||||
static void | |||||
rt2560_watchdog(void *arg) | rt2560_watchdog(void *arg) | ||||
{ | { | ||||
struct rt2560_softc *sc = arg; | struct rt2560_softc *sc = arg; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
RAL_LOCK_ASSERT(sc); | RAL_LOCK_ASSERT(sc); | ||||
KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, ("not running")); | KASSERT(sc->sc_flags & RT2560_F_RUNNING, ("not running")); | ||||
if (sc->sc_invalid) /* card ejected */ | if (sc->sc_invalid) /* card ejected */ | ||||
return; | return; | ||||
rt2560_encryption_intr(sc); | rt2560_encryption_intr(sc); | ||||
rt2560_tx_intr(sc); | rt2560_tx_intr(sc); | ||||
if (sc->sc_tx_timer > 0 && --sc->sc_tx_timer == 0) { | if (sc->sc_tx_timer > 0 && --sc->sc_tx_timer == 0) { | ||||
if_printf(ifp, "device timeout\n"); | device_printf(sc->sc_dev, "device timeout\n"); | ||||
rt2560_init_locked(sc); | rt2560_init_locked(sc); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | counter_u64_add(sc->sc_ic.ic_oerrors, 1); | ||||
/* NB: callout is reset in rt2560_init() */ | /* NB: callout is reset in rt2560_init() */ | ||||
return; | return; | ||||
} | } | ||||
callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); | callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); | ||||
} | } | ||||
static int | static void | ||||
rt2560_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | rt2560_parent(struct ieee80211com *ic) | ||||
{ | { | ||||
struct rt2560_softc *sc = ifp->if_softc; | struct rt2560_softc *sc = ic->ic_softc; | ||||
struct ieee80211com *ic = ifp->if_l2com; | int startall = 0; | ||||
struct ifreq *ifr = (struct ifreq *) data; | |||||
int error = 0, startall = 0; | |||||
switch (cmd) { | |||||
case SIOCSIFFLAGS: | |||||
RAL_LOCK(sc); | RAL_LOCK(sc); | ||||
if (ifp->if_flags & IFF_UP) { | if (ic->ic_nrunning > 0) { | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | if ((sc->sc_flags & RT2560_F_RUNNING) == 0) { | ||||
rt2560_init_locked(sc); | rt2560_init_locked(sc); | ||||
startall = 1; | startall = 1; | ||||
} else | } else | ||||
rt2560_update_promisc(ic); | rt2560_update_promisc(ic); | ||||
} else { | } else if (sc->sc_flags & RT2560_F_RUNNING) | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | |||||
rt2560_stop_locked(sc); | rt2560_stop_locked(sc); | ||||
} | |||||
RAL_UNLOCK(sc); | RAL_UNLOCK(sc); | ||||
if (startall) | if (startall) | ||||
ieee80211_start_all(ic); | ieee80211_start_all(ic); | ||||
break; | |||||
case SIOCGIFMEDIA: | |||||
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); | |||||
break; | |||||
case SIOCGIFADDR: | |||||
error = ether_ioctl(ifp, cmd, data); | |||||
break; | |||||
default: | |||||
error = EINVAL; | |||||
break; | |||||
} | } | ||||
return error; | |||||
} | |||||
static void | static void | ||||
rt2560_bbp_write(struct rt2560_softc *sc, uint8_t reg, uint8_t val) | rt2560_bbp_write(struct rt2560_softc *sc, uint8_t reg, uint8_t val) | ||||
{ | { | ||||
uint32_t tmp; | uint32_t tmp; | ||||
int ntries; | int ntries; | ||||
for (ntries = 0; ntries < 100; ntries++) { | for (ntries = 0; ntries < 100; ntries++) { | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | rt2560_rf_write(struct rt2560_softc *sc, uint8_t reg, uint32_t val) | ||||
sc->rf_regs[reg] = val; | sc->rf_regs[reg] = val; | ||||
DPRINTFN(sc, 15, "RF R[%u] <- 0x%05x\n", reg & 0x3, val & 0xfffff); | DPRINTFN(sc, 15, "RF R[%u] <- 0x%05x\n", reg & 0x3, val & 0xfffff); | ||||
} | } | ||||
static void | static void | ||||
rt2560_set_chan(struct rt2560_softc *sc, struct ieee80211_channel *c) | rt2560_set_chan(struct rt2560_softc *sc, struct ieee80211_channel *c) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
uint8_t power, tmp; | uint8_t power, tmp; | ||||
u_int i, chan; | u_int i, chan; | ||||
chan = ieee80211_chan2ieee(ic, c); | chan = ieee80211_chan2ieee(ic, c); | ||||
KASSERT(chan != 0 && chan != IEEE80211_CHAN_ANY, ("chan 0x%x", chan)); | KASSERT(chan != 0 && chan != IEEE80211_CHAN_ANY, ("chan 0x%x", chan)); | ||||
if (IEEE80211_IS_CHAN_2GHZ(c)) | if (IEEE80211_IS_CHAN_2GHZ(c)) | ||||
power = min(sc->txpow[chan - 1], 31); | power = min(sc->txpow[chan - 1], 31); | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { | ||||
/* clear CRC errors */ | /* clear CRC errors */ | ||||
RAL_READ(sc, RT2560_CNT0); | RAL_READ(sc, RT2560_CNT0); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
rt2560_set_channel(struct ieee80211com *ic) | rt2560_set_channel(struct ieee80211com *ic) | ||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | struct rt2560_softc *sc = ic->ic_softc; | ||||
struct rt2560_softc *sc = ifp->if_softc; | |||||
RAL_LOCK(sc); | RAL_LOCK(sc); | ||||
rt2560_set_chan(sc, ic->ic_curchan); | rt2560_set_chan(sc, ic->ic_curchan); | ||||
RAL_UNLOCK(sc); | RAL_UNLOCK(sc); | ||||
} | } | ||||
#if 0 | #if 0 | ||||
Show All 19 Lines | |||||
/* | /* | ||||
* Refer to IEEE Std 802.11-1999 pp. 123 for more information on TSF | * Refer to IEEE Std 802.11-1999 pp. 123 for more information on TSF | ||||
* synchronization. | * synchronization. | ||||
*/ | */ | ||||
static void | static void | ||||
rt2560_enable_tsf_sync(struct rt2560_softc *sc) | rt2560_enable_tsf_sync(struct rt2560_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
uint16_t logcwmin, preload; | uint16_t logcwmin, preload; | ||||
uint32_t tmp; | uint32_t tmp; | ||||
/* first, disable TSF synchronization */ | /* first, disable TSF synchronization */ | ||||
RAL_WRITE(sc, RT2560_CSR14, 0); | RAL_WRITE(sc, RT2560_CSR14, 0); | ||||
tmp = 16 * vap->iv_bss->ni_intval; | tmp = 16 * vap->iv_bss->ni_intval; | ||||
Show All 24 Lines | rt2560_enable_tsf(struct rt2560_softc *sc) | ||||
RAL_WRITE(sc, RT2560_CSR14, 0); | RAL_WRITE(sc, RT2560_CSR14, 0); | ||||
RAL_WRITE(sc, RT2560_CSR14, | RAL_WRITE(sc, RT2560_CSR14, | ||||
RT2560_ENABLE_TSF_SYNC(2) | RT2560_ENABLE_TSF); | RT2560_ENABLE_TSF_SYNC(2) | RT2560_ENABLE_TSF); | ||||
} | } | ||||
static void | static void | ||||
rt2560_update_plcp(struct rt2560_softc *sc) | rt2560_update_plcp(struct rt2560_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
/* no short preamble for 1Mbps */ | /* no short preamble for 1Mbps */ | ||||
RAL_WRITE(sc, RT2560_PLCP1MCSR, 0x00700400); | RAL_WRITE(sc, RT2560_PLCP1MCSR, 0x00700400); | ||||
if (!(ic->ic_flags & IEEE80211_F_SHPREAMBLE)) { | if (!(ic->ic_flags & IEEE80211_F_SHPREAMBLE)) { | ||||
/* values taken from the reference driver */ | /* values taken from the reference driver */ | ||||
RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380401); | RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380401); | ||||
RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x00150402); | RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x00150402); | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | #endif | ||||
DPRINTF(sc, "setting slottime to %uus\n", slottime); | DPRINTF(sc, "setting slottime to %uus\n", slottime); | ||||
} | } | ||||
static void | static void | ||||
rt2560_set_basicrates(struct rt2560_softc *sc, | rt2560_set_basicrates(struct rt2560_softc *sc, | ||||
const struct ieee80211_rateset *rs) | const struct ieee80211_rateset *rs) | ||||
{ | { | ||||
#define RV(r) ((r) & IEEE80211_RATE_VAL) | #define RV(r) ((r) & IEEE80211_RATE_VAL) | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
uint32_t mask = 0; | uint32_t mask = 0; | ||||
uint8_t rate; | uint8_t rate; | ||||
int i; | int i; | ||||
for (i = 0; i < rs->rs_nrates; i++) { | for (i = 0; i < rs->rs_nrates; i++) { | ||||
rate = rs->rs_rates[i]; | rate = rs->rs_rates[i]; | ||||
if (!(rate & IEEE80211_RATE_BASIC)) | if (!(rate & IEEE80211_RATE_BASIC)) | ||||
Show All 28 Lines | rt2560_set_bssid(struct rt2560_softc *sc, const uint8_t *bssid) | ||||
tmp = bssid[4] | bssid[5] << 8; | tmp = bssid[4] | bssid[5] << 8; | ||||
RAL_WRITE(sc, RT2560_CSR6, tmp); | RAL_WRITE(sc, RT2560_CSR6, tmp); | ||||
DPRINTF(sc, "setting BSSID to %6D\n", bssid, ":"); | DPRINTF(sc, "setting BSSID to %6D\n", bssid, ":"); | ||||
} | } | ||||
static void | static void | ||||
rt2560_set_macaddr(struct rt2560_softc *sc, uint8_t *addr) | rt2560_set_macaddr(struct rt2560_softc *sc, const uint8_t *addr) | ||||
{ | { | ||||
uint32_t tmp; | uint32_t tmp; | ||||
tmp = addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24; | tmp = addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24; | ||||
RAL_WRITE(sc, RT2560_CSR3, tmp); | RAL_WRITE(sc, RT2560_CSR3, tmp); | ||||
tmp = addr[4] | addr[5] << 8; | tmp = addr[4] | addr[5] << 8; | ||||
RAL_WRITE(sc, RT2560_CSR4, tmp); | RAL_WRITE(sc, RT2560_CSR4, tmp); | ||||
Show All 21 Lines | |||||
rt2560_update_promisc(struct ieee80211com *ic) | rt2560_update_promisc(struct ieee80211com *ic) | ||||
{ | { | ||||
struct rt2560_softc *sc = ic->ic_softc; | struct rt2560_softc *sc = ic->ic_softc; | ||||
uint32_t tmp; | uint32_t tmp; | ||||
tmp = RAL_READ(sc, RT2560_RXCSR0); | tmp = RAL_READ(sc, RT2560_RXCSR0); | ||||
tmp &= ~RT2560_DROP_NOT_TO_ME; | tmp &= ~RT2560_DROP_NOT_TO_ME; | ||||
if (!(ic->ic_ifp->if_flags & IFF_PROMISC)) | if (ic->ic_promisc == 0) | ||||
tmp |= RT2560_DROP_NOT_TO_ME; | tmp |= RT2560_DROP_NOT_TO_ME; | ||||
RAL_WRITE(sc, RT2560_RXCSR0, tmp); | RAL_WRITE(sc, RT2560_RXCSR0, tmp); | ||||
DPRINTF(sc, "%s promiscuous mode\n", | DPRINTF(sc, "%s promiscuous mode\n", | ||||
(ic->ic_ifp->if_flags & IFF_PROMISC) ? "entering" : "leaving"); | (ic->ic_promisc > 0) ? "entering" : "leaving"); | ||||
} | } | ||||
static const char * | static const char * | ||||
rt2560_get_rf(int rev) | rt2560_get_rf(int rev) | ||||
{ | { | ||||
switch (rev) { | switch (rev) { | ||||
case RT2560_RF_2522: return "RT2522"; | case RT2560_RF_2522: return "RT2522"; | ||||
case RT2560_RF_2523: return "RT2523"; | case RT2560_RF_2523: return "RT2523"; | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | rt2560_read_config(struct rt2560_softc *sc) | ||||
DPRINTF(sc, "rssi correction %d, calibrate 0x%02x\n", | DPRINTF(sc, "rssi correction %d, calibrate 0x%02x\n", | ||||
sc->rssi_corr, val); | sc->rssi_corr, val); | ||||
} | } | ||||
static void | static void | ||||
rt2560_scan_start(struct ieee80211com *ic) | rt2560_scan_start(struct ieee80211com *ic) | ||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | struct rt2560_softc *sc = ic->ic_softc; | ||||
struct rt2560_softc *sc = ifp->if_softc; | |||||
/* abort TSF synchronization */ | /* abort TSF synchronization */ | ||||
RAL_WRITE(sc, RT2560_CSR14, 0); | RAL_WRITE(sc, RT2560_CSR14, 0); | ||||
rt2560_set_bssid(sc, ifp->if_broadcastaddr); | rt2560_set_bssid(sc, ieee80211broadcastaddr); | ||||
} | } | ||||
static void | static void | ||||
rt2560_scan_end(struct ieee80211com *ic) | rt2560_scan_end(struct ieee80211com *ic) | ||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | struct rt2560_softc *sc = ic->ic_softc; | ||||
struct rt2560_softc *sc = ifp->if_softc; | |||||
struct ieee80211vap *vap = ic->ic_scan->ss_vap; | struct ieee80211vap *vap = ic->ic_scan->ss_vap; | ||||
rt2560_enable_tsf_sync(sc); | rt2560_enable_tsf_sync(sc); | ||||
/* XXX keep local copy */ | /* XXX keep local copy */ | ||||
rt2560_set_bssid(sc, vap->iv_bss->ni_bssid); | rt2560_set_bssid(sc, vap->iv_bss->ni_bssid); | ||||
} | } | ||||
static int | static int | ||||
▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | rt2560_set_rxantenna(struct rt2560_softc *sc, int antenna) | ||||
rt2560_bbp_write(sc, RT2560_BBP_RX, rx); | rt2560_bbp_write(sc, RT2560_BBP_RX, rx); | ||||
} | } | ||||
static void | static void | ||||
rt2560_init_locked(struct rt2560_softc *sc) | rt2560_init_locked(struct rt2560_softc *sc) | ||||
{ | { | ||||
#define N(a) (sizeof (a) / sizeof ((a)[0])) | #define N(a) (sizeof (a) / sizeof ((a)[0])) | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
uint32_t tmp; | uint32_t tmp; | ||||
int i; | int i; | ||||
RAL_LOCK_ASSERT(sc); | RAL_LOCK_ASSERT(sc); | ||||
rt2560_stop_locked(sc); | rt2560_stop_locked(sc); | ||||
/* setup tx rings */ | /* setup tx rings */ | ||||
Show All 14 Lines | #define N(a) (sizeof (a) / sizeof ((a)[0])) | ||||
RAL_WRITE(sc, RT2560_RXCSR1, tmp); | RAL_WRITE(sc, RT2560_RXCSR1, tmp); | ||||
RAL_WRITE(sc, RT2560_RXCSR2, sc->rxq.physaddr); | RAL_WRITE(sc, RT2560_RXCSR2, sc->rxq.physaddr); | ||||
/* initialize MAC registers to default values */ | /* initialize MAC registers to default values */ | ||||
for (i = 0; i < N(rt2560_def_mac); i++) | for (i = 0; i < N(rt2560_def_mac); i++) | ||||
RAL_WRITE(sc, rt2560_def_mac[i].reg, rt2560_def_mac[i].val); | RAL_WRITE(sc, rt2560_def_mac[i].reg, rt2560_def_mac[i].val); | ||||
rt2560_set_macaddr(sc, IF_LLADDR(ifp)); | rt2560_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); | ||||
/* set basic rate set (will be updated later) */ | /* set basic rate set (will be updated later) */ | ||||
RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x153); | RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x153); | ||||
rt2560_update_slot(ic); | rt2560_update_slot(ic); | ||||
rt2560_update_plcp(sc); | rt2560_update_plcp(sc); | ||||
rt2560_update_led(sc, 0, 0); | rt2560_update_led(sc, 0, 0); | ||||
Show All 13 Lines | #define N(a) (sizeof (a) / sizeof ((a)[0])) | ||||
/* kick Rx */ | /* kick Rx */ | ||||
tmp = RT2560_DROP_PHY_ERROR | RT2560_DROP_CRC_ERROR; | tmp = RT2560_DROP_PHY_ERROR | RT2560_DROP_CRC_ERROR; | ||||
if (ic->ic_opmode != IEEE80211_M_MONITOR) { | if (ic->ic_opmode != IEEE80211_M_MONITOR) { | ||||
tmp |= RT2560_DROP_CTL | RT2560_DROP_VERSION_ERROR; | tmp |= RT2560_DROP_CTL | RT2560_DROP_VERSION_ERROR; | ||||
if (ic->ic_opmode != IEEE80211_M_HOSTAP && | if (ic->ic_opmode != IEEE80211_M_HOSTAP && | ||||
ic->ic_opmode != IEEE80211_M_MBSS) | ic->ic_opmode != IEEE80211_M_MBSS) | ||||
tmp |= RT2560_DROP_TODS; | tmp |= RT2560_DROP_TODS; | ||||
if (!(ifp->if_flags & IFF_PROMISC)) | if (ic->ic_promisc == 0) | ||||
tmp |= RT2560_DROP_NOT_TO_ME; | tmp |= RT2560_DROP_NOT_TO_ME; | ||||
} | } | ||||
RAL_WRITE(sc, RT2560_RXCSR0, tmp); | RAL_WRITE(sc, RT2560_RXCSR0, tmp); | ||||
/* clear old FCS and Rx FIFO errors */ | /* clear old FCS and Rx FIFO errors */ | ||||
RAL_READ(sc, RT2560_CNT0); | RAL_READ(sc, RT2560_CNT0); | ||||
RAL_READ(sc, RT2560_CNT4); | RAL_READ(sc, RT2560_CNT4); | ||||
/* clear any pending interrupts */ | /* clear any pending interrupts */ | ||||
RAL_WRITE(sc, RT2560_CSR7, 0xffffffff); | RAL_WRITE(sc, RT2560_CSR7, 0xffffffff); | ||||
/* enable interrupts */ | /* enable interrupts */ | ||||
RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); | RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | sc->sc_flags |= RT2560_F_RUNNING; | ||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | |||||
callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); | callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); | ||||
#undef N | #undef N | ||||
} | } | ||||
static void | static void | ||||
rt2560_init(void *priv) | rt2560_init(void *priv) | ||||
{ | { | ||||
struct rt2560_softc *sc = priv; | struct rt2560_softc *sc = priv; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
RAL_LOCK(sc); | RAL_LOCK(sc); | ||||
rt2560_init_locked(sc); | rt2560_init_locked(sc); | ||||
RAL_UNLOCK(sc); | RAL_UNLOCK(sc); | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (sc->sc_flags & RT2560_F_RUNNING) | ||||
ieee80211_start_all(ic); /* start all vap's */ | ieee80211_start_all(ic); /* start all vap's */ | ||||
} | } | ||||
static void | static void | ||||
rt2560_stop_locked(struct rt2560_softc *sc) | rt2560_stop_locked(struct rt2560_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
volatile int *flags = &sc->sc_flags; | volatile int *flags = &sc->sc_flags; | ||||
RAL_LOCK_ASSERT(sc); | RAL_LOCK_ASSERT(sc); | ||||
while (*flags & RT2560_F_INPUT_RUNNING) | while (*flags & RT2560_F_INPUT_RUNNING) | ||||
msleep(sc, &sc->sc_mtx, 0, "ralrunning", hz/10); | msleep(sc, &sc->sc_mtx, 0, "ralrunning", hz/10); | ||||
callout_stop(&sc->watchdog_ch); | callout_stop(&sc->watchdog_ch); | ||||
sc->sc_tx_timer = 0; | sc->sc_tx_timer = 0; | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | if (sc->sc_flags & RT2560_F_RUNNING) { | ||||
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); | sc->sc_flags &= ~RT2560_F_RUNNING; | ||||
/* abort Tx */ | /* abort Tx */ | ||||
RAL_WRITE(sc, RT2560_TXCSR0, RT2560_ABORT_TX); | RAL_WRITE(sc, RT2560_TXCSR0, RT2560_ABORT_TX); | ||||
/* disable Rx */ | /* disable Rx */ | ||||
RAL_WRITE(sc, RT2560_RXCSR0, RT2560_DISABLE_RX); | RAL_WRITE(sc, RT2560_RXCSR0, RT2560_DISABLE_RX); | ||||
/* reset ASIC (imply reset BBP) */ | /* reset ASIC (imply reset BBP) */ | ||||
RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); | RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); | ||||
RAL_WRITE(sc, RT2560_CSR1, 0); | RAL_WRITE(sc, RT2560_CSR1, 0); | ||||
/* disable interrupts */ | /* disable interrupts */ | ||||
RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); | RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); | ||||
/* reset Tx and Rx rings */ | /* reset Tx and Rx rings */ | ||||
rt2560_reset_tx_ring(sc, &sc->txq); | rt2560_reset_tx_ring(sc, &sc->txq); | ||||
rt2560_reset_tx_ring(sc, &sc->atimq); | rt2560_reset_tx_ring(sc, &sc->atimq); | ||||
rt2560_reset_tx_ring(sc, &sc->prioq); | rt2560_reset_tx_ring(sc, &sc->prioq); | ||||
rt2560_reset_tx_ring(sc, &sc->bcnq); | rt2560_reset_tx_ring(sc, &sc->bcnq); | ||||
rt2560_reset_rx_ring(sc, &sc->rxq); | rt2560_reset_rx_ring(sc, &sc->rxq); | ||||
} | } | ||||
sc->sc_flags &= ~(RT2560_F_PRIO_OACTIVE | RT2560_F_DATA_OACTIVE); | |||||
} | } | ||||
void | void | ||||
rt2560_stop(void *arg) | rt2560_stop(void *arg) | ||||
{ | { | ||||
struct rt2560_softc *sc = arg; | struct rt2560_softc *sc = arg; | ||||
RAL_LOCK(sc); | RAL_LOCK(sc); | ||||
rt2560_stop_locked(sc); | rt2560_stop_locked(sc); | ||||
RAL_UNLOCK(sc); | RAL_UNLOCK(sc); | ||||
} | } | ||||
static int | static int | ||||
rt2560_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, | rt2560_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, | ||||
const struct ieee80211_bpf_params *params) | const struct ieee80211_bpf_params *params) | ||||
{ | { | ||||
struct ieee80211com *ic = ni->ni_ic; | struct ieee80211com *ic = ni->ni_ic; | ||||
struct ifnet *ifp = ic->ic_ifp; | struct rt2560_softc *sc = ic->ic_softc; | ||||
struct rt2560_softc *sc = ifp->if_softc; | |||||
RAL_LOCK(sc); | RAL_LOCK(sc); | ||||
/* prevent management frames from being sent if we're not ready */ | /* prevent management frames from being sent if we're not ready */ | ||||
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { | if (!(sc->sc_flags & RT2560_F_RUNNING)) { | ||||
RAL_UNLOCK(sc); | RAL_UNLOCK(sc); | ||||
m_freem(m); | m_freem(m); | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
return ENETDOWN; | return ENETDOWN; | ||||
} | } | ||||
if (sc->prioq.queued >= RT2560_PRIO_RING_COUNT) { | if (sc->prioq.queued >= RT2560_PRIO_RING_COUNT) { | ||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | |||||
sc->sc_flags |= RT2560_F_PRIO_OACTIVE; | |||||
RAL_UNLOCK(sc); | RAL_UNLOCK(sc); | ||||
m_freem(m); | m_freem(m); | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
return ENOBUFS; /* XXX */ | return ENOBUFS; /* XXX */ | ||||
} | } | ||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | |||||
if (params == NULL) { | if (params == NULL) { | ||||
/* | /* | ||||
* Legacy path; interpret frame contents to decide | * Legacy path; interpret frame contents to decide | ||||
* precisely how to send the frame. | * precisely how to send the frame. | ||||
*/ | */ | ||||
if (rt2560_tx_mgt(sc, m, ni) != 0) | if (rt2560_tx_mgt(sc, m, ni) != 0) | ||||
goto bad; | goto bad; | ||||
} else { | } else { | ||||
/* | /* | ||||
* Caller supplied explicit parameters to use in | * Caller supplied explicit parameters to use in | ||||
* sending the frame. | * sending the frame. | ||||
*/ | */ | ||||
if (rt2560_tx_raw(sc, m, ni, params)) | if (rt2560_tx_raw(sc, m, ni, params)) | ||||
goto bad; | goto bad; | ||||
} | } | ||||
sc->sc_tx_timer = 5; | sc->sc_tx_timer = 5; | ||||
RAL_UNLOCK(sc); | RAL_UNLOCK(sc); | ||||
return 0; | return 0; | ||||
bad: | bad: | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
RAL_UNLOCK(sc); | RAL_UNLOCK(sc); | ||||
return EIO; /* XXX */ | return EIO; /* XXX */ | ||||
} | } |