Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/bwi/if_bwi.c
Show First 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | struct bwi_myaddr_bssid { | ||||
uint8_t bssid[IEEE80211_ADDR_LEN]; | uint8_t bssid[IEEE80211_ADDR_LEN]; | ||||
} __packed; | } __packed; | ||||
static struct ieee80211vap *bwi_vap_create(struct ieee80211com *, | static struct ieee80211vap *bwi_vap_create(struct ieee80211com *, | ||||
const char [IFNAMSIZ], int, enum ieee80211_opmode, int, | const char [IFNAMSIZ], int, enum ieee80211_opmode, int, | ||||
const uint8_t [IEEE80211_ADDR_LEN], | const uint8_t [IEEE80211_ADDR_LEN], | ||||
const uint8_t [IEEE80211_ADDR_LEN]); | const uint8_t [IEEE80211_ADDR_LEN]); | ||||
static void bwi_vap_delete(struct ieee80211vap *); | static void bwi_vap_delete(struct ieee80211vap *); | ||||
static void bwi_init(void *); | static void bwi_init(struct bwi_softc *); | ||||
static int bwi_ioctl(struct ifnet *, u_long, caddr_t); | static void bwi_parent(struct ieee80211com *); | ||||
static void bwi_start(struct ifnet *); | static int bwi_transmit(struct ieee80211com *, struct mbuf *); | ||||
static void bwi_start_locked(struct ifnet *); | static void bwi_start_locked(struct bwi_softc *); | ||||
static int bwi_raw_xmit(struct ieee80211_node *, struct mbuf *, | static int bwi_raw_xmit(struct ieee80211_node *, struct mbuf *, | ||||
const struct ieee80211_bpf_params *); | const struct ieee80211_bpf_params *); | ||||
static void bwi_watchdog(void *); | static void bwi_watchdog(void *); | ||||
static void bwi_scan_start(struct ieee80211com *); | static void bwi_scan_start(struct ieee80211com *); | ||||
static void bwi_set_channel(struct ieee80211com *); | static void bwi_set_channel(struct ieee80211com *); | ||||
static void bwi_scan_end(struct ieee80211com *); | static void bwi_scan_end(struct ieee80211com *); | ||||
static int bwi_newstate(struct ieee80211vap *, enum ieee80211_state, int); | static int bwi_newstate(struct ieee80211vap *, enum ieee80211_state, int); | ||||
static void bwi_updateslot(struct ieee80211com *); | static void bwi_updateslot(struct ieee80211com *); | ||||
▲ Show 20 Lines • Show All 230 Lines • ▼ Show 20 Lines | bwi_setup_desc32(struct bwi_softc *sc, struct bwi_desc32 *desc_array, | ||||
desc->addr = htole32(addr); | desc->addr = htole32(addr); | ||||
desc->ctrl = htole32(ctrl); | desc->ctrl = htole32(ctrl); | ||||
} | } | ||||
int | int | ||||
bwi_attach(struct bwi_softc *sc) | bwi_attach(struct bwi_softc *sc) | ||||
{ | { | ||||
struct ieee80211com *ic; | struct ieee80211com *ic = &sc->sc_ic; | ||||
device_t dev = sc->sc_dev; | device_t dev = sc->sc_dev; | ||||
struct ifnet *ifp; | |||||
struct bwi_mac *mac; | struct bwi_mac *mac; | ||||
struct bwi_phy *phy; | struct bwi_phy *phy; | ||||
int i, error; | int i, error; | ||||
uint8_t bands; | uint8_t bands; | ||||
uint8_t macaddr[IEEE80211_ADDR_LEN]; | |||||
BWI_LOCK_INIT(sc); | BWI_LOCK_INIT(sc); | ||||
/* | /* | ||||
* Initialize taskq and various tasks | * Initialize taskq and various tasks | ||||
*/ | */ | ||||
sc->sc_tq = taskqueue_create("bwi_taskq", M_NOWAIT | M_ZERO, | sc->sc_tq = taskqueue_create("bwi_taskq", M_NOWAIT | M_ZERO, | ||||
taskqueue_thread_enqueue, &sc->sc_tq); | taskqueue_thread_enqueue, &sc->sc_tq); | ||||
taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq", | taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq", | ||||
device_get_nameunit(dev)); | device_get_nameunit(dev)); | ||||
TASK_INIT(&sc->sc_restart_task, 0, bwi_restart, sc); | TASK_INIT(&sc->sc_restart_task, 0, bwi_restart, sc); | ||||
callout_init_mtx(&sc->sc_calib_ch, &sc->sc_mtx, 0); | callout_init_mtx(&sc->sc_calib_ch, &sc->sc_mtx, 0); | ||||
mbufq_init(&sc->sc_snd, ifqmaxlen); | |||||
/* | /* | ||||
* Initialize sysctl variables | * Initialize sysctl variables | ||||
*/ | */ | ||||
sc->sc_fw_version = BWI_FW_VERSION3; | sc->sc_fw_version = BWI_FW_VERSION3; | ||||
sc->sc_led_idle = (2350 * hz) / 1000; | sc->sc_led_idle = (2350 * hz) / 1000; | ||||
sc->sc_led_blink = 1; | sc->sc_led_blink = 1; | ||||
sc->sc_txpwr_calib = 1; | sc->sc_txpwr_calib = 1; | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | #endif | ||||
error = bwi_dma_alloc(sc); | error = bwi_dma_alloc(sc); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
error = bwi_mac_fw_alloc(mac); | error = bwi_mac_fw_alloc(mac); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); | |||||
if (ifp == NULL) { | |||||
device_printf(dev, "can not if_alloc()\n"); | |||||
error = ENOSPC; | |||||
goto fail; | |||||
} | |||||
ic = ifp->if_l2com; | |||||
/* set these up early for if_printf use */ | |||||
if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | |||||
ifp->if_softc = sc; | |||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |||||
ifp->if_init = bwi_init; | |||||
ifp->if_ioctl = bwi_ioctl; | |||||
ifp->if_start = bwi_start; | |||||
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); | |||||
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; | |||||
IFQ_SET_READY(&ifp->if_snd); | |||||
callout_init_mtx(&sc->sc_watchdog_timer, &sc->sc_mtx, 0); | callout_init_mtx(&sc->sc_watchdog_timer, &sc->sc_mtx, 0); | ||||
/* | /* | ||||
* Setup ratesets, phytype, channels and get MAC address | * Setup ratesets, phytype, channels and get MAC address | ||||
*/ | */ | ||||
bands = 0; | bands = 0; | ||||
if (phy->phy_mode == IEEE80211_MODE_11B || | if (phy->phy_mode == IEEE80211_MODE_11B || | ||||
phy->phy_mode == IEEE80211_MODE_11G) { | phy->phy_mode == IEEE80211_MODE_11G) { | ||||
setbit(&bands, IEEE80211_MODE_11B); | setbit(&bands, IEEE80211_MODE_11B); | ||||
if (phy->phy_mode == IEEE80211_MODE_11B) { | if (phy->phy_mode == IEEE80211_MODE_11B) { | ||||
ic->ic_phytype = IEEE80211_T_DS; | ic->ic_phytype = IEEE80211_T_DS; | ||||
} else { | } else { | ||||
ic->ic_phytype = IEEE80211_T_OFDM; | ic->ic_phytype = IEEE80211_T_OFDM; | ||||
setbit(&bands, IEEE80211_MODE_11G); | setbit(&bands, IEEE80211_MODE_11G); | ||||
} | } | ||||
bwi_get_eaddr(sc, BWI_SPROM_11BG_EADDR, macaddr); | bwi_get_eaddr(sc, BWI_SPROM_11BG_EADDR, ic->ic_macaddr); | ||||
if (IEEE80211_IS_MULTICAST(macaddr)) { | if (IEEE80211_IS_MULTICAST(ic->ic_macaddr)) { | ||||
bwi_get_eaddr(sc, BWI_SPROM_11A_EADDR, macaddr); | bwi_get_eaddr(sc, BWI_SPROM_11A_EADDR, ic->ic_macaddr); | ||||
if (IEEE80211_IS_MULTICAST(macaddr)) { | if (IEEE80211_IS_MULTICAST(ic->ic_macaddr)) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"invalid MAC address: %6D\n", | "invalid MAC address: %6D\n", | ||||
macaddr, ":"); | ic->ic_macaddr, ":"); | ||||
} | } | ||||
} | } | ||||
} else if (phy->phy_mode == IEEE80211_MODE_11A) { | } else if (phy->phy_mode == IEEE80211_MODE_11A) { | ||||
/* TODO:11A */ | /* TODO:11A */ | ||||
setbit(&bands, IEEE80211_MODE_11A); | setbit(&bands, IEEE80211_MODE_11A); | ||||
error = ENXIO; | error = ENXIO; | ||||
goto fail; | goto fail; | ||||
} else { | } else { | ||||
panic("unknown phymode %d\n", phy->phy_mode); | panic("unknown phymode %d\n", phy->phy_mode); | ||||
} | } | ||||
/* Get locale */ | /* Get locale */ | ||||
sc->sc_locale = __SHIFTOUT(bwi_read_sprom(sc, BWI_SPROM_CARD_INFO), | sc->sc_locale = __SHIFTOUT(bwi_read_sprom(sc, BWI_SPROM_CARD_INFO), | ||||
BWI_SPROM_CARD_INFO_LOCALE); | BWI_SPROM_CARD_INFO_LOCALE); | ||||
DPRINTF(sc, BWI_DBG_ATTACH, "locale: %d\n", sc->sc_locale); | DPRINTF(sc, BWI_DBG_ATTACH, "locale: %d\n", sc->sc_locale); | ||||
/* XXX use locale */ | /* XXX use locale */ | ||||
ieee80211_init_channels(ic, NULL, &bands); | ieee80211_init_channels(ic, NULL, &bands); | ||||
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_caps = IEEE80211_C_STA | | ic->ic_caps = IEEE80211_C_STA | | ||||
IEEE80211_C_SHSLOT | | IEEE80211_C_SHSLOT | | ||||
IEEE80211_C_SHPREAMBLE | | IEEE80211_C_SHPREAMBLE | | ||||
IEEE80211_C_WPA | | IEEE80211_C_WPA | | ||||
IEEE80211_C_BGSCAN | | IEEE80211_C_BGSCAN | | ||||
IEEE80211_C_MONITOR; | IEEE80211_C_MONITOR; | ||||
ic->ic_opmode = IEEE80211_M_STA; | ic->ic_opmode = IEEE80211_M_STA; | ||||
ieee80211_ifattach(ic, macaddr); | ieee80211_ifattach(ic); | ||||
ic->ic_headroom = sizeof(struct bwi_txbuf_hdr); | ic->ic_headroom = sizeof(struct bwi_txbuf_hdr); | ||||
/* override default methods */ | /* override default methods */ | ||||
ic->ic_vap_create = bwi_vap_create; | ic->ic_vap_create = bwi_vap_create; | ||||
ic->ic_vap_delete = bwi_vap_delete; | ic->ic_vap_delete = bwi_vap_delete; | ||||
ic->ic_raw_xmit = bwi_raw_xmit; | ic->ic_raw_xmit = bwi_raw_xmit; | ||||
ic->ic_updateslot = bwi_updateslot; | ic->ic_updateslot = bwi_updateslot; | ||||
ic->ic_scan_start = bwi_scan_start; | ic->ic_scan_start = bwi_scan_start; | ||||
ic->ic_scan_end = bwi_scan_end; | ic->ic_scan_end = bwi_scan_end; | ||||
ic->ic_set_channel = bwi_set_channel; | ic->ic_set_channel = bwi_set_channel; | ||||
ic->ic_transmit = bwi_transmit; | |||||
ic->ic_parent = bwi_parent; | |||||
sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan); | sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan); | ||||
ieee80211_radiotap_attach(ic, | ieee80211_radiotap_attach(ic, | ||||
&sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th), | &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th), | ||||
BWI_TX_RADIOTAP_PRESENT, | BWI_TX_RADIOTAP_PRESENT, | ||||
&sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th), | &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th), | ||||
BWI_RX_RADIOTAP_PRESENT); | BWI_RX_RADIOTAP_PRESENT); | ||||
Show All 29 Lines | |||||
fail: | fail: | ||||
BWI_LOCK_DESTROY(sc); | BWI_LOCK_DESTROY(sc); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
bwi_detach(struct bwi_softc *sc) | bwi_detach(struct bwi_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
int i; | int i; | ||||
bwi_stop(sc, 1); | bwi_stop(sc, 1); | ||||
callout_drain(&sc->sc_led_blink_ch); | callout_drain(&sc->sc_led_blink_ch); | ||||
callout_drain(&sc->sc_calib_ch); | callout_drain(&sc->sc_calib_ch); | ||||
callout_drain(&sc->sc_watchdog_timer); | callout_drain(&sc->sc_watchdog_timer); | ||||
ieee80211_ifdetach(ic); | ieee80211_ifdetach(ic); | ||||
for (i = 0; i < sc->sc_nmac; ++i) | for (i = 0; i < sc->sc_nmac; ++i) | ||||
bwi_mac_detach(&sc->sc_mac[i]); | bwi_mac_detach(&sc->sc_mac[i]); | ||||
bwi_dma_free(sc); | bwi_dma_free(sc); | ||||
if_free(ifp); | |||||
taskqueue_free(sc->sc_tq); | taskqueue_free(sc->sc_tq); | ||||
BWI_LOCK_DESTROY(sc); | BWI_LOCK_DESTROY(sc); | ||||
return (0); | return (0); | ||||
} | } | ||||
static struct ieee80211vap * | static struct ieee80211vap * | ||||
bwi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, | bwi_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 bwi_vap *bvp; | struct bwi_vap *bvp; | ||||
struct ieee80211vap *vap; | struct ieee80211vap *vap; | ||||
if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ | if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ | ||||
return NULL; | return NULL; | ||||
bvp = (struct bwi_vap *) malloc(sizeof(struct bwi_vap), | bvp = malloc(sizeof(struct bwi_vap), M_80211_VAP, M_WAITOK | M_ZERO); | ||||
M_80211_VAP, M_WAITOK | M_ZERO); | |||||
if (bvp == NULL) | |||||
return NULL; | |||||
vap = &bvp->bv_vap; | vap = &bvp->bv_vap; | ||||
/* enable s/w bmiss handling for sta mode */ | /* enable s/w bmiss handling for sta mode */ | ||||
ieee80211_vap_setup(ic, vap, name, unit, opmode, | ieee80211_vap_setup(ic, vap, name, unit, opmode, | ||||
flags | IEEE80211_CLONE_NOBEACONS, bssid, mac); | flags | IEEE80211_CLONE_NOBEACONS, bssid); | ||||
/* override default methods */ | /* override default methods */ | ||||
bvp->bv_newstate = vap->iv_newstate; | bvp->bv_newstate = vap->iv_newstate; | ||||
vap->iv_newstate = bwi_newstate; | vap->iv_newstate = bwi_newstate; | ||||
#if 0 | #if 0 | ||||
vap->iv_update_beacon = bwi_beacon_update; | vap->iv_update_beacon = bwi_beacon_update; | ||||
#endif | #endif | ||||
ieee80211_ratectl_init(vap); | ieee80211_ratectl_init(vap); | ||||
/* complete setup */ | /* complete setup */ | ||||
ieee80211_vap_attach(vap, bwi_media_change, ieee80211_media_status); | ieee80211_vap_attach(vap, bwi_media_change, ieee80211_media_status, | ||||
mac); | |||||
ic->ic_opmode = opmode; | ic->ic_opmode = opmode; | ||||
return vap; | return vap; | ||||
} | } | ||||
static void | static void | ||||
bwi_vap_delete(struct ieee80211vap *vap) | bwi_vap_delete(struct ieee80211vap *vap) | ||||
{ | { | ||||
struct bwi_vap *bvp = BWI_VAP(vap); | struct bwi_vap *bvp = BWI_VAP(vap); | ||||
ieee80211_ratectl_deinit(vap); | ieee80211_ratectl_deinit(vap); | ||||
ieee80211_vap_detach(vap); | ieee80211_vap_detach(vap); | ||||
free(bvp, M_80211_VAP); | free(bvp, M_80211_VAP); | ||||
} | } | ||||
void | void | ||||
bwi_suspend(struct bwi_softc *sc) | bwi_suspend(struct bwi_softc *sc) | ||||
{ | { | ||||
bwi_stop(sc, 1); | bwi_stop(sc, 1); | ||||
} | } | ||||
void | void | ||||
bwi_resume(struct bwi_softc *sc) | bwi_resume(struct bwi_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
if (ifp->if_flags & IFF_UP) | if (sc->sc_ic.ic_nrunning > 0) | ||||
bwi_init(sc); | bwi_init(sc); | ||||
} | } | ||||
int | int | ||||
bwi_shutdown(struct bwi_softc *sc) | bwi_shutdown(struct bwi_softc *sc) | ||||
{ | { | ||||
bwi_stop(sc, 1); | bwi_stop(sc, 1); | ||||
return 0; | return 0; | ||||
▲ Show 20 Lines • Show All 547 Lines • ▼ Show 20 Lines | if (com->rw_rev >= 10) { | ||||
howmany(freq.clkfreq_max * 15, 1000000)); | howmany(freq.clkfreq_max * 15, 1000000)); | ||||
} | } | ||||
} | } | ||||
return bwi_regwin_switch(sc, old, NULL); | return bwi_regwin_switch(sc, old, NULL); | ||||
} | } | ||||
static void | static void | ||||
bwi_init(void *xsc) | bwi_init(struct bwi_softc *sc) | ||||
{ | { | ||||
struct bwi_softc *sc = xsc; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
BWI_LOCK(sc); | BWI_LOCK(sc); | ||||
bwi_init_statechg(sc, 1); | bwi_init_statechg(sc, 1); | ||||
BWI_UNLOCK(sc); | BWI_UNLOCK(sc); | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (sc->sc_flags & BWI_F_RUNNING) | ||||
ieee80211_start_all(ic); /* start all vap's */ | ieee80211_start_all(ic); /* start all vap's */ | ||||
} | } | ||||
static void | static void | ||||
bwi_init_statechg(struct bwi_softc *sc, int statechg) | bwi_init_statechg(struct bwi_softc *sc, int statechg) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct bwi_mac *mac; | struct bwi_mac *mac; | ||||
int error; | int error; | ||||
BWI_ASSERT_LOCKED(sc); | |||||
bwi_stop_locked(sc, statechg); | bwi_stop_locked(sc, statechg); | ||||
bwi_bbp_power_on(sc, BWI_CLOCK_MODE_FAST); | bwi_bbp_power_on(sc, BWI_CLOCK_MODE_FAST); | ||||
/* TODO: 2 MAC */ | /* TODO: 2 MAC */ | ||||
mac = &sc->sc_mac[0]; | mac = &sc->sc_mac[0]; | ||||
error = bwi_regwin_switch(sc, &mac->mac_regwin, NULL); | error = bwi_regwin_switch(sc, &mac->mac_regwin, NULL); | ||||
if (error) { | if (error) { | ||||
if_printf(ifp, "%s: error %d on regwin switch\n", | device_printf(sc->sc_dev, "%s: error %d on regwin switch\n", | ||||
__func__, error); | __func__, error); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
error = bwi_mac_init(mac); | error = bwi_mac_init(mac); | ||||
if (error) { | if (error) { | ||||
if_printf(ifp, "%s: error %d on MAC init\n", __func__, error); | device_printf(sc->sc_dev, "%s: error %d on MAC init\n", | ||||
__func__, error); | |||||
goto bad; | goto bad; | ||||
} | } | ||||
bwi_bbp_power_on(sc, BWI_CLOCK_MODE_DYN); | bwi_bbp_power_on(sc, BWI_CLOCK_MODE_DYN); | ||||
bwi_set_bssid(sc, bwi_zero_addr); /* Clear BSSID */ | bwi_set_bssid(sc, bwi_zero_addr); /* Clear BSSID */ | ||||
bwi_set_addr_filter(sc, BWI_ADDR_FILTER_MYADDR, IF_LLADDR(ifp)); | bwi_set_addr_filter(sc, BWI_ADDR_FILTER_MYADDR, sc->sc_ic.ic_macaddr); | ||||
bwi_mac_reset_hwkeys(mac); | bwi_mac_reset_hwkeys(mac); | ||||
if ((mac->mac_flags & BWI_MAC_F_HAS_TXSTATS) == 0) { | if ((mac->mac_flags & BWI_MAC_F_HAS_TXSTATS) == 0) { | ||||
int i; | int i; | ||||
#define NRETRY 1000 | #define NRETRY 1000 | ||||
/* | /* | ||||
* Drain any possible pending TX status | * Drain any possible pending TX status | ||||
*/ | */ | ||||
for (i = 0; i < NRETRY; ++i) { | for (i = 0; i < NRETRY; ++i) { | ||||
if ((CSR_READ_4(sc, BWI_TXSTATUS0) & | if ((CSR_READ_4(sc, BWI_TXSTATUS0) & | ||||
BWI_TXSTATUS0_VALID) == 0) | BWI_TXSTATUS0_VALID) == 0) | ||||
break; | break; | ||||
CSR_READ_4(sc, BWI_TXSTATUS1); | CSR_READ_4(sc, BWI_TXSTATUS1); | ||||
} | } | ||||
if (i == NRETRY) | if (i == NRETRY) | ||||
if_printf(ifp, "%s: can't drain TX status\n", __func__); | device_printf(sc->sc_dev, | ||||
"%s: can't drain TX status\n", __func__); | |||||
#undef NRETRY | #undef NRETRY | ||||
} | } | ||||
if (mac->mac_phy.phy_mode == IEEE80211_MODE_11G) | if (mac->mac_phy.phy_mode == IEEE80211_MODE_11G) | ||||
bwi_mac_updateslot(mac, 1); | bwi_mac_updateslot(mac, 1); | ||||
/* Start MAC */ | /* Start MAC */ | ||||
error = bwi_mac_start(mac); | error = bwi_mac_start(mac); | ||||
if (error) { | if (error) { | ||||
if_printf(ifp, "%s: error %d starting MAC\n", __func__, error); | device_printf(sc->sc_dev, "%s: error %d starting MAC\n", | ||||
__func__, error); | |||||
goto bad; | goto bad; | ||||
} | } | ||||
/* Clear stop flag before enabling interrupt */ | /* Clear stop flag before enabling interrupt */ | ||||
sc->sc_flags &= ~BWI_F_STOP; | sc->sc_flags &= ~BWI_F_STOP; | ||||
sc->sc_flags |= BWI_F_RUNNING; | |||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | |||||
callout_reset(&sc->sc_watchdog_timer, hz, bwi_watchdog, sc); | callout_reset(&sc->sc_watchdog_timer, hz, bwi_watchdog, sc); | ||||
/* Enable intrs */ | /* Enable intrs */ | ||||
bwi_enable_intrs(sc, BWI_INIT_INTRS); | bwi_enable_intrs(sc, BWI_INIT_INTRS); | ||||
return; | return; | ||||
bad: | bad: | ||||
bwi_stop_locked(sc, 1); | bwi_stop_locked(sc, 1); | ||||
} | } | ||||
static int | static void | ||||
bwi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | bwi_parent(struct ieee80211com *ic) | ||||
{ | { | ||||
#define IS_RUNNING(ifp) \ | struct bwi_softc *sc = ic->ic_softc; | ||||
((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) | int startall = 0; | ||||
struct bwi_softc *sc = ifp->if_softc; | |||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ifreq *ifr = (struct ifreq *) data; | |||||
int error = 0, startall = 0; | |||||
switch (cmd) { | |||||
case SIOCSIFFLAGS: | |||||
BWI_LOCK(sc); | BWI_LOCK(sc); | ||||
if (IS_RUNNING(ifp)) { | if (ic->ic_nrunning > 0) { | ||||
struct bwi_mac *mac; | struct bwi_mac *mac; | ||||
int promisc = -1; | int promisc = -1; | ||||
KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, | ||||
("current regwin type %d", | ("current regwin type %d", | ||||
sc->sc_cur_regwin->rw_type)); | sc->sc_cur_regwin->rw_type)); | ||||
mac = (struct bwi_mac *)sc->sc_cur_regwin; | mac = (struct bwi_mac *)sc->sc_cur_regwin; | ||||
if ((ifp->if_flags & IFF_PROMISC) && | if (ic->ic_promisc > 0 && (sc->sc_flags & BWI_F_PROMISC) == 0) { | ||||
(sc->sc_flags & BWI_F_PROMISC) == 0) { | |||||
promisc = 1; | promisc = 1; | ||||
sc->sc_flags |= BWI_F_PROMISC; | sc->sc_flags |= BWI_F_PROMISC; | ||||
} else if ((ifp->if_flags & IFF_PROMISC) == 0 && | } else if (ic->ic_promisc == 0 && | ||||
(sc->sc_flags & BWI_F_PROMISC)) { | (sc->sc_flags & BWI_F_PROMISC) != 0) { | ||||
promisc = 0; | promisc = 0; | ||||
sc->sc_flags &= ~BWI_F_PROMISC; | sc->sc_flags &= ~BWI_F_PROMISC; | ||||
} | } | ||||
if (promisc >= 0) | if (promisc >= 0) | ||||
bwi_mac_set_promisc(mac, promisc); | bwi_mac_set_promisc(mac, promisc); | ||||
} | } | ||||
if (ic->ic_nrunning > 0) { | |||||
if (ifp->if_flags & IFF_UP) { | if ((sc->sc_flags & BWI_F_RUNNING) == 0) { | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | |||||
bwi_init_statechg(sc, 1); | bwi_init_statechg(sc, 1); | ||||
startall = 1; | startall = 1; | ||||
} | } | ||||
} else { | } else if (sc->sc_flags & BWI_F_RUNNING) | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | |||||
bwi_stop_locked(sc, 1); | bwi_stop_locked(sc, 1); | ||||
} | |||||
BWI_UNLOCK(sc); | BWI_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; | |||||
#undef IS_RUNNING | |||||
} | |||||
static void | static int | ||||
bwi_start(struct ifnet *ifp) | bwi_transmit(struct ieee80211com *ic, struct mbuf *m) | ||||
{ | { | ||||
struct bwi_softc *sc = ifp->if_softc; | struct bwi_softc *sc = ic->ic_softc; | ||||
int error; | |||||
BWI_LOCK(sc); | BWI_LOCK(sc); | ||||
bwi_start_locked(ifp); | if ((sc->sc_flags & BWI_F_RUNNING) == 0) { | ||||
BWI_UNLOCK(sc); | BWI_UNLOCK(sc); | ||||
return (ENXIO); | |||||
} | } | ||||
error = mbufq_enqueue(&sc->sc_snd, m); | |||||
if (error) { | |||||
BWI_UNLOCK(sc); | |||||
return (error); | |||||
} | |||||
bwi_start_locked(sc); | |||||
BWI_UNLOCK(sc); | |||||
return (0); | |||||
} | |||||
static void | static void | ||||
bwi_start_locked(struct ifnet *ifp) | bwi_start_locked(struct bwi_softc *sc) | ||||
{ | { | ||||
struct bwi_softc *sc = ifp->if_softc; | |||||
struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; | struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct ieee80211_key *k; | |||||
struct mbuf *m; | struct mbuf *m; | ||||
int trans, idx; | int trans, idx; | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | BWI_ASSERT_LOCKED(sc); | ||||
return; | |||||
trans = 0; | trans = 0; | ||||
idx = tbd->tbd_idx; | idx = tbd->tbd_idx; | ||||
while (tbd->tbd_buf[idx].tb_mbuf == NULL) { | while (tbd->tbd_buf[idx].tb_mbuf == NULL && | ||||
IFQ_DRV_DEQUEUE(&ifp->if_snd, m); /* XXX: LOCK */ | tbd->tbd_used + BWI_TX_NSPRDESC < BWI_TX_NDESC && | ||||
if (m == NULL) | (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { | ||||
break; | |||||
ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; | ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; | ||||
wh = mtod(m, struct ieee80211_frame *); | wh = mtod(m, struct ieee80211_frame *); | ||||
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { | if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) != 0 && | ||||
k = ieee80211_crypto_encap(ni, m); | ieee80211_crypto_encap(ni, m) == NULL) { | ||||
if (k == NULL) { | if_inc_counter(ni->ni_vap->iv_ifp, | ||||
IFCOUNTER_OERRORS, 1); | |||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
m_freem(m); | m_freem(m); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
continue; | continue; | ||||
} | } | ||||
} | |||||
wh = NULL; /* Catch any invalid use */ | |||||
if (bwi_encap(sc, idx, m, ni) != 0) { | if (bwi_encap(sc, idx, m, ni) != 0) { | ||||
/* 'm' is freed in bwi_encap() if we reach here */ | /* 'm' is freed in bwi_encap() if we reach here */ | ||||
if (ni != NULL) | if (ni != NULL) { | ||||
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); | } else | ||||
counter_u64_add(sc->sc_ic.ic_oerrors, 1); | |||||
continue; | continue; | ||||
} | } | ||||
trans = 1; | trans = 1; | ||||
tbd->tbd_used++; | tbd->tbd_used++; | ||||
idx = (idx + 1) % BWI_TX_NDESC; | idx = (idx + 1) % BWI_TX_NDESC; | ||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | |||||
if (tbd->tbd_used + BWI_TX_NSPRDESC >= BWI_TX_NDESC) { | |||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | |||||
break; | |||||
} | } | ||||
} | |||||
tbd->tbd_idx = idx; | |||||
tbd->tbd_idx = idx; | |||||
if (trans) | if (trans) | ||||
sc->sc_tx_timer = 5; | sc->sc_tx_timer = 5; | ||||
} | } | ||||
static int | static int | ||||
bwi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, | bwi_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 bwi_softc *sc = ic->ic_softc; | ||||
struct bwi_softc *sc = ifp->if_softc; | |||||
/* XXX wme? */ | /* XXX wme? */ | ||||
struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; | struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; | ||||
int idx, error; | int idx, error; | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | if ((sc->sc_flags & BWI_F_RUNNING) == 0) { | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
m_freem(m); | m_freem(m); | ||||
return ENETDOWN; | return ENETDOWN; | ||||
} | } | ||||
BWI_LOCK(sc); | BWI_LOCK(sc); | ||||
idx = tbd->tbd_idx; | idx = tbd->tbd_idx; | ||||
KASSERT(tbd->tbd_buf[idx].tb_mbuf == NULL, ("slot %d not empty", idx)); | KASSERT(tbd->tbd_buf[idx].tb_mbuf == NULL, ("slot %d not empty", idx)); | ||||
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. | ||||
*/ | */ | ||||
error = bwi_encap(sc, idx, m, ni); | error = bwi_encap(sc, idx, m, ni); | ||||
} else { | } else { | ||||
/* | /* | ||||
* Caller supplied explicit parameters to use in | * Caller supplied explicit parameters to use in | ||||
* sending the frame. | * sending the frame. | ||||
*/ | */ | ||||
error = bwi_encap_raw(sc, idx, m, ni, params); | error = bwi_encap_raw(sc, idx, m, ni, params); | ||||
} | } | ||||
if (error == 0) { | if (error == 0) { | ||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | tbd->tbd_used++; | ||||
if (++tbd->tbd_used + BWI_TX_NSPRDESC >= BWI_TX_NDESC) | |||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | |||||
tbd->tbd_idx = (idx + 1) % BWI_TX_NDESC; | tbd->tbd_idx = (idx + 1) % BWI_TX_NDESC; | ||||
sc->sc_tx_timer = 5; | sc->sc_tx_timer = 5; | ||||
} else { | } else | ||||
/* NB: m is reclaimed on encap failure */ | /* NB: m is reclaimed on encap failure */ | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
} | |||||
BWI_UNLOCK(sc); | BWI_UNLOCK(sc); | ||||
return error; | return error; | ||||
} | } | ||||
static void | static void | ||||
bwi_watchdog(void *arg) | bwi_watchdog(void *arg) | ||||
{ | { | ||||
struct bwi_softc *sc; | struct bwi_softc *sc; | ||||
struct ifnet *ifp; | |||||
sc = arg; | sc = arg; | ||||
ifp = sc->sc_ifp; | |||||
BWI_ASSERT_LOCKED(sc); | BWI_ASSERT_LOCKED(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, "watchdog timeout\n"); | device_printf(sc->sc_dev, "watchdog timeout\n"); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | counter_u64_add(sc->sc_ic.ic_oerrors, 1); | ||||
taskqueue_enqueue(sc->sc_tq, &sc->sc_restart_task); | taskqueue_enqueue(sc->sc_tq, &sc->sc_restart_task); | ||||
} | } | ||||
callout_reset(&sc->sc_watchdog_timer, hz, bwi_watchdog, sc); | callout_reset(&sc->sc_watchdog_timer, hz, bwi_watchdog, sc); | ||||
} | } | ||||
static void | static void | ||||
bwi_stop(struct bwi_softc *sc, int statechg) | bwi_stop(struct bwi_softc *sc, int statechg) | ||||
{ | { | ||||
BWI_LOCK(sc); | BWI_LOCK(sc); | ||||
bwi_stop_locked(sc, statechg); | bwi_stop_locked(sc, statechg); | ||||
BWI_UNLOCK(sc); | BWI_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
bwi_stop_locked(struct bwi_softc *sc, int statechg) | bwi_stop_locked(struct bwi_softc *sc, int statechg) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct bwi_mac *mac; | struct bwi_mac *mac; | ||||
int i, error, pwr_off = 0; | int i, error, pwr_off = 0; | ||||
BWI_ASSERT_LOCKED(sc); | BWI_ASSERT_LOCKED(sc); | ||||
callout_stop(&sc->sc_calib_ch); | callout_stop(&sc->sc_calib_ch); | ||||
callout_stop(&sc->sc_led_blink_ch); | callout_stop(&sc->sc_led_blink_ch); | ||||
sc->sc_led_blinking = 0; | sc->sc_led_blinking = 0; | ||||
sc->sc_flags |= BWI_F_STOP; | sc->sc_flags |= BWI_F_STOP; | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | if (sc->sc_flags & BWI_F_RUNNING) { | ||||
KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, | ||||
("current regwin type %d", sc->sc_cur_regwin->rw_type)); | ("current regwin type %d", sc->sc_cur_regwin->rw_type)); | ||||
mac = (struct bwi_mac *)sc->sc_cur_regwin; | mac = (struct bwi_mac *)sc->sc_cur_regwin; | ||||
bwi_disable_intrs(sc, BWI_ALL_INTRS); | bwi_disable_intrs(sc, BWI_ALL_INTRS); | ||||
CSR_READ_4(sc, BWI_MAC_INTR_MASK); | CSR_READ_4(sc, BWI_MAC_INTR_MASK); | ||||
bwi_mac_stop(mac); | bwi_mac_stop(mac); | ||||
} | } | ||||
Show All 15 Lines | for (i = 0; i < sc->sc_nmac; ++i) { | ||||
bwi_regwin_switch(sc, old_rw, NULL); | bwi_regwin_switch(sc, old_rw, NULL); | ||||
} | } | ||||
if (pwr_off) | if (pwr_off) | ||||
bwi_bbp_power_off(sc); | bwi_bbp_power_off(sc); | ||||
sc->sc_tx_timer = 0; | sc->sc_tx_timer = 0; | ||||
callout_stop(&sc->sc_watchdog_timer); | callout_stop(&sc->sc_watchdog_timer); | ||||
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); | sc->sc_flags &= ~BWI_F_RUNNING; | ||||
} | } | ||||
void | void | ||||
bwi_intr(void *xsc) | bwi_intr(void *xsc) | ||||
{ | { | ||||
struct bwi_softc *sc = xsc; | struct bwi_softc *sc = xsc; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct bwi_mac *mac; | struct bwi_mac *mac; | ||||
uint32_t intr_status; | uint32_t intr_status; | ||||
uint32_t txrx_intr_status[BWI_TXRX_NRING]; | uint32_t txrx_intr_status[BWI_TXRX_NRING]; | ||||
int i, txrx_error, tx = 0, rx_data = -1; | int i, txrx_error, tx = 0, rx_data = -1; | ||||
BWI_LOCK(sc); | BWI_LOCK(sc); | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || | if ((sc->sc_flags & BWI_F_RUNNING) == 0 || | ||||
(sc->sc_flags & BWI_F_STOP)) { | (sc->sc_flags & BWI_F_STOP)) { | ||||
BWI_UNLOCK(sc); | BWI_UNLOCK(sc); | ||||
return; | return; | ||||
} | } | ||||
/* | /* | ||||
* Get interrupt status | * Get interrupt status | ||||
*/ | */ | ||||
intr_status = CSR_READ_4(sc, BWI_MAC_INTR_STATUS); | intr_status = CSR_READ_4(sc, BWI_MAC_INTR_STATUS); | ||||
Show All 26 Lines | for (i = 0; i < BWI_TXRX_NRING; ++i) { | ||||
txrx_intr_status[i] = | txrx_intr_status[i] = | ||||
CSR_READ_4(sc, BWI_TXRX_INTR_STATUS(i)) & mask; | CSR_READ_4(sc, BWI_TXRX_INTR_STATUS(i)) & mask; | ||||
_DPRINTF(sc, BWI_DBG_INTR, ", %d 0x%08x", | _DPRINTF(sc, BWI_DBG_INTR, ", %d 0x%08x", | ||||
i, txrx_intr_status[i]); | i, txrx_intr_status[i]); | ||||
if (txrx_intr_status[i] & BWI_TXRX_INTR_ERROR) { | if (txrx_intr_status[i] & BWI_TXRX_INTR_ERROR) { | ||||
if_printf(ifp, | device_printf(sc->sc_dev, | ||||
"%s: intr fatal TX/RX (%d) error 0x%08x\n", | "%s: intr fatal TX/RX (%d) error 0x%08x\n", | ||||
__func__, i, txrx_intr_status[i]); | __func__, i, txrx_intr_status[i]); | ||||
txrx_error = 1; | txrx_error = 1; | ||||
} | } | ||||
} | } | ||||
_DPRINTF(sc, BWI_DBG_INTR, "%s\n", ""); | _DPRINTF(sc, BWI_DBG_INTR, "%s\n", ""); | ||||
/* | /* | ||||
Show All 21 Lines | bwi_intr(void *xsc) | ||||
* Suggesting that we should never get it and if we do we're not | * Suggesting that we should never get it and if we do we're not | ||||
* feeding TX packets into the MAC correctly if we do... Apparently, | * feeding TX packets into the MAC correctly if we do... Apparently, | ||||
* it is valid only on mac version 5 and higher, but I couldn't | * it is valid only on mac version 5 and higher, but I couldn't | ||||
* find a reference for that... Since I see them from time to time | * find a reference for that... Since I see them from time to time | ||||
* on my card, this suggests an error in the tx path still... | * on my card, this suggests an error in the tx path still... | ||||
*/ | */ | ||||
if (intr_status & BWI_INTR_PHY_TXERR) { | if (intr_status & BWI_INTR_PHY_TXERR) { | ||||
if (mac->mac_flags & BWI_MAC_F_PHYE_RESET) { | if (mac->mac_flags & BWI_MAC_F_PHYE_RESET) { | ||||
if_printf(ifp, "%s: intr PHY TX error\n", __func__); | device_printf(sc->sc_dev, "%s: intr PHY TX error\n", | ||||
__func__); | |||||
taskqueue_enqueue(sc->sc_tq, &sc->sc_restart_task); | taskqueue_enqueue(sc->sc_tq, &sc->sc_restart_task); | ||||
BWI_UNLOCK(sc); | BWI_UNLOCK(sc); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
if (txrx_error) { | if (txrx_error) { | ||||
/* TODO: reset device */ | /* TODO: reset device */ | ||||
} | } | ||||
if (intr_status & BWI_INTR_TBTT) | if (intr_status & BWI_INTR_TBTT) | ||||
bwi_mac_config_ps(mac); | bwi_mac_config_ps(mac); | ||||
if (intr_status & BWI_INTR_EO_ATIM) | if (intr_status & BWI_INTR_EO_ATIM) | ||||
if_printf(ifp, "EO_ATIM\n"); | device_printf(sc->sc_dev, "EO_ATIM\n"); | ||||
if (intr_status & BWI_INTR_PMQ) { | if (intr_status & BWI_INTR_PMQ) { | ||||
for (;;) { | for (;;) { | ||||
if ((CSR_READ_4(sc, BWI_MAC_PS_STATUS) & 0x8) == 0) | if ((CSR_READ_4(sc, BWI_MAC_PS_STATUS) & 0x8) == 0) | ||||
break; | break; | ||||
} | } | ||||
CSR_WRITE_2(sc, BWI_MAC_PS_STATUS, 0x2); | CSR_WRITE_2(sc, BWI_MAC_PS_STATUS, 0x2); | ||||
} | } | ||||
if (intr_status & BWI_INTR_NOISE) | if (intr_status & BWI_INTR_NOISE) | ||||
if_printf(ifp, "intr noise\n"); | device_printf(sc->sc_dev, "intr noise\n"); | ||||
if (txrx_intr_status[0] & BWI_TXRX_INTR_RX) { | if (txrx_intr_status[0] & BWI_TXRX_INTR_RX) { | ||||
rx_data = sc->sc_rxeof(sc); | rx_data = sc->sc_rxeof(sc); | ||||
if (sc->sc_flags & BWI_F_STOP) { | if (sc->sc_flags & BWI_F_STOP) { | ||||
BWI_UNLOCK(sc); | BWI_UNLOCK(sc); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
Show All 32 Lines | bwi_intr(void *xsc) | ||||
} | } | ||||
BWI_UNLOCK(sc); | BWI_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
bwi_scan_start(struct ieee80211com *ic) | bwi_scan_start(struct ieee80211com *ic) | ||||
{ | { | ||||
struct bwi_softc *sc = ic->ic_ifp->if_softc; | struct bwi_softc *sc = ic->ic_softc; | ||||
BWI_LOCK(sc); | BWI_LOCK(sc); | ||||
/* Enable MAC beacon promiscuity */ | /* Enable MAC beacon promiscuity */ | ||||
CSR_SETBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_PASS_BCN); | CSR_SETBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_PASS_BCN); | ||||
BWI_UNLOCK(sc); | BWI_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
bwi_set_channel(struct ieee80211com *ic) | bwi_set_channel(struct ieee80211com *ic) | ||||
{ | { | ||||
struct bwi_softc *sc = ic->ic_ifp->if_softc; | struct bwi_softc *sc = ic->ic_softc; | ||||
struct ieee80211_channel *c = ic->ic_curchan; | struct ieee80211_channel *c = ic->ic_curchan; | ||||
struct bwi_mac *mac; | struct bwi_mac *mac; | ||||
BWI_LOCK(sc); | BWI_LOCK(sc); | ||||
KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, | ||||
("current regwin type %d", sc->sc_cur_regwin->rw_type)); | ("current regwin type %d", sc->sc_cur_regwin->rw_type)); | ||||
mac = (struct bwi_mac *)sc->sc_cur_regwin; | mac = (struct bwi_mac *)sc->sc_cur_regwin; | ||||
bwi_rf_set_chan(mac, ieee80211_chan2ieee(ic, c), 0); | bwi_rf_set_chan(mac, ieee80211_chan2ieee(ic, c), 0); | ||||
Show All 9 Lines | sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags = | ||||
htole16(c->ic_flags & 0xffff); | htole16(c->ic_flags & 0xffff); | ||||
BWI_UNLOCK(sc); | BWI_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
bwi_scan_end(struct ieee80211com *ic) | bwi_scan_end(struct ieee80211com *ic) | ||||
{ | { | ||||
struct bwi_softc *sc = ic->ic_ifp->if_softc; | struct bwi_softc *sc = ic->ic_softc; | ||||
BWI_LOCK(sc); | BWI_LOCK(sc); | ||||
CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_PASS_BCN); | CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_PASS_BCN); | ||||
BWI_UNLOCK(sc); | BWI_UNLOCK(sc); | ||||
} | } | ||||
static int | static int | ||||
bwi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) | bwi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) | ||||
{ | { | ||||
struct bwi_vap *bvp = BWI_VAP(vap); | struct bwi_vap *bvp = BWI_VAP(vap); | ||||
struct ieee80211com *ic= vap->iv_ic; | struct ieee80211com *ic= vap->iv_ic; | ||||
struct ifnet *ifp = ic->ic_ifp; | struct bwi_softc *sc = ic->ic_softc; | ||||
enum ieee80211_state ostate = vap->iv_state; | enum ieee80211_state ostate = vap->iv_state; | ||||
struct bwi_softc *sc = ifp->if_softc; | |||||
struct bwi_mac *mac; | struct bwi_mac *mac; | ||||
int error; | int error; | ||||
BWI_LOCK(sc); | BWI_LOCK(sc); | ||||
callout_stop(&sc->sc_calib_ch); | callout_stop(&sc->sc_calib_ch); | ||||
if (nstate == IEEE80211_S_INIT) | if (nstate == IEEE80211_S_INIT) | ||||
▲ Show 20 Lines • Show All 829 Lines • ▼ Show 20 Lines | bwi_set_addr_filter(struct bwi_softc *sc, uint16_t addr_ofs, | ||||
} | } | ||||
} | } | ||||
static int | static int | ||||
bwi_rxeof(struct bwi_softc *sc, int end_idx) | bwi_rxeof(struct bwi_softc *sc, int end_idx) | ||||
{ | { | ||||
struct bwi_ring_data *rd = &sc->sc_rx_rdata; | struct bwi_ring_data *rd = &sc->sc_rx_rdata; | ||||
struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata; | struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
int idx, rx_data = 0; | int idx, rx_data = 0; | ||||
idx = rbd->rbd_idx; | idx = rbd->rbd_idx; | ||||
while (idx != end_idx) { | while (idx != end_idx) { | ||||
struct bwi_rxbuf *rb = &rbd->rbd_buf[idx]; | struct bwi_rxbuf *rb = &rbd->rbd_buf[idx]; | ||||
struct bwi_rxbuf_hdr *hdr; | struct bwi_rxbuf_hdr *hdr; | ||||
struct ieee80211_frame_min *wh; | struct ieee80211_frame_min *wh; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
uint32_t plcp; | uint32_t plcp; | ||||
uint16_t flags2; | uint16_t flags2; | ||||
int buflen, wh_ofs, hdr_extra, rssi, noise, type, rate; | int buflen, wh_ofs, hdr_extra, rssi, noise, type, rate; | ||||
m = rb->rb_mbuf; | m = rb->rb_mbuf; | ||||
bus_dmamap_sync(sc->sc_buf_dtag, rb->rb_dmap, | bus_dmamap_sync(sc->sc_buf_dtag, rb->rb_dmap, | ||||
BUS_DMASYNC_POSTREAD); | BUS_DMASYNC_POSTREAD); | ||||
if (bwi_newbuf(sc, idx, 0)) { | if (bwi_newbuf(sc, idx, 0)) { | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
goto next; | goto next; | ||||
} | } | ||||
hdr = mtod(m, struct bwi_rxbuf_hdr *); | hdr = mtod(m, struct bwi_rxbuf_hdr *); | ||||
flags2 = le16toh(hdr->rxh_flags2); | flags2 = le16toh(hdr->rxh_flags2); | ||||
hdr_extra = 0; | hdr_extra = 0; | ||||
if (flags2 & BWI_RXH_F2_TYPE2FRAME) | if (flags2 & BWI_RXH_F2_TYPE2FRAME) | ||||
hdr_extra = 2; | hdr_extra = 2; | ||||
wh_ofs = hdr_extra + 6; /* XXX magic number */ | wh_ofs = hdr_extra + 6; /* XXX magic number */ | ||||
buflen = le16toh(hdr->rxh_buflen); | buflen = le16toh(hdr->rxh_buflen); | ||||
if (buflen < BWI_FRAME_MIN_LEN(wh_ofs)) { | if (buflen < BWI_FRAME_MIN_LEN(wh_ofs)) { | ||||
if_printf(ifp, "%s: zero length data, hdr_extra %d\n", | device_printf(sc->sc_dev, | ||||
"%s: zero length data, hdr_extra %d\n", | |||||
__func__, hdr_extra); | __func__, hdr_extra); | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
m_freem(m); | m_freem(m); | ||||
goto next; | goto next; | ||||
} | } | ||||
bcopy((uint8_t *)(hdr + 1) + hdr_extra, &plcp, sizeof(plcp)); | bcopy((uint8_t *)(hdr + 1) + hdr_extra, &plcp, sizeof(plcp)); | ||||
rssi = bwi_calc_rssi(sc, hdr); | rssi = bwi_calc_rssi(sc, hdr); | ||||
noise = bwi_calc_noise(sc); | noise = bwi_calc_noise(sc); | ||||
m->m_pkthdr.rcvif = ifp; | |||||
m->m_len = m->m_pkthdr.len = buflen + sizeof(*hdr); | m->m_len = m->m_pkthdr.len = buflen + sizeof(*hdr); | ||||
m_adj(m, sizeof(*hdr) + wh_ofs); | m_adj(m, sizeof(*hdr) + wh_ofs); | ||||
if (htole16(hdr->rxh_flags1) & BWI_RXH_F1_OFDM) | if (htole16(hdr->rxh_flags1) & BWI_RXH_F1_OFDM) | ||||
rate = bwi_plcp2rate(plcp, IEEE80211_T_OFDM); | rate = bwi_plcp2rate(plcp, IEEE80211_T_OFDM); | ||||
else | else | ||||
rate = bwi_plcp2rate(plcp, IEEE80211_T_CCK); | rate = bwi_plcp2rate(plcp, IEEE80211_T_CCK); | ||||
▲ Show 20 Lines • Show All 117 Lines • ▼ Show 20 Lines | bwi_free_rx_ring32(struct bwi_softc *sc) | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
bwi_free_tx_ring32(struct bwi_softc *sc, int ring_idx) | bwi_free_tx_ring32(struct bwi_softc *sc, int ring_idx) | ||||
{ | { | ||||
struct bwi_ring_data *rd; | struct bwi_ring_data *rd; | ||||
struct bwi_txbuf_data *tbd; | struct bwi_txbuf_data *tbd; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
uint32_t state, val; | uint32_t state, val; | ||||
int i; | int i; | ||||
KASSERT(ring_idx < BWI_TX_NRING, ("ring_idx %d", ring_idx)); | KASSERT(ring_idx < BWI_TX_NRING, ("ring_idx %d", ring_idx)); | ||||
rd = &sc->sc_tx_rdata[ring_idx]; | rd = &sc->sc_tx_rdata[ring_idx]; | ||||
tbd = &sc->sc_tx_bdata[ring_idx]; | tbd = &sc->sc_tx_bdata[ring_idx]; | ||||
#define NRETRY 10 | #define NRETRY 10 | ||||
for (i = 0; i < NRETRY; ++i) { | for (i = 0; i < NRETRY; ++i) { | ||||
val = CSR_READ_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_STATUS); | val = CSR_READ_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_STATUS); | ||||
state = __SHIFTOUT(val, BWI_TX32_STATUS_STATE_MASK); | state = __SHIFTOUT(val, BWI_TX32_STATUS_STATE_MASK); | ||||
if (state == BWI_TX32_STATUS_STATE_DISABLED || | if (state == BWI_TX32_STATUS_STATE_DISABLED || | ||||
state == BWI_TX32_STATUS_STATE_IDLE || | state == BWI_TX32_STATUS_STATE_IDLE || | ||||
state == BWI_TX32_STATUS_STATE_STOPPED) | state == BWI_TX32_STATUS_STATE_STOPPED) | ||||
break; | break; | ||||
DELAY(1000); | DELAY(1000); | ||||
} | } | ||||
if (i == NRETRY) { | if (i == NRETRY) { | ||||
if_printf(ifp, "%s: wait for TX ring(%d) stable timed out\n", | device_printf(sc->sc_dev, | ||||
"%s: wait for TX ring(%d) stable timed out\n", | |||||
__func__, ring_idx); | __func__, ring_idx); | ||||
} | } | ||||
CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_CTRL, 0); | CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_CTRL, 0); | ||||
for (i = 0; i < NRETRY; ++i) { | for (i = 0; i < NRETRY; ++i) { | ||||
val = CSR_READ_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_STATUS); | val = CSR_READ_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_STATUS); | ||||
state = __SHIFTOUT(val, BWI_TX32_STATUS_STATE_MASK); | state = __SHIFTOUT(val, BWI_TX32_STATUS_STATE_MASK); | ||||
if (state == BWI_TX32_STATUS_STATE_DISABLED) | if (state == BWI_TX32_STATUS_STATE_DISABLED) | ||||
break; | break; | ||||
DELAY(1000); | DELAY(1000); | ||||
} | } | ||||
if (i == NRETRY) | if (i == NRETRY) | ||||
if_printf(ifp, "%s: reset TX ring (%d) timed out\n", | device_printf(sc->sc_dev, "%s: reset TX ring (%d) timed out\n", | ||||
__func__, ring_idx); | __func__, ring_idx); | ||||
#undef NRETRY | #undef NRETRY | ||||
DELAY(1000); | DELAY(1000); | ||||
CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_RINGINFO, 0); | CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_RINGINFO, 0); | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | else | ||||
panic("unsupport modulation type %u\n", modtype); | panic("unsupport modulation type %u\n", modtype); | ||||
} | } | ||||
static int | static int | ||||
bwi_encap(struct bwi_softc *sc, int idx, struct mbuf *m, | bwi_encap(struct bwi_softc *sc, int idx, struct mbuf *m, | ||||
struct ieee80211_node *ni) | struct ieee80211_node *ni) | ||||
{ | { | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct bwi_ring_data *rd = &sc->sc_tx_rdata[BWI_TX_DATA_RING]; | struct bwi_ring_data *rd = &sc->sc_tx_rdata[BWI_TX_DATA_RING]; | ||||
struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; | struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; | ||||
struct bwi_txbuf *tb = &tbd->tbd_buf[idx]; | struct bwi_txbuf *tb = &tbd->tbd_buf[idx]; | ||||
struct bwi_mac *mac; | struct bwi_mac *mac; | ||||
struct bwi_txbuf_hdr *hdr; | struct bwi_txbuf_hdr *hdr; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
const struct ieee80211_txparam *tp; | const struct ieee80211_txparam *tp; | ||||
uint8_t rate, rate_fb; | uint8_t rate, rate_fb; | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | if (ieee80211_radiotap_active_vap(vap)) { | ||||
ieee80211_radiotap_tx(vap, m); | ieee80211_radiotap_tx(vap, m); | ||||
} | } | ||||
/* | /* | ||||
* Setup the embedded TX header | * Setup the embedded TX header | ||||
*/ | */ | ||||
M_PREPEND(m, sizeof(*hdr), M_NOWAIT); | M_PREPEND(m, sizeof(*hdr), M_NOWAIT); | ||||
if (m == NULL) { | if (m == NULL) { | ||||
if_printf(ifp, "%s: prepend TX header failed\n", __func__); | device_printf(sc->sc_dev, "%s: prepend TX header failed\n", | ||||
__func__); | |||||
return ENOBUFS; | return ENOBUFS; | ||||
} | } | ||||
hdr = mtod(m, struct bwi_txbuf_hdr *); | hdr = mtod(m, struct bwi_txbuf_hdr *); | ||||
bzero(hdr, sizeof(*hdr)); | bzero(hdr, sizeof(*hdr)); | ||||
bcopy(wh->i_fc, hdr->txh_fc, sizeof(hdr->txh_fc)); | bcopy(wh->i_fc, hdr->txh_fc, sizeof(hdr->txh_fc)); | ||||
bcopy(wh->i_addr1, hdr->txh_addr1, sizeof(hdr->txh_addr1)); | bcopy(wh->i_addr1, hdr->txh_addr1, sizeof(hdr->txh_addr1)); | ||||
Show All 32 Lines | #endif | ||||
/* Catch any further usage */ | /* Catch any further usage */ | ||||
hdr = NULL; | hdr = NULL; | ||||
wh = NULL; | wh = NULL; | ||||
/* DMA load */ | /* DMA load */ | ||||
error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m, | error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m, | ||||
bwi_dma_buf_addr, &paddr, BUS_DMA_NOWAIT); | bwi_dma_buf_addr, &paddr, BUS_DMA_NOWAIT); | ||||
if (error && error != EFBIG) { | if (error && error != EFBIG) { | ||||
if_printf(ifp, "%s: can't load TX buffer (1) %d\n", | device_printf(sc->sc_dev, "%s: can't load TX buffer (1) %d\n", | ||||
__func__, error); | __func__, error); | ||||
goto back; | goto back; | ||||
} | } | ||||
if (error) { /* error == EFBIG */ | if (error) { /* error == EFBIG */ | ||||
struct mbuf *m_new; | struct mbuf *m_new; | ||||
m_new = m_defrag(m, M_NOWAIT); | m_new = m_defrag(m, M_NOWAIT); | ||||
if (m_new == NULL) { | if (m_new == NULL) { | ||||
if_printf(ifp, "%s: can't defrag TX buffer\n", | device_printf(sc->sc_dev, | ||||
__func__); | "%s: can't defrag TX buffer\n", __func__); | ||||
error = ENOBUFS; | error = ENOBUFS; | ||||
goto back; | goto back; | ||||
} else { | } else { | ||||
m = m_new; | m = m_new; | ||||
} | } | ||||
error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m, | error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m, | ||||
bwi_dma_buf_addr, &paddr, | bwi_dma_buf_addr, &paddr, | ||||
BUS_DMA_NOWAIT); | BUS_DMA_NOWAIT); | ||||
if (error) { | if (error) { | ||||
if_printf(ifp, "%s: can't load TX buffer (2) %d\n", | device_printf(sc->sc_dev, | ||||
"%s: can't load TX buffer (2) %d\n", | |||||
__func__, error); | __func__, error); | ||||
goto back; | goto back; | ||||
} | } | ||||
} | } | ||||
error = 0; | error = 0; | ||||
bus_dmamap_sync(sc->sc_buf_dtag, tb->tb_dmap, BUS_DMASYNC_PREWRITE); | bus_dmamap_sync(sc->sc_buf_dtag, tb->tb_dmap, BUS_DMASYNC_PREWRITE); | ||||
Show All 25 Lines | if (error) | ||||
m_freem(m); | m_freem(m); | ||||
return error; | return error; | ||||
} | } | ||||
static int | static int | ||||
bwi_encap_raw(struct bwi_softc *sc, int idx, struct mbuf *m, | bwi_encap_raw(struct bwi_softc *sc, int idx, struct mbuf *m, | ||||
struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) | struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct ieee80211com *ic = ni->ni_ic; | struct ieee80211com *ic = ni->ni_ic; | ||||
struct bwi_ring_data *rd = &sc->sc_tx_rdata[BWI_TX_DATA_RING]; | struct bwi_ring_data *rd = &sc->sc_tx_rdata[BWI_TX_DATA_RING]; | ||||
struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; | struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; | ||||
struct bwi_txbuf *tb = &tbd->tbd_buf[idx]; | struct bwi_txbuf *tb = &tbd->tbd_buf[idx]; | ||||
struct bwi_mac *mac; | struct bwi_mac *mac; | ||||
struct bwi_txbuf_hdr *hdr; | struct bwi_txbuf_hdr *hdr; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | if (ieee80211_radiotap_active_vap(vap)) { | ||||
ieee80211_radiotap_tx(vap, m); | ieee80211_radiotap_tx(vap, m); | ||||
} | } | ||||
/* | /* | ||||
* Setup the embedded TX header | * Setup the embedded TX header | ||||
*/ | */ | ||||
M_PREPEND(m, sizeof(*hdr), M_NOWAIT); | M_PREPEND(m, sizeof(*hdr), M_NOWAIT); | ||||
if (m == NULL) { | if (m == NULL) { | ||||
if_printf(ifp, "%s: prepend TX header failed\n", __func__); | device_printf(sc->sc_dev, "%s: prepend TX header failed\n", | ||||
__func__); | |||||
return ENOBUFS; | return ENOBUFS; | ||||
} | } | ||||
hdr = mtod(m, struct bwi_txbuf_hdr *); | hdr = mtod(m, struct bwi_txbuf_hdr *); | ||||
bzero(hdr, sizeof(*hdr)); | bzero(hdr, sizeof(*hdr)); | ||||
bcopy(wh->i_fc, hdr->txh_fc, sizeof(hdr->txh_fc)); | bcopy(wh->i_fc, hdr->txh_fc, sizeof(hdr->txh_fc)); | ||||
bcopy(wh->i_addr1, hdr->txh_addr1, sizeof(hdr->txh_addr1)); | bcopy(wh->i_addr1, hdr->txh_addr1, sizeof(hdr->txh_addr1)); | ||||
Show All 31 Lines | bwi_encap_raw(struct bwi_softc *sc, int idx, struct mbuf *m, | ||||
/* DMA load */ | /* DMA load */ | ||||
error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m, | error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m, | ||||
bwi_dma_buf_addr, &paddr, BUS_DMA_NOWAIT); | bwi_dma_buf_addr, &paddr, BUS_DMA_NOWAIT); | ||||
if (error != 0) { | if (error != 0) { | ||||
struct mbuf *m_new; | struct mbuf *m_new; | ||||
if (error != EFBIG) { | if (error != EFBIG) { | ||||
if_printf(ifp, "%s: can't load TX buffer (1) %d\n", | device_printf(sc->sc_dev, | ||||
"%s: can't load TX buffer (1) %d\n", | |||||
__func__, error); | __func__, error); | ||||
goto back; | goto back; | ||||
} | } | ||||
m_new = m_defrag(m, M_NOWAIT); | m_new = m_defrag(m, M_NOWAIT); | ||||
if (m_new == NULL) { | if (m_new == NULL) { | ||||
if_printf(ifp, "%s: can't defrag TX buffer\n", | device_printf(sc->sc_dev, | ||||
__func__); | "%s: can't defrag TX buffer\n", __func__); | ||||
error = ENOBUFS; | error = ENOBUFS; | ||||
goto back; | goto back; | ||||
} | } | ||||
m = m_new; | m = m_new; | ||||
error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m, | error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m, | ||||
bwi_dma_buf_addr, &paddr, | bwi_dma_buf_addr, &paddr, | ||||
BUS_DMA_NOWAIT); | BUS_DMA_NOWAIT); | ||||
if (error) { | if (error) { | ||||
if_printf(ifp, "%s: can't load TX buffer (2) %d\n", | device_printf(sc->sc_dev, | ||||
"%s: can't load TX buffer (2) %d\n", | |||||
__func__, error); | __func__, error); | ||||
goto back; | goto back; | ||||
} | } | ||||
} | } | ||||
bus_dmamap_sync(sc->sc_buf_dtag, tb->tb_dmap, BUS_DMASYNC_PREWRITE); | bus_dmamap_sync(sc->sc_buf_dtag, tb->tb_dmap, BUS_DMASYNC_PREWRITE); | ||||
tb->tb_mbuf = m; | tb->tb_mbuf = m; | ||||
Show All 27 Lines | |||||
bwi_start_tx64(struct bwi_softc *sc, uint32_t tx_ctrl, int idx) | bwi_start_tx64(struct bwi_softc *sc, uint32_t tx_ctrl, int idx) | ||||
{ | { | ||||
/* TODO:64 */ | /* TODO:64 */ | ||||
} | } | ||||
static void | static void | ||||
bwi_txeof_status32(struct bwi_softc *sc) | bwi_txeof_status32(struct bwi_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
uint32_t val, ctrl_base; | uint32_t val, ctrl_base; | ||||
int end_idx; | int end_idx; | ||||
ctrl_base = sc->sc_txstats->stats_ctrl_base; | ctrl_base = sc->sc_txstats->stats_ctrl_base; | ||||
val = CSR_READ_4(sc, ctrl_base + BWI_RX32_STATUS); | val = CSR_READ_4(sc, ctrl_base + BWI_RX32_STATUS); | ||||
end_idx = __SHIFTOUT(val, BWI_RX32_STATUS_INDEX_MASK) / | end_idx = __SHIFTOUT(val, BWI_RX32_STATUS_INDEX_MASK) / | ||||
sizeof(struct bwi_desc32); | sizeof(struct bwi_desc32); | ||||
bwi_txeof_status(sc, end_idx); | bwi_txeof_status(sc, end_idx); | ||||
CSR_WRITE_4(sc, ctrl_base + BWI_RX32_INDEX, | CSR_WRITE_4(sc, ctrl_base + BWI_RX32_INDEX, | ||||
end_idx * sizeof(struct bwi_desc32)); | end_idx * sizeof(struct bwi_desc32)); | ||||
if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) | bwi_start_locked(sc); | ||||
ifp->if_start(ifp); | |||||
} | } | ||||
static void | static void | ||||
bwi_txeof_status64(struct bwi_softc *sc) | bwi_txeof_status64(struct bwi_softc *sc) | ||||
{ | { | ||||
/* TODO:64 */ | /* TODO:64 */ | ||||
} | } | ||||
static void | static void | ||||
_bwi_txeof(struct bwi_softc *sc, uint16_t tx_id, int acked, int data_txcnt) | _bwi_txeof(struct bwi_softc *sc, uint16_t tx_id, int acked, int data_txcnt) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct bwi_txbuf_data *tbd; | struct bwi_txbuf_data *tbd; | ||||
struct bwi_txbuf *tb; | struct bwi_txbuf *tb; | ||||
int ring_idx, buf_idx; | int ring_idx, buf_idx; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct ieee80211vap *vap; | struct ieee80211vap *vap; | ||||
if (tx_id == 0) { | if (tx_id == 0) { | ||||
if_printf(ifp, "%s: zero tx id\n", __func__); | device_printf(sc->sc_dev, "%s: zero tx id\n", __func__); | ||||
return; | return; | ||||
} | } | ||||
ring_idx = __SHIFTOUT(tx_id, BWI_TXH_ID_RING_MASK); | ring_idx = __SHIFTOUT(tx_id, BWI_TXH_ID_RING_MASK); | ||||
buf_idx = __SHIFTOUT(tx_id, BWI_TXH_ID_IDX_MASK); | buf_idx = __SHIFTOUT(tx_id, BWI_TXH_ID_IDX_MASK); | ||||
KASSERT(ring_idx == BWI_TX_DATA_RING, ("ring_idx %d", ring_idx)); | KASSERT(ring_idx == BWI_TX_DATA_RING, ("ring_idx %d", ring_idx)); | ||||
KASSERT(buf_idx < BWI_TX_NDESC, ("buf_idx %d", buf_idx)); | KASSERT(buf_idx < BWI_TX_NDESC, ("buf_idx %d", buf_idx)); | ||||
tbd = &sc->sc_tx_bdata[ring_idx]; | tbd = &sc->sc_tx_bdata[ring_idx]; | ||||
KASSERT(tbd->tbd_used > 0, ("tbd_used %d", tbd->tbd_used)); | KASSERT(tbd->tbd_used > 0, ("tbd_used %d", tbd->tbd_used)); | ||||
tbd->tbd_used--; | tbd->tbd_used--; | ||||
tb = &tbd->tbd_buf[buf_idx]; | tb = &tbd->tbd_buf[buf_idx]; | ||||
DPRINTF(sc, BWI_DBG_TXEOF, "txeof idx %d, " | DPRINTF(sc, BWI_DBG_TXEOF, "txeof idx %d, " | ||||
"acked %d, data_txcnt %d, ni %p\n", | "acked %d, data_txcnt %d, ni %p\n", | ||||
buf_idx, acked, data_txcnt, tb->tb_ni); | buf_idx, acked, data_txcnt, tb->tb_ni); | ||||
bus_dmamap_unload(sc->sc_buf_dtag, tb->tb_dmap); | bus_dmamap_unload(sc->sc_buf_dtag, tb->tb_dmap); | ||||
ni = tb->tb_ni; | if ((ni = tb->tb_ni) != NULL) { | ||||
if (tb->tb_ni != NULL) { | |||||
const struct bwi_txbuf_hdr *hdr = | const struct bwi_txbuf_hdr *hdr = | ||||
mtod(tb->tb_mbuf, const struct bwi_txbuf_hdr *); | mtod(tb->tb_mbuf, const struct bwi_txbuf_hdr *); | ||||
vap = ni->ni_vap; | vap = ni->ni_vap; | ||||
/* NB: update rate control only for unicast frames */ | /* NB: update rate control only for unicast frames */ | ||||
if (hdr->txh_mac_ctrl & htole32(BWI_TXH_MAC_C_ACK)) { | if (hdr->txh_mac_ctrl & htole32(BWI_TXH_MAC_C_ACK)) { | ||||
/* | /* | ||||
* Feed back 'acked and data_txcnt'. Note that the | * Feed back 'acked and data_txcnt'. Note that the | ||||
* generic AMRR code only understands one tx rate | * generic AMRR code only understands one tx rate | ||||
* and the estimator doesn't handle real retry counts | * and the estimator doesn't handle real retry counts | ||||
* well so to avoid over-aggressive downshifting we | * well so to avoid over-aggressive downshifting we | ||||
* treat any number of retries as "1". | * treat any number of retries as "1". | ||||
*/ | */ | ||||
ieee80211_ratectl_tx_complete(vap, ni, | ieee80211_ratectl_tx_complete(vap, ni, | ||||
(data_txcnt > 1) ? IEEE80211_RATECTL_TX_SUCCESS : | (data_txcnt > 1) ? IEEE80211_RATECTL_TX_SUCCESS : | ||||
IEEE80211_RATECTL_TX_FAILURE, &acked, NULL); | IEEE80211_RATECTL_TX_FAILURE, &acked, NULL); | ||||
} | } | ||||
ieee80211_tx_complete(ni, tb->tb_mbuf, !acked); | |||||
/* | |||||
* Do any tx complete callback. Note this must | |||||
* be done before releasing the node reference. | |||||
*/ | |||||
if (tb->tb_mbuf->m_flags & M_TXCB) | |||||
ieee80211_process_callback(ni, tb->tb_mbuf, !acked); | |||||
ieee80211_free_node(tb->tb_ni); | |||||
tb->tb_ni = NULL; | tb->tb_ni = NULL; | ||||
} | } else | ||||
m_freem(tb->tb_mbuf); | m_freem(tb->tb_mbuf); | ||||
tb->tb_mbuf = NULL; | tb->tb_mbuf = NULL; | ||||
if (tbd->tbd_used == 0) | if (tbd->tbd_used == 0) | ||||
sc->sc_tx_timer = 0; | sc->sc_tx_timer = 0; | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
} | } | ||||
static void | static void | ||||
bwi_txeof_status(struct bwi_softc *sc, int end_idx) | bwi_txeof_status(struct bwi_softc *sc, int end_idx) | ||||
{ | { | ||||
struct bwi_txstats_data *st = sc->sc_txstats; | struct bwi_txstats_data *st = sc->sc_txstats; | ||||
int idx; | int idx; | ||||
Show All 15 Lines | while (idx != end_idx) { | ||||
idx = (idx + 1) % BWI_TXSTATS_NDESC; | idx = (idx + 1) % BWI_TXSTATS_NDESC; | ||||
} | } | ||||
st->stats_idx = idx; | st->stats_idx = idx; | ||||
} | } | ||||
static void | static void | ||||
bwi_txeof(struct bwi_softc *sc) | bwi_txeof(struct bwi_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
for (;;) { | for (;;) { | ||||
uint32_t tx_status0, tx_status1; | uint32_t tx_status0, tx_status1; | ||||
uint16_t tx_id; | uint16_t tx_id; | ||||
int data_txcnt; | int data_txcnt; | ||||
tx_status0 = CSR_READ_4(sc, BWI_TXSTATUS0); | tx_status0 = CSR_READ_4(sc, BWI_TXSTATUS0); | ||||
if ((tx_status0 & BWI_TXSTATUS0_VALID) == 0) | if ((tx_status0 & BWI_TXSTATUS0_VALID) == 0) | ||||
break; | break; | ||||
tx_status1 = CSR_READ_4(sc, BWI_TXSTATUS1); | tx_status1 = CSR_READ_4(sc, BWI_TXSTATUS1); | ||||
tx_id = __SHIFTOUT(tx_status0, BWI_TXSTATUS0_TXID_MASK); | tx_id = __SHIFTOUT(tx_status0, BWI_TXSTATUS0_TXID_MASK); | ||||
data_txcnt = __SHIFTOUT(tx_status0, | data_txcnt = __SHIFTOUT(tx_status0, | ||||
BWI_TXSTATUS0_DATA_TXCNT_MASK); | BWI_TXSTATUS0_DATA_TXCNT_MASK); | ||||
if (tx_status0 & (BWI_TXSTATUS0_AMPDU | BWI_TXSTATUS0_PENDING)) | if (tx_status0 & (BWI_TXSTATUS0_AMPDU | BWI_TXSTATUS0_PENDING)) | ||||
continue; | continue; | ||||
_bwi_txeof(sc, le16toh(tx_id), tx_status0 & BWI_TXSTATUS0_ACKED, | _bwi_txeof(sc, le16toh(tx_id), tx_status0 & BWI_TXSTATUS0_ACKED, | ||||
data_txcnt); | data_txcnt); | ||||
} | } | ||||
if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) | bwi_start_locked(sc); | ||||
ifp->if_start(ifp); | |||||
} | } | ||||
static int | static int | ||||
bwi_bbp_power_on(struct bwi_softc *sc, enum bwi_clock_mode clk_mode) | bwi_bbp_power_on(struct bwi_softc *sc, enum bwi_clock_mode clk_mode) | ||||
{ | { | ||||
bwi_power_on(sc, 1); | bwi_power_on(sc, 1); | ||||
return bwi_set_clock_mode(sc, clk_mode); | return bwi_set_clock_mode(sc, clk_mode); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 231 Lines • ▼ Show 20 Lines | bwi_regwin_enable(struct bwi_softc *sc, struct bwi_regwin *rw, uint32_t flags) | ||||
/* Flush pending bus write */ | /* Flush pending bus write */ | ||||
CSR_READ_4(sc, BWI_STATE_LO); | CSR_READ_4(sc, BWI_STATE_LO); | ||||
DELAY(1); | DELAY(1); | ||||
} | } | ||||
static void | static void | ||||
bwi_set_bssid(struct bwi_softc *sc, const uint8_t *bssid) | bwi_set_bssid(struct bwi_softc *sc, const uint8_t *bssid) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct bwi_mac *mac; | struct bwi_mac *mac; | ||||
struct bwi_myaddr_bssid buf; | struct bwi_myaddr_bssid buf; | ||||
const uint8_t *p; | const uint8_t *p; | ||||
uint32_t val; | uint32_t val; | ||||
int n, i; | int n, i; | ||||
KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, | ||||
("current regwin type %d", sc->sc_cur_regwin->rw_type)); | ("current regwin type %d", sc->sc_cur_regwin->rw_type)); | ||||
mac = (struct bwi_mac *)sc->sc_cur_regwin; | mac = (struct bwi_mac *)sc->sc_cur_regwin; | ||||
bwi_set_addr_filter(sc, BWI_ADDR_FILTER_BSSID, bssid); | bwi_set_addr_filter(sc, BWI_ADDR_FILTER_BSSID, bssid); | ||||
bcopy(IF_LLADDR(ifp), buf.myaddr, sizeof(buf.myaddr)); | bcopy(sc->sc_ic.ic_macaddr, buf.myaddr, sizeof(buf.myaddr)); | ||||
bcopy(bssid, buf.bssid, sizeof(buf.bssid)); | bcopy(bssid, buf.bssid, sizeof(buf.bssid)); | ||||
n = sizeof(buf) / sizeof(val); | n = sizeof(buf) / sizeof(val); | ||||
p = (const uint8_t *)&buf; | p = (const uint8_t *)&buf; | ||||
for (i = 0; i < n; ++i) { | for (i = 0; i < n; ++i) { | ||||
int j; | int j; | ||||
val = 0; | val = 0; | ||||
for (j = 0; j < sizeof(val); ++j) | for (j = 0; j < sizeof(val); ++j) | ||||
val |= ((uint32_t)(*p++)) << (j * 8); | val |= ((uint32_t)(*p++)) << (j * 8); | ||||
TMPLT_WRITE_4(mac, 0x20 + (i * sizeof(val)), val); | TMPLT_WRITE_4(mac, 0x20 + (i * sizeof(val)), val); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
bwi_updateslot(struct ieee80211com *ic) | bwi_updateslot(struct ieee80211com *ic) | ||||
{ | { | ||||
struct bwi_softc *sc = ic->ic_softc; | struct bwi_softc *sc = ic->ic_softc; | ||||
struct bwi_mac *mac; | struct bwi_mac *mac; | ||||
BWI_LOCK(sc); | BWI_LOCK(sc); | ||||
if (ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) { | if (sc->sc_flags & BWI_F_RUNNING) { | ||||
DPRINTF(sc, BWI_DBG_80211, "%s\n", __func__); | DPRINTF(sc, BWI_DBG_80211, "%s\n", __func__); | ||||
KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, | ||||
("current regwin type %d", sc->sc_cur_regwin->rw_type)); | ("current regwin type %d", sc->sc_cur_regwin->rw_type)); | ||||
mac = (struct bwi_mac *)sc->sc_cur_regwin; | mac = (struct bwi_mac *)sc->sc_cur_regwin; | ||||
bwi_mac_updateslot(mac, (ic->ic_flags & IEEE80211_F_SHSLOT)); | bwi_mac_updateslot(mac, (ic->ic_flags & IEEE80211_F_SHSLOT)); | ||||
} | } | ||||
BWI_UNLOCK(sc); | BWI_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
bwi_calibrate(void *xsc) | bwi_calibrate(void *xsc) | ||||
{ | { | ||||
struct bwi_softc *sc = xsc; | struct bwi_softc *sc = xsc; | ||||
#ifdef INVARIANTS | |||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
#endif | |||||
struct bwi_mac *mac; | struct bwi_mac *mac; | ||||
BWI_ASSERT_LOCKED(sc); | BWI_ASSERT_LOCKED(sc); | ||||
KASSERT(ic->ic_opmode != IEEE80211_M_MONITOR, | KASSERT(sc->sc_ic.ic_opmode != IEEE80211_M_MONITOR, | ||||
("opmode %d", ic->ic_opmode)); | ("opmode %d", sc->sc_ic.ic_opmode)); | ||||
KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, | ||||
("current regwin type %d", sc->sc_cur_regwin->rw_type)); | ("current regwin type %d", sc->sc_cur_regwin->rw_type)); | ||||
mac = (struct bwi_mac *)sc->sc_cur_regwin; | mac = (struct bwi_mac *)sc->sc_cur_regwin; | ||||
bwi_mac_calibrate_txpower(mac, sc->sc_txpwrcb_type); | bwi_mac_calibrate_txpower(mac, sc->sc_txpwrcb_type); | ||||
sc->sc_txpwrcb_type = BWI_TXPWR_CALIB; | sc->sc_txpwrcb_type = BWI_TXPWR_CALIB; | ||||
▲ Show 20 Lines • Show All 125 Lines • ▼ Show 20 Lines | bwi_led_onoff(const struct bwi_led *led, uint16_t val, int on) | ||||
else | else | ||||
val &= ~led->l_mask; | val &= ~led->l_mask; | ||||
return val; | return val; | ||||
} | } | ||||
static void | static void | ||||
bwi_led_newstate(struct bwi_softc *sc, enum ieee80211_state nstate) | bwi_led_newstate(struct bwi_softc *sc, enum ieee80211_state nstate) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
uint16_t val; | uint16_t val; | ||||
int i; | int i; | ||||
if (nstate == IEEE80211_S_INIT) { | if (nstate == IEEE80211_S_INIT) { | ||||
callout_stop(&sc->sc_led_blink_ch); | callout_stop(&sc->sc_led_blink_ch); | ||||
sc->sc_led_blinking = 0; | sc->sc_led_blinking = 0; | ||||
} | } | ||||
if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | if ((sc->sc_flags & BWI_F_RUNNING) == 0) | ||||
return; | return; | ||||
val = CSR_READ_2(sc, BWI_MAC_GPIO_CTRL); | val = CSR_READ_2(sc, BWI_MAC_GPIO_CTRL); | ||||
for (i = 0; i < BWI_LED_MAX; ++i) { | for (i = 0; i < BWI_LED_MAX; ++i) { | ||||
struct bwi_led *led = &sc->sc_leds[i]; | struct bwi_led *led = &sc->sc_leds[i]; | ||||
int on; | int on; | ||||
if (led->l_act == BWI_LED_ACT_UNKN || | if (led->l_act == BWI_LED_ACT_UNKN || | ||||
▲ Show 20 Lines • Show All 111 Lines • ▼ Show 20 Lines | bwi_led_blink_end(void *xsc) | ||||
struct bwi_softc *sc = xsc; | struct bwi_softc *sc = xsc; | ||||
sc->sc_led_blinking = 0; | sc->sc_led_blinking = 0; | ||||
} | } | ||||
static void | static void | ||||
bwi_restart(void *xsc, int pending) | bwi_restart(void *xsc, int pending) | ||||
{ | { | ||||
struct bwi_softc *sc = xsc; | struct bwi_softc *sc = xsc; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
if_printf(ifp, "%s begin, help!\n", __func__); | device_printf(sc->sc_dev, "%s begin, help!\n", __func__); | ||||
BWI_LOCK(sc); | BWI_LOCK(sc); | ||||
bwi_init_statechg(xsc, 0); | bwi_init_statechg(sc, 0); | ||||
#if 0 | #if 0 | ||||
bwi_start_locked(ifp); | bwi_start_locked(sc); | ||||
#endif | #endif | ||||
BWI_UNLOCK(sc); | BWI_UNLOCK(sc); | ||||
} | } |