Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/iwn/if_iwn.c
Show First 20 Lines • Show All 228 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
static int iwn_tx_data(struct iwn_softc *, struct mbuf *, | static int iwn_tx_data(struct iwn_softc *, struct mbuf *, | ||||
struct ieee80211_node *); | struct ieee80211_node *); | ||||
static int iwn_tx_data_raw(struct iwn_softc *, struct mbuf *, | static int iwn_tx_data_raw(struct iwn_softc *, struct mbuf *, | ||||
struct ieee80211_node *, | struct ieee80211_node *, | ||||
const struct ieee80211_bpf_params *params); | const struct ieee80211_bpf_params *params); | ||||
static int iwn_raw_xmit(struct ieee80211_node *, struct mbuf *, | static int iwn_raw_xmit(struct ieee80211_node *, struct mbuf *, | ||||
const struct ieee80211_bpf_params *); | const struct ieee80211_bpf_params *); | ||||
static void iwn_start(struct ifnet *); | static int iwn_transmit(struct ieee80211com *, struct mbuf *); | ||||
static void iwn_start_locked(struct ifnet *); | static void iwn_start_locked(struct iwn_softc *); | ||||
static void iwn_watchdog(void *); | static void iwn_watchdog(void *); | ||||
static int iwn_ioctl(struct ifnet *, u_long, caddr_t); | static int iwn_ioctl(struct ieee80211com *, u_long , char *); | ||||
static void iwn_parent(struct ieee80211com *); | |||||
static int iwn_cmd(struct iwn_softc *, int, const void *, int, int); | static int iwn_cmd(struct iwn_softc *, int, const void *, int, int); | ||||
static int iwn4965_add_node(struct iwn_softc *, struct iwn_node_info *, | static int iwn4965_add_node(struct iwn_softc *, struct iwn_node_info *, | ||||
int); | int); | ||||
static int iwn5000_add_node(struct iwn_softc *, struct iwn_node_info *, | static int iwn5000_add_node(struct iwn_softc *, struct iwn_node_info *, | ||||
int); | int); | ||||
static int iwn_set_link_quality(struct iwn_softc *, | static int iwn_set_link_quality(struct iwn_softc *, | ||||
struct ieee80211_node *); | struct ieee80211_node *); | ||||
static int iwn_add_broadcast_node(struct iwn_softc *, int); | static int iwn_add_broadcast_node(struct iwn_softc *, int); | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | |||||
static int iwn5000_nic_config(struct iwn_softc *); | static int iwn5000_nic_config(struct iwn_softc *); | ||||
static int iwn_hw_prepare(struct iwn_softc *); | static int iwn_hw_prepare(struct iwn_softc *); | ||||
static int iwn_hw_init(struct iwn_softc *); | static int iwn_hw_init(struct iwn_softc *); | ||||
static void iwn_hw_stop(struct iwn_softc *); | static void iwn_hw_stop(struct iwn_softc *); | ||||
static void iwn_radio_on(void *, int); | static void iwn_radio_on(void *, int); | ||||
static void iwn_radio_off(void *, int); | static void iwn_radio_off(void *, int); | ||||
static void iwn_panicked(void *, int); | static void iwn_panicked(void *, int); | ||||
static void iwn_init_locked(struct iwn_softc *); | static void iwn_init_locked(struct iwn_softc *); | ||||
static void iwn_init(void *); | static void iwn_init(struct iwn_softc *); | ||||
static void iwn_stop_locked(struct iwn_softc *); | static void iwn_stop_locked(struct iwn_softc *); | ||||
static void iwn_stop(struct iwn_softc *); | static void iwn_stop(struct iwn_softc *); | ||||
static void iwn_scan_start(struct ieee80211com *); | static void iwn_scan_start(struct ieee80211com *); | ||||
static void iwn_scan_end(struct ieee80211com *); | static void iwn_scan_end(struct ieee80211com *); | ||||
static void iwn_set_channel(struct ieee80211com *); | static void iwn_set_channel(struct ieee80211com *); | ||||
static void iwn_scan_curchan(struct ieee80211_scan_state *, unsigned long); | static void iwn_scan_curchan(struct ieee80211_scan_state *, unsigned long); | ||||
static void iwn_scan_mindwell(struct ieee80211_scan_state *); | static void iwn_scan_mindwell(struct ieee80211_scan_state *); | ||||
static void iwn_hw_reset(void *, int); | static void iwn_hw_reset(void *, int); | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | iwn_is_3stream_device(struct iwn_softc *sc) | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
iwn_attach(device_t dev) | iwn_attach(device_t dev) | ||||
{ | { | ||||
struct iwn_softc *sc = (struct iwn_softc *)device_get_softc(dev); | struct iwn_softc *sc = (struct iwn_softc *)device_get_softc(dev); | ||||
struct ieee80211com *ic; | struct ieee80211com *ic; | ||||
struct ifnet *ifp; | |||||
int i, error, rid; | int i, error, rid; | ||||
uint8_t macaddr[IEEE80211_ADDR_LEN]; | |||||
sc->sc_dev = dev; | sc->sc_dev = dev; | ||||
#ifdef IWN_DEBUG | #ifdef IWN_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 All 39 Lines | sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | | ||||
(rid != 0 ? 0 : RF_SHAREABLE)); | (rid != 0 ? 0 : RF_SHAREABLE)); | ||||
if (sc->irq == NULL) { | if (sc->irq == NULL) { | ||||
device_printf(dev, "can't map interrupt\n"); | device_printf(dev, "can't map interrupt\n"); | ||||
error = ENOMEM; | error = ENOMEM; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
IWN_LOCK_INIT(sc); | IWN_LOCK_INIT(sc); | ||||
mbufq_init(&sc->sc_snd, ifqmaxlen); | |||||
/* Read hardware revision and attach. */ | /* Read hardware revision and attach. */ | ||||
sc->hw_type = (IWN_READ(sc, IWN_HW_REV) >> IWN_HW_REV_TYPE_SHIFT) | sc->hw_type = (IWN_READ(sc, IWN_HW_REV) >> IWN_HW_REV_TYPE_SHIFT) | ||||
& IWN_HW_REV_TYPE_MASK; | & IWN_HW_REV_TYPE_MASK; | ||||
sc->subdevice_id = pci_get_subdevice(dev); | sc->subdevice_id = pci_get_subdevice(dev); | ||||
/* | /* | ||||
* 4965 versus 5000 and later have different methods. | * 4965 versus 5000 and later have different methods. | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | if ((error = iwn_alloc_rx_ring(sc, &sc->rxq)) != 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. */ | ||||
IWN_WRITE(sc, IWN_INT, 0xffffffff); | IWN_WRITE(sc, IWN_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 */ | ||||
| IEEE80211_C_MONITOR /* monitor mode supported */ | | IEEE80211_C_MONITOR /* monitor mode supported */ | ||||
| IEEE80211_C_BGSCAN /* background scanning */ | | IEEE80211_C_BGSCAN /* background scanning */ | ||||
| IEEE80211_C_TXPMGT /* tx power management */ | | IEEE80211_C_TXPMGT /* tx power management */ | ||||
| IEEE80211_C_SHSLOT /* short slot time supported */ | | IEEE80211_C_SHSLOT /* short slot time supported */ | ||||
| IEEE80211_C_WPA | | IEEE80211_C_WPA | ||||
| IEEE80211_C_SHPREAMBLE /* short preamble supported */ | | IEEE80211_C_SHPREAMBLE /* short preamble supported */ | ||||
#if 0 | #if 0 | ||||
| IEEE80211_C_IBSS /* ibss/adhoc mode */ | | IEEE80211_C_IBSS /* ibss/adhoc mode */ | ||||
#endif | #endif | ||||
| IEEE80211_C_WME /* WME */ | | IEEE80211_C_WME /* WME */ | ||||
| IEEE80211_C_PMGT /* Station-side power mgmt */ | | IEEE80211_C_PMGT /* Station-side power mgmt */ | ||||
; | ; | ||||
/* Read MAC address, channels, etc from EEPROM. */ | /* Read MAC address, channels, etc from EEPROM. */ | ||||
if ((error = iwn_read_eeprom(sc, macaddr)) != 0) { | if ((error = iwn_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; | ||||
} | } | ||||
/* Count the number of available chains. */ | /* Count the number of available chains. */ | ||||
sc->ntxchains = | sc->ntxchains = | ||||
((sc->txchainmask >> 2) & 1) + | ((sc->txchainmask >> 2) & 1) + | ||||
((sc->txchainmask >> 1) & 1) + | ((sc->txchainmask >> 1) & 1) + | ||||
((sc->txchainmask >> 0) & 1); | ((sc->txchainmask >> 0) & 1); | ||||
sc->nrxchains = | sc->nrxchains = | ||||
((sc->rxchainmask >> 2) & 1) + | ((sc->rxchainmask >> 2) & 1) + | ||||
((sc->rxchainmask >> 1) & 1) + | ((sc->rxchainmask >> 1) & 1) + | ||||
((sc->rxchainmask >> 0) & 1); | ((sc->rxchainmask >> 0) & 1); | ||||
if (bootverbose) { | if (bootverbose) { | ||||
device_printf(dev, "MIMO %dT%dR, %.4s, address %6D\n", | device_printf(dev, "MIMO %dT%dR, %.4s, address %6D\n", | ||||
sc->ntxchains, sc->nrxchains, sc->eeprom_domain, | sc->ntxchains, sc->nrxchains, sc->eeprom_domain, | ||||
macaddr, ":"); | ic->ic_macaddr, ":"); | ||||
} | } | ||||
if (sc->sc_flags & IWN_FLAG_HAS_11N) { | if (sc->sc_flags & IWN_FLAG_HAS_11N) { | ||||
ic->ic_rxstream = sc->nrxchains; | ic->ic_rxstream = sc->nrxchains; | ||||
ic->ic_txstream = sc->ntxchains; | ic->ic_txstream = sc->ntxchains; | ||||
/* | /* | ||||
* Some of the 3 antenna devices (ie, the 4965) only supports | * Some of the 3 antenna devices (ie, the 4965) only supports | ||||
Show All 24 Lines | #endif | ||||
| IEEE80211_HTC_HT /* HT operation */ | | IEEE80211_HTC_HT /* HT operation */ | ||||
| IEEE80211_HTC_AMPDU /* tx A-MPDU */ | | IEEE80211_HTC_AMPDU /* tx A-MPDU */ | ||||
#ifdef notyet | #ifdef notyet | ||||
| IEEE80211_HTC_AMSDU /* tx A-MSDU */ | | IEEE80211_HTC_AMSDU /* tx A-MSDU */ | ||||
#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 = iwn_init; | |||||
ifp->if_ioctl = iwn_ioctl; | |||||
ifp->if_start = iwn_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 = iwn_vap_create; | ic->ic_vap_create = iwn_vap_create; | ||||
ic->ic_ioctl = iwn_ioctl; | |||||
ic->ic_parent = iwn_parent; | |||||
ic->ic_vap_delete = iwn_vap_delete; | ic->ic_vap_delete = iwn_vap_delete; | ||||
ic->ic_transmit = iwn_transmit; | |||||
ic->ic_raw_xmit = iwn_raw_xmit; | ic->ic_raw_xmit = iwn_raw_xmit; | ||||
ic->ic_node_alloc = iwn_node_alloc; | ic->ic_node_alloc = iwn_node_alloc; | ||||
sc->sc_ampdu_rx_start = ic->ic_ampdu_rx_start; | sc->sc_ampdu_rx_start = ic->ic_ampdu_rx_start; | ||||
ic->ic_ampdu_rx_start = iwn_ampdu_rx_start; | ic->ic_ampdu_rx_start = iwn_ampdu_rx_start; | ||||
sc->sc_ampdu_rx_stop = ic->ic_ampdu_rx_stop; | sc->sc_ampdu_rx_stop = ic->ic_ampdu_rx_stop; | ||||
ic->ic_ampdu_rx_stop = iwn_ampdu_rx_stop; | ic->ic_ampdu_rx_stop = iwn_ampdu_rx_stop; | ||||
sc->sc_addba_request = ic->ic_addba_request; | sc->sc_addba_request = ic->ic_addba_request; | ||||
ic->ic_addba_request = iwn_addba_request; | ic->ic_addba_request = iwn_addba_request; | ||||
▲ Show 20 Lines • Show All 621 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Attach the interface to 802.11 radiotap. | * Attach the interface to 802.11 radiotap. | ||||
*/ | */ | ||||
static void | static void | ||||
iwn_radiotap_attach(struct iwn_softc *sc) | iwn_radiotap_attach(struct iwn_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | ||||
ieee80211_radiotap_attach(ic, | ieee80211_radiotap_attach(&sc->sc_ic, | ||||
&sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), | &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), | ||||
IWN_TX_RADIOTAP_PRESENT, | IWN_TX_RADIOTAP_PRESENT, | ||||
&sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), | &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), | ||||
IWN_RX_RADIOTAP_PRESENT); | IWN_RX_RADIOTAP_PRESENT); | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__); | ||||
} | } | ||||
static void | static void | ||||
Show All 13 Lines | |||||
iwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, | iwn_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 iwn_softc *sc = ic->ic_softc; | struct iwn_softc *sc = ic->ic_softc; | ||||
struct iwn_vap *ivp; | struct iwn_vap *ivp; | ||||
struct ieee80211vap *vap; | struct ieee80211vap *vap; | ||||
uint8_t mac1[IEEE80211_ADDR_LEN]; | |||||
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; | ||||
IEEE80211_ADDR_COPY(mac1, mac); | ivp = malloc(sizeof(struct iwn_vap), M_80211_VAP, M_WAITOK | M_ZERO); | ||||
ivp = (struct iwn_vap *) malloc(sizeof(struct iwn_vap), | |||||
M_80211_VAP, M_NOWAIT | M_ZERO); | |||||
if (ivp == NULL) | |||||
return NULL; | |||||
vap = &ivp->iv_vap; | vap = &ivp->iv_vap; | ||||
ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac1); | ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); | ||||
ivp->ctx = IWN_RXON_BSS_CTX; | ivp->ctx = IWN_RXON_BSS_CTX; | ||||
IEEE80211_ADDR_COPY(ivp->macaddr, mac1); | |||||
vap->iv_bmissthreshold = 10; /* override default */ | vap->iv_bmissthreshold = 10; /* override default */ | ||||
/* Override with driver methods. */ | /* Override with driver methods. */ | ||||
ivp->iv_newstate = vap->iv_newstate; | ivp->iv_newstate = vap->iv_newstate; | ||||
vap->iv_newstate = iwn_newstate; | vap->iv_newstate = iwn_newstate; | ||||
sc->ivap[IWN_RXON_BSS_CTX] = vap; | sc->ivap[IWN_RXON_BSS_CTX] = vap; | ||||
ieee80211_ratectl_init(vap); | ieee80211_ratectl_init(vap); | ||||
/* Complete setup. */ | /* Complete setup. */ | ||||
ieee80211_vap_attach(vap, iwn_media_change, ieee80211_media_status); | ieee80211_vap_attach(vap, iwn_media_change, ieee80211_media_status, | ||||
mac); | |||||
ic->ic_opmode = opmode; | ic->ic_opmode = opmode; | ||||
return vap; | return vap; | ||||
} | } | ||||
static void | static void | ||||
iwn_vap_delete(struct ieee80211vap *vap) | iwn_vap_delete(struct ieee80211vap *vap) | ||||
{ | { | ||||
struct iwn_vap *ivp = IWN_VAP(vap); | struct iwn_vap *ivp = IWN_VAP(vap); | ||||
ieee80211_ratectl_deinit(vap); | ieee80211_ratectl_deinit(vap); | ||||
ieee80211_vap_detach(vap); | ieee80211_vap_detach(vap); | ||||
free(ivp, M_80211_VAP); | free(ivp, M_80211_VAP); | ||||
} | } | ||||
static int | static int | ||||
iwn_detach(device_t dev) | iwn_detach(device_t dev) | ||||
{ | { | ||||
struct iwn_softc *sc = device_get_softc(dev); | struct iwn_softc *sc = device_get_softc(dev); | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct ieee80211com *ic; | |||||
int qid; | int qid; | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | ||||
if (ifp != NULL) { | if (sc->sc_ic.ic_softc != NULL) { | ||||
ic = ifp->if_l2com; | ieee80211_draintask(&sc->sc_ic, &sc->sc_reinit_task); | ||||
ieee80211_draintask(&sc->sc_ic, &sc->sc_radioon_task); | |||||
ieee80211_draintask(ic, &sc->sc_reinit_task); | ieee80211_draintask(&sc->sc_ic, &sc->sc_radiooff_task); | ||||
ieee80211_draintask(ic, &sc->sc_radioon_task); | |||||
ieee80211_draintask(ic, &sc->sc_radiooff_task); | |||||
iwn_stop(sc); | iwn_stop(sc); | ||||
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_to); | callout_drain(&sc->watchdog_to); | ||||
callout_drain(&sc->calib_to); | callout_drain(&sc->calib_to); | ||||
ieee80211_ifdetach(ic); | ieee80211_ifdetach(&sc->sc_ic); | ||||
} | } | ||||
/* Uninstall interrupt handler. */ | /* Uninstall interrupt handler. */ | ||||
if (sc->irq != NULL) { | if (sc->irq != NULL) { | ||||
bus_teardown_intr(dev, sc->irq, sc->sc_ih); | bus_teardown_intr(dev, sc->irq, sc->sc_ih); | ||||
bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq), | bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq), | ||||
sc->irq); | sc->irq); | ||||
pci_release_msi(dev); | pci_release_msi(dev); | ||||
} | } | ||||
/* Free DMA resources. */ | /* Free DMA resources. */ | ||||
iwn_free_rx_ring(sc, &sc->rxq); | iwn_free_rx_ring(sc, &sc->rxq); | ||||
for (qid = 0; qid < sc->ntxqs; qid++) | for (qid = 0; qid < sc->ntxqs; qid++) | ||||
iwn_free_tx_ring(sc, &sc->txq[qid]); | iwn_free_tx_ring(sc, &sc->txq[qid]); | ||||
iwn_free_sched(sc); | iwn_free_sched(sc); | ||||
iwn_free_kw(sc); | iwn_free_kw(sc); | ||||
if (sc->ict != NULL) | if (sc->ict != NULL) | ||||
iwn_free_ict(sc); | iwn_free_ict(sc); | ||||
iwn_free_fwmem(sc); | iwn_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, IWN_DEBUG_TRACE, "->%s: end\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n", __func__); | ||||
IWN_LOCK_DESTROY(sc); | IWN_LOCK_DESTROY(sc); | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
iwn_shutdown(device_t dev) | iwn_shutdown(device_t dev) | ||||
{ | { | ||||
struct iwn_softc *sc = device_get_softc(dev); | struct iwn_softc *sc = device_get_softc(dev); | ||||
iwn_stop(sc); | iwn_stop(sc); | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
iwn_suspend(device_t dev) | iwn_suspend(device_t dev) | ||||
{ | { | ||||
struct iwn_softc *sc = device_get_softc(dev); | struct iwn_softc *sc = device_get_softc(dev); | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | |||||
ieee80211_suspend_all(ic); | ieee80211_suspend_all(&sc->sc_ic); | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
iwn_resume(device_t dev) | iwn_resume(device_t dev) | ||||
{ | { | ||||
struct iwn_softc *sc = device_get_softc(dev); | struct iwn_softc *sc = device_get_softc(dev); | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | |||||
/* 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(&sc->sc_ic); | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
iwn_nic_lock(struct iwn_softc *sc) | iwn_nic_lock(struct iwn_softc *sc) | ||||
{ | { | ||||
int ntries; | int ntries; | ||||
▲ Show 20 Lines • Show All 892 Lines • ▼ Show 20 Lines | iwn_eeprom_channel_flags(struct iwn_eeprom_chan *channel) | ||||
} | } | ||||
return nflags; | return nflags; | ||||
} | } | ||||
static void | static void | ||||
iwn_read_eeprom_band(struct iwn_softc *sc, int n) | iwn_read_eeprom_band(struct iwn_softc *sc, int n) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct iwn_eeprom_chan *channels = sc->eeprom_channels[n]; | struct iwn_eeprom_chan *channels = sc->eeprom_channels[n]; | ||||
const struct iwn_chan_band *band = &iwn_bands[n]; | const struct iwn_chan_band *band = &iwn_bands[n]; | ||||
struct ieee80211_channel *c; | struct ieee80211_channel *c; | ||||
uint8_t chan; | uint8_t chan; | ||||
int i, nflags; | int i, nflags; | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | iwn_read_eeprom_band(struct iwn_softc *sc, int n) | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__); | ||||
} | } | ||||
static void | static void | ||||
iwn_read_eeprom_ht40(struct iwn_softc *sc, int n) | iwn_read_eeprom_ht40(struct iwn_softc *sc, int n) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct iwn_eeprom_chan *channels = sc->eeprom_channels[n]; | struct iwn_eeprom_chan *channels = sc->eeprom_channels[n]; | ||||
const struct iwn_chan_band *band = &iwn_bands[n]; | const struct iwn_chan_band *band = &iwn_bands[n]; | ||||
struct ieee80211_channel *c, *cent, *extc; | struct ieee80211_channel *c, *cent, *extc; | ||||
uint8_t chan; | uint8_t chan; | ||||
int i, nflags; | int i, nflags; | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s start\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s start\n", __func__); | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | iwn_read_eeprom_ht40(struct iwn_softc *sc, int n) | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__); | ||||
} | } | ||||
static void | static void | ||||
iwn_read_eeprom_channels(struct iwn_softc *sc, int n, uint32_t addr) | iwn_read_eeprom_channels(struct iwn_softc *sc, int n, uint32_t addr) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
iwn_read_prom_data(sc, addr, &sc->eeprom_channels[n], | iwn_read_prom_data(sc, addr, &sc->eeprom_channels[n], | ||||
iwn_bands[n].nchan * sizeof (struct iwn_eeprom_chan)); | iwn_bands[n].nchan * sizeof (struct iwn_eeprom_chan)); | ||||
if (n < 5) | if (n < 5) | ||||
iwn_read_eeprom_band(sc, n); | iwn_read_eeprom_band(sc, n); | ||||
else | else | ||||
iwn_read_eeprom_ht40(sc, n); | iwn_read_eeprom_ht40(sc, n); | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | iwn_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *rd, | ||||
return 0; | return 0; | ||||
} | } | ||||
static void | static void | ||||
iwn_read_eeprom_enhinfo(struct iwn_softc *sc) | iwn_read_eeprom_enhinfo(struct iwn_softc *sc) | ||||
{ | { | ||||
struct iwn_eeprom_enhinfo enhinfo[35]; | struct iwn_eeprom_enhinfo enhinfo[35]; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211_channel *c; | struct ieee80211_channel *c; | ||||
uint16_t val, base; | uint16_t val, base; | ||||
int8_t maxpwr; | int8_t maxpwr; | ||||
uint8_t flags; | uint8_t flags; | ||||
int i, j; | int i, j; | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | ||||
▲ Show 20 Lines • Show All 354 Lines • ▼ Show 20 Lines | |||||
* Process an RX_DONE (4965AGN only) or MPDU_RX_DONE firmware notification. | * Process an RX_DONE (4965AGN only) or MPDU_RX_DONE firmware notification. | ||||
* Each MPDU_RX_DONE notification must be preceded by an RX_PHY one. | * Each MPDU_RX_DONE notification must be preceded by an RX_PHY one. | ||||
*/ | */ | ||||
static void | static void | ||||
iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, | iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, | ||||
struct iwn_rx_data *data) | struct iwn_rx_data *data) | ||||
{ | { | ||||
struct iwn_ops *ops = &sc->ops; | struct iwn_ops *ops = &sc->ops; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct iwn_rx_ring *ring = &sc->rxq; | struct iwn_rx_ring *ring = &sc->rxq; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct mbuf *m, *m1; | struct mbuf *m, *m1; | ||||
struct iwn_rx_stat *stat; | struct iwn_rx_stat *stat; | ||||
caddr_t head; | caddr_t head; | ||||
bus_addr_t paddr; | bus_addr_t paddr; | ||||
uint32_t flags; | uint32_t flags; | ||||
Show All 30 Lines | iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, | ||||
} | } | ||||
flags = le32toh(*(uint32_t *)(head + len)); | flags = le32toh(*(uint32_t *)(head + len)); | ||||
/* Discard frames with a bad FCS early. */ | /* Discard frames with a bad FCS early. */ | ||||
if ((flags & IWN_RX_NOERROR) != IWN_RX_NOERROR) { | if ((flags & IWN_RX_NOERROR) != IWN_RX_NOERROR) { | ||||
DPRINTF(sc, IWN_DEBUG_RECV, "%s: RX flags error %x\n", | DPRINTF(sc, IWN_DEBUG_RECV, "%s: RX flags error %x\n", | ||||
__func__, flags); | __func__, flags); | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
return; | return; | ||||
} | } | ||||
/* Discard frames that are too short. */ | /* Discard frames that are too short. */ | ||||
if (len < sizeof (struct ieee80211_frame_ack)) { | if (len < sizeof (struct ieee80211_frame_ack)) { | ||||
DPRINTF(sc, IWN_DEBUG_RECV, "%s: frame too short: %d\n", | DPRINTF(sc, IWN_DEBUG_RECV, "%s: frame too short: %d\n", | ||||
__func__, len); | __func__, len); | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
return; | return; | ||||
} | } | ||||
m1 = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, IWN_RBUF_SIZE); | m1 = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, IWN_RBUF_SIZE); | ||||
if (m1 == NULL) { | if (m1 == NULL) { | ||||
DPRINTF(sc, IWN_DEBUG_ANY, "%s: no mbuf to restock ring\n", | DPRINTF(sc, IWN_DEBUG_ANY, "%s: no mbuf to restock ring\n", | ||||
__func__); | __func__); | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
return; | return; | ||||
} | } | ||||
bus_dmamap_unload(ring->data_dmat, data->map); | bus_dmamap_unload(ring->data_dmat, data->map); | ||||
error = bus_dmamap_load(ring->data_dmat, data->map, mtod(m1, void *), | error = bus_dmamap_load(ring->data_dmat, data->map, mtod(m1, void *), | ||||
IWN_RBUF_SIZE, iwn_dma_map_addr, &paddr, BUS_DMA_NOWAIT); | IWN_RBUF_SIZE, iwn_dma_map_addr, &paddr, BUS_DMA_NOWAIT); | ||||
if (error != 0 && error != EFBIG) { | if (error != 0 && error != EFBIG) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"%s: bus_dmamap_load failed, error %d\n", __func__, error); | "%s: bus_dmamap_load failed, error %d\n", __func__, error); | ||||
m_freem(m1); | m_freem(m1); | ||||
/* Try to reload the old mbuf. */ | /* Try to reload the old mbuf. */ | ||||
error = bus_dmamap_load(ring->data_dmat, data->map, | error = bus_dmamap_load(ring->data_dmat, data->map, | ||||
mtod(data->m, void *), IWN_RBUF_SIZE, iwn_dma_map_addr, | mtod(data->m, void *), IWN_RBUF_SIZE, iwn_dma_map_addr, | ||||
&paddr, BUS_DMA_NOWAIT); | &paddr, BUS_DMA_NOWAIT); | ||||
if (error != 0 && error != EFBIG) { | if (error != 0 && error != EFBIG) { | ||||
panic("%s: could not load old RX mbuf", __func__); | panic("%s: could not load old RX mbuf", __func__); | ||||
} | } | ||||
/* Physical address may have changed. */ | /* Physical address may have changed. */ | ||||
ring->desc[ring->cur] = htole32(paddr >> 8); | ring->desc[ring->cur] = htole32(paddr >> 8); | ||||
bus_dmamap_sync(ring->data_dmat, ring->desc_dma.map, | bus_dmamap_sync(ring->data_dmat, ring->desc_dma.map, | ||||
BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREWRITE); | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
return; | return; | ||||
} | } | ||||
m = data->m; | m = data->m; | ||||
data->m = m1; | data->m = m1; | ||||
/* Update RX descriptor. */ | /* Update RX descriptor. */ | ||||
ring->desc[ring->cur] = htole32(paddr >> 8); | ring->desc[ring->cur] = htole32(paddr >> 8); | ||||
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 = head; | m->m_data = head; | ||||
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 (len >= sizeof(struct ieee80211_frame_min)) | if (len >= sizeof(struct ieee80211_frame_min)) | ||||
ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); | ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); | ||||
else | else | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* Process an incoming Compressed BlockAck. */ | /* Process an incoming Compressed BlockAck. */ | ||||
static void | static void | ||||
iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc, | iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc, | ||||
struct iwn_rx_data *data) | struct iwn_rx_data *data) | ||||
{ | { | ||||
struct iwn_ops *ops = &sc->ops; | struct iwn_ops *ops = &sc->ops; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct iwn_node *wn; | struct iwn_node *wn; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct iwn_compressed_ba *ba = (struct iwn_compressed_ba *)(desc + 1); | struct iwn_compressed_ba *ba = (struct iwn_compressed_ba *)(desc + 1); | ||||
struct iwn_tx_ring *txq; | struct iwn_tx_ring *txq; | ||||
struct iwn_tx_data *txdata; | struct iwn_tx_data *txdata; | ||||
struct ieee80211_tx_ampdu *tap; | struct ieee80211_tx_ampdu *tap; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
uint64_t bitmap; | uint64_t bitmap; | ||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc, | ||||
* | * | ||||
* Yes, the rate control code doesn't know these are A-MPDU | * Yes, the rate control code doesn't know these are A-MPDU | ||||
* subframes and that it's okay to fail some of these. | * subframes and that it's okay to fail some of these. | ||||
*/ | */ | ||||
ni = tap->txa_ni; | ni = tap->txa_ni; | ||||
bitmap = (le64toh(ba->bitmap) >> shift) & wn->agg[tid].bitmap; | bitmap = (le64toh(ba->bitmap) >> shift) & wn->agg[tid].bitmap; | ||||
for (i = 0; bitmap; i++) { | for (i = 0; bitmap; i++) { | ||||
if ((bitmap & 1) == 0) { | if ((bitmap & 1) == 0) { | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
tx_err ++; | tx_err ++; | ||||
ieee80211_ratectl_tx_complete(ni->ni_vap, ni, | ieee80211_ratectl_tx_complete(ni->ni_vap, ni, | ||||
IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); | IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); | ||||
} else { | } else { | ||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | |||||
tx_ok ++; | tx_ok ++; | ||||
ieee80211_ratectl_tx_complete(ni->ni_vap, ni, | ieee80211_ratectl_tx_complete(ni->ni_vap, ni, | ||||
IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); | IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); | ||||
} | } | ||||
bitmap >>= 1; | bitmap >>= 1; | ||||
} | } | ||||
DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, | DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, | ||||
▲ Show 20 Lines • Show All 129 Lines • ▼ Show 20 Lines | |||||
* Process an RX_STATISTICS or BEACON_STATISTICS firmware notification. | * Process an RX_STATISTICS or BEACON_STATISTICS firmware notification. | ||||
* The latter is sent by the firmware after each received beacon. | * The latter is sent by the firmware after each received beacon. | ||||
*/ | */ | ||||
static void | static void | ||||
iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc, | iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc, | ||||
struct iwn_rx_data *data) | struct iwn_rx_data *data) | ||||
{ | { | ||||
struct iwn_ops *ops = &sc->ops; | struct iwn_ops *ops = &sc->ops; | ||||
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 iwn_calib_state *calib = &sc->calib; | struct iwn_calib_state *calib = &sc->calib; | ||||
struct iwn_stats *stats = (struct iwn_stats *)(desc + 1); | struct iwn_stats *stats = (struct iwn_stats *)(desc + 1); | ||||
struct iwn_stats *lstats; | struct iwn_stats *lstats; | ||||
int temp; | int temp; | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | ||||
▲ Show 20 Lines • Show All 156 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Adapter-independent backend for TX_DONE firmware notifications. | * Adapter-independent backend for TX_DONE firmware notifications. | ||||
*/ | */ | ||||
static void | static void | ||||
iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, int ackfailcnt, | iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, int ackfailcnt, | ||||
uint8_t status) | uint8_t status) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct iwn_tx_ring *ring = &sc->txq[desc->qid & 0xf]; | struct iwn_tx_ring *ring = &sc->txq[desc->qid & 0xf]; | ||||
struct iwn_tx_data *data = &ring->data[desc->idx]; | struct iwn_tx_data *data = &ring->data[desc->idx]; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct ieee80211vap *vap; | struct ieee80211vap *vap; | ||||
KASSERT(data->ni != NULL, ("no node")); | KASSERT(data->ni != NULL, ("no node")); | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | ||||
/* Unmap and free mbuf. */ | /* Unmap and free mbuf. */ | ||||
bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); | bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); | ||||
bus_dmamap_unload(ring->data_dmat, data->map); | bus_dmamap_unload(ring->data_dmat, data->map); | ||||
m = data->m, data->m = NULL; | m = data->m, data->m = NULL; | ||||
ni = data->ni, data->ni = NULL; | ni = data->ni, data->ni = NULL; | ||||
vap = ni->ni_vap; | vap = ni->ni_vap; | ||||
/* | /* | ||||
* Update rate control statistics for the node. | * Update rate control statistics for the node. | ||||
*/ | */ | ||||
if (status & IWN_TX_FAIL) { | if (status & IWN_TX_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); | ||||
} | |||||
/* | /* | ||||
* Channels marked for "radar" require traffic to be received | * Channels marked for "radar" require traffic to be received | ||||
* to unlock before we can transmit. Until traffic is seen | * to unlock before we can transmit. Until traffic is seen | ||||
* any attempt to transmit is returned immediately with status | * any attempt to transmit is returned immediately with status | ||||
* set to IWN_TX_FAIL_TX_LOCKED. Unfortunately this can easily | * set to IWN_TX_FAIL_TX_LOCKED. Unfortunately this can easily | ||||
* happen on first authenticate after scanning. To workaround | * happen on first authenticate after scanning. To workaround | ||||
* this we ignore a failure of this sort in AUTH state so the | * this we ignore a failure of this sort in AUTH state so the | ||||
Show All 9 Lines | if (status == IWN_TX_FAIL_TX_LOCKED && | ||||
ieee80211_tx_complete(ni, m, 0); | ieee80211_tx_complete(ni, m, 0); | ||||
else | else | ||||
ieee80211_tx_complete(ni, m, | ieee80211_tx_complete(ni, m, | ||||
(status & IWN_TX_FAIL) != 0); | (status & IWN_TX_FAIL) != 0); | ||||
sc->sc_tx_timer = 0; | sc->sc_tx_timer = 0; | ||||
if (--ring->queued < IWN_TX_RING_LOMARK) { | if (--ring->queued < IWN_TX_RING_LOMARK) { | ||||
sc->qfullmsk &= ~(1 << ring->qid); | sc->qfullmsk &= ~(1 << ring->qid); | ||||
if (sc->qfullmsk == 0 && | if (sc->qfullmsk == 0) | ||||
(ifp->if_drv_flags & IFF_DRV_OACTIVE)) { | iwn_start_locked(sc); | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
iwn_start_locked(ifp); | |||||
} | } | ||||
} | |||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); | ||||
} | } | ||||
/* | /* | ||||
* Process a "command done" firmware notification. This is where we wakeup | * Process a "command done" firmware notification. This is where we wakeup | ||||
* processes waiting for a synchronous command completion. | * processes waiting for a synchronous command completion. | ||||
Show All 27 Lines | iwn_cmd_done(struct iwn_softc *sc, struct iwn_rx_desc *desc) | ||||
wakeup(&ring->desc[desc->idx]); | wakeup(&ring->desc[desc->idx]); | ||||
} | } | ||||
static void | static void | ||||
iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int idx, int nframes, | iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int idx, int nframes, | ||||
int ackfailcnt, void *stat) | int ackfailcnt, void *stat) | ||||
{ | { | ||||
struct iwn_ops *ops = &sc->ops; | struct iwn_ops *ops = &sc->ops; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct iwn_tx_ring *ring = &sc->txq[qid]; | struct iwn_tx_ring *ring = &sc->txq[qid]; | ||||
struct iwn_tx_data *data; | struct iwn_tx_data *data; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
struct iwn_node *wn; | struct iwn_node *wn; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct ieee80211_tx_ampdu *tap; | struct ieee80211_tx_ampdu *tap; | ||||
uint64_t bitmap; | uint64_t bitmap; | ||||
uint32_t *status = stat; | uint32_t *status = stat; | ||||
▲ Show 20 Lines • Show All 122 Lines • ▼ Show 20 Lines | if (ring->queued == 0 && res != NULL) { | ||||
sc->qid2tap[qid] = NULL; | sc->qid2tap[qid] = NULL; | ||||
free(res, M_DEVBUF); | free(res, M_DEVBUF); | ||||
return; | return; | ||||
} | } | ||||
sc->sc_tx_timer = 0; | sc->sc_tx_timer = 0; | ||||
if (ring->queued < IWN_TX_RING_LOMARK) { | if (ring->queued < IWN_TX_RING_LOMARK) { | ||||
sc->qfullmsk &= ~(1 << ring->qid); | sc->qfullmsk &= ~(1 << ring->qid); | ||||
if (sc->qfullmsk == 0 && | if (sc->qfullmsk == 0) | ||||
(ifp->if_drv_flags & IFF_DRV_OACTIVE)) { | iwn_start_locked(sc); | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
iwn_start_locked(ifp); | |||||
} | } | ||||
} | |||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); | ||||
} | } | ||||
/* | /* | ||||
* Process an INT_FH_RX or INT_SW_RX interrupt. | * Process an INT_FH_RX or INT_SW_RX interrupt. | ||||
*/ | */ | ||||
static void | static void | ||||
iwn_notif_intr(struct iwn_softc *sc) | iwn_notif_intr(struct iwn_softc *sc) | ||||
{ | { | ||||
struct iwn_ops *ops = &sc->ops; | struct iwn_ops *ops = &sc->ops; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
uint16_t hw; | uint16_t hw; | ||||
bus_dmamap_sync(sc->rxq.stat_dma.tag, sc->rxq.stat_dma.map, | bus_dmamap_sync(sc->rxq.stat_dma.tag, sc->rxq.stat_dma.map, | ||||
BUS_DMASYNC_POSTREAD); | BUS_DMASYNC_POSTREAD); | ||||
hw = le16toh(sc->rxq.stat->closed_count) & 0xfff; | hw = le16toh(sc->rxq.stat->closed_count) & 0xfff; | ||||
while (sc->rxq.cur != hw) { | while (sc->rxq.cur != hw) { | ||||
▲ Show 20 Lines • Show All 177 Lines • ▼ Show 20 Lines | for (qid = 0; qid < sc->ntxqs; qid++) { | ||||
struct iwn_tx_ring *ring = &sc->txq[qid]; | struct iwn_tx_ring *ring = &sc->txq[qid]; | ||||
IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | ring->cur); | IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | ring->cur); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
iwn_rftoggle_intr(struct iwn_softc *sc) | iwn_rftoggle_intr(struct iwn_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
uint32_t tmp = IWN_READ(sc, IWN_GP_CNTRL); | uint32_t tmp = IWN_READ(sc, IWN_GP_CNTRL); | ||||
IWN_LOCK_ASSERT(sc); | IWN_LOCK_ASSERT(sc); | ||||
device_printf(sc->sc_dev, "RF switch: radio %s\n", | device_printf(sc->sc_dev, "RF switch: radio %s\n", | ||||
(tmp & IWN_GP_CNTRL_RFKILL) ? "enabled" : "disabled"); | (tmp & IWN_GP_CNTRL_RFKILL) ? "enabled" : "disabled"); | ||||
if (tmp & IWN_GP_CNTRL_RFKILL) | if (tmp & IWN_GP_CNTRL_RFKILL) | ||||
ieee80211_runtask(ic, &sc->sc_radioon_task); | ieee80211_runtask(ic, &sc->sc_radioon_task); | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | iwn_fatal_intr(struct iwn_softc *sc) | ||||
} | } | ||||
printf(" rx ring: cur=%d\n", sc->rxq.cur); | printf(" rx ring: cur=%d\n", sc->rxq.cur); | ||||
} | } | ||||
static void | static void | ||||
iwn_intr(void *arg) | iwn_intr(void *arg) | ||||
{ | { | ||||
struct iwn_softc *sc = arg; | struct iwn_softc *sc = arg; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
uint32_t r1, r2, tmp; | uint32_t r1, r2, tmp; | ||||
IWN_LOCK(sc); | IWN_LOCK(sc); | ||||
/* Disable interrupts. */ | /* Disable interrupts. */ | ||||
IWN_WRITE(sc, IWN_INT_MASK, 0); | IWN_WRITE(sc, IWN_INT_MASK, 0); | ||||
/* Read interrupts from ICT (fast) or from registers (slow). */ | /* Read interrupts from ICT (fast) or from registers (slow). */ | ||||
▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | #endif | ||||
if (r1 & IWN_INT_ALIVE) | if (r1 & IWN_INT_ALIVE) | ||||
wakeup(sc); /* Firmware is alive. */ | wakeup(sc); /* Firmware is alive. */ | ||||
if (r1 & IWN_INT_WAKEUP) | if (r1 & IWN_INT_WAKEUP) | ||||
iwn_wakeup_intr(sc); | iwn_wakeup_intr(sc); | ||||
done: | done: | ||||
/* Re-enable interrupts. */ | /* Re-enable interrupts. */ | ||||
if (ifp->if_flags & IFF_UP) | if (sc->sc_flags & IWN_FLAG_RUNNING) | ||||
IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); | IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); | ||||
IWN_UNLOCK(sc); | IWN_UNLOCK(sc); | ||||
} | } | ||||
/* | /* | ||||
* Update TX scheduler ring when transmitting an 802.11 frame (4965AGN and | * Update TX scheduler ring when transmitting an 802.11 frame (4965AGN and | ||||
* 5000 adapters use a slightly different format). | * 5000 adapters use a slightly different format). | ||||
▲ Show 20 Lines • Show All 467 Lines • ▼ Show 20 Lines | iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, | iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, | ||||
struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) | struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) | ||||
{ | { | ||||
struct iwn_ops *ops = &sc->ops; | struct iwn_ops *ops = &sc->ops; | ||||
// struct ifnet *ifp = sc->sc_ifp; | |||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
// struct ieee80211com *ic = ifp->if_l2com; | |||||
struct iwn_tx_cmd *cmd; | struct iwn_tx_cmd *cmd; | ||||
struct iwn_cmd_data *tx; | struct iwn_cmd_data *tx; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct iwn_tx_ring *ring; | struct iwn_tx_ring *ring; | ||||
struct iwn_tx_desc *desc; | struct iwn_tx_desc *desc; | ||||
struct iwn_tx_data *data; | struct iwn_tx_data *data; | ||||
struct mbuf *m1; | struct mbuf *m1; | ||||
bus_dma_segment_t *seg, segs[IWN_MAX_SCATTER]; | bus_dma_segment_t *seg, segs[IWN_MAX_SCATTER]; | ||||
▲ Show 20 Lines • Show All 179 Lines • ▼ Show 20 Lines | iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
iwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, | iwn_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 iwn_softc *sc = ic->ic_softc; | ||||
struct iwn_softc *sc = ifp->if_softc; | |||||
int error = 0; | int error = 0; | ||||
DPRINTF(sc, IWN_DEBUG_XMIT | IWN_DEBUG_TRACE, "->%s begin\n", __func__); | DPRINTF(sc, IWN_DEBUG_XMIT | IWN_DEBUG_TRACE, "->%s begin\n", __func__); | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | if ((sc->sc_flags & IWN_FLAG_RUNNING) == 0) { | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
m_freem(m); | m_freem(m); | ||||
return ENETDOWN; | return ENETDOWN; | ||||
} | } | ||||
IWN_LOCK(sc); | IWN_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 = iwn_tx_data(sc, m, ni); | error = iwn_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 = iwn_tx_data_raw(sc, m, ni, params); | error = iwn_tx_data_raw(sc, m, ni, params); | ||||
} | } | ||||
if (error != 0) { | if (error != 0) { | ||||
/* NB: m is reclaimed on tx failure */ | /* NB: m is reclaimed on tx failure */ | ||||
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 | } else | ||||
sc->sc_tx_timer = 5; | sc->sc_tx_timer = 5; | ||||
IWN_UNLOCK(sc); | IWN_UNLOCK(sc); | ||||
DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, "->%s: end\n",__func__); | DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, "->%s: end\n",__func__); | ||||
return error; | return error; | ||||
} | } | ||||
static void | static int | ||||
iwn_start(struct ifnet *ifp) | iwn_transmit(struct ieee80211com *ic, struct mbuf *m) | ||||
{ | { | ||||
struct iwn_softc *sc = ifp->if_softc; | struct iwn_softc *sc; | ||||
int error; | |||||
sc = ic->ic_softc; | |||||
IWN_LOCK(sc); | IWN_LOCK(sc); | ||||
iwn_start_locked(ifp); | if ((sc->sc_flags & IWN_FLAG_RUNNING) == 0) { | ||||
IWN_UNLOCK(sc); | IWN_UNLOCK(sc); | ||||
return (ENXIO); | |||||
} | } | ||||
error = mbufq_enqueue(&sc->sc_snd, m); | |||||
if (error) { | |||||
IWN_UNLOCK(sc); | |||||
return (error); | |||||
} | |||||
iwn_start_locked(sc); | |||||
IWN_UNLOCK(sc); | |||||
return (0); | |||||
} | |||||
static void | static void | ||||
iwn_start_locked(struct ifnet *ifp) | iwn_start_locked(struct iwn_softc *sc) | ||||
{ | { | ||||
struct iwn_softc *sc = ifp->if_softc; | |||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
IWN_LOCK_ASSERT(sc); | IWN_LOCK_ASSERT(sc); | ||||
DPRINTF(sc, IWN_DEBUG_XMIT, "%s: called\n", __func__); | DPRINTF(sc, IWN_DEBUG_XMIT, "%s: called\n", __func__); | ||||
while (sc->qfullmsk == 0 && | |||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || | (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { | ||||
(ifp->if_drv_flags & IFF_DRV_OACTIVE)) | |||||
return; | |||||
for (;;) { | |||||
if (sc->qfullmsk != 0) { | |||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | |||||
break; | |||||
} | |||||
IFQ_DRV_DEQUEUE(&ifp->if_snd, m); | |||||
if (m == NULL) | |||||
break; | |||||
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; | ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; | ||||
if (iwn_tx_data(sc, m, ni) != 0) { | if (iwn_tx_data(sc, m, ni) != 0) { | ||||
if_inc_counter(ni->ni_vap->iv_ifp, | |||||
IFCOUNTER_OERRORS, 1); | |||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
} else | } else | ||||
sc->sc_tx_timer = 5; | sc->sc_tx_timer = 5; | ||||
} | } | ||||
DPRINTF(sc, IWN_DEBUG_XMIT, "%s: done\n", __func__); | DPRINTF(sc, IWN_DEBUG_XMIT, "%s: done\n", __func__); | ||||
} | } | ||||
static void | static void | ||||
iwn_watchdog(void *arg) | iwn_watchdog(void *arg) | ||||
{ | { | ||||
struct iwn_softc *sc = arg; | struct iwn_softc *sc = arg; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
IWN_LOCK_ASSERT(sc); | IWN_LOCK_ASSERT(sc); | ||||
KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, ("not running")); | KASSERT(sc->sc_flags & IWN_FLAG_RUNNING, ("not running")); | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); | ||||
if (sc->sc_tx_timer > 0) { | if (sc->sc_tx_timer > 0) { | ||||
if (--sc->sc_tx_timer == 0) { | if (--sc->sc_tx_timer == 0) { | ||||
ic_printf(ic, "device timeout\n"); | ic_printf(ic, "device timeout\n"); | ||||
ieee80211_runtask(ic, &sc->sc_reinit_task); | ieee80211_runtask(ic, &sc->sc_reinit_task); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
callout_reset(&sc->watchdog_to, hz, iwn_watchdog, sc); | callout_reset(&sc->watchdog_to, hz, iwn_watchdog, sc); | ||||
} | } | ||||
static int | static int | ||||
iwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | iwn_ioctl(struct ieee80211com *ic, u_long cmd, char *data) | ||||
{ | { | ||||
struct iwn_softc *sc = ifp->if_softc; | struct iwn_softc *sc = ic->ic_softc; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | |||||
struct ifreq *ifr = (struct ifreq *) data; | struct ifreq *ifr = (struct ifreq *) data; | ||||
int error = 0, startall = 0, stop = 0; | int error = 0; | ||||
switch (cmd) { | switch (cmd) { | ||||
case SIOCGIFADDR: | |||||
error = ether_ioctl(ifp, cmd, data); | |||||
break; | |||||
case SIOCSIFFLAGS: | |||||
IWN_LOCK(sc); | |||||
if (ifp->if_flags & IFF_UP) { | |||||
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { | |||||
iwn_init_locked(sc); | |||||
if (IWN_READ(sc, IWN_GP_CNTRL) & IWN_GP_CNTRL_RFKILL) | |||||
startall = 1; | |||||
else | |||||
stop = 1; | |||||
} | |||||
} else { | |||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | |||||
iwn_stop_locked(sc); | |||||
} | |||||
IWN_UNLOCK(sc); | |||||
if (startall) | |||||
ieee80211_start_all(ic); | |||||
else if (vap != NULL && stop) | |||||
ieee80211_stop(vap); | |||||
break; | |||||
case SIOCGIFMEDIA: | |||||
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); | |||||
break; | |||||
case SIOCGIWNSTATS: | case SIOCGIWNSTATS: | ||||
IWN_LOCK(sc); | IWN_LOCK(sc); | ||||
/* XXX validate permissions/memory/etc? */ | /* XXX validate permissions/memory/etc? */ | ||||
error = copyout(&sc->last_stat, ifr->ifr_data, | error = copyout(&sc->last_stat, ifr->ifr_data, | ||||
sizeof(struct iwn_stats)); | sizeof(struct iwn_stats)); | ||||
IWN_UNLOCK(sc); | IWN_UNLOCK(sc); | ||||
break; | break; | ||||
case SIOCZIWNSTATS: | case SIOCZIWNSTATS: | ||||
IWN_LOCK(sc); | IWN_LOCK(sc); | ||||
memset(&sc->last_stat, 0, sizeof(struct iwn_stats)); | memset(&sc->last_stat, 0, sizeof(struct iwn_stats)); | ||||
IWN_UNLOCK(sc); | IWN_UNLOCK(sc); | ||||
break; | break; | ||||
default: | default: | ||||
error = EINVAL; | error = ENOTTY; | ||||
break; | break; | ||||
} | } | ||||
return error; | return (error); | ||||
} | } | ||||
static void | |||||
iwn_parent(struct ieee80211com *ic) | |||||
{ | |||||
struct iwn_softc *sc = ic->ic_softc; | |||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | |||||
int startall = 0, stop = 0; | |||||
IWN_LOCK(sc); | |||||
if (ic->ic_nrunning > 0) { | |||||
if (!(sc->sc_flags & IWN_FLAG_RUNNING)) { | |||||
iwn_init_locked(sc); | |||||
if (IWN_READ(sc, IWN_GP_CNTRL) & IWN_GP_CNTRL_RFKILL) | |||||
startall = 1; | |||||
else | |||||
stop = 1; | |||||
} | |||||
} else if (sc->sc_flags & IWN_FLAG_RUNNING) | |||||
iwn_stop_locked(sc); | |||||
IWN_UNLOCK(sc); | |||||
if (startall) | |||||
ieee80211_start_all(ic); | |||||
else if (vap != NULL && stop) | |||||
ieee80211_stop(vap); | |||||
} | |||||
/* | /* | ||||
* Send a command to the firmware. | * Send a command to the firmware. | ||||
*/ | */ | ||||
static int | static int | ||||
iwn_cmd(struct iwn_softc *sc, int code, const void *buf, int size, int async) | iwn_cmd(struct iwn_softc *sc, int code, const void *buf, int size, int async) | ||||
{ | { | ||||
struct iwn_tx_ring *ring; | struct iwn_tx_ring *ring; | ||||
struct iwn_tx_desc *desc; | struct iwn_tx_desc *desc; | ||||
▲ Show 20 Lines • Show All 215 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 | ||||
iwn_add_broadcast_node(struct iwn_softc *sc, int async) | iwn_add_broadcast_node(struct iwn_softc *sc, int async) | ||||
{ | { | ||||
struct iwn_ops *ops = &sc->ops; | struct iwn_ops *ops = &sc->ops; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct iwn_node_info node; | struct iwn_node_info node; | ||||
struct iwn_cmd_link_quality linkq; | struct iwn_cmd_link_quality linkq; | ||||
uint8_t txant; | uint8_t txant; | ||||
int i, error; | int i, error; | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | ||||
sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX]; | sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX]; | ||||
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 = sc->broadcast_id; | node.id = sc->broadcast_id; | ||||
DPRINTF(sc, IWN_DEBUG_RESET, "%s: adding broadcast node\n", __func__); | DPRINTF(sc, IWN_DEBUG_RESET, "%s: adding broadcast node\n", __func__); | ||||
if ((error = ops->add_node(sc, &node, async)) != 0) | if ((error = ops->add_node(sc, &node, async)) != 0) | ||||
return error; | return error; | ||||
/* Use the first valid TX antenna. */ | /* Use the first valid TX antenna. */ | ||||
txant = IWN_LSB(sc->txchainmask); | txant = IWN_LSB(sc->txchainmask); | ||||
▲ Show 20 Lines • Show All 132 Lines • ▼ Show 20 Lines | DPRINTF(sc, IWN_DEBUG_RESET, "timing bintval=%u tstamp=%ju, init=%u\n", | ||||
ni->ni_intval, le64toh(cmd.tstamp), (uint32_t)(val - mod)); | ni->ni_intval, le64toh(cmd.tstamp), (uint32_t)(val - mod)); | ||||
return iwn_cmd(sc, IWN_CMD_TIMING, &cmd, sizeof cmd, 1); | return iwn_cmd(sc, IWN_CMD_TIMING, &cmd, sizeof cmd, 1); | ||||
} | } | ||||
static void | static void | ||||
iwn4965_power_calibration(struct iwn_softc *sc, int temp) | iwn4965_power_calibration(struct iwn_softc *sc, int temp) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); | ||||
/* Adjust TX power if need be (delta >= 3 degC). */ | /* Adjust TX power if need be (delta >= 3 degC). */ | ||||
DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: temperature %d->%d\n", | DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: temperature %d->%d\n", | ||||
__func__, sc->temp, temp); | __func__, sc->temp, temp); | ||||
if (abs(temp - sc->temp) >= 3) { | if (abs(temp - sc->temp) >= 3) { | ||||
/* Record temperature of last calibration. */ | /* Record temperature of last calibration. */ | ||||
▲ Show 20 Lines • Show All 353 Lines • ▼ Show 20 Lines | |||||
* to set differential gains. | * to set differential gains. | ||||
*/ | */ | ||||
static void | static void | ||||
iwn_collect_noise(struct iwn_softc *sc, | iwn_collect_noise(struct iwn_softc *sc, | ||||
const struct iwn_rx_general_stats *stats) | const struct iwn_rx_general_stats *stats) | ||||
{ | { | ||||
struct iwn_ops *ops = &sc->ops; | struct iwn_ops *ops = &sc->ops; | ||||
struct iwn_calib_state *calib = &sc->calib; | struct iwn_calib_state *calib = &sc->calib; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
uint32_t val; | uint32_t val; | ||||
int i; | int i; | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | ||||
/* Accumulate RSSI and noise for all 3 antennas. */ | /* Accumulate RSSI and noise for all 3 antennas. */ | ||||
for (i = 0; i < 3; i++) { | for (i = 0; i < 3; i++) { | ||||
calib->rssi[i] += le32toh(stats->rssi[i]) & 0xff; | calib->rssi[i] += le32toh(stats->rssi[i]) & 0xff; | ||||
▲ Show 20 Lines • Show All 617 Lines • ▼ Show 20 Lines | DPRINTF(sc, IWN_DEBUG_CALIBRATE, | ||||
"%s: configuring runtime calibration\n", __func__); | "%s: configuring runtime calibration\n", __func__); | ||||
return iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof(cmd), 0); | return iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof(cmd), 0); | ||||
} | } | ||||
static int | static int | ||||
iwn_config(struct iwn_softc *sc) | iwn_config(struct iwn_softc *sc) | ||||
{ | { | ||||
struct iwn_ops *ops = &sc->ops; | struct iwn_ops *ops = &sc->ops; | ||||
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); | ||||
const uint8_t *macaddr; | |||||
uint32_t txmask; | uint32_t txmask; | ||||
uint16_t rxchain; | uint16_t rxchain; | ||||
int error; | int error; | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | ||||
if ((sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET) | if ((sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET) | ||||
&& (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2)) { | && (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2)) { | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | device_printf(sc->sc_dev, | ||||
"%s: could not configure bluetooth coexistence, error %d\n", | "%s: could not configure bluetooth coexistence, error %d\n", | ||||
__func__, error); | __func__, error); | ||||
return error; | return error; | ||||
} | } | ||||
/* Set mode, channel, RX filter and enable RX. */ | /* Set mode, channel, RX filter and enable RX. */ | ||||
sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX]; | sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX]; | ||||
memset(sc->rxon, 0, sizeof (struct iwn_rxon)); | memset(sc->rxon, 0, sizeof (struct iwn_rxon)); | ||||
IEEE80211_ADDR_COPY(sc->rxon->myaddr, IF_LLADDR(ifp)); | macaddr = vap ? vap->iv_myaddr : ic->ic_macaddr; | ||||
IEEE80211_ADDR_COPY(sc->rxon->wlap, IF_LLADDR(ifp)); | IEEE80211_ADDR_COPY(sc->rxon->myaddr, macaddr); | ||||
IEEE80211_ADDR_COPY(sc->rxon->wlap, macaddr); | |||||
sc->rxon->chan = ieee80211_chan2ieee(ic, ic->ic_curchan); | sc->rxon->chan = ieee80211_chan2ieee(ic, ic->ic_curchan); | ||||
sc->rxon->flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF); | sc->rxon->flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF); | ||||
if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) | if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) | ||||
sc->rxon->flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ); | sc->rxon->flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ); | ||||
switch (ic->ic_opmode) { | switch (ic->ic_opmode) { | ||||
case IEEE80211_M_STA: | case IEEE80211_M_STA: | ||||
sc->rxon->mode = IWN_MODE_STA; | sc->rxon->mode = IWN_MODE_STA; | ||||
sc->rxon->filter = htole32(IWN_FILTER_MULTICAST); | sc->rxon->filter = htole32(IWN_FILTER_MULTICAST); | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Limit the total dwell time to 85% of the beacon interval. | * Limit the total dwell time to 85% of the beacon interval. | ||||
* | * | ||||
* Returns the dwell time in milliseconds. | * Returns the dwell time in milliseconds. | ||||
*/ | */ | ||||
static uint16_t | static uint16_t | ||||
iwn_limit_dwell(struct iwn_softc *sc, uint16_t dwell_time) | iwn_limit_dwell(struct iwn_softc *sc, uint16_t dwell_time) | ||||
{ | { | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211vap *vap = NULL; | struct ieee80211vap *vap = NULL; | ||||
int bintval = 0; | int bintval = 0; | ||||
/* bintval is in TU (1.024mS) */ | /* bintval is in TU (1.024mS) */ | ||||
if (! TAILQ_EMPTY(&ic->ic_vaps)) { | if (! TAILQ_EMPTY(&ic->ic_vaps)) { | ||||
vap = TAILQ_FIRST(&ic->ic_vaps); | vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
bintval = vap->iv_bss->ni_intval; | bintval = vap->iv_bss->ni_intval; | ||||
} | } | ||||
Show All 31 Lines | iwn_get_passive_dwell_time(struct iwn_softc *sc, struct ieee80211_channel *c) | ||||
/* Clamp to the beacon interval if we're associated */ | /* Clamp to the beacon interval if we're associated */ | ||||
return (iwn_limit_dwell(sc, passive)); | return (iwn_limit_dwell(sc, passive)); | ||||
} | } | ||||
static int | static int | ||||
iwn_scan(struct iwn_softc *sc, struct ieee80211vap *vap, | iwn_scan(struct iwn_softc *sc, struct ieee80211vap *vap, | ||||
struct ieee80211_scan_state *ss, struct ieee80211_channel *c) | struct ieee80211_scan_state *ss, struct ieee80211_channel *c) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211_node *ni = vap->iv_bss; | struct ieee80211_node *ni = vap->iv_bss; | ||||
struct iwn_scan_hdr *hdr; | struct iwn_scan_hdr *hdr; | ||||
struct iwn_cmd_data *tx; | struct iwn_cmd_data *tx; | ||||
struct iwn_scan_essid *essid; | struct iwn_scan_essid *essid; | ||||
struct iwn_scan_chan *chan; | struct iwn_scan_chan *chan; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct ieee80211_rateset *rs; | struct ieee80211_rateset *rs; | ||||
uint8_t *buf, *frm; | uint8_t *buf, *frm; | ||||
▲ Show 20 Lines • Show All 121 Lines • ▼ Show 20 Lines | iwn_scan(struct iwn_softc *sc, struct ieee80211vap *vap, | ||||
/* | /* | ||||
* 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 *)(essid + 20); | wh = (struct ieee80211_frame *)(essid + 20); | ||||
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, vap->iv_ifp->if_broadcastaddr); | ||||
IEEE80211_ADDR_COPY(wh->i_addr2, IF_LLADDR(ifp)); | IEEE80211_ADDR_COPY(wh->i_addr2, IF_LLADDR(vap->iv_ifp)); | ||||
IEEE80211_ADDR_COPY(wh->i_addr3, ifp->if_broadcastaddr); | IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_ifp->if_broadcastaddr); | ||||
*(uint16_t *)&wh->i_dur[0] = 0; /* filled by HW */ | *(uint16_t *)&wh->i_dur[0] = 0; /* filled by HW */ | ||||
*(uint16_t *)&wh->i_seq[0] = 0; /* filled by HW */ | *(uint16_t *)&wh->i_seq[0] = 0; /* filled by HW */ | ||||
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); | ||||
▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | iwn_scan(struct iwn_softc *sc, struct ieee80211vap *vap, | ||||
return error; | return error; | ||||
} | } | ||||
static int | static int | ||||
iwn_auth(struct iwn_softc *sc, struct ieee80211vap *vap) | iwn_auth(struct iwn_softc *sc, struct ieee80211vap *vap) | ||||
{ | { | ||||
struct iwn_ops *ops = &sc->ops; | struct iwn_ops *ops = &sc->ops; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211_node *ni = vap->iv_bss; | struct ieee80211_node *ni = vap->iv_bss; | ||||
int error; | int error; | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | ||||
sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX]; | sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX]; | ||||
/* Update adapter configuration. */ | /* Update adapter configuration. */ | ||||
IEEE80211_ADDR_COPY(sc->rxon->bssid, ni->ni_bssid); | IEEE80211_ADDR_COPY(sc->rxon->bssid, ni->ni_bssid); | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | iwn_auth(struct iwn_softc *sc, struct ieee80211vap *vap) | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
iwn_run(struct iwn_softc *sc, struct ieee80211vap *vap) | iwn_run(struct iwn_softc *sc, struct ieee80211vap *vap) | ||||
{ | { | ||||
struct iwn_ops *ops = &sc->ops; | struct iwn_ops *ops = &sc->ops; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211_node *ni = vap->iv_bss; | struct ieee80211_node *ni = vap->iv_bss; | ||||
struct iwn_node_info node; | struct iwn_node_info node; | ||||
uint32_t htflags = 0; | uint32_t htflags = 0; | ||||
int error; | int error; | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | ||||
sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX]; | sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX]; | ||||
▲ Show 20 Lines • Show All 1,569 Lines • ▼ Show 20 Lines | iwn_hw_stop(struct iwn_softc *sc) | ||||
/* Power OFF adapter. */ | /* Power OFF adapter. */ | ||||
iwn_apm_stop(sc); | iwn_apm_stop(sc); | ||||
} | } | ||||
static void | static void | ||||
iwn_radio_on(void *arg0, int pending) | iwn_radio_on(void *arg0, int pending) | ||||
{ | { | ||||
struct iwn_softc *sc = arg0; | struct iwn_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); | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); | ||||
if (vap != NULL) { | if (vap != NULL) { | ||||
iwn_init(sc); | iwn_init(sc); | ||||
ieee80211_init(vap); | ieee80211_init(vap); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
iwn_radio_off(void *arg0, int pending) | iwn_radio_off(void *arg0, int pending) | ||||
{ | { | ||||
struct iwn_softc *sc = arg0; | struct iwn_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); | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); | ||||
iwn_stop(sc); | iwn_stop(sc); | ||||
if (vap != NULL) | if (vap != NULL) | ||||
ieee80211_stop(vap); | ieee80211_stop(vap); | ||||
/* Enable interrupts to get RF toggle notification. */ | /* Enable interrupts to get RF toggle notification. */ | ||||
IWN_LOCK(sc); | IWN_LOCK(sc); | ||||
IWN_WRITE(sc, IWN_INT, 0xffffffff); | IWN_WRITE(sc, IWN_INT, 0xffffffff); | ||||
IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); | IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); | ||||
IWN_UNLOCK(sc); | IWN_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
iwn_panicked(void *arg0, int pending) | iwn_panicked(void *arg0, int pending) | ||||
{ | { | ||||
struct iwn_softc *sc = arg0; | struct iwn_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); | ||||
int error; | int error; | ||||
if (vap == NULL) { | if (vap == NULL) { | ||||
printf("%s: null vap\n", __func__); | printf("%s: null vap\n", __func__); | ||||
return; | return; | ||||
} | } | ||||
Show All 11 Lines | iwn_panicked(void *arg0, int pending) | ||||
} | } | ||||
if (vap->iv_state >= IEEE80211_S_RUN && | if (vap->iv_state >= IEEE80211_S_RUN && | ||||
(error = iwn_run(sc, vap)) != 0) { | (error = iwn_run(sc, vap)) != 0) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"%s: could not move to run state\n", __func__); | "%s: could not move to run state\n", __func__); | ||||
} | } | ||||
/* Only run start once the NIC is in a useful state, like associated */ | /* Only run start once the NIC is in a useful state, like associated */ | ||||
iwn_start_locked(sc->sc_ifp); | iwn_start_locked(sc); | ||||
IWN_UNLOCK(sc); | IWN_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
iwn_init_locked(struct iwn_softc *sc) | iwn_init_locked(struct iwn_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
int error; | int error; | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); | ||||
IWN_LOCK_ASSERT(sc); | IWN_LOCK_ASSERT(sc); | ||||
sc->sc_flags |= IWN_FLAG_RUNNING; | |||||
if ((error = iwn_hw_prepare(sc)) != 0) { | if ((error = iwn_hw_prepare(sc)) != 0) { | ||||
device_printf(sc->sc_dev, "%s: hardware not ready, error %d\n", | device_printf(sc->sc_dev, "%s: hardware not ready, error %d\n", | ||||
__func__, error); | __func__, error); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
/* Initialize interrupt mask to default value. */ | /* Initialize interrupt mask to default value. */ | ||||
sc->int_mask = IWN_INT_MASK_DEF; | sc->int_mask = IWN_INT_MASK_DEF; | ||||
Show All 31 Lines | iwn_init_locked(struct iwn_softc *sc) | ||||
/* Configure adapter now that it is ready. */ | /* Configure adapter now that it is ready. */ | ||||
if ((error = iwn_config(sc)) != 0) { | if ((error = iwn_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; | ||||
} | } | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | |||||
callout_reset(&sc->watchdog_to, hz, iwn_watchdog, sc); | callout_reset(&sc->watchdog_to, hz, iwn_watchdog, sc); | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); | ||||
return; | return; | ||||
fail: iwn_stop_locked(sc); | fail: | ||||
sc->sc_flags &= ~IWN_FLAG_RUNNING; | |||||
iwn_stop_locked(sc); | |||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end in error\n",__func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end in error\n",__func__); | ||||
} | } | ||||
static void | static void | ||||
iwn_init(void *arg) | iwn_init(struct iwn_softc *sc) | ||||
{ | { | ||||
struct iwn_softc *sc = arg; | |||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
IWN_LOCK(sc); | IWN_LOCK(sc); | ||||
iwn_init_locked(sc); | iwn_init_locked(sc); | ||||
IWN_UNLOCK(sc); | IWN_UNLOCK(sc); | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (sc->sc_flags & IWN_FLAG_RUNNING) | ||||
ieee80211_start_all(ic); | ieee80211_start_all(&sc->sc_ic); | ||||
} | } | ||||
static void | static void | ||||
iwn_stop_locked(struct iwn_softc *sc) | iwn_stop_locked(struct iwn_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
IWN_LOCK_ASSERT(sc); | IWN_LOCK_ASSERT(sc); | ||||
sc->sc_is_scanning = 0; | sc->sc_is_scanning = 0; | ||||
sc->sc_tx_timer = 0; | sc->sc_tx_timer = 0; | ||||
callout_stop(&sc->watchdog_to); | callout_stop(&sc->watchdog_to); | ||||
callout_stop(&sc->calib_to); | callout_stop(&sc->calib_to); | ||||
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); | sc->sc_flags &= ~IWN_FLAG_RUNNING; | ||||
/* Power OFF hardware. */ | /* Power OFF hardware. */ | ||||
iwn_hw_stop(sc); | iwn_hw_stop(sc); | ||||
} | } | ||||
static void | static void | ||||
iwn_stop(struct iwn_softc *sc) | iwn_stop(struct iwn_softc *sc) | ||||
{ | { | ||||
IWN_LOCK(sc); | IWN_LOCK(sc); | ||||
iwn_stop_locked(sc); | iwn_stop_locked(sc); | ||||
IWN_UNLOCK(sc); | IWN_UNLOCK(sc); | ||||
} | } | ||||
/* | /* | ||||
* Callback from net80211 to start a scan. | * Callback from net80211 to start a scan. | ||||
*/ | */ | ||||
static void | static void | ||||
iwn_scan_start(struct ieee80211com *ic) | iwn_scan_start(struct ieee80211com *ic) | ||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | struct iwn_softc *sc = ic->ic_softc; | ||||
struct iwn_softc *sc = ifp->if_softc; | |||||
IWN_LOCK(sc); | IWN_LOCK(sc); | ||||
/* make the link LED blink while we're scanning */ | /* make the link LED blink while we're scanning */ | ||||
iwn_set_led(sc, IWN_LED_LINK, 20, 2); | iwn_set_led(sc, IWN_LED_LINK, 20, 2); | ||||
IWN_UNLOCK(sc); | IWN_UNLOCK(sc); | ||||
} | } | ||||
/* | /* | ||||
* Callback from net80211 to terminate a scan. | * Callback from net80211 to terminate a scan. | ||||
*/ | */ | ||||
static void | static void | ||||
iwn_scan_end(struct ieee80211com *ic) | iwn_scan_end(struct ieee80211com *ic) | ||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | struct iwn_softc *sc = ic->ic_softc; | ||||
struct iwn_softc *sc = ifp->if_softc; | |||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
IWN_LOCK(sc); | IWN_LOCK(sc); | ||||
if (vap->iv_state == IEEE80211_S_RUN) { | if (vap->iv_state == IEEE80211_S_RUN) { | ||||
/* Set link LED to ON status if we are associated */ | /* Set link LED to ON status if we are associated */ | ||||
iwn_set_led(sc, IWN_LED_LINK, 0, 1); | iwn_set_led(sc, IWN_LED_LINK, 0, 1); | ||||
} | } | ||||
IWN_UNLOCK(sc); | IWN_UNLOCK(sc); | ||||
} | } | ||||
/* | /* | ||||
* Callback from net80211 to force a channel change. | * Callback from net80211 to force a channel change. | ||||
*/ | */ | ||||
static void | static void | ||||
iwn_set_channel(struct ieee80211com *ic) | iwn_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 iwn_softc *sc = ic->ic_softc; | ||||
struct iwn_softc *sc = ifp->if_softc; | |||||
int error; | int error; | ||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); | ||||
IWN_LOCK(sc); | IWN_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); | ||||
sc->sc_txtap.wt_chan_freq = htole16(c->ic_freq); | sc->sc_txtap.wt_chan_freq = htole16(c->ic_freq); | ||||
Show All 40 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 | ||||
iwn_hw_reset(void *arg0, int pending) | iwn_hw_reset(void *arg0, int pending) | ||||
{ | { | ||||
struct iwn_softc *sc = arg0; | struct iwn_softc *sc = arg0; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); | DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); | ||||
iwn_stop(sc); | iwn_stop(sc); | ||||
iwn_init(sc); | iwn_init(sc); | ||||
ieee80211_notify_radio(ic, 1); | ieee80211_notify_radio(ic, 1); | ||||
} | } | ||||
#ifdef IWN_DEBUG | #ifdef IWN_DEBUG | ||||
▲ Show 20 Lines • Show All 80 Lines • Show Last 20 Lines |