Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/wpi/if_wpi.c
Show First 20 Lines • Show All 199 Lines • ▼ Show 20 Lines | |||||
static int wpi_cmd2(struct wpi_softc *, struct wpi_buf *); | static int wpi_cmd2(struct wpi_softc *, struct wpi_buf *); | ||||
static int wpi_tx_data(struct wpi_softc *, struct mbuf *, | static int wpi_tx_data(struct wpi_softc *, struct mbuf *, | ||||
struct ieee80211_node *); | struct ieee80211_node *); | ||||
static int wpi_tx_data_raw(struct wpi_softc *, struct mbuf *, | static int wpi_tx_data_raw(struct wpi_softc *, struct mbuf *, | ||||
struct ieee80211_node *, | struct ieee80211_node *, | ||||
const struct ieee80211_bpf_params *); | const struct ieee80211_bpf_params *); | ||||
static int wpi_raw_xmit(struct ieee80211_node *, struct mbuf *, | static int wpi_raw_xmit(struct ieee80211_node *, struct mbuf *, | ||||
const struct ieee80211_bpf_params *); | const struct ieee80211_bpf_params *); | ||||
static void wpi_start(struct ifnet *); | static int wpi_transmit(struct ieee80211com *, struct mbuf *); | ||||
static void wpi_start_task(void *, int); | static void wpi_start(void *, int); | ||||
static void wpi_watchdog_rfkill(void *); | static void wpi_watchdog_rfkill(void *); | ||||
static void wpi_scan_timeout(void *); | static void wpi_scan_timeout(void *); | ||||
static void wpi_tx_timeout(void *); | static void wpi_tx_timeout(void *); | ||||
static int wpi_ioctl(struct ifnet *, u_long, caddr_t); | static void wpi_parent(struct ieee80211com *); | ||||
static int wpi_cmd(struct wpi_softc *, int, const void *, size_t, int); | static int wpi_cmd(struct wpi_softc *, int, const void *, size_t, int); | ||||
static int wpi_mrr_setup(struct wpi_softc *); | static int wpi_mrr_setup(struct wpi_softc *); | ||||
static int wpi_add_node(struct wpi_softc *, struct ieee80211_node *); | static int wpi_add_node(struct wpi_softc *, struct ieee80211_node *); | ||||
static int wpi_add_broadcast_node(struct wpi_softc *, int); | static int wpi_add_broadcast_node(struct wpi_softc *, int); | ||||
static int wpi_add_ibss_node(struct wpi_softc *, struct ieee80211_node *); | static int wpi_add_ibss_node(struct wpi_softc *, struct ieee80211_node *); | ||||
static void wpi_del_node(struct wpi_softc *, struct ieee80211_node *); | static void wpi_del_node(struct wpi_softc *, struct ieee80211_node *); | ||||
static int wpi_updateedca(struct ieee80211com *); | static int wpi_updateedca(struct ieee80211com *); | ||||
static void wpi_set_promisc(struct wpi_softc *); | static void wpi_set_promisc(struct wpi_softc *); | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
static int wpi_apm_init(struct wpi_softc *); | static int wpi_apm_init(struct wpi_softc *); | ||||
static void wpi_apm_stop_master(struct wpi_softc *); | static void wpi_apm_stop_master(struct wpi_softc *); | ||||
static void wpi_apm_stop(struct wpi_softc *); | static void wpi_apm_stop(struct wpi_softc *); | ||||
static void wpi_nic_config(struct wpi_softc *); | static void wpi_nic_config(struct wpi_softc *); | ||||
static int wpi_hw_init(struct wpi_softc *); | static int wpi_hw_init(struct wpi_softc *); | ||||
static void wpi_hw_stop(struct wpi_softc *); | static void wpi_hw_stop(struct wpi_softc *); | ||||
static void wpi_radio_on(void *, int); | static void wpi_radio_on(void *, int); | ||||
static void wpi_radio_off(void *, int); | static void wpi_radio_off(void *, int); | ||||
static void wpi_init(void *); | static int wpi_init(struct wpi_softc *); | ||||
static void wpi_stop_locked(struct wpi_softc *); | static void wpi_stop_locked(struct wpi_softc *); | ||||
static void wpi_stop(struct wpi_softc *); | static void wpi_stop(struct wpi_softc *); | ||||
static void wpi_scan_start(struct ieee80211com *); | static void wpi_scan_start(struct ieee80211com *); | ||||
static void wpi_scan_end(struct ieee80211com *); | static void wpi_scan_end(struct ieee80211com *); | ||||
static void wpi_set_channel(struct ieee80211com *); | static void wpi_set_channel(struct ieee80211com *); | ||||
static void wpi_scan_curchan(struct ieee80211_scan_state *, unsigned long); | static void wpi_scan_curchan(struct ieee80211_scan_state *, unsigned long); | ||||
static void wpi_scan_mindwell(struct ieee80211_scan_state *); | static void wpi_scan_mindwell(struct ieee80211_scan_state *); | ||||
static void wpi_hw_reset(void *, int); | static void wpi_hw_reset(void *, int); | ||||
Show All 40 Lines | wpi_probe(device_t dev) | ||||
return ENXIO; | return ENXIO; | ||||
} | } | ||||
static int | static int | ||||
wpi_attach(device_t dev) | wpi_attach(device_t dev) | ||||
{ | { | ||||
struct wpi_softc *sc = (struct wpi_softc *)device_get_softc(dev); | struct wpi_softc *sc = (struct wpi_softc *)device_get_softc(dev); | ||||
struct ieee80211com *ic; | struct ieee80211com *ic; | ||||
struct ifnet *ifp; | |||||
int i, error, rid; | int i, error, rid; | ||||
#ifdef WPI_DEBUG | #ifdef WPI_DEBUG | ||||
int supportsa = 1; | int supportsa = 1; | ||||
const struct wpi_ident *ident; | const struct wpi_ident *ident; | ||||
#endif | #endif | ||||
uint8_t macaddr[IEEE80211_ADDR_LEN]; | |||||
sc->sc_dev = dev; | sc->sc_dev = dev; | ||||
#ifdef WPI_DEBUG | #ifdef WPI_DEBUG | ||||
error = resource_int_value(device_get_name(sc->sc_dev), | error = resource_int_value(device_get_name(sc->sc_dev), | ||||
device_get_unit(sc->sc_dev), "debug", &(sc->sc_debug)); | device_get_unit(sc->sc_dev), "debug", &(sc->sc_debug)); | ||||
if (error != 0) | if (error != 0) | ||||
sc->sc_debug = 0; | sc->sc_debug = 0; | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | if ((error = wpi_alloc_rx_ring(sc)) != 0) { | ||||
device_printf(dev, "could not allocate RX ring, error %d\n", | device_printf(dev, "could not allocate RX ring, error %d\n", | ||||
error); | error); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
/* Clear pending interrupts. */ | /* Clear pending interrupts. */ | ||||
WPI_WRITE(sc, WPI_INT, 0xffffffff); | WPI_WRITE(sc, WPI_INT, 0xffffffff); | ||||
ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); | ic = &sc->sc_ic; | ||||
if (ifp == NULL) { | |||||
device_printf(dev, "can not allocate ifnet structure\n"); | |||||
goto fail; | |||||
} | |||||
ic = ifp->if_l2com; | |||||
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_phytype = IEEE80211_T_OFDM; /* not only, but not used */ | ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ | ||||
ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ | ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ | ||||
/* Set device capabilities. */ | /* Set device capabilities. */ | ||||
ic->ic_caps = | ic->ic_caps = | ||||
IEEE80211_C_STA /* station mode supported */ | IEEE80211_C_STA /* station mode supported */ | ||||
Show All 12 Lines | #endif | ||||
ic->ic_cryptocaps = | ic->ic_cryptocaps = | ||||
IEEE80211_CRYPTO_AES_CCM; | IEEE80211_CRYPTO_AES_CCM; | ||||
/* | /* | ||||
* Read in the eeprom and also setup the channels for | * Read in the eeprom and also setup the channels for | ||||
* net80211. We don't set the rates as net80211 does this for us | * net80211. We don't set the rates as net80211 does this for us | ||||
*/ | */ | ||||
if ((error = wpi_read_eeprom(sc, macaddr)) != 0) { | if ((error = wpi_read_eeprom(sc, ic->ic_macaddr)) != 0) { | ||||
device_printf(dev, "could not read EEPROM, error %d\n", | device_printf(dev, "could not read EEPROM, error %d\n", | ||||
error); | error); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
#ifdef WPI_DEBUG | #ifdef WPI_DEBUG | ||||
if (bootverbose) { | if (bootverbose) { | ||||
device_printf(sc->sc_dev, "Regulatory Domain: %.4s\n", | device_printf(sc->sc_dev, "Regulatory Domain: %.4s\n", | ||||
sc->domain); | sc->domain); | ||||
device_printf(sc->sc_dev, "Hardware Type: %c\n", | device_printf(sc->sc_dev, "Hardware Type: %c\n", | ||||
sc->type > 1 ? 'B': '?'); | sc->type > 1 ? 'B': '?'); | ||||
device_printf(sc->sc_dev, "Hardware Revision: %c\n", | device_printf(sc->sc_dev, "Hardware Revision: %c\n", | ||||
((sc->rev & 0xf0) == 0xd0) ? 'D': '?'); | ((sc->rev & 0xf0) == 0xd0) ? 'D': '?'); | ||||
device_printf(sc->sc_dev, "SKU %s support 802.11a\n", | device_printf(sc->sc_dev, "SKU %s support 802.11a\n", | ||||
supportsa ? "does" : "does not"); | supportsa ? "does" : "does not"); | ||||
/* XXX hw_config uses the PCIDEV for the Hardware rev. Must | /* XXX hw_config uses the PCIDEV for the Hardware rev. Must | ||||
check what sc->rev really represents - benjsc 20070615 */ | check what sc->rev really represents - benjsc 20070615 */ | ||||
} | } | ||||
#endif | #endif | ||||
if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | ieee80211_ifattach(ic); | ||||
ifp->if_softc = sc; | |||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |||||
ifp->if_init = wpi_init; | |||||
ifp->if_ioctl = wpi_ioctl; | |||||
ifp->if_start = wpi_start; | |||||
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); | |||||
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; | |||||
IFQ_SET_READY(&ifp->if_snd); | |||||
ieee80211_ifattach(ic, macaddr); | |||||
ic->ic_vap_create = wpi_vap_create; | ic->ic_vap_create = wpi_vap_create; | ||||
ic->ic_vap_delete = wpi_vap_delete; | ic->ic_vap_delete = wpi_vap_delete; | ||||
ic->ic_parent = wpi_parent; | |||||
ic->ic_raw_xmit = wpi_raw_xmit; | ic->ic_raw_xmit = wpi_raw_xmit; | ||||
ic->ic_transmit = wpi_transmit; | |||||
ic->ic_node_alloc = wpi_node_alloc; | ic->ic_node_alloc = wpi_node_alloc; | ||||
sc->sc_node_free = ic->ic_node_free; | sc->sc_node_free = ic->ic_node_free; | ||||
ic->ic_node_free = wpi_node_free; | ic->ic_node_free = wpi_node_free; | ||||
ic->ic_wme.wme_update = wpi_updateedca; | ic->ic_wme.wme_update = wpi_updateedca; | ||||
ic->ic_update_promisc = wpi_update_promisc; | ic->ic_update_promisc = wpi_update_promisc; | ||||
ic->ic_update_mcast = wpi_update_mcast; | ic->ic_update_mcast = wpi_update_mcast; | ||||
ic->ic_newassoc = wpi_newassoc; | ic->ic_newassoc = wpi_newassoc; | ||||
ic->ic_scan_start = wpi_scan_start; | ic->ic_scan_start = wpi_scan_start; | ||||
Show All 10 Lines | #endif | ||||
callout_init_mtx(&sc->calib_to, &sc->rxon_mtx, 0); | callout_init_mtx(&sc->calib_to, &sc->rxon_mtx, 0); | ||||
callout_init_mtx(&sc->scan_timeout, &sc->rxon_mtx, 0); | callout_init_mtx(&sc->scan_timeout, &sc->rxon_mtx, 0); | ||||
callout_init_mtx(&sc->tx_timeout, &sc->txq_state_mtx, 0); | callout_init_mtx(&sc->tx_timeout, &sc->txq_state_mtx, 0); | ||||
callout_init_mtx(&sc->watchdog_rfkill, &sc->sc_mtx, 0); | callout_init_mtx(&sc->watchdog_rfkill, &sc->sc_mtx, 0); | ||||
TASK_INIT(&sc->sc_reinittask, 0, wpi_hw_reset, sc); | TASK_INIT(&sc->sc_reinittask, 0, wpi_hw_reset, sc); | ||||
TASK_INIT(&sc->sc_radiooff_task, 0, wpi_radio_off, sc); | TASK_INIT(&sc->sc_radiooff_task, 0, wpi_radio_off, sc); | ||||
TASK_INIT(&sc->sc_radioon_task, 0, wpi_radio_on, sc); | TASK_INIT(&sc->sc_radioon_task, 0, wpi_radio_on, sc); | ||||
TASK_INIT(&sc->sc_start_task, 0, wpi_start_task, sc); | TASK_INIT(&sc->sc_start_task, 0, wpi_start, sc); | ||||
sc->sc_tq = taskqueue_create("wpi_taskq", M_WAITOK, | sc->sc_tq = taskqueue_create("wpi_taskq", M_WAITOK, | ||||
taskqueue_thread_enqueue, &sc->sc_tq); | taskqueue_thread_enqueue, &sc->sc_tq); | ||||
error = taskqueue_start_threads(&sc->sc_tq, 1, 0, "wpi_taskq"); | error = taskqueue_start_threads(&sc->sc_tq, 1, 0, "wpi_taskq"); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(dev, "can't start threads, error %d\n", error); | device_printf(dev, "can't start threads, error %d\n", error); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
Show All 28 Lines | |||||
} | } | ||||
/* | /* | ||||
* Attach the interface to 802.11 radiotap. | * Attach the interface to 802.11 radiotap. | ||||
*/ | */ | ||||
static void | static void | ||||
wpi_radiotap_attach(struct wpi_softc *sc) | wpi_radiotap_attach(struct wpi_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct wpi_rx_radiotap_header *rxtap = &sc->sc_rxtap; | ||||
struct ieee80211com *ic = ifp->if_l2com; | struct wpi_tx_radiotap_header *txtap = &sc->sc_txtap; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
ieee80211_radiotap_attach(ic, | ieee80211_radiotap_attach(&sc->sc_ic, | ||||
&sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), | &txtap->wt_ihdr, sizeof(*txtap), WPI_TX_RADIOTAP_PRESENT, | ||||
WPI_TX_RADIOTAP_PRESENT, | &rxtap->wr_ihdr, sizeof(*rxtap), WPI_RX_RADIOTAP_PRESENT); | ||||
&sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), | |||||
WPI_RX_RADIOTAP_PRESENT); | |||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | ||||
} | } | ||||
static void | static void | ||||
wpi_sysctlattach(struct wpi_softc *sc) | wpi_sysctlattach(struct wpi_softc *sc) | ||||
{ | { | ||||
#ifdef WPI_DEBUG | #ifdef WPI_DEBUG | ||||
struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); | struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); | ||||
Show All 34 Lines | wpi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, | ||||
const uint8_t mac[IEEE80211_ADDR_LEN]) | const uint8_t mac[IEEE80211_ADDR_LEN]) | ||||
{ | { | ||||
struct wpi_vap *wvp; | struct wpi_vap *wvp; | ||||
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; | ||||
wvp = (struct wpi_vap *) malloc(sizeof(struct wpi_vap), | wvp = malloc(sizeof(struct wpi_vap), M_80211_VAP, M_WAITOK | M_ZERO); | ||||
M_80211_VAP, M_NOWAIT | M_ZERO); | |||||
if (wvp == NULL) | |||||
return NULL; | |||||
vap = &wvp->wv_vap; | vap = &wvp->wv_vap; | ||||
ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); | ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); | ||||
if (opmode == IEEE80211_M_IBSS || opmode == IEEE80211_M_HOSTAP) { | if (opmode == IEEE80211_M_IBSS || opmode == IEEE80211_M_HOSTAP) { | ||||
WPI_VAP_LOCK_INIT(wvp); | WPI_VAP_LOCK_INIT(wvp); | ||||
wpi_init_beacon(wvp); | wpi_init_beacon(wvp); | ||||
} | } | ||||
/* Override with driver methods. */ | /* Override with driver methods. */ | ||||
vap->iv_key_set = wpi_key_set; | vap->iv_key_set = wpi_key_set; | ||||
vap->iv_key_delete = wpi_key_delete; | vap->iv_key_delete = wpi_key_delete; | ||||
wvp->wv_recv_mgmt = vap->iv_recv_mgmt; | wvp->wv_recv_mgmt = vap->iv_recv_mgmt; | ||||
vap->iv_recv_mgmt = wpi_recv_mgmt; | vap->iv_recv_mgmt = wpi_recv_mgmt; | ||||
wvp->wv_newstate = vap->iv_newstate; | wvp->wv_newstate = vap->iv_newstate; | ||||
vap->iv_newstate = wpi_newstate; | vap->iv_newstate = wpi_newstate; | ||||
vap->iv_update_beacon = wpi_update_beacon; | vap->iv_update_beacon = wpi_update_beacon; | ||||
vap->iv_max_aid = WPI_ID_IBSS_MAX - WPI_ID_IBSS_MIN + 1; | vap->iv_max_aid = WPI_ID_IBSS_MAX - WPI_ID_IBSS_MIN + 1; | ||||
ieee80211_ratectl_init(vap); | ieee80211_ratectl_init(vap); | ||||
/* Complete setup. */ | /* Complete setup. */ | ||||
ieee80211_vap_attach(vap, ieee80211_media_change, | ieee80211_vap_attach(vap, ieee80211_media_change, | ||||
ieee80211_media_status); | ieee80211_media_status, mac); | ||||
ic->ic_opmode = opmode; | ic->ic_opmode = opmode; | ||||
return vap; | return vap; | ||||
} | } | ||||
static void | static void | ||||
wpi_vap_delete(struct ieee80211vap *vap) | wpi_vap_delete(struct ieee80211vap *vap) | ||||
{ | { | ||||
struct wpi_vap *wvp = WPI_VAP(vap); | struct wpi_vap *wvp = WPI_VAP(vap); | ||||
Show All 12 Lines | wpi_vap_delete(struct ieee80211vap *vap) | ||||
free(wvp, M_80211_VAP); | free(wvp, M_80211_VAP); | ||||
} | } | ||||
static int | static int | ||||
wpi_detach(device_t dev) | wpi_detach(device_t dev) | ||||
{ | { | ||||
struct wpi_softc *sc = device_get_softc(dev); | struct wpi_softc *sc = device_get_softc(dev); | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic; | |||||
int qid; | int qid; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
if (ifp != NULL) { | if (ic->ic_vap_create == wpi_vap_create) { | ||||
ic = ifp->if_l2com; | |||||
ieee80211_draintask(ic, &sc->sc_radioon_task); | ieee80211_draintask(ic, &sc->sc_radioon_task); | ||||
ieee80211_draintask(ic, &sc->sc_start_task); | ieee80211_draintask(ic, &sc->sc_start_task); | ||||
wpi_stop(sc); | wpi_stop(sc); | ||||
if (sc->sc_tq != NULL) { | |||||
taskqueue_drain_all(sc->sc_tq); | taskqueue_drain_all(sc->sc_tq); | ||||
taskqueue_free(sc->sc_tq); | taskqueue_free(sc->sc_tq); | ||||
} | |||||
callout_drain(&sc->watchdog_rfkill); | callout_drain(&sc->watchdog_rfkill); | ||||
callout_drain(&sc->tx_timeout); | callout_drain(&sc->tx_timeout); | ||||
callout_drain(&sc->scan_timeout); | callout_drain(&sc->scan_timeout); | ||||
callout_drain(&sc->calib_to); | callout_drain(&sc->calib_to); | ||||
ieee80211_ifdetach(ic); | ieee80211_ifdetach(ic); | ||||
} | } | ||||
Show All 16 Lines | wpi_detach(device_t dev) | ||||
if (sc->fw_dma.tag) | if (sc->fw_dma.tag) | ||||
wpi_free_fwmem(sc); | wpi_free_fwmem(sc); | ||||
if (sc->mem != NULL) | if (sc->mem != NULL) | ||||
bus_release_resource(dev, SYS_RES_MEMORY, | bus_release_resource(dev, SYS_RES_MEMORY, | ||||
rman_get_rid(sc->mem), sc->mem); | rman_get_rid(sc->mem), sc->mem); | ||||
if (ifp != NULL) | |||||
if_free(ifp); | |||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | ||||
WPI_TXQ_STATE_LOCK_DESTROY(sc); | WPI_TXQ_STATE_LOCK_DESTROY(sc); | ||||
WPI_TXQ_LOCK_DESTROY(sc); | WPI_TXQ_LOCK_DESTROY(sc); | ||||
WPI_NT_LOCK_DESTROY(sc); | WPI_NT_LOCK_DESTROY(sc); | ||||
WPI_RXON_LOCK_DESTROY(sc); | WPI_RXON_LOCK_DESTROY(sc); | ||||
WPI_TX_LOCK_DESTROY(sc); | WPI_TX_LOCK_DESTROY(sc); | ||||
WPI_LOCK_DESTROY(sc); | WPI_LOCK_DESTROY(sc); | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
wpi_shutdown(device_t dev) | wpi_shutdown(device_t dev) | ||||
{ | { | ||||
struct wpi_softc *sc = device_get_softc(dev); | struct wpi_softc *sc = device_get_softc(dev); | ||||
wpi_stop(sc); | wpi_stop(sc); | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
wpi_suspend(device_t dev) | wpi_suspend(device_t dev) | ||||
{ | { | ||||
struct wpi_softc *sc = device_get_softc(dev); | struct wpi_softc *sc = device_get_softc(dev); | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
ieee80211_suspend_all(ic); | ieee80211_suspend_all(ic); | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
wpi_resume(device_t dev) | wpi_resume(device_t dev) | ||||
{ | { | ||||
struct wpi_softc *sc = device_get_softc(dev); | struct wpi_softc *sc = device_get_softc(dev); | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
/* Clear device-specific "PCI retry timeout" register (41h). */ | /* Clear device-specific "PCI retry timeout" register (41h). */ | ||||
pci_write_config(dev, 0x41, 0, 1); | pci_write_config(dev, 0x41, 0, 1); | ||||
ieee80211_resume_all(ic); | ieee80211_resume_all(ic); | ||||
return 0; | return 0; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 390 Lines • ▼ Show 20 Lines | wpi_alloc_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring, int qid) | ||||
bus_addr_t paddr; | bus_addr_t paddr; | ||||
bus_size_t size; | bus_size_t size; | ||||
int i, error; | int i, error; | ||||
ring->qid = qid; | ring->qid = qid; | ||||
ring->queued = 0; | ring->queued = 0; | ||||
ring->cur = 0; | ring->cur = 0; | ||||
ring->update = 0; | ring->update = 0; | ||||
mbufq_init(&ring->snd, ifqmaxlen); | |||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
/* Allocate TX descriptors (16KB aligned.) */ | /* Allocate TX descriptors (16KB aligned.) */ | ||||
size = WPI_TX_RING_COUNT * sizeof (struct wpi_tx_desc); | size = WPI_TX_RING_COUNT * sizeof (struct wpi_tx_desc); | ||||
error = wpi_dma_contig_alloc(sc, &ring->desc_dma, (void **)&ring->desc, | error = wpi_dma_contig_alloc(sc, &ring->desc_dma, (void **)&ring->desc, | ||||
size, WPI_RING_DMA_ALIGN); | size, WPI_RING_DMA_ALIGN); | ||||
if (error != 0) { | if (error != 0) { | ||||
▲ Show 20 Lines • Show All 111 Lines • ▼ Show 20 Lines | if (data->ni != NULL) { | ||||
ieee80211_free_node(data->ni); | ieee80211_free_node(data->ni); | ||||
data->ni = NULL; | data->ni = NULL; | ||||
} | } | ||||
} | } | ||||
/* Clear TX descriptors. */ | /* Clear TX descriptors. */ | ||||
memset(ring->desc, 0, ring->desc_dma.size); | memset(ring->desc, 0, ring->desc_dma.size); | ||||
bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, | bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, | ||||
BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREWRITE); | ||||
mbufq_drain(&ring->snd); | |||||
sc->qfullmsk &= ~(1 << ring->qid); | sc->qfullmsk &= ~(1 << ring->qid); | ||||
ring->queued = 0; | ring->queued = 0; | ||||
ring->cur = 0; | ring->cur = 0; | ||||
ring->update = 0; | ring->update = 0; | ||||
} | } | ||||
static void | static void | ||||
wpi_free_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) | wpi_free_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) | ||||
▲ Show 20 Lines • Show All 114 Lines • ▼ Show 20 Lines | if (nflags & IEEE80211_CHAN_NOADHOC) | ||||
nflags |= IEEE80211_CHAN_NOHOSTAP; | nflags |= IEEE80211_CHAN_NOHOSTAP; | ||||
return nflags; | return nflags; | ||||
} | } | ||||
static void | static void | ||||
wpi_read_eeprom_band(struct wpi_softc *sc, int n) | wpi_read_eeprom_band(struct wpi_softc *sc, int n) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct wpi_eeprom_chan *channels = sc->eeprom_channels[n]; | struct wpi_eeprom_chan *channels = sc->eeprom_channels[n]; | ||||
const struct wpi_chan_band *band = &wpi_bands[n]; | const struct wpi_chan_band *band = &wpi_bands[n]; | ||||
struct ieee80211_channel *c; | struct ieee80211_channel *c; | ||||
uint8_t chan; | uint8_t chan; | ||||
int i, nflags; | int i, nflags; | ||||
for (i = 0; i < band->nchan; i++) { | for (i = 0; i < band->nchan; i++) { | ||||
if (!(channels[i].flags & WPI_EEPROM_CHAN_VALID)) { | if (!(channels[i].flags & WPI_EEPROM_CHAN_VALID)) { | ||||
Show All 40 Lines | |||||
/** | /** | ||||
* Read the eeprom to find out what channels are valid for the given | * Read the eeprom to find out what channels are valid for the given | ||||
* band and update net80211 with what we find. | * band and update net80211 with what we find. | ||||
*/ | */ | ||||
static int | static int | ||||
wpi_read_eeprom_channels(struct wpi_softc *sc, int n) | wpi_read_eeprom_channels(struct wpi_softc *sc, int n) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
const struct wpi_chan_band *band = &wpi_bands[n]; | const struct wpi_chan_band *band = &wpi_bands[n]; | ||||
int error; | int error; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
error = wpi_read_prom_data(sc, band->addr, &sc->eeprom_channels[n], | error = wpi_read_prom_data(sc, band->addr, &sc->eeprom_channels[n], | ||||
band->nchan * sizeof (struct wpi_eeprom_chan)); | band->nchan * sizeof (struct wpi_eeprom_chan)); | ||||
if (error != 0) { | if (error != 0) { | ||||
Show All 25 Lines | |||||
/* | /* | ||||
* Enforce flags read from EEPROM. | * Enforce flags read from EEPROM. | ||||
*/ | */ | ||||
static int | static int | ||||
wpi_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *rd, | wpi_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *rd, | ||||
int nchan, struct ieee80211_channel chans[]) | int nchan, struct ieee80211_channel chans[]) | ||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct wpi_softc *sc = ifp->if_softc; | |||||
int i; | int i; | ||||
for (i = 0; i < nchan; i++) { | for (i = 0; i < nchan; i++) { | ||||
struct ieee80211_channel *c = &chans[i]; | struct ieee80211_channel *c = &chans[i]; | ||||
struct wpi_eeprom_chan *channel; | struct wpi_eeprom_chan *channel; | ||||
channel = wpi_find_eeprom_channel(sc, c); | channel = wpi_find_eeprom_channel(sc, c); | ||||
if (channel == NULL) { | if (channel == NULL) { | ||||
if_printf(ic->ic_ifp, | ic_printf(ic, "%s: invalid channel %u freq %u/0x%x\n", | ||||
"%s: invalid channel %u freq %u/0x%x\n", | |||||
__func__, c->ic_ieee, c->ic_freq, c->ic_flags); | __func__, c->ic_ieee, c->ic_freq, c->ic_flags); | ||||
return EINVAL; | return EINVAL; | ||||
} | } | ||||
c->ic_flags |= wpi_eeprom_channel_flags(channel); | c->ic_flags |= wpi_eeprom_channel_flags(channel); | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 95 Lines • ▼ Show 20 Lines | wpi_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) | ||||
wn->id = WPI_ID_UNDEFINED; | wn->id = WPI_ID_UNDEFINED; | ||||
return &wn->ni; | return &wn->ni; | ||||
} | } | ||||
static void | static void | ||||
wpi_node_free(struct ieee80211_node *ni) | wpi_node_free(struct ieee80211_node *ni) | ||||
{ | { | ||||
struct ieee80211com *ic = ni->ni_ic; | struct wpi_softc *sc = ni->ni_ic->ic_softc; | ||||
struct wpi_softc *sc = ic->ic_ifp->if_softc; | |||||
struct wpi_node *wn = WPI_NODE(ni); | struct wpi_node *wn = WPI_NODE(ni); | ||||
if (wn->id != WPI_ID_UNDEFINED) { | if (wn->id != WPI_ID_UNDEFINED) { | ||||
WPI_NT_LOCK(sc); | WPI_NT_LOCK(sc); | ||||
if (wpi_check_node_entry(sc, wn->id)) { | if (wpi_check_node_entry(sc, wn->id)) { | ||||
wpi_del_node_entry(sc, wn->id); | wpi_del_node_entry(sc, wn->id); | ||||
wpi_del_node(sc, ni); | wpi_del_node(sc, ni); | ||||
} | } | ||||
Show All 10 Lines | |||||
} | } | ||||
static void | static void | ||||
wpi_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, | wpi_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, | ||||
const struct ieee80211_rx_stats *rxs, | const struct ieee80211_rx_stats *rxs, | ||||
int rssi, int nf) | int rssi, int nf) | ||||
{ | { | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct wpi_softc *sc = vap->iv_ic->ic_ifp->if_softc; | struct wpi_softc *sc = vap->iv_ic->ic_softc; | ||||
struct wpi_vap *wvp = WPI_VAP(vap); | struct wpi_vap *wvp = WPI_VAP(vap); | ||||
uint64_t ni_tstamp, rx_tstamp; | uint64_t ni_tstamp, rx_tstamp; | ||||
wvp->wv_recv_mgmt(ni, m, subtype, rxs, rssi, nf); | wvp->wv_recv_mgmt(ni, m, subtype, rxs, rssi, nf); | ||||
if (vap->iv_opmode == IEEE80211_M_IBSS && | if (vap->iv_opmode == IEEE80211_M_IBSS && | ||||
vap->iv_state == IEEE80211_S_RUN && | vap->iv_state == IEEE80211_S_RUN && | ||||
(subtype == IEEE80211_FC0_SUBTYPE_BEACON || | (subtype == IEEE80211_FC0_SUBTYPE_BEACON || | ||||
Show All 27 Lines | if (wn->id != WPI_ID_UNDEFINED) { | ||||
} | } | ||||
} | } | ||||
WPI_NT_UNLOCK(sc); | WPI_NT_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
wpi_restore_node_table(struct wpi_softc *sc, struct wpi_vap *wvp) | wpi_restore_node_table(struct wpi_softc *sc, struct wpi_vap *wvp) | ||||
{ | { | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
/* Set group keys once. */ | /* Set group keys once. */ | ||||
WPI_NT_LOCK(sc); | WPI_NT_LOCK(sc); | ||||
wvp->wv_gtk = 0; | wvp->wv_gtk = 0; | ||||
WPI_NT_UNLOCK(sc); | WPI_NT_UNLOCK(sc); | ||||
ieee80211_iterate_nodes(&ic->ic_sta, wpi_restore_node, sc); | ieee80211_iterate_nodes(&ic->ic_sta, wpi_restore_node, sc); | ||||
ieee80211_crypto_reload_keys(ic); | ieee80211_crypto_reload_keys(ic); | ||||
} | } | ||||
/** | /** | ||||
* Called by net80211 when ever there is a change to 80211 state machine | * Called by net80211 when ever there is a change to 80211 state machine | ||||
*/ | */ | ||||
static int | static int | ||||
wpi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) | wpi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) | ||||
{ | { | ||||
struct wpi_vap *wvp = WPI_VAP(vap); | struct wpi_vap *wvp = WPI_VAP(vap); | ||||
struct ieee80211com *ic = vap->iv_ic; | struct ieee80211com *ic = vap->iv_ic; | ||||
struct ifnet *ifp = ic->ic_ifp; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct wpi_softc *sc = ifp->if_softc; | |||||
int error = 0; | int error = 0; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
WPI_TXQ_LOCK(sc); | |||||
if (nstate > IEEE80211_S_INIT && sc->sc_running == 0) { | |||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); | |||||
WPI_TXQ_UNLOCK(sc); | |||||
return ENXIO; | |||||
} | |||||
WPI_TXQ_UNLOCK(sc); | |||||
DPRINTF(sc, WPI_DEBUG_STATE, "%s: %s -> %s\n", __func__, | DPRINTF(sc, WPI_DEBUG_STATE, "%s: %s -> %s\n", __func__, | ||||
ieee80211_state_name[vap->iv_state], | ieee80211_state_name[vap->iv_state], | ||||
ieee80211_state_name[nstate]); | ieee80211_state_name[nstate]); | ||||
if (vap->iv_state == IEEE80211_S_RUN && nstate < IEEE80211_S_RUN) { | if (vap->iv_state == IEEE80211_S_RUN && nstate < IEEE80211_S_RUN) { | ||||
if ((error = wpi_set_pslevel(sc, 0, 0, 1)) != 0) { | if ((error = wpi_set_pslevel(sc, 0, 0, 1)) != 0) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"%s: could not set power saving level\n", | "%s: could not set power saving level\n", | ||||
▲ Show 20 Lines • Show All 152 Lines • ▼ Show 20 Lines | |||||
/* Quickly determine if a given rate is CCK or OFDM. */ | /* Quickly determine if a given rate is CCK or OFDM. */ | ||||
#define WPI_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) | #define WPI_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) | ||||
static void | static void | ||||
wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, | wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, | ||||
struct wpi_rx_data *data) | struct wpi_rx_data *data) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct wpi_rx_ring *ring = &sc->rxq; | struct wpi_rx_ring *ring = &sc->rxq; | ||||
struct wpi_rx_stat *stat; | struct wpi_rx_stat *stat; | ||||
struct wpi_rx_head *head; | struct wpi_rx_head *head; | ||||
struct wpi_rx_tail *tail; | struct wpi_rx_tail *tail; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct mbuf *m, *m1; | struct mbuf *m, *m1; | ||||
bus_addr_t paddr; | bus_addr_t paddr; | ||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, | ||||
m = data->m; | m = data->m; | ||||
data->m = m1; | data->m = m1; | ||||
/* Update RX descriptor. */ | /* Update RX descriptor. */ | ||||
ring->desc[ring->cur] = htole32(paddr); | ring->desc[ring->cur] = htole32(paddr); | ||||
bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, | bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, | ||||
BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREWRITE); | ||||
/* Finalize mbuf. */ | /* Finalize mbuf. */ | ||||
m->m_pkthdr.rcvif = ifp; | |||||
m->m_data = (caddr_t)(head + 1); | m->m_data = (caddr_t)(head + 1); | ||||
m->m_pkthdr.len = m->m_len = len; | m->m_pkthdr.len = m->m_len = len; | ||||
/* Grab a reference to the source node. */ | /* Grab a reference to the source node. */ | ||||
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) && | ||||
(flags & WPI_RX_CIPHER_MASK) == WPI_RX_CIPHER_CCMP) { | (flags & WPI_RX_CIPHER_MASK) == WPI_RX_CIPHER_CCMP) { | ||||
Show All 37 Lines | if (ni != NULL) { | ||||
(void)ieee80211_input_all(ic, m, stat->rssi, WPI_RSSI_OFFSET); | (void)ieee80211_input_all(ic, m, stat->rssi, WPI_RSSI_OFFSET); | ||||
WPI_LOCK(sc); | WPI_LOCK(sc); | ||||
return; | return; | ||||
fail2: m_freem(m); | fail2: m_freem(m); | ||||
fail1: if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | fail1: counter_u64_add(ic->ic_ierrors, 1); | ||||
} | } | ||||
static void | static void | ||||
wpi_rx_statistics(struct wpi_softc *sc, struct wpi_rx_desc *desc, | wpi_rx_statistics(struct wpi_softc *sc, struct wpi_rx_desc *desc, | ||||
struct wpi_rx_data *data) | struct wpi_rx_data *data) | ||||
{ | { | ||||
/* Ignore */ | /* Ignore */ | ||||
} | } | ||||
static void | static void | ||||
wpi_tx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc) | wpi_tx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct wpi_tx_ring *ring = &sc->txq[desc->qid & 0x3]; | struct wpi_tx_ring *ring = &sc->txq[desc->qid & 0x3]; | ||||
struct wpi_tx_data *data = &ring->data[desc->idx]; | struct wpi_tx_data *data = &ring->data[desc->idx]; | ||||
struct wpi_tx_stat *stat = (struct wpi_tx_stat *)(desc + 1); | struct wpi_tx_stat *stat = (struct wpi_tx_stat *)(desc + 1); | ||||
struct mbuf *m; | struct mbuf *m; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct ieee80211vap *vap; | struct ieee80211vap *vap; | ||||
struct ieee80211com *ic; | struct ieee80211com *ic; | ||||
uint32_t status = le32toh(stat->status); | uint32_t status = le32toh(stat->status); | ||||
Show All 16 Lines | wpi_tx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc) | ||||
ni = data->ni, data->ni = NULL; | ni = data->ni, data->ni = NULL; | ||||
vap = ni->ni_vap; | vap = ni->ni_vap; | ||||
ic = vap->iv_ic; | ic = vap->iv_ic; | ||||
/* | /* | ||||
* Update rate control statistics for the node. | * Update rate control statistics for the node. | ||||
*/ | */ | ||||
if (status & WPI_TX_STATUS_FAIL) { | if (status & WPI_TX_STATUS_FAIL) { | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
ieee80211_ratectl_tx_complete(vap, ni, | ieee80211_ratectl_tx_complete(vap, ni, | ||||
IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); | IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); | ||||
} else { | } else | ||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | |||||
ieee80211_ratectl_tx_complete(vap, ni, | ieee80211_ratectl_tx_complete(vap, ni, | ||||
IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); | IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); | ||||
} | |||||
ieee80211_tx_complete(ni, m, (status & WPI_TX_STATUS_FAIL) != 0); | ieee80211_tx_complete(ni, m, (status & WPI_TX_STATUS_FAIL) != 0); | ||||
WPI_TXQ_STATE_LOCK(sc); | WPI_TXQ_STATE_LOCK(sc); | ||||
ring->queued -= 1; | ring->queued -= 1; | ||||
if (ring->queued > 0) { | if (ring->queued > 0) { | ||||
callout_reset(&sc->tx_timeout, 5*hz, wpi_tx_timeout, sc); | callout_reset(&sc->tx_timeout, 5*hz, wpi_tx_timeout, sc); | ||||
if (sc->qfullmsk != 0 && | if ((sc->qfullmsk & (1 << ring->qid)) != 0 && | ||||
ring->queued < WPI_TX_RING_LOMARK) { | ring->queued < WPI_TX_RING_LOMARK) { | ||||
sc->qfullmsk &= ~(1 << ring->qid); | sc->qfullmsk &= ~(1 << ring->qid); | ||||
IF_LOCK(&ifp->if_snd); | |||||
if (sc->qfullmsk == 0 && | |||||
(ifp->if_drv_flags & IFF_DRV_OACTIVE)) { | |||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
IF_UNLOCK(&ifp->if_snd); | |||||
ieee80211_runtask(ic, &sc->sc_start_task); | ieee80211_runtask(ic, &sc->sc_start_task); | ||||
} else | |||||
IF_UNLOCK(&ifp->if_snd); | |||||
} | } | ||||
} else | } else | ||||
callout_stop(&sc->tx_timeout); | callout_stop(&sc->tx_timeout); | ||||
WPI_TXQ_STATE_UNLOCK(sc); | WPI_TXQ_STATE_UNLOCK(sc); | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | if (desc->type == WPI_CMD_SET_POWER_MODE) { | ||||
} | } | ||||
WPI_TXQ_UNLOCK(sc); | WPI_TXQ_UNLOCK(sc); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
wpi_notif_intr(struct wpi_softc *sc) | wpi_notif_intr(struct wpi_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); | ||||
uint32_t hw; | uint32_t hw; | ||||
bus_dmamap_sync(sc->shared_dma.tag, sc->shared_dma.map, | bus_dmamap_sync(sc->shared_dma.tag, sc->shared_dma.map, | ||||
BUS_DMASYNC_POSTREAD); | BUS_DMASYNC_POSTREAD); | ||||
hw = le32toh(sc->shared->next) & 0xfff; | hw = le32toh(sc->shared->next) & 0xfff; | ||||
hw = (hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1; | hw = (hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1; | ||||
Show All 18 Lines | if (!(desc->qid & WPI_UNSOLICITED_RX_NOTIF)) { | ||||
wpi_cmd_done(sc, desc); | wpi_cmd_done(sc, desc); | ||||
} | } | ||||
switch (desc->type) { | switch (desc->type) { | ||||
case WPI_RX_DONE: | case WPI_RX_DONE: | ||||
/* An 802.11 frame has been received. */ | /* An 802.11 frame has been received. */ | ||||
wpi_rx_done(sc, desc, data); | wpi_rx_done(sc, desc, data); | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | if (sc->sc_running == 0) { | ||||
/* wpi_stop() was called. */ | /* wpi_stop() was called. */ | ||||
return; | return; | ||||
} | } | ||||
break; | break; | ||||
case WPI_TX_DONE: | case WPI_TX_DONE: | ||||
/* An 802.11 frame has been transmitted. */ | /* An 802.11 frame has been transmitted. */ | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | case WPI_UC_READY: | ||||
"microcode alive notification version=%d.%d " | "microcode alive notification version=%d.%d " | ||||
"subtype=%x alive=%x\n", uc->major, uc->minor, | "subtype=%x alive=%x\n", uc->major, uc->minor, | ||||
uc->subtype, le32toh(uc->valid)); | uc->subtype, le32toh(uc->valid)); | ||||
if (le32toh(uc->valid) != 1) { | if (le32toh(uc->valid) != 1) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"microcontroller initialization failed\n"); | "microcontroller initialization failed\n"); | ||||
wpi_stop_locked(sc); | wpi_stop_locked(sc); | ||||
return; | |||||
} | } | ||||
/* Save the address of the error log in SRAM. */ | /* Save the address of the error log in SRAM. */ | ||||
sc->errptr = le32toh(uc->errptr); | sc->errptr = le32toh(uc->errptr); | ||||
break; | break; | ||||
} | } | ||||
case WPI_STATE_CHANGED: | case WPI_STATE_CHANGED: | ||||
{ | { | ||||
bus_dmamap_sync(sc->rxq.data_dmat, data->map, | bus_dmamap_sync(sc->rxq.data_dmat, data->map, | ||||
▲ Show 20 Lines • Show All 214 Lines • ▼ Show 20 Lines | wpi_fatal_intr(struct wpi_softc *sc) | ||||
WPI_TXQ_UNLOCK(sc); | WPI_TXQ_UNLOCK(sc); | ||||
printf(" rx ring: cur=%d\n", sc->rxq.cur); | printf(" rx ring: cur=%d\n", sc->rxq.cur); | ||||
} | } | ||||
static void | static void | ||||
wpi_intr(void *arg) | wpi_intr(void *arg) | ||||
{ | { | ||||
struct wpi_softc *sc = arg; | struct wpi_softc *sc = arg; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
uint32_t r1, r2; | uint32_t r1, r2; | ||||
WPI_LOCK(sc); | WPI_LOCK(sc); | ||||
/* Disable interrupts. */ | /* Disable interrupts. */ | ||||
WPI_WRITE(sc, WPI_INT_MASK, 0); | WPI_WRITE(sc, WPI_INT_MASK, 0); | ||||
r1 = WPI_READ(sc, WPI_INT); | r1 = WPI_READ(sc, WPI_INT); | ||||
Show All 33 Lines | #endif | ||||
if (r1 & WPI_INT_ALIVE) | if (r1 & WPI_INT_ALIVE) | ||||
wakeup(sc); /* Firmware is alive. */ | wakeup(sc); /* Firmware is alive. */ | ||||
if (r1 & WPI_INT_WAKEUP) | if (r1 & WPI_INT_WAKEUP) | ||||
wpi_wakeup_intr(sc); | wpi_wakeup_intr(sc); | ||||
done: | done: | ||||
/* Re-enable interrupts. */ | /* Re-enable interrupts. */ | ||||
if (ifp->if_flags & IFF_UP) | if (sc->sc_running) | ||||
WPI_WRITE(sc, WPI_INT_MASK, WPI_INT_MASK_DEF); | WPI_WRITE(sc, WPI_INT_MASK, WPI_INT_MASK_DEF); | ||||
end: WPI_UNLOCK(sc); | end: WPI_UNLOCK(sc); | ||||
} | } | ||||
static int | static int | ||||
wpi_cmd2(struct wpi_softc *sc, struct wpi_buf *buf) | wpi_cmd2(struct wpi_softc *sc, struct wpi_buf *buf) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct wpi_tx_cmd *cmd; | struct wpi_tx_cmd *cmd; | ||||
struct wpi_tx_data *data; | struct wpi_tx_data *data; | ||||
struct wpi_tx_desc *desc; | struct wpi_tx_desc *desc; | ||||
struct wpi_tx_ring *ring; | struct wpi_tx_ring *ring; | ||||
struct mbuf *m1; | struct mbuf *m1; | ||||
bus_dma_segment_t *seg, segs[WPI_MAX_SCATTER]; | bus_dma_segment_t *seg, segs[WPI_MAX_SCATTER]; | ||||
int error, i, hdrlen, nsegs, totlen, pad; | int error, i, hdrlen, nsegs, totlen, pad; | ||||
WPI_TXQ_LOCK(sc); | WPI_TXQ_LOCK(sc); | ||||
KASSERT(buf->size <= sizeof(buf->data), ("buffer overflow")); | KASSERT(buf->size <= sizeof(buf->data), ("buffer overflow")); | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
if (sc->txq_active == 0) { | if (sc->sc_running == 0) { | ||||
/* wpi_stop() was called */ | /* wpi_stop() was called */ | ||||
error = ENETDOWN; | error = ENETDOWN; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
wh = mtod(buf->m, struct ieee80211_frame *); | wh = mtod(buf->m, struct ieee80211_frame *); | ||||
hdrlen = ieee80211_anyhdrsize(wh); | hdrlen = ieee80211_anyhdrsize(wh); | ||||
totlen = buf->m->m_pkthdr.len; | totlen = buf->m->m_pkthdr.len; | ||||
▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | wpi_cmd2(struct wpi_softc *sc, struct wpi_buf *buf) | ||||
/* Kick TX ring. */ | /* Kick TX ring. */ | ||||
ring->cur = (ring->cur + 1) % WPI_TX_RING_COUNT; | ring->cur = (ring->cur + 1) % WPI_TX_RING_COUNT; | ||||
sc->sc_update_tx_ring(sc, ring); | sc->sc_update_tx_ring(sc, ring); | ||||
if (ring->qid < WPI_CMD_QUEUE_NUM) { | if (ring->qid < WPI_CMD_QUEUE_NUM) { | ||||
/* Mark TX ring as full if we reach a certain threshold. */ | /* Mark TX ring as full if we reach a certain threshold. */ | ||||
WPI_TXQ_STATE_LOCK(sc); | WPI_TXQ_STATE_LOCK(sc); | ||||
if (++ring->queued > WPI_TX_RING_HIMARK) { | if (++ring->queued > WPI_TX_RING_HIMARK) | ||||
sc->qfullmsk |= 1 << ring->qid; | sc->qfullmsk |= 1 << ring->qid; | ||||
IF_LOCK(&ifp->if_snd); | |||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | |||||
IF_UNLOCK(&ifp->if_snd); | |||||
} | |||||
callout_reset(&sc->tx_timeout, 5*hz, wpi_tx_timeout, sc); | callout_reset(&sc->tx_timeout, 5*hz, wpi_tx_timeout, sc); | ||||
WPI_TXQ_STATE_UNLOCK(sc); | WPI_TXQ_STATE_UNLOCK(sc); | ||||
} | } | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | ||||
WPI_TXQ_UNLOCK(sc); | WPI_TXQ_UNLOCK(sc); | ||||
▲ Show 20 Lines • Show All 277 Lines • ▼ Show 20 Lines | wpi_tx_data_raw(struct wpi_softc *sc, struct mbuf *m, | ||||
tx_data.m = m; | tx_data.m = m; | ||||
tx_data.size = sizeof(struct wpi_cmd_data); | tx_data.size = sizeof(struct wpi_cmd_data); | ||||
tx_data.code = WPI_CMD_TX_DATA; | tx_data.code = WPI_CMD_TX_DATA; | ||||
tx_data.ac = ac; | tx_data.ac = ac; | ||||
return wpi_cmd2(sc, &tx_data); | return wpi_cmd2(sc, &tx_data); | ||||
} | } | ||||
static __inline int | |||||
wpi_tx_ring_is_full(struct wpi_softc *sc, int ac) | |||||
{ | |||||
struct wpi_tx_ring *ring = &sc->txq[ac]; | |||||
int retval; | |||||
WPI_TXQ_STATE_LOCK(sc); | |||||
retval = (ring->queued > WPI_TX_RING_HIMARK); | |||||
WPI_TXQ_STATE_UNLOCK(sc); | |||||
return retval; | |||||
} | |||||
static __inline void | |||||
wpi_handle_tx_failure(struct ieee80211_node *ni) | |||||
{ | |||||
/* NB: m is reclaimed on tx failure */ | |||||
if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); | |||||
ieee80211_free_node(ni); | |||||
} | |||||
static int | static int | ||||
wpi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, | wpi_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 wpi_softc *sc = ic->ic_softc; | ||||
struct wpi_softc *sc = ifp->if_softc; | int ac, error = 0; | ||||
int error = 0; | |||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | ac = M_WME_GETAC(m); | ||||
ieee80211_free_node(ni); | |||||
WPI_TX_LOCK(sc); | |||||
if (sc->sc_running == 0 || wpi_tx_ring_is_full(sc, ac)) { | |||||
m_freem(m); | m_freem(m); | ||||
return ENETDOWN; | error = sc->sc_running ? ENOBUFS : ENETDOWN; | ||||
goto unlock; | |||||
} | } | ||||
WPI_TX_LOCK(sc); | |||||
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 = wpi_tx_data(sc, m, ni); | error = wpi_tx_data(sc, 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 = wpi_tx_data_raw(sc, m, ni, params); | error = wpi_tx_data_raw(sc, m, ni, params); | ||||
} | } | ||||
WPI_TX_UNLOCK(sc); | |||||
if (error != 0) { | unlock: WPI_TX_UNLOCK(sc); | ||||
/* NB: m is reclaimed on tx failure */ | |||||
ieee80211_free_node(ni); | |||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
if (error != 0) { | |||||
wpi_handle_tx_failure(ni); | |||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); | ||||
return error; | return error; | ||||
} | } | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | |||||
wpi_transmit(struct ieee80211com *ic, struct mbuf *m) | |||||
{ | |||||
struct wpi_softc *sc = ic->ic_softc; | |||||
struct ieee80211_node *ni; | |||||
struct mbufq *sndq; | |||||
int ac, error; | |||||
WPI_TX_LOCK(sc); | |||||
DPRINTF(sc, WPI_DEBUG_XMIT, "%s: called\n", __func__); | |||||
/* Check if interface is up & running. */ | |||||
if (sc->sc_running == 0) { | |||||
error = ENXIO; | |||||
goto unlock; | |||||
} | |||||
/* Check for available space. */ | |||||
ac = M_WME_GETAC(m); | |||||
sndq = &sc->txq[ac].snd; | |||||
if (wpi_tx_ring_is_full(sc, ac) || mbufq_len(sndq) != 0) { | |||||
/* wpi_tx_done() will dequeue it. */ | |||||
error = mbufq_enqueue(sndq, m); | |||||
goto unlock; | |||||
} | |||||
error = 0; | |||||
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; | |||||
if (wpi_tx_data(sc, m, ni) != 0) { | |||||
wpi_handle_tx_failure(ni); | |||||
} | |||||
DPRINTF(sc, WPI_DEBUG_XMIT, "%s: done\n", __func__); | |||||
unlock: WPI_TX_UNLOCK(sc); | |||||
return (error); | |||||
} | |||||
/** | /** | ||||
* Process data waiting to be sent on the IFNET output queue | * Process data waiting to be sent on the output queue | ||||
*/ | */ | ||||
static void | static void | ||||
wpi_start(struct ifnet *ifp) | wpi_start(void *arg0, int pending) | ||||
{ | { | ||||
struct wpi_softc *sc = ifp->if_softc; | struct wpi_softc *sc = arg0; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
uint8_t i; | |||||
WPI_TX_LOCK(sc); | WPI_TX_LOCK(sc); | ||||
if (sc->sc_running == 0) | |||||
goto unlock; | |||||
DPRINTF(sc, WPI_DEBUG_XMIT, "%s: called\n", __func__); | DPRINTF(sc, WPI_DEBUG_XMIT, "%s: called\n", __func__); | ||||
for (i = 0; i < WPI_CMD_QUEUE_NUM; i++) { | |||||
struct mbufq *sndq = &sc->txq[i].snd; | |||||
for (;;) { | for (;;) { | ||||
IF_LOCK(&ifp->if_snd); | if (wpi_tx_ring_is_full(sc, i)) | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || | |||||
(ifp->if_drv_flags & IFF_DRV_OACTIVE)) { | |||||
IF_UNLOCK(&ifp->if_snd); | |||||
break; | break; | ||||
} | |||||
IF_UNLOCK(&ifp->if_snd); | |||||
IFQ_DRV_DEQUEUE(&ifp->if_snd, m); | if ((m = mbufq_dequeue(sndq)) == NULL) | ||||
if (m == NULL) | |||||
break; | break; | ||||
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; | ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; | ||||
if (wpi_tx_data(sc, m, ni) != 0) { | if (wpi_tx_data(sc, m, ni) != 0) { | ||||
ieee80211_free_node(ni); | wpi_handle_tx_failure(ni); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
} | } | ||||
} | } | ||||
} | |||||
DPRINTF(sc, WPI_DEBUG_XMIT, "%s: done\n", __func__); | DPRINTF(sc, WPI_DEBUG_XMIT, "%s: done\n", __func__); | ||||
WPI_TX_UNLOCK(sc); | unlock: WPI_TX_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
wpi_start_task(void *arg0, int pending) | |||||
{ | |||||
struct wpi_softc *sc = arg0; | |||||
struct ifnet *ifp = sc->sc_ifp; | |||||
wpi_start(ifp); | |||||
} | |||||
static void | |||||
wpi_watchdog_rfkill(void *arg) | wpi_watchdog_rfkill(void *arg) | ||||
{ | { | ||||
struct wpi_softc *sc = arg; | struct wpi_softc *sc = arg; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
DPRINTF(sc, WPI_DEBUG_WATCHDOG, "RFkill Watchdog: tick\n"); | DPRINTF(sc, WPI_DEBUG_WATCHDOG, "RFkill Watchdog: tick\n"); | ||||
/* No need to lock firmware memory. */ | /* No need to lock firmware memory. */ | ||||
if ((wpi_prph_read(sc, WPI_APMG_RFKILL) & 0x1) == 0) { | if ((wpi_prph_read(sc, WPI_APMG_RFKILL) & 0x1) == 0) { | ||||
/* Radio kill switch is still off. */ | /* Radio kill switch is still off. */ | ||||
callout_reset(&sc->watchdog_rfkill, hz, wpi_watchdog_rfkill, | callout_reset(&sc->watchdog_rfkill, hz, wpi_watchdog_rfkill, | ||||
sc); | sc); | ||||
} else | } else | ||||
ieee80211_runtask(ic, &sc->sc_radioon_task); | ieee80211_runtask(ic, &sc->sc_radioon_task); | ||||
} | } | ||||
static void | static void | ||||
wpi_scan_timeout(void *arg) | wpi_scan_timeout(void *arg) | ||||
{ | { | ||||
struct wpi_softc *sc = arg; | struct wpi_softc *sc = arg; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
if_printf(ifp, "scan timeout\n"); | ic_printf(ic, "scan timeout\n"); | ||||
taskqueue_enqueue(sc->sc_tq, &sc->sc_reinittask); | taskqueue_enqueue(sc->sc_tq, &sc->sc_reinittask); | ||||
} | } | ||||
static void | static void | ||||
wpi_tx_timeout(void *arg) | wpi_tx_timeout(void *arg) | ||||
{ | { | ||||
struct wpi_softc *sc = arg; | struct wpi_softc *sc = arg; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
if_printf(ifp, "device timeout\n"); | ic_printf(ic, "device timeout\n"); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
taskqueue_enqueue(sc->sc_tq, &sc->sc_reinittask); | taskqueue_enqueue(sc->sc_tq, &sc->sc_reinittask); | ||||
} | } | ||||
static int | static void | ||||
wpi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | wpi_parent(struct ieee80211com *ic) | ||||
{ | { | ||||
struct wpi_softc *sc = ifp->if_softc; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
struct ifreq *ifr = (struct ifreq *) data; | |||||
int error = 0; | |||||
switch (cmd) { | if (ic->ic_nrunning > 0) { | ||||
case SIOCGIFADDR: | if (wpi_init(sc) == 0) { | ||||
error = ether_ioctl(ifp, cmd, data); | ieee80211_notify_radio(ic, 1); | ||||
break; | ieee80211_start_all(ic); | ||||
case SIOCSIFFLAGS: | } else { | ||||
if (ifp->if_flags & IFF_UP) { | ieee80211_notify_radio(ic, 0); | ||||
wpi_init(sc); | |||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 && | |||||
vap != NULL) | |||||
ieee80211_stop(vap); | ieee80211_stop(vap); | ||||
} else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) | } | ||||
} else | |||||
wpi_stop(sc); | wpi_stop(sc); | ||||
break; | |||||
case SIOCGIFMEDIA: | |||||
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); | |||||
break; | |||||
default: | |||||
error = EINVAL; | |||||
break; | |||||
} | } | ||||
return error; | |||||
} | |||||
/* | /* | ||||
* Send a command to the firmware. | * Send a command to the firmware. | ||||
*/ | */ | ||||
static int | static int | ||||
wpi_cmd(struct wpi_softc *sc, int code, const void *buf, size_t size, | wpi_cmd(struct wpi_softc *sc, int code, const void *buf, size_t size, | ||||
int async) | int async) | ||||
{ | { | ||||
struct wpi_tx_ring *ring = &sc->txq[WPI_CMD_QUEUE_NUM]; | struct wpi_tx_ring *ring = &sc->txq[WPI_CMD_QUEUE_NUM]; | ||||
struct wpi_tx_desc *desc; | struct wpi_tx_desc *desc; | ||||
struct wpi_tx_data *data; | struct wpi_tx_data *data; | ||||
struct wpi_tx_cmd *cmd; | struct wpi_tx_cmd *cmd; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
bus_addr_t paddr; | bus_addr_t paddr; | ||||
int totlen, error; | int totlen, error; | ||||
WPI_TXQ_LOCK(sc); | WPI_TXQ_LOCK(sc); | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
if (sc->txq_active == 0) { | if (sc->sc_running == 0) { | ||||
/* wpi_stop() was called */ | /* wpi_stop() was called */ | ||||
if (code == WPI_CMD_SCAN) | |||||
error = ENETDOWN; | |||||
else | |||||
error = 0; | error = 0; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
if (async == 0) | if (async == 0) | ||||
WPI_LOCK_ASSERT(sc); | WPI_LOCK_ASSERT(sc); | ||||
DPRINTF(sc, WPI_DEBUG_CMD, "%s: cmd %s size %zu async %d\n", | DPRINTF(sc, WPI_DEBUG_CMD, "%s: cmd %s size %zu async %d\n", | ||||
__func__, wpi_cmd_str(code), size, async); | __func__, wpi_cmd_str(code), size, async); | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | wpi_cmd(struct wpi_softc *sc, int code, const void *buf, size_t size, | ||||
/* Kick command ring. */ | /* Kick command ring. */ | ||||
ring->cur = (ring->cur + 1) % WPI_TX_RING_COUNT; | ring->cur = (ring->cur + 1) % WPI_TX_RING_COUNT; | ||||
sc->sc_update_tx_ring(sc, ring); | sc->sc_update_tx_ring(sc, ring); | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | ||||
WPI_TXQ_UNLOCK(sc); | WPI_TXQ_UNLOCK(sc); | ||||
if (async) | return async ? 0 : mtx_sleep(cmd, &sc->sc_mtx, PCATCH, "wpicmd", hz); | ||||
return 0; | |||||
return mtx_sleep(cmd, &sc->sc_mtx, PCATCH, "wpicmd", hz); | |||||
fail: DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); | fail: DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); | ||||
WPI_TXQ_UNLOCK(sc); | WPI_TXQ_UNLOCK(sc); | ||||
return error; | return error; | ||||
} | } | ||||
/* | /* | ||||
* Configure HW multi-rate retries. | * Configure HW multi-rate retries. | ||||
*/ | */ | ||||
static int | static int | ||||
wpi_mrr_setup(struct wpi_softc *sc) | wpi_mrr_setup(struct wpi_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct wpi_mrr_setup mrr; | struct wpi_mrr_setup mrr; | ||||
int i, error; | int i, error; | ||||
/* CCK rates (not used with 802.11a). */ | /* CCK rates (not used with 802.11a). */ | ||||
for (i = WPI_RIDX_CCK1; i <= WPI_RIDX_CCK11; i++) { | for (i = WPI_RIDX_CCK1; i <= WPI_RIDX_CCK11; i++) { | ||||
mrr.rates[i].flags = 0; | mrr.rates[i].flags = 0; | ||||
mrr.rates[i].plcp = wpi_ridx_to_plcp[i]; | mrr.rates[i].plcp = wpi_ridx_to_plcp[i]; | ||||
/* Fallback to the immediate lower CCK rate (if any.) */ | /* Fallback to the immediate lower CCK rate (if any.) */ | ||||
▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Broadcast node is used to send group-addressed and management frames. | * Broadcast node is used to send group-addressed and management frames. | ||||
*/ | */ | ||||
static int | static int | ||||
wpi_add_broadcast_node(struct wpi_softc *sc, int async) | wpi_add_broadcast_node(struct wpi_softc *sc, int async) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct wpi_node_info node; | struct wpi_node_info node; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | ||||
memset(&node, 0, sizeof node); | memset(&node, 0, sizeof node); | ||||
IEEE80211_ADDR_COPY(node.macaddr, ifp->if_broadcastaddr); | IEEE80211_ADDR_COPY(node.macaddr, ieee80211broadcastaddr); | ||||
node.id = WPI_ID_BROADCAST; | node.id = WPI_ID_BROADCAST; | ||||
node.plcp = (ic->ic_curmode == IEEE80211_MODE_11A) ? | node.plcp = (ic->ic_curmode == IEEE80211_MODE_11A) ? | ||||
wpi_ridx_to_plcp[WPI_RIDX_OFDM6] : wpi_ridx_to_plcp[WPI_RIDX_CCK1]; | wpi_ridx_to_plcp[WPI_RIDX_OFDM6] : wpi_ridx_to_plcp[WPI_RIDX_CCK1]; | ||||
node.action = htole32(WPI_ACTION_SET_RATE); | node.action = htole32(WPI_ACTION_SET_RATE); | ||||
node.antenna = WPI_ANTENNA_BOTH; | node.antenna = WPI_ANTENNA_BOTH; | ||||
DPRINTF(sc, WPI_DEBUG_NODE, "%s: adding broadcast node\n", __func__); | DPRINTF(sc, WPI_DEBUG_NODE, "%s: adding broadcast node\n", __func__); | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | device_printf(sc->sc_dev, | ||||
wn->id, error); | wn->id, error); | ||||
} | } | ||||
} | } | ||||
static int | static int | ||||
wpi_updateedca(struct ieee80211com *ic) | wpi_updateedca(struct ieee80211com *ic) | ||||
{ | { | ||||
#define WPI_EXP2(x) ((1 << (x)) - 1) /* CWmin = 2^ECWmin - 1 */ | #define WPI_EXP2(x) ((1 << (x)) - 1) /* CWmin = 2^ECWmin - 1 */ | ||||
struct wpi_softc *sc = ic->ic_ifp->if_softc; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct wpi_edca_params cmd; | struct wpi_edca_params cmd; | ||||
int aci, error; | int aci, error; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
memset(&cmd, 0, sizeof cmd); | memset(&cmd, 0, sizeof cmd); | ||||
cmd.flags = htole32(WPI_EDCA_UPDATE); | cmd.flags = htole32(WPI_EDCA_UPDATE); | ||||
for (aci = 0; aci < WME_NUM_AC; aci++) { | for (aci = 0; aci < WME_NUM_AC; aci++) { | ||||
Show All 17 Lines | #define WPI_EXP2(x) ((1 << (x)) - 1) /* CWmin = 2^ECWmin - 1 */ | ||||
return error; | return error; | ||||
#undef WPI_EXP2 | #undef WPI_EXP2 | ||||
} | } | ||||
static void | static void | ||||
wpi_set_promisc(struct wpi_softc *sc) | wpi_set_promisc(struct wpi_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); | ||||
uint32_t promisc_filter; | uint32_t promisc_filter; | ||||
promisc_filter = WPI_FILTER_CTL; | promisc_filter = WPI_FILTER_CTL; | ||||
if (vap != NULL && vap->iv_opmode != IEEE80211_M_HOSTAP) | if (vap != NULL && vap->iv_opmode != IEEE80211_M_HOSTAP) | ||||
promisc_filter |= WPI_FILTER_PROMISC; | promisc_filter |= WPI_FILTER_PROMISC; | ||||
if (ifp->if_flags & IFF_PROMISC) | if (ic->ic_promisc > 0) | ||||
sc->rxon.filter |= htole32(promisc_filter); | sc->rxon.filter |= htole32(promisc_filter); | ||||
else | else | ||||
sc->rxon.filter &= ~htole32(promisc_filter); | sc->rxon.filter &= ~htole32(promisc_filter); | ||||
} | } | ||||
static void | static void | ||||
wpi_update_promisc(struct ieee80211com *ic) | wpi_update_promisc(struct ieee80211com *ic) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 348 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* Configure the card to listen to a particular channel, this transisions the | * Configure the card to listen to a particular channel, this transisions the | ||||
* card in to being able to receive frames from remote devices. | * card in to being able to receive frames from remote devices. | ||||
*/ | */ | ||||
static int | static int | ||||
wpi_config(struct wpi_softc *sc) | wpi_config(struct wpi_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 ieee80211_channel *c = ic->ic_curchan; | struct ieee80211_channel *c = ic->ic_curchan; | ||||
int error; | int error; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
/* Set power saving level to CAM during initialization. */ | /* Set power saving level to CAM during initialization. */ | ||||
if ((error = wpi_set_pslevel(sc, 0, 0, 0)) != 0) { | if ((error = wpi_set_pslevel(sc, 0, 0, 0)) != 0) { | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Limit the total dwell time. | * Limit the total dwell time. | ||||
* | * | ||||
* Returns the dwell time in milliseconds. | * Returns the dwell time in milliseconds. | ||||
*/ | */ | ||||
static uint16_t | static uint16_t | ||||
wpi_limit_dwell(struct wpi_softc *sc, uint16_t dwell_time) | wpi_limit_dwell(struct wpi_softc *sc, uint16_t dwell_time) | ||||
{ | { | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
int bintval = 0; | int bintval = 0; | ||||
/* bintval is in TU (1.024mS) */ | /* bintval is in TU (1.024mS) */ | ||||
if (vap != NULL) | if (vap != NULL) | ||||
bintval = vap->iv_bss->ni_intval; | bintval = vap->iv_bss->ni_intval; | ||||
/* | /* | ||||
Show All 40 Lines | |||||
} | } | ||||
/* | /* | ||||
* Send a scan request to the firmware. | * Send a scan request to the firmware. | ||||
*/ | */ | ||||
static int | static int | ||||
wpi_scan(struct wpi_softc *sc, struct ieee80211_channel *c) | wpi_scan(struct wpi_softc *sc, struct ieee80211_channel *c) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211_scan_state *ss = ic->ic_scan; | struct ieee80211_scan_state *ss = ic->ic_scan; | ||||
struct ieee80211vap *vap = ss->ss_vap; | struct ieee80211vap *vap = ss->ss_vap; | ||||
struct wpi_scan_hdr *hdr; | struct wpi_scan_hdr *hdr; | ||||
struct wpi_cmd_data *tx; | struct wpi_cmd_data *tx; | ||||
struct wpi_scan_essid *essids; | struct wpi_scan_essid *essids; | ||||
struct wpi_scan_chan *chan; | struct wpi_scan_chan *chan; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct ieee80211_rateset *rs; | struct ieee80211_rateset *rs; | ||||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | #endif | ||||
/* | /* | ||||
* Build a probe request frame. Most of the following code is a | * Build a probe request frame. Most of the following code is a | ||||
* copy & paste of what is done in net80211. | * copy & paste of what is done in net80211. | ||||
*/ | */ | ||||
wh = (struct ieee80211_frame *)(essids + WPI_SCAN_MAX_ESSIDS); | wh = (struct ieee80211_frame *)(essids + WPI_SCAN_MAX_ESSIDS); | ||||
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | | wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | | ||||
IEEE80211_FC0_SUBTYPE_PROBE_REQ; | IEEE80211_FC0_SUBTYPE_PROBE_REQ; | ||||
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; | wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; | ||||
IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); | IEEE80211_ADDR_COPY(wh->i_addr1, ieee80211broadcastaddr); | ||||
IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); | IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); | ||||
IEEE80211_ADDR_COPY(wh->i_addr3, ifp->if_broadcastaddr); | IEEE80211_ADDR_COPY(wh->i_addr3, ieee80211broadcastaddr); | ||||
*(uint16_t *)&wh->i_dur[0] = 0; /* filled by h/w */ | |||||
*(uint16_t *)&wh->i_seq[0] = 0; /* filled by h/w */ | |||||
frm = (uint8_t *)(wh + 1); | frm = (uint8_t *)(wh + 1); | ||||
frm = ieee80211_add_ssid(frm, NULL, 0); | frm = ieee80211_add_ssid(frm, NULL, 0); | ||||
frm = ieee80211_add_rates(frm, rs); | frm = ieee80211_add_rates(frm, rs); | ||||
if (rs->rs_nrates > IEEE80211_RATE_SIZE) | if (rs->rs_nrates > IEEE80211_RATE_SIZE) | ||||
frm = ieee80211_add_xrates(frm, rs); | frm = ieee80211_add_xrates(frm, rs); | ||||
/* Set length of probe request. */ | /* Set length of probe request. */ | ||||
Show All 14 Lines | if (nssid) { | ||||
hdr->crc_threshold = WPI_SCAN_CRC_TH_NEVER; | hdr->crc_threshold = WPI_SCAN_CRC_TH_NEVER; | ||||
if (!IEEE80211_IS_CHAN_PASSIVE(c)) | if (!IEEE80211_IS_CHAN_PASSIVE(c)) | ||||
chan->flags |= WPI_CHAN_ACTIVE; | chan->flags |= WPI_CHAN_ACTIVE; | ||||
/* | /* | ||||
* Calculate the active/passive dwell times. | * Calculate the active/passive dwell times. | ||||
*/ | */ | ||||
dwell_active = wpi_get_active_dwell_time(sc, c, nssid); | dwell_active = wpi_get_active_dwell_time(sc, c, nssid); | ||||
dwell_passive = wpi_get_passive_dwell_time(sc, c); | dwell_passive = wpi_get_passive_dwell_time(sc, c); | ||||
/* Make sure they're valid. */ | /* Make sure they're valid. */ | ||||
if (dwell_active > dwell_passive) | if (dwell_active > dwell_passive) | ||||
dwell_active = dwell_passive; | dwell_active = dwell_passive; | ||||
chan->active = htole16(dwell_active); | chan->active = htole16(dwell_active); | ||||
▲ Show 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static int | static int | ||||
wpi_config_beacon(struct wpi_vap *wvp) | wpi_config_beacon(struct wpi_vap *wvp) | ||||
{ | { | ||||
struct ieee80211com *ic = wvp->wv_vap.iv_ic; | struct ieee80211com *ic = wvp->wv_vap.iv_ic; | ||||
struct ieee80211_beacon_offsets *bo = &wvp->wv_boff; | struct ieee80211_beacon_offsets *bo = &wvp->wv_boff; | ||||
struct wpi_buf *bcn = &wvp->wv_bcbuf; | struct wpi_buf *bcn = &wvp->wv_bcbuf; | ||||
struct wpi_softc *sc = ic->ic_ifp->if_softc; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct wpi_cmd_beacon *cmd = (struct wpi_cmd_beacon *)&bcn->data; | struct wpi_cmd_beacon *cmd = (struct wpi_cmd_beacon *)&bcn->data; | ||||
struct ieee80211_tim_ie *tie; | struct ieee80211_tim_ie *tie; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
uint8_t *ptr; | uint8_t *ptr; | ||||
int error; | int error; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | wpi_setup_beacon(struct wpi_softc *sc, struct ieee80211_node *ni) | ||||
WPI_VAP_UNLOCK(wvp); | WPI_VAP_UNLOCK(wvp); | ||||
return error; | return error; | ||||
} | } | ||||
static void | static void | ||||
wpi_update_beacon(struct ieee80211vap *vap, int item) | wpi_update_beacon(struct ieee80211vap *vap, int item) | ||||
{ | { | ||||
struct wpi_softc *sc = vap->iv_ic->ic_ifp->if_softc; | struct wpi_softc *sc = vap->iv_ic->ic_softc; | ||||
struct wpi_vap *wvp = WPI_VAP(vap); | struct wpi_vap *wvp = WPI_VAP(vap); | ||||
struct wpi_buf *bcn = &wvp->wv_bcbuf; | struct wpi_buf *bcn = &wvp->wv_bcbuf; | ||||
struct ieee80211_beacon_offsets *bo = &wvp->wv_boff; | struct ieee80211_beacon_offsets *bo = &wvp->wv_boff; | ||||
struct ieee80211_node *ni = vap->iv_bss; | struct ieee80211_node *ni = vap->iv_bss; | ||||
int mcast = 0; | int mcast = 0; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
Show All 25 Lines | wpi_update_beacon(struct ieee80211vap *vap, int item) | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | ||||
} | } | ||||
static void | static void | ||||
wpi_newassoc(struct ieee80211_node *ni, int isnew) | wpi_newassoc(struct ieee80211_node *ni, int isnew) | ||||
{ | { | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; | struct wpi_softc *sc = ni->ni_ic->ic_softc; | ||||
struct wpi_node *wn = WPI_NODE(ni); | struct wpi_node *wn = WPI_NODE(ni); | ||||
int error; | int error; | ||||
WPI_NT_LOCK(sc); | WPI_NT_LOCK(sc); | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | ||||
if (vap->iv_opmode != IEEE80211_M_STA && wn->id == WPI_ID_UNDEFINED) { | if (vap->iv_opmode != IEEE80211_M_STA && wn->id == WPI_ID_UNDEFINED) { | ||||
▲ Show 20 Lines • Show All 110 Lines • ▼ Show 20 Lines | wpi_run(struct wpi_softc *sc, struct ieee80211vap *vap) | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
wpi_load_key(struct ieee80211_node *ni, const struct ieee80211_key *k) | wpi_load_key(struct ieee80211_node *ni, const struct ieee80211_key *k) | ||||
{ | { | ||||
const struct ieee80211_cipher *cip = k->wk_cipher; | const struct ieee80211_cipher *cip = k->wk_cipher; | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; | struct wpi_softc *sc = ni->ni_ic->ic_softc; | ||||
struct wpi_node *wn = WPI_NODE(ni); | struct wpi_node *wn = WPI_NODE(ni); | ||||
struct wpi_node_info node; | struct wpi_node_info node; | ||||
uint16_t kflags; | uint16_t kflags; | ||||
int error; | int error; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | ||||
if (wpi_check_node_entry(sc, wn->id) == 0) { | if (wpi_check_node_entry(sc, wn->id) == 0) { | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | again: | ||||
return 1; | return 1; | ||||
} | } | ||||
static void | static void | ||||
wpi_load_key_cb(void *arg, struct ieee80211_node *ni) | wpi_load_key_cb(void *arg, struct ieee80211_node *ni) | ||||
{ | { | ||||
const struct ieee80211_key *k = arg; | const struct ieee80211_key *k = arg; | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; | struct wpi_softc *sc = ni->ni_ic->ic_softc; | ||||
struct wpi_node *wn = WPI_NODE(ni); | struct wpi_node *wn = WPI_NODE(ni); | ||||
int error; | int error; | ||||
if (vap->iv_bss == ni && wn->id == WPI_ID_UNDEFINED) | if (vap->iv_bss == ni && wn->id == WPI_ID_UNDEFINED) | ||||
return; | return; | ||||
WPI_NT_LOCK(sc); | WPI_NT_LOCK(sc); | ||||
error = wpi_load_key(ni, k); | error = wpi_load_key(ni, k); | ||||
Show All 18 Lines | wpi_set_global_keys(struct ieee80211_node *ni) | ||||
return !error; | return !error; | ||||
} | } | ||||
static int | static int | ||||
wpi_del_key(struct ieee80211_node *ni, const struct ieee80211_key *k) | wpi_del_key(struct ieee80211_node *ni, const struct ieee80211_key *k) | ||||
{ | { | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; | struct wpi_softc *sc = ni->ni_ic->ic_softc; | ||||
struct wpi_node *wn = WPI_NODE(ni); | struct wpi_node *wn = WPI_NODE(ni); | ||||
struct wpi_node_info node; | struct wpi_node_info node; | ||||
uint16_t kflags; | uint16_t kflags; | ||||
int error; | int error; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | ||||
if (wpi_check_node_entry(sc, wn->id) == 0) { | if (wpi_check_node_entry(sc, wn->id) == 0) { | ||||
Show All 33 Lines | again: | ||||
return 1; | return 1; | ||||
} | } | ||||
static void | static void | ||||
wpi_del_key_cb(void *arg, struct ieee80211_node *ni) | wpi_del_key_cb(void *arg, struct ieee80211_node *ni) | ||||
{ | { | ||||
const struct ieee80211_key *k = arg; | const struct ieee80211_key *k = arg; | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; | struct wpi_softc *sc = ni->ni_ic->ic_softc; | ||||
struct wpi_node *wn = WPI_NODE(ni); | struct wpi_node *wn = WPI_NODE(ni); | ||||
int error; | int error; | ||||
if (vap->iv_bss == ni && wn->id == WPI_ID_UNDEFINED) | if (vap->iv_bss == ni && wn->id == WPI_ID_UNDEFINED) | ||||
return; | return; | ||||
WPI_NT_LOCK(sc); | WPI_NT_LOCK(sc); | ||||
error = wpi_del_key(ni, k); | error = wpi_del_key(ni, k); | ||||
WPI_NT_UNLOCK(sc); | WPI_NT_UNLOCK(sc); | ||||
if (error == 0) { | if (error == 0) { | ||||
device_printf(sc->sc_dev, "%s: error while deleting key\n", | device_printf(sc->sc_dev, "%s: error while deleting key\n", | ||||
__func__); | __func__); | ||||
} | } | ||||
} | } | ||||
static int | static int | ||||
wpi_process_key(struct ieee80211vap *vap, const struct ieee80211_key *k, | wpi_process_key(struct ieee80211vap *vap, const struct ieee80211_key *k, | ||||
int set) | int set) | ||||
{ | { | ||||
struct ieee80211com *ic = vap->iv_ic; | struct ieee80211com *ic = vap->iv_ic; | ||||
struct wpi_softc *sc = ic->ic_ifp->if_softc; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct wpi_vap *wvp = WPI_VAP(vap); | struct wpi_vap *wvp = WPI_VAP(vap); | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
int error, ni_ref = 0; | int error, ni_ref = 0; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | ||||
if (k->wk_flags & IEEE80211_KEY_SWCRYPT) { | if (k->wk_flags & IEEE80211_KEY_SWCRYPT) { | ||||
/* Not for us. */ | /* Not for us. */ | ||||
▲ Show 20 Lines • Show All 633 Lines • ▼ Show 20 Lines | wpi_hw_stop(struct wpi_softc *sc) | ||||
/* Power OFF adapter. */ | /* Power OFF adapter. */ | ||||
wpi_apm_stop(sc); | wpi_apm_stop(sc); | ||||
} | } | ||||
static void | static void | ||||
wpi_radio_on(void *arg0, int pending) | wpi_radio_on(void *arg0, int pending) | ||||
{ | { | ||||
struct wpi_softc *sc = arg0; | struct wpi_softc *sc = arg0; | ||||
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); | ||||
device_printf(sc->sc_dev, "RF switch: radio enabled\n"); | device_printf(sc->sc_dev, "RF switch: radio enabled\n"); | ||||
if (vap != NULL) { | |||||
wpi_init(sc); | |||||
ieee80211_init(vap); | |||||
} | |||||
if (WPI_READ(sc, WPI_GP_CNTRL) & WPI_GP_CNTRL_RFKILL) { | |||||
WPI_LOCK(sc); | WPI_LOCK(sc); | ||||
callout_stop(&sc->watchdog_rfkill); | callout_stop(&sc->watchdog_rfkill); | ||||
WPI_UNLOCK(sc); | WPI_UNLOCK(sc); | ||||
if (vap != NULL) | |||||
ieee80211_init(vap); | |||||
} | } | ||||
} | |||||
static void | static void | ||||
wpi_radio_off(void *arg0, int pending) | wpi_radio_off(void *arg0, int pending) | ||||
{ | { | ||||
struct wpi_softc *sc = arg0; | struct wpi_softc *sc = arg0; | ||||
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); | ||||
device_printf(sc->sc_dev, "RF switch: radio disabled\n"); | device_printf(sc->sc_dev, "RF switch: radio disabled\n"); | ||||
ieee80211_notify_radio(ic, 0); | |||||
wpi_stop(sc); | wpi_stop(sc); | ||||
if (vap != NULL) | if (vap != NULL) | ||||
ieee80211_stop(vap); | ieee80211_stop(vap); | ||||
WPI_LOCK(sc); | WPI_LOCK(sc); | ||||
callout_reset(&sc->watchdog_rfkill, hz, wpi_watchdog_rfkill, sc); | callout_reset(&sc->watchdog_rfkill, hz, wpi_watchdog_rfkill, sc); | ||||
WPI_UNLOCK(sc); | WPI_UNLOCK(sc); | ||||
} | } | ||||
static void | static int | ||||
wpi_init(void *arg) | wpi_init(struct wpi_softc *sc) | ||||
{ | { | ||||
struct wpi_softc *sc = arg; | int error = 0; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
int error; | |||||
WPI_LOCK(sc); | WPI_LOCK(sc); | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) | if (sc->sc_running != 0) | ||||
goto end; | goto end; | ||||
/* Check that the radio is not disabled by hardware switch. */ | /* Check that the radio is not disabled by hardware switch. */ | ||||
if (!(WPI_READ(sc, WPI_GP_CNTRL) & WPI_GP_CNTRL_RFKILL)) { | if (!(WPI_READ(sc, WPI_GP_CNTRL) & WPI_GP_CNTRL_RFKILL)) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"RF switch: radio disabled (%s)\n", __func__); | "RF switch: radio disabled (%s)\n", __func__); | ||||
callout_reset(&sc->watchdog_rfkill, hz, wpi_watchdog_rfkill, | callout_reset(&sc->watchdog_rfkill, hz, wpi_watchdog_rfkill, | ||||
sc); | sc); | ||||
error = EINPROGRESS; | |||||
goto end; | goto end; | ||||
} | } | ||||
/* Read firmware images from the filesystem. */ | /* Read firmware images from the filesystem. */ | ||||
if ((error = wpi_read_firmware(sc)) != 0) { | if ((error = wpi_read_firmware(sc)) != 0) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"%s: could not read firmware, error %d\n", __func__, | "%s: could not read firmware, error %d\n", __func__, | ||||
error); | error); | ||||
goto fail; | goto end; | ||||
} | } | ||||
sc->sc_running = 1; | |||||
/* Initialize hardware and upload firmware. */ | /* Initialize hardware and upload firmware. */ | ||||
error = wpi_hw_init(sc); | error = wpi_hw_init(sc); | ||||
wpi_unload_firmware(sc); | wpi_unload_firmware(sc); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"%s: could not initialize hardware, error %d\n", __func__, | "%s: could not initialize hardware, error %d\n", __func__, | ||||
error); | error); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
/* Configure adapter now that it is ready. */ | /* Configure adapter now that it is ready. */ | ||||
sc->txq_active = 1; | |||||
if ((error = wpi_config(sc)) != 0) { | if ((error = wpi_config(sc)) != 0) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"%s: could not configure device, error %d\n", __func__, | "%s: could not configure device, error %d\n", __func__, | ||||
error); | error); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
IF_LOCK(&ifp->if_snd); | |||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | |||||
IF_UNLOCK(&ifp->if_snd); | |||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | ||||
WPI_UNLOCK(sc); | WPI_UNLOCK(sc); | ||||
ieee80211_start_all(ic); | return 0; | ||||
return; | |||||
fail: wpi_stop_locked(sc); | fail: wpi_stop_locked(sc); | ||||
end: DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); | end: DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); | ||||
WPI_UNLOCK(sc); | WPI_UNLOCK(sc); | ||||
return error; | |||||
} | } | ||||
static void | static void | ||||
wpi_stop_locked(struct wpi_softc *sc) | wpi_stop_locked(struct wpi_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
WPI_LOCK_ASSERT(sc); | WPI_LOCK_ASSERT(sc); | ||||
if (sc->sc_running == 0) | |||||
return; | |||||
WPI_TX_LOCK(sc); | |||||
WPI_TXQ_LOCK(sc); | WPI_TXQ_LOCK(sc); | ||||
sc->txq_active = 0; | sc->sc_running = 0; | ||||
WPI_TXQ_UNLOCK(sc); | WPI_TXQ_UNLOCK(sc); | ||||
WPI_TX_UNLOCK(sc); | |||||
WPI_TXQ_STATE_LOCK(sc); | WPI_TXQ_STATE_LOCK(sc); | ||||
callout_stop(&sc->tx_timeout); | callout_stop(&sc->tx_timeout); | ||||
WPI_TXQ_STATE_UNLOCK(sc); | WPI_TXQ_STATE_UNLOCK(sc); | ||||
WPI_RXON_LOCK(sc); | WPI_RXON_LOCK(sc); | ||||
callout_stop(&sc->scan_timeout); | callout_stop(&sc->scan_timeout); | ||||
callout_stop(&sc->calib_to); | callout_stop(&sc->calib_to); | ||||
WPI_RXON_UNLOCK(sc); | WPI_RXON_UNLOCK(sc); | ||||
IF_LOCK(&ifp->if_snd); | |||||
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); | |||||
IF_UNLOCK(&ifp->if_snd); | |||||
/* Power OFF hardware. */ | /* Power OFF hardware. */ | ||||
wpi_hw_stop(sc); | wpi_hw_stop(sc); | ||||
} | } | ||||
static void | static void | ||||
wpi_stop(struct wpi_softc *sc) | wpi_stop(struct wpi_softc *sc) | ||||
{ | { | ||||
WPI_LOCK(sc); | WPI_LOCK(sc); | ||||
wpi_stop_locked(sc); | wpi_stop_locked(sc); | ||||
WPI_UNLOCK(sc); | WPI_UNLOCK(sc); | ||||
} | } | ||||
/* | /* | ||||
* Callback from net80211 to start a scan. | * Callback from net80211 to start a scan. | ||||
*/ | */ | ||||
static void | static void | ||||
wpi_scan_start(struct ieee80211com *ic) | wpi_scan_start(struct ieee80211com *ic) | ||||
{ | { | ||||
struct wpi_softc *sc = ic->ic_ifp->if_softc; | struct wpi_softc *sc = ic->ic_softc; | ||||
wpi_set_led(sc, WPI_LED_LINK, 20, 2); | wpi_set_led(sc, WPI_LED_LINK, 20, 2); | ||||
} | } | ||||
/* | /* | ||||
* Callback from net80211 to terminate a scan. | * Callback from net80211 to terminate a scan. | ||||
*/ | */ | ||||
static void | static void | ||||
wpi_scan_end(struct ieee80211com *ic) | wpi_scan_end(struct ieee80211com *ic) | ||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct wpi_softc *sc = ifp->if_softc; | |||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
if (vap->iv_state == IEEE80211_S_RUN) | if (vap->iv_state == IEEE80211_S_RUN) | ||||
wpi_set_led(sc, WPI_LED_LINK, 0, 1); | wpi_set_led(sc, WPI_LED_LINK, 0, 1); | ||||
} | } | ||||
/** | /** | ||||
* Called by the net80211 framework to indicate to the driver | * Called by the net80211 framework to indicate to the driver | ||||
* that the channel should be changed | * that the channel should be changed | ||||
*/ | */ | ||||
static void | static void | ||||
wpi_set_channel(struct ieee80211com *ic) | wpi_set_channel(struct ieee80211com *ic) | ||||
{ | { | ||||
const struct ieee80211_channel *c = ic->ic_curchan; | const struct ieee80211_channel *c = ic->ic_curchan; | ||||
struct ifnet *ifp = ic->ic_ifp; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct wpi_softc *sc = ifp->if_softc; | |||||
int error; | int error; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | ||||
WPI_LOCK(sc); | WPI_LOCK(sc); | ||||
sc->sc_rxtap.wr_chan_freq = htole16(c->ic_freq); | sc->sc_rxtap.wr_chan_freq = htole16(c->ic_freq); | ||||
sc->sc_rxtap.wr_chan_flags = htole16(c->ic_flags); | sc->sc_rxtap.wr_chan_flags = htole16(c->ic_flags); | ||||
WPI_UNLOCK(sc); | WPI_UNLOCK(sc); | ||||
Show All 29 Lines | |||||
* channel. The channel is previously be set via the wpi_set_channel | * channel. The channel is previously be set via the wpi_set_channel | ||||
* callback. | * callback. | ||||
*/ | */ | ||||
static void | static void | ||||
wpi_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) | wpi_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) | ||||
{ | { | ||||
struct ieee80211vap *vap = ss->ss_vap; | struct ieee80211vap *vap = ss->ss_vap; | ||||
struct ieee80211com *ic = vap->iv_ic; | struct ieee80211com *ic = vap->iv_ic; | ||||
struct wpi_softc *sc = ic->ic_ifp->if_softc; | struct wpi_softc *sc = ic->ic_softc; | ||||
int error; | int error; | ||||
WPI_RXON_LOCK(sc); | WPI_RXON_LOCK(sc); | ||||
error = wpi_scan(sc, ic->ic_curchan); | error = wpi_scan(sc, ic->ic_curchan); | ||||
WPI_RXON_UNLOCK(sc); | WPI_RXON_UNLOCK(sc); | ||||
if (error != 0) | if (error != 0) | ||||
ieee80211_cancel_scan(vap); | ieee80211_cancel_scan(vap); | ||||
} | } | ||||
Show All 9 Lines | |||||
{ | { | ||||
/* NB: don't try to abort scan; wait for firmware to finish */ | /* NB: don't try to abort scan; wait for firmware to finish */ | ||||
} | } | ||||
static void | static void | ||||
wpi_hw_reset(void *arg, int pending) | wpi_hw_reset(void *arg, int pending) | ||||
{ | { | ||||
struct wpi_softc *sc = arg; | struct wpi_softc *sc = arg; | ||||
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); | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | ||||
ieee80211_notify_radio(ic, 0); | |||||
if (vap != NULL && (ic->ic_flags & IEEE80211_F_SCAN)) | if (vap != NULL && (ic->ic_flags & IEEE80211_F_SCAN)) | ||||
ieee80211_cancel_scan(vap); | ieee80211_cancel_scan(vap); | ||||
wpi_stop(sc); | wpi_stop(sc); | ||||
if (vap != NULL) | if (vap != NULL) { | ||||
ieee80211_stop(vap); | ieee80211_stop(vap); | ||||
wpi_init(sc); | |||||
if (vap != NULL) | |||||
ieee80211_init(vap); | ieee80211_init(vap); | ||||
} | |||||
} | } |