Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/iwi/if_iwi.c
Show First 20 Lines • Show All 160 Lines • ▼ Show 20 Lines | |||||
static void iwi_frame_intr(struct iwi_softc *, struct iwi_rx_data *, int, | static void iwi_frame_intr(struct iwi_softc *, struct iwi_rx_data *, int, | ||||
struct iwi_frame *); | struct iwi_frame *); | ||||
static void iwi_notification_intr(struct iwi_softc *, struct iwi_notif *); | static void iwi_notification_intr(struct iwi_softc *, struct iwi_notif *); | ||||
static void iwi_rx_intr(struct iwi_softc *); | static void iwi_rx_intr(struct iwi_softc *); | ||||
static void iwi_tx_intr(struct iwi_softc *, struct iwi_tx_ring *); | static void iwi_tx_intr(struct iwi_softc *, struct iwi_tx_ring *); | ||||
static void iwi_intr(void *); | static void iwi_intr(void *); | ||||
static int iwi_cmd(struct iwi_softc *, uint8_t, void *, uint8_t); | static int iwi_cmd(struct iwi_softc *, uint8_t, void *, uint8_t); | ||||
static void iwi_write_ibssnode(struct iwi_softc *, const u_int8_t [], int); | static void iwi_write_ibssnode(struct iwi_softc *, const u_int8_t [], int); | ||||
static int iwi_tx_start(struct ifnet *, struct mbuf *, | static int iwi_tx_start(struct iwi_softc *, struct mbuf *, | ||||
struct ieee80211_node *, int); | struct ieee80211_node *, int); | ||||
static int iwi_raw_xmit(struct ieee80211_node *, struct mbuf *, | static int iwi_raw_xmit(struct ieee80211_node *, struct mbuf *, | ||||
const struct ieee80211_bpf_params *); | const struct ieee80211_bpf_params *); | ||||
static void iwi_start_locked(struct ifnet *); | static void iwi_start(struct iwi_softc *); | ||||
static void iwi_start(struct ifnet *); | static int iwi_transmit(struct ieee80211com *, struct mbuf *); | ||||
static void iwi_watchdog(void *); | static void iwi_watchdog(void *); | ||||
static int iwi_ioctl(struct ifnet *, u_long, caddr_t); | static int iwi_ioctl(struct ieee80211com *, u_long, void *); | ||||
static void iwi_parent(struct ieee80211com *); | |||||
static void iwi_stop_master(struct iwi_softc *); | static void iwi_stop_master(struct iwi_softc *); | ||||
static int iwi_reset(struct iwi_softc *); | static int iwi_reset(struct iwi_softc *); | ||||
static int iwi_load_ucode(struct iwi_softc *, const struct iwi_fw *); | static int iwi_load_ucode(struct iwi_softc *, const struct iwi_fw *); | ||||
static int iwi_load_firmware(struct iwi_softc *, const struct iwi_fw *); | static int iwi_load_firmware(struct iwi_softc *, const struct iwi_fw *); | ||||
static void iwi_release_fw_dma(struct iwi_softc *sc); | static void iwi_release_fw_dma(struct iwi_softc *sc); | ||||
static int iwi_config(struct iwi_softc *); | static int iwi_config(struct iwi_softc *); | ||||
static int iwi_get_firmware(struct iwi_softc *, enum ieee80211_opmode); | static int iwi_get_firmware(struct iwi_softc *, enum ieee80211_opmode); | ||||
static void iwi_put_firmware(struct iwi_softc *); | static void iwi_put_firmware(struct iwi_softc *); | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | iwi_probe(device_t dev) | ||||
} | } | ||||
return ENXIO; | return ENXIO; | ||||
} | } | ||||
static int | static int | ||||
iwi_attach(device_t dev) | iwi_attach(device_t dev) | ||||
{ | { | ||||
struct iwi_softc *sc = device_get_softc(dev); | struct iwi_softc *sc = device_get_softc(dev); | ||||
struct ifnet *ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic; | |||||
uint16_t val; | uint16_t val; | ||||
int i, error; | int i, error; | ||||
uint8_t bands; | uint8_t bands; | ||||
uint8_t macaddr[IEEE80211_ADDR_LEN]; | |||||
sc->sc_dev = dev; | sc->sc_dev = dev; | ||||
ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); | |||||
if (ifp == NULL) { | |||||
device_printf(dev, "can not if_alloc()\n"); | |||||
return ENXIO; | |||||
} | |||||
ic = ifp->if_l2com; | |||||
IWI_LOCK_INIT(sc); | IWI_LOCK_INIT(sc); | ||||
mbufq_init(&sc->sc_snd, ifqmaxlen); | |||||
sc->sc_unr = new_unrhdr(1, IWI_MAX_IBSSNODE-1, &sc->sc_mtx); | sc->sc_unr = new_unrhdr(1, IWI_MAX_IBSSNODE-1, &sc->sc_mtx); | ||||
TASK_INIT(&sc->sc_radiontask, 0, iwi_radio_on, sc); | TASK_INIT(&sc->sc_radiontask, 0, iwi_radio_on, sc); | ||||
TASK_INIT(&sc->sc_radiofftask, 0, iwi_radio_off, sc); | TASK_INIT(&sc->sc_radiofftask, 0, iwi_radio_off, sc); | ||||
TASK_INIT(&sc->sc_restarttask, 0, iwi_restart, sc); | TASK_INIT(&sc->sc_restarttask, 0, iwi_restart, sc); | ||||
TASK_INIT(&sc->sc_disassoctask, 0, iwi_disassoc, sc); | TASK_INIT(&sc->sc_disassoctask, 0, iwi_disassoc, sc); | ||||
TASK_INIT(&sc->sc_wmetask, 0, iwi_update_wme, sc); | TASK_INIT(&sc->sc_wmetask, 0, iwi_update_wme, sc); | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | iwi_attach(device_t dev) | ||||
if (iwi_alloc_rx_ring(sc, &sc->rxq, IWI_RX_RING_COUNT) != 0) { | if (iwi_alloc_rx_ring(sc, &sc->rxq, IWI_RX_RING_COUNT) != 0) { | ||||
device_printf(dev, "could not allocate Rx ring\n"); | device_printf(dev, "could not allocate Rx ring\n"); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
iwi_wme_init(sc); | iwi_wme_init(sc); | ||||
ifp->if_softc = sc; | |||||
if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | |||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |||||
ifp->if_init = iwi_init; | |||||
ifp->if_ioctl = iwi_ioctl; | |||||
ifp->if_start = iwi_start; | |||||
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); | |||||
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; | |||||
IFQ_SET_READY(&ifp->if_snd); | |||||
ic->ic_ifp = ifp; | |||||
ic->ic_softc = sc; | ic->ic_softc = sc; | ||||
ic->ic_name = device_get_nameunit(dev); | ic->ic_name = device_get_nameunit(dev); | ||||
ic->ic_opmode = IEEE80211_M_STA; | ic->ic_opmode = IEEE80211_M_STA; | ||||
ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ | ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ | ||||
/* set device capabilities */ | /* set device capabilities */ | ||||
ic->ic_caps = | ic->ic_caps = | ||||
IEEE80211_C_STA /* station mode supported */ | IEEE80211_C_STA /* station mode supported */ | ||||
| IEEE80211_C_IBSS /* IBSS mode supported */ | | IEEE80211_C_IBSS /* IBSS mode supported */ | ||||
| IEEE80211_C_MONITOR /* monitor mode supported */ | | IEEE80211_C_MONITOR /* monitor mode supported */ | ||||
| IEEE80211_C_PMGT /* power save supported */ | | IEEE80211_C_PMGT /* power save supported */ | ||||
| IEEE80211_C_SHPREAMBLE /* short preamble supported */ | | IEEE80211_C_SHPREAMBLE /* short preamble supported */ | ||||
| IEEE80211_C_WPA /* 802.11i */ | | IEEE80211_C_WPA /* 802.11i */ | ||||
| IEEE80211_C_WME /* 802.11e */ | | IEEE80211_C_WME /* 802.11e */ | ||||
#if 0 | #if 0 | ||||
| IEEE80211_C_BGSCAN /* capable of bg scanning */ | | IEEE80211_C_BGSCAN /* capable of bg scanning */ | ||||
#endif | #endif | ||||
; | ; | ||||
/* read MAC address from EEPROM */ | /* read MAC address from EEPROM */ | ||||
val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 0); | val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 0); | ||||
macaddr[0] = val & 0xff; | ic->ic_macaddr[0] = val & 0xff; | ||||
macaddr[1] = val >> 8; | ic->ic_macaddr[1] = val >> 8; | ||||
val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 1); | val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 1); | ||||
macaddr[2] = val & 0xff; | ic->ic_macaddr[2] = val & 0xff; | ||||
macaddr[3] = val >> 8; | ic->ic_macaddr[3] = val >> 8; | ||||
val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 2); | val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 2); | ||||
macaddr[4] = val & 0xff; | ic->ic_macaddr[4] = val & 0xff; | ||||
macaddr[5] = val >> 8; | ic->ic_macaddr[5] = val >> 8; | ||||
bands = 0; | bands = 0; | ||||
setbit(&bands, IEEE80211_MODE_11B); | setbit(&bands, IEEE80211_MODE_11B); | ||||
setbit(&bands, IEEE80211_MODE_11G); | setbit(&bands, IEEE80211_MODE_11G); | ||||
if (pci_get_device(dev) >= 0x4223) | if (pci_get_device(dev) >= 0x4223) | ||||
setbit(&bands, IEEE80211_MODE_11A); | setbit(&bands, IEEE80211_MODE_11A); | ||||
ieee80211_init_channels(ic, NULL, &bands); | ieee80211_init_channels(ic, NULL, &bands); | ||||
ieee80211_ifattach(ic, macaddr); | ieee80211_ifattach(ic); | ||||
/* override default methods */ | /* override default methods */ | ||||
ic->ic_node_alloc = iwi_node_alloc; | ic->ic_node_alloc = iwi_node_alloc; | ||||
sc->sc_node_free = ic->ic_node_free; | sc->sc_node_free = ic->ic_node_free; | ||||
ic->ic_node_free = iwi_node_free; | ic->ic_node_free = iwi_node_free; | ||||
ic->ic_raw_xmit = iwi_raw_xmit; | ic->ic_raw_xmit = iwi_raw_xmit; | ||||
ic->ic_scan_start = iwi_scan_start; | ic->ic_scan_start = iwi_scan_start; | ||||
ic->ic_scan_end = iwi_scan_end; | ic->ic_scan_end = iwi_scan_end; | ||||
ic->ic_set_channel = iwi_set_channel; | ic->ic_set_channel = iwi_set_channel; | ||||
ic->ic_scan_curchan = iwi_scan_curchan; | ic->ic_scan_curchan = iwi_scan_curchan; | ||||
ic->ic_scan_mindwell = iwi_scan_mindwell; | ic->ic_scan_mindwell = iwi_scan_mindwell; | ||||
ic->ic_wme.wme_update = iwi_wme_update; | ic->ic_wme.wme_update = iwi_wme_update; | ||||
ic->ic_vap_create = iwi_vap_create; | ic->ic_vap_create = iwi_vap_create; | ||||
ic->ic_vap_delete = iwi_vap_delete; | ic->ic_vap_delete = iwi_vap_delete; | ||||
ic->ic_ioctl = iwi_ioctl; | |||||
ic->ic_transmit = iwi_transmit; | |||||
ic->ic_parent = iwi_parent; | |||||
ieee80211_radiotap_attach(ic, | ieee80211_radiotap_attach(ic, | ||||
&sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), | &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), | ||||
IWI_TX_RADIOTAP_PRESENT, | IWI_TX_RADIOTAP_PRESENT, | ||||
&sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), | &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), | ||||
IWI_RX_RADIOTAP_PRESENT); | IWI_RX_RADIOTAP_PRESENT); | ||||
iwi_sysctlattach(sc); | iwi_sysctlattach(sc); | ||||
Show All 18 Lines | fail: | ||||
iwi_detach(dev); | iwi_detach(dev); | ||||
return ENXIO; | return ENXIO; | ||||
} | } | ||||
static int | static int | ||||
iwi_detach(device_t dev) | iwi_detach(device_t dev) | ||||
{ | { | ||||
struct iwi_softc *sc = device_get_softc(dev); | struct iwi_softc *sc = device_get_softc(dev); | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
bus_teardown_intr(dev, sc->irq, sc->sc_ih); | bus_teardown_intr(dev, sc->irq, sc->sc_ih); | ||||
/* NB: do early to drain any pending tasks */ | /* NB: do early to drain any pending tasks */ | ||||
ieee80211_draintask(ic, &sc->sc_radiontask); | ieee80211_draintask(ic, &sc->sc_radiontask); | ||||
ieee80211_draintask(ic, &sc->sc_radiofftask); | ieee80211_draintask(ic, &sc->sc_radiofftask); | ||||
ieee80211_draintask(ic, &sc->sc_restarttask); | ieee80211_draintask(ic, &sc->sc_restarttask); | ||||
ieee80211_draintask(ic, &sc->sc_disassoctask); | ieee80211_draintask(ic, &sc->sc_disassoctask); | ||||
Show All 14 Lines | iwi_detach(device_t dev) | ||||
iwi_free_rx_ring(sc, &sc->rxq); | iwi_free_rx_ring(sc, &sc->rxq); | ||||
bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq), sc->irq); | bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq), sc->irq); | ||||
bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->mem), | bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->mem), | ||||
sc->mem); | sc->mem); | ||||
delete_unrhdr(sc->sc_unr); | delete_unrhdr(sc->sc_unr); | ||||
mbufq_drain(&sc->sc_snd); | |||||
IWI_LOCK_DESTROY(sc); | IWI_LOCK_DESTROY(sc); | ||||
if_free(ifp); | |||||
return 0; | return 0; | ||||
} | } | ||||
static struct ieee80211vap * | static struct ieee80211vap * | ||||
iwi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, | iwi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, | ||||
enum ieee80211_opmode opmode, int flags, | enum ieee80211_opmode opmode, int flags, | ||||
const uint8_t bssid[IEEE80211_ADDR_LEN], | const uint8_t bssid[IEEE80211_ADDR_LEN], | ||||
const uint8_t mac[IEEE80211_ADDR_LEN]) | const uint8_t mac[IEEE80211_ADDR_LEN]) | ||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | struct iwi_softc *sc = ic->ic_softc; | ||||
struct iwi_softc *sc = ifp->if_softc; | |||||
struct iwi_vap *ivp; | struct iwi_vap *ivp; | ||||
struct ieee80211vap *vap; | struct ieee80211vap *vap; | ||||
int i; | int i; | ||||
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; | ||||
/* | /* | ||||
* Get firmware image (and possibly dma memory) on mode change. | * Get firmware image (and possibly dma memory) on mode change. | ||||
*/ | */ | ||||
if (iwi_get_firmware(sc, opmode)) | if (iwi_get_firmware(sc, opmode)) | ||||
return NULL; | return NULL; | ||||
/* allocate DMA memory for mapping firmware image */ | /* allocate DMA memory for mapping firmware image */ | ||||
i = sc->fw_fw.size; | i = sc->fw_fw.size; | ||||
if (sc->fw_boot.size > i) | if (sc->fw_boot.size > i) | ||||
i = sc->fw_boot.size; | i = sc->fw_boot.size; | ||||
/* XXX do we dma the ucode as well ? */ | /* XXX do we dma the ucode as well ? */ | ||||
if (sc->fw_uc.size > i) | if (sc->fw_uc.size > i) | ||||
i = sc->fw_uc.size; | i = sc->fw_uc.size; | ||||
if (iwi_init_fw_dma(sc, i)) | if (iwi_init_fw_dma(sc, i)) | ||||
return NULL; | return NULL; | ||||
ivp = (struct iwi_vap *) malloc(sizeof(struct iwi_vap), | ivp = malloc(sizeof(struct iwi_vap), M_80211_VAP, M_WAITOK | M_ZERO); | ||||
M_80211_VAP, M_NOWAIT | M_ZERO); | |||||
if (ivp == NULL) | |||||
return NULL; | |||||
vap = &ivp->iwi_vap; | vap = &ivp->iwi_vap; | ||||
ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); | ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); | ||||
/* override the default, the setting comes from the linux driver */ | /* override the default, the setting comes from the linux driver */ | ||||
vap->iv_bmissthreshold = 24; | vap->iv_bmissthreshold = 24; | ||||
/* override with driver methods */ | /* override with driver methods */ | ||||
ivp->iwi_newstate = vap->iv_newstate; | ivp->iwi_newstate = vap->iv_newstate; | ||||
vap->iv_newstate = iwi_newstate; | vap->iv_newstate = iwi_newstate; | ||||
/* complete setup */ | /* complete setup */ | ||||
ieee80211_vap_attach(vap, ieee80211_media_change, iwi_media_status); | ieee80211_vap_attach(vap, ieee80211_media_change, iwi_media_status, | ||||
mac); | |||||
ic->ic_opmode = opmode; | ic->ic_opmode = opmode; | ||||
return vap; | return vap; | ||||
} | } | ||||
static void | static void | ||||
iwi_vap_delete(struct ieee80211vap *vap) | iwi_vap_delete(struct ieee80211vap *vap) | ||||
{ | { | ||||
struct iwi_vap *ivp = IWI_VAP(vap); | struct iwi_vap *ivp = IWI_VAP(vap); | ||||
▲ Show 20 Lines • Show All 310 Lines • ▼ Show 20 Lines | iwi_shutdown(device_t dev) | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
iwi_suspend(device_t dev) | iwi_suspend(device_t dev) | ||||
{ | { | ||||
struct iwi_softc *sc = device_get_softc(dev); | struct iwi_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 | ||||
iwi_resume(device_t dev) | iwi_resume(device_t dev) | ||||
{ | { | ||||
struct iwi_softc *sc = device_get_softc(dev); | struct iwi_softc *sc = device_get_softc(dev); | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
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; | ||||
} | } | ||||
static struct ieee80211_node * | static struct ieee80211_node * | ||||
Show All 9 Lines | iwi_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) | ||||
return &in->in_node; | return &in->in_node; | ||||
} | } | ||||
static void | static void | ||||
iwi_node_free(struct ieee80211_node *ni) | iwi_node_free(struct ieee80211_node *ni) | ||||
{ | { | ||||
struct ieee80211com *ic = ni->ni_ic; | struct ieee80211com *ic = ni->ni_ic; | ||||
struct iwi_softc *sc = ic->ic_ifp->if_softc; | struct iwi_softc *sc = ic->ic_softc; | ||||
struct iwi_node *in = (struct iwi_node *)ni; | struct iwi_node *in = (struct iwi_node *)ni; | ||||
if (in->in_station != -1) { | if (in->in_station != -1) { | ||||
DPRINTF(("%s mac %6D station %u\n", __func__, | DPRINTF(("%s mac %6D station %u\n", __func__, | ||||
ni->ni_macaddr, ":", in->in_station)); | ni->ni_macaddr, ":", in->in_station)); | ||||
free_unr(sc->sc_unr, in->in_station); | free_unr(sc->sc_unr, in->in_station); | ||||
} | } | ||||
Show All 27 Lines | |||||
* The firmware automatically adapts the transmit speed. We report its current | * The firmware automatically adapts the transmit speed. We report its current | ||||
* value here. | * value here. | ||||
*/ | */ | ||||
static void | static void | ||||
iwi_media_status(struct ifnet *ifp, struct ifmediareq *imr) | iwi_media_status(struct ifnet *ifp, struct ifmediareq *imr) | ||||
{ | { | ||||
struct ieee80211vap *vap = ifp->if_softc; | struct ieee80211vap *vap = ifp->if_softc; | ||||
struct ieee80211com *ic = vap->iv_ic; | struct ieee80211com *ic = vap->iv_ic; | ||||
struct iwi_softc *sc = ic->ic_ifp->if_softc; | struct iwi_softc *sc = ic->ic_softc; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
/* read current transmission rate from adapter */ | /* read current transmission rate from adapter */ | ||||
ni = ieee80211_ref_node(vap->iv_bss); | ni = ieee80211_ref_node(vap->iv_bss); | ||||
ni->ni_txrate = | ni->ni_txrate = | ||||
iwi_cvtrate(CSR_READ_4(sc, IWI_CSR_CURRENT_TX_RATE)); | iwi_cvtrate(CSR_READ_4(sc, IWI_CSR_CURRENT_TX_RATE)); | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
ieee80211_media_status(ifp, imr); | ieee80211_media_status(ifp, imr); | ||||
} | } | ||||
static int | static int | ||||
iwi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) | iwi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) | ||||
{ | { | ||||
struct iwi_vap *ivp = IWI_VAP(vap); | struct iwi_vap *ivp = IWI_VAP(vap); | ||||
struct ieee80211com *ic = vap->iv_ic; | struct ieee80211com *ic = vap->iv_ic; | ||||
struct ifnet *ifp = ic->ic_ifp; | struct iwi_softc *sc = ic->ic_softc; | ||||
struct iwi_softc *sc = ifp->if_softc; | |||||
IWI_LOCK_DECL; | IWI_LOCK_DECL; | ||||
DPRINTF(("%s: %s -> %s flags 0x%x\n", __func__, | DPRINTF(("%s: %s -> %s flags 0x%x\n", __func__, | ||||
ieee80211_state_name[vap->iv_state], | ieee80211_state_name[vap->iv_state], | ||||
ieee80211_state_name[nstate], sc->flags)); | ieee80211_state_name[nstate], sc->flags)); | ||||
IEEE80211_UNLOCK(ic); | IEEE80211_UNLOCK(ic); | ||||
IWI_LOCK(sc); | IWI_LOCK(sc); | ||||
▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | for (ac = 0; ac < WME_NUM_AC; ac++) { | ||||
sc->wme[2].burst[ac] = IWI_USEC(wmep->wmep_txopLimit); | sc->wme[2].burst[ac] = IWI_USEC(wmep->wmep_txopLimit); | ||||
sc->wme[2].acm[ac] = wmep->wmep_acm; | sc->wme[2].acm[ac] = wmep->wmep_acm; | ||||
} | } | ||||
} | } | ||||
static int | static int | ||||
iwi_wme_setparams(struct iwi_softc *sc) | iwi_wme_setparams(struct iwi_softc *sc) | ||||
{ | { | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
const struct wmeParams *wmep; | const struct wmeParams *wmep; | ||||
int ac; | int ac; | ||||
for (ac = 0; ac < WME_NUM_AC; ac++) { | for (ac = 0; ac < WME_NUM_AC; ac++) { | ||||
/* set WME values for current operating mode */ | /* set WME values for current operating mode */ | ||||
wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[ac]; | wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[ac]; | ||||
sc->wme[0].aifsn[ac] = wmep->wmep_aifsn; | sc->wme[0].aifsn[ac] = wmep->wmep_aifsn; | ||||
sc->wme[0].cwmin[ac] = IWI_EXP2(wmep->wmep_logcwmin); | sc->wme[0].cwmin[ac] = IWI_EXP2(wmep->wmep_logcwmin); | ||||
Show All 17 Lines | iwi_update_wme(void *arg, int npending) | ||||
IWI_LOCK(sc); | IWI_LOCK(sc); | ||||
(void) iwi_wme_setparams(sc); | (void) iwi_wme_setparams(sc); | ||||
IWI_UNLOCK(sc); | IWI_UNLOCK(sc); | ||||
} | } | ||||
static int | static int | ||||
iwi_wme_update(struct ieee80211com *ic) | iwi_wme_update(struct ieee80211com *ic) | ||||
{ | { | ||||
struct iwi_softc *sc = ic->ic_ifp->if_softc; | struct iwi_softc *sc = ic->ic_softc; | ||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
/* | /* | ||||
* We may be called to update the WME parameters in | * We may be called to update the WME parameters in | ||||
* the adapter at various places. If we're already | * the adapter at various places. If we're already | ||||
* associated then initiate the request immediately; | * associated then initiate the request immediately; | ||||
* otherwise we assume the params will get sent down | * otherwise we assume the params will get sent down | ||||
* to the adapter as part of the work iwi_auth_and_assoc | * to the adapter as part of the work iwi_auth_and_assoc | ||||
▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | iwi_read_prom_word(struct iwi_softc *sc, uint8_t addr) | ||||
IWI_EEPROM_CTL(sc, IWI_EEPROM_C); | IWI_EEPROM_CTL(sc, IWI_EEPROM_C); | ||||
return val; | return val; | ||||
} | } | ||||
static void | static void | ||||
iwi_setcurchan(struct iwi_softc *sc, int chan) | iwi_setcurchan(struct iwi_softc *sc, int chan) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
sc->curchan = chan; | sc->curchan = chan; | ||||
ieee80211_radiotap_chan_change(ic); | ieee80211_radiotap_chan_change(ic); | ||||
} | } | ||||
static void | static void | ||||
iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, int i, | iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, int i, | ||||
struct iwi_frame *frame) | struct iwi_frame *frame) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct mbuf *mnew, *m; | struct mbuf *mnew, *m; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
int type, error, framelen; | int type, error, framelen; | ||||
int8_t rssi, nf; | int8_t rssi, nf; | ||||
IWI_LOCK_DECL; | IWI_LOCK_DECL; | ||||
framelen = le16toh(frame->len); | framelen = le16toh(frame->len); | ||||
if (framelen < IEEE80211_MIN_LEN || framelen > MCLBYTES) { | if (framelen < IEEE80211_MIN_LEN || framelen > MCLBYTES) { | ||||
Show All 19 Lines | iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, int i, | ||||
/* | /* | ||||
* Try to allocate a new mbuf for this ring element and load it before | * Try to allocate a new mbuf for this ring element and load it before | ||||
* processing the current mbuf. If the ring element cannot be loaded, | * processing the current mbuf. If the ring element cannot be loaded, | ||||
* drop the received packet and reuse the old mbuf. In the unlikely | * drop the received packet and reuse the old mbuf. In the unlikely | ||||
* case that the old mbuf can't be reloaded either, explicitly panic. | * case that the old mbuf can't be reloaded either, explicitly panic. | ||||
*/ | */ | ||||
mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); | mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); | ||||
if (mnew == NULL) { | if (mnew == NULL) { | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
return; | return; | ||||
} | } | ||||
bus_dmamap_unload(sc->rxq.data_dmat, data->map); | bus_dmamap_unload(sc->rxq.data_dmat, data->map); | ||||
error = bus_dmamap_load(sc->rxq.data_dmat, data->map, | error = bus_dmamap_load(sc->rxq.data_dmat, data->map, | ||||
mtod(mnew, void *), MCLBYTES, iwi_dma_map_addr, &data->physaddr, | mtod(mnew, void *), MCLBYTES, iwi_dma_map_addr, &data->physaddr, | ||||
0); | 0); | ||||
if (error != 0) { | if (error != 0) { | ||||
m_freem(mnew); | m_freem(mnew); | ||||
/* try to reload the old mbuf */ | /* try to reload the old mbuf */ | ||||
error = bus_dmamap_load(sc->rxq.data_dmat, data->map, | error = bus_dmamap_load(sc->rxq.data_dmat, data->map, | ||||
mtod(data->m, void *), MCLBYTES, iwi_dma_map_addr, | mtod(data->m, void *), MCLBYTES, iwi_dma_map_addr, | ||||
&data->physaddr, 0); | &data->physaddr, 0); | ||||
if (error != 0) { | if (error != 0) { | ||||
/* very unlikely that it will fail... */ | /* very unlikely that it will fail... */ | ||||
panic("%s: could not load old rx mbuf", | panic("%s: could not load old rx mbuf", | ||||
device_get_name(sc->sc_dev)); | device_get_name(sc->sc_dev)); | ||||
} | } | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
return; | return; | ||||
} | } | ||||
/* | /* | ||||
* New mbuf successfully loaded, update Rx ring and continue | * New mbuf successfully loaded, update Rx ring and continue | ||||
* processing. | * processing. | ||||
*/ | */ | ||||
m = data->m; | m = data->m; | ||||
data->m = mnew; | data->m = mnew; | ||||
CSR_WRITE_4(sc, data->reg, data->physaddr); | CSR_WRITE_4(sc, data->reg, data->physaddr); | ||||
/* finalize mbuf */ | /* finalize mbuf */ | ||||
m->m_pkthdr.rcvif = ifp; | |||||
m->m_pkthdr.len = m->m_len = sizeof (struct iwi_hdr) + | m->m_pkthdr.len = m->m_len = sizeof (struct iwi_hdr) + | ||||
sizeof (struct iwi_frame) + framelen; | sizeof (struct iwi_frame) + framelen; | ||||
m_adj(m, sizeof (struct iwi_hdr) + sizeof (struct iwi_frame)); | m_adj(m, sizeof (struct iwi_hdr) + sizeof (struct iwi_frame)); | ||||
rssi = frame->rssi_dbm; | rssi = frame->rssi_dbm; | ||||
nf = -95; | nf = -95; | ||||
if (ieee80211_radiotap_active(ic)) { | if (ieee80211_radiotap_active(ic)) { | ||||
▲ Show 20 Lines • Show All 122 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Task queue callbacks for iwi_notification_intr used to avoid LOR's. | * Task queue callbacks for iwi_notification_intr used to avoid LOR's. | ||||
*/ | */ | ||||
static void | static void | ||||
iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif) | iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif) | ||||
{ | { | ||||
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 iwi_notif_scan_channel *chan; | struct iwi_notif_scan_channel *chan; | ||||
struct iwi_notif_scan_complete *scan; | struct iwi_notif_scan_complete *scan; | ||||
struct iwi_notif_authentication *auth; | struct iwi_notif_authentication *auth; | ||||
struct iwi_notif_association *assoc; | struct iwi_notif_association *assoc; | ||||
struct iwi_notif_beacon_state *beacon; | struct iwi_notif_beacon_state *beacon; | ||||
switch (notif->type) { | switch (notif->type) { | ||||
▲ Show 20 Lines • Show All 204 Lines • ▼ Show 20 Lines | iwi_rx_intr(struct iwi_softc *sc) | ||||
/* tell the firmware what we have processed */ | /* tell the firmware what we have processed */ | ||||
hw = (hw == 0) ? IWI_RX_RING_COUNT - 1 : hw - 1; | hw = (hw == 0) ? IWI_RX_RING_COUNT - 1 : hw - 1; | ||||
CSR_WRITE_4(sc, IWI_CSR_RX_WIDX, hw); | CSR_WRITE_4(sc, IWI_CSR_RX_WIDX, hw); | ||||
} | } | ||||
static void | static void | ||||
iwi_tx_intr(struct iwi_softc *sc, struct iwi_tx_ring *txq) | iwi_tx_intr(struct iwi_softc *sc, struct iwi_tx_ring *txq) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct iwi_tx_data *data; | struct iwi_tx_data *data; | ||||
uint32_t hw; | uint32_t hw; | ||||
hw = CSR_READ_4(sc, txq->csr_ridx); | hw = CSR_READ_4(sc, txq->csr_ridx); | ||||
for (; txq->next != hw;) { | while (txq->next != hw) { | ||||
data = &txq->data[txq->next]; | data = &txq->data[txq->next]; | ||||
DPRINTFN(15, ("tx done idx=%u\n", txq->next)); | |||||
bus_dmamap_sync(txq->data_dmat, data->map, | bus_dmamap_sync(txq->data_dmat, data->map, | ||||
BUS_DMASYNC_POSTWRITE); | BUS_DMASYNC_POSTWRITE); | ||||
bus_dmamap_unload(txq->data_dmat, data->map); | bus_dmamap_unload(txq->data_dmat, data->map); | ||||
if (data->m->m_flags & M_TXCB) | ieee80211_tx_complete(data->ni, data->m, 0); | ||||
ieee80211_process_callback(data->ni, data->m, 0/*XXX*/); | |||||
m_freem(data->m); | |||||
data->m = NULL; | |||||
ieee80211_free_node(data->ni); | |||||
data->ni = NULL; | data->ni = NULL; | ||||
data->m = NULL; | |||||
DPRINTFN(15, ("tx done idx=%u\n", txq->next)); | |||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | |||||
txq->queued--; | txq->queued--; | ||||
txq->next = (txq->next + 1) % IWI_TX_RING_COUNT; | txq->next = (txq->next + 1) % IWI_TX_RING_COUNT; | ||||
} | } | ||||
sc->sc_tx_timer = 0; | sc->sc_tx_timer = 0; | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
if (sc->sc_softled) | if (sc->sc_softled) | ||||
iwi_led_event(sc, IWI_LED_TX); | iwi_led_event(sc, IWI_LED_TX); | ||||
iwi_start(sc); | |||||
iwi_start_locked(ifp); | |||||
} | } | ||||
static void | static void | ||||
iwi_fatal_error_intr(struct iwi_softc *sc) | iwi_fatal_error_intr(struct iwi_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); | ||||
device_printf(sc->sc_dev, "firmware error\n"); | device_printf(sc->sc_dev, "firmware error\n"); | ||||
if (vap != NULL) | if (vap != NULL) | ||||
ieee80211_cancel_scan(vap); | ieee80211_cancel_scan(vap); | ||||
ieee80211_runtask(ic, &sc->sc_restarttask); | ieee80211_runtask(ic, &sc->sc_restarttask); | ||||
sc->flags &= ~IWI_FLAG_BUSY; | sc->flags &= ~IWI_FLAG_BUSY; | ||||
sc->sc_busy_timer = 0; | sc->sc_busy_timer = 0; | ||||
wakeup(sc); | wakeup(sc); | ||||
} | } | ||||
static void | static void | ||||
iwi_radio_off_intr(struct iwi_softc *sc) | iwi_radio_off_intr(struct iwi_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
ieee80211_runtask(ic, &sc->sc_radiofftask); | ieee80211_runtask(&sc->sc_ic, &sc->sc_radiofftask); | ||||
} | } | ||||
static void | static void | ||||
iwi_intr(void *arg) | iwi_intr(void *arg) | ||||
{ | { | ||||
struct iwi_softc *sc = arg; | struct iwi_softc *sc = arg; | ||||
uint32_t r; | uint32_t r; | ||||
IWI_LOCK_DECL; | IWI_LOCK_DECL; | ||||
▲ Show 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | iwi_write_ibssnode(struct iwi_softc *sc, | ||||
DPRINTF(("%s mac %6D station %u\n", __func__, node.bssid, ":", entry)); | DPRINTF(("%s mac %6D station %u\n", __func__, node.bssid, ":", entry)); | ||||
CSR_WRITE_REGION_1(sc, | CSR_WRITE_REGION_1(sc, | ||||
IWI_CSR_NODE_BASE + entry * sizeof node, | IWI_CSR_NODE_BASE + entry * sizeof node, | ||||
(uint8_t *)&node, sizeof node); | (uint8_t *)&node, sizeof node); | ||||
} | } | ||||
static int | static int | ||||
iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni, | iwi_tx_start(struct iwi_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, | ||||
int ac) | int ac) | ||||
{ | { | ||||
struct iwi_softc *sc = ifp->if_softc; | |||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct ieee80211com *ic = ni->ni_ic; | struct ieee80211com *ic = ni->ni_ic; | ||||
struct iwi_node *in = (struct iwi_node *)ni; | struct iwi_node *in = (struct iwi_node *)ni; | ||||
const struct ieee80211_frame *wh; | const struct ieee80211_frame *wh; | ||||
struct ieee80211_key *k; | struct ieee80211_key *k; | ||||
const struct chanAccParams *cap; | const struct chanAccParams *cap; | ||||
struct iwi_tx_ring *txq = &sc->txq[ac]; | struct iwi_tx_ring *txq = &sc->txq[ac]; | ||||
struct iwi_tx_data *data; | struct iwi_tx_data *data; | ||||
Show All 26 Lines | iwi_tx_start(struct iwi_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, | ||||
* in a h/w table instead of a destination address. | * in a h/w table instead of a destination address. | ||||
*/ | */ | ||||
if (vap->iv_opmode == IEEE80211_M_IBSS) { | if (vap->iv_opmode == IEEE80211_M_IBSS) { | ||||
if (!ismcast) { | if (!ismcast) { | ||||
if (in->in_station == -1) { | if (in->in_station == -1) { | ||||
in->in_station = alloc_unr(sc->sc_unr); | in->in_station = alloc_unr(sc->sc_unr); | ||||
if (in->in_station == -1) { | if (in->in_station == -1) { | ||||
/* h/w table is full */ | /* h/w table is full */ | ||||
if_inc_counter(ni->ni_vap->iv_ifp, | |||||
IFCOUNTER_OERRORS, 1); | |||||
m_freem(m0); | m_freem(m0); | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
return 0; | return 0; | ||||
} | } | ||||
iwi_write_ibssnode(sc, | iwi_write_ibssnode(sc, | ||||
ni->ni_macaddr, in->in_station); | ni->ni_macaddr, in->in_station); | ||||
} | } | ||||
staid = in->in_station; | staid = in->in_station; | ||||
} else { | } else { | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 109 Lines • ▼ Show 20 Lines | iwi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, | ||||
const struct ieee80211_bpf_params *params) | const struct ieee80211_bpf_params *params) | ||||
{ | { | ||||
/* no support; just discard */ | /* no support; just discard */ | ||||
m_freem(m); | m_freem(m); | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | |||||
iwi_transmit(struct ieee80211com *ic, struct mbuf *m) | |||||
{ | |||||
struct iwi_softc *sc = ic->ic_softc; | |||||
int error; | |||||
IWI_LOCK_DECL; | |||||
IWI_LOCK(sc); | |||||
if (!sc->sc_running) { | |||||
IWI_UNLOCK(sc); | |||||
return (ENXIO); | |||||
} | |||||
error = mbufq_enqueue(&sc->sc_snd, m); | |||||
if (error) { | |||||
IWI_UNLOCK(sc); | |||||
return (error); | |||||
} | |||||
iwi_start(sc); | |||||
IWI_UNLOCK(sc); | |||||
return (0); | |||||
} | |||||
static void | static void | ||||
iwi_start_locked(struct ifnet *ifp) | iwi_start(struct iwi_softc *sc) | ||||
{ | { | ||||
struct iwi_softc *sc = ifp->if_softc; | |||||
struct mbuf *m; | struct mbuf *m; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
int ac; | int ac; | ||||
IWI_LOCK_ASSERT(sc); | IWI_LOCK_ASSERT(sc); | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { | ||||
return; | |||||
for (;;) { | |||||
IFQ_DRV_DEQUEUE(&ifp->if_snd, m); | |||||
if (m == NULL) | |||||
break; | |||||
ac = M_WME_GETAC(m); | ac = M_WME_GETAC(m); | ||||
if (sc->txq[ac].queued > IWI_TX_RING_COUNT - 8) { | if (sc->txq[ac].queued > IWI_TX_RING_COUNT - 8) { | ||||
/* there is no place left in this ring; tail drop */ | /* there is no place left in this ring; tail drop */ | ||||
/* XXX tail drop */ | /* XXX tail drop */ | ||||
IFQ_DRV_PREPEND(&ifp->if_snd, m); | mbufq_prepend(&sc->sc_snd, m); | ||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | |||||
break; | break; | ||||
} | } | ||||
ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; | ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; | ||||
if (iwi_tx_start(ifp, m, ni, ac) != 0) { | if (iwi_tx_start(sc, m, ni, ac) != 0) { | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ni->ni_vap->iv_ifp, | ||||
IFCOUNTER_OERRORS, 1); | |||||
break; | break; | ||||
} | } | ||||
sc->sc_tx_timer = 5; | sc->sc_tx_timer = 5; | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
iwi_start(struct ifnet *ifp) | |||||
{ | |||||
struct iwi_softc *sc = ifp->if_softc; | |||||
IWI_LOCK_DECL; | |||||
IWI_LOCK(sc); | |||||
iwi_start_locked(ifp); | |||||
IWI_UNLOCK(sc); | |||||
} | |||||
static void | |||||
iwi_watchdog(void *arg) | iwi_watchdog(void *arg) | ||||
{ | { | ||||
struct iwi_softc *sc = arg; | struct iwi_softc *sc = arg; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
IWI_LOCK_ASSERT(sc); | IWI_LOCK_ASSERT(sc); | ||||
if (sc->sc_tx_timer > 0) { | if (sc->sc_tx_timer > 0) { | ||||
if (--sc->sc_tx_timer == 0) { | if (--sc->sc_tx_timer == 0) { | ||||
if_printf(ifp, "device timeout\n"); | device_printf(sc->sc_dev, "device timeout\n"); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | counter_u64_add(ic->ic_oerrors, 1); | ||||
ieee80211_runtask(ic, &sc->sc_restarttask); | ieee80211_runtask(ic, &sc->sc_restarttask); | ||||
} | } | ||||
} | } | ||||
if (sc->sc_state_timer > 0) { | if (sc->sc_state_timer > 0) { | ||||
if (--sc->sc_state_timer == 0) { | if (--sc->sc_state_timer == 0) { | ||||
if_printf(ifp, "firmware stuck in state %d, resetting\n", | device_printf(sc->sc_dev, | ||||
"firmware stuck in state %d, resetting\n", | |||||
sc->fw_state); | sc->fw_state); | ||||
if (sc->fw_state == IWI_FW_SCANNING) { | if (sc->fw_state == IWI_FW_SCANNING) | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
ieee80211_cancel_scan(TAILQ_FIRST(&ic->ic_vaps)); | ieee80211_cancel_scan(TAILQ_FIRST(&ic->ic_vaps)); | ||||
} | |||||
ieee80211_runtask(ic, &sc->sc_restarttask); | ieee80211_runtask(ic, &sc->sc_restarttask); | ||||
sc->sc_state_timer = 3; | sc->sc_state_timer = 3; | ||||
} | } | ||||
} | } | ||||
if (sc->sc_busy_timer > 0) { | if (sc->sc_busy_timer > 0) { | ||||
if (--sc->sc_busy_timer == 0) { | if (--sc->sc_busy_timer == 0) { | ||||
if_printf(ifp, "firmware command timeout, resetting\n"); | device_printf(sc->sc_dev, | ||||
"firmware command timeout, resetting\n"); | |||||
ieee80211_runtask(ic, &sc->sc_restarttask); | ieee80211_runtask(ic, &sc->sc_restarttask); | ||||
} | } | ||||
} | } | ||||
callout_reset(&sc->sc_wdtimer, hz, iwi_watchdog, sc); | callout_reset(&sc->sc_wdtimer, hz, iwi_watchdog, sc); | ||||
} | } | ||||
static int | static void | ||||
iwi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | iwi_parent(struct ieee80211com *ic) | ||||
{ | { | ||||
struct iwi_softc *sc = ifp->if_softc; | struct iwi_softc *sc = ic->ic_softc; | ||||
struct ieee80211com *ic = ifp->if_l2com; | int startall = 0; | ||||
struct ifreq *ifr = (struct ifreq *) data; | |||||
int error = 0, startall = 0; | |||||
IWI_LOCK_DECL; | IWI_LOCK_DECL; | ||||
switch (cmd) { | |||||
case SIOCSIFFLAGS: | |||||
IWI_LOCK(sc); | IWI_LOCK(sc); | ||||
if (ifp->if_flags & IFF_UP) { | if (ic->ic_nrunning > 0) { | ||||
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { | if (!sc->sc_running) { | ||||
iwi_init_locked(sc); | iwi_init_locked(sc); | ||||
startall = 1; | startall = 1; | ||||
} | } | ||||
} else { | } else if (sc->sc_running) | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | |||||
iwi_stop_locked(sc); | iwi_stop_locked(sc); | ||||
} | |||||
IWI_UNLOCK(sc); | IWI_UNLOCK(sc); | ||||
if (startall) | if (startall) | ||||
ieee80211_start_all(ic); | ieee80211_start_all(ic); | ||||
break; | } | ||||
case SIOCGIFMEDIA: | |||||
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); | static int | ||||
break; | iwi_ioctl(struct ieee80211com *ic, u_long cmd, void *data) | ||||
case SIOCGIFADDR: | { | ||||
error = ether_ioctl(ifp, cmd, data); | struct ifreq *ifr = data; | ||||
break; | struct iwi_softc *sc = ic->ic_softc; | ||||
case SIOCGIWISTATS: | int error; | ||||
IWI_LOCK_DECL; | |||||
IWI_LOCK(sc); | IWI_LOCK(sc); | ||||
switch (cmd) { | |||||
case SIOCGIWISTATS: | |||||
/* XXX validate permissions/memory/etc? */ | /* XXX validate permissions/memory/etc? */ | ||||
error = copyout(&sc->sc_linkqual, ifr->ifr_data, | error = copyout(&sc->sc_linkqual, ifr->ifr_data, | ||||
sizeof(struct iwi_notif_link_quality)); | sizeof(struct iwi_notif_link_quality)); | ||||
IWI_UNLOCK(sc); | |||||
break; | break; | ||||
case SIOCZIWISTATS: | case SIOCZIWISTATS: | ||||
IWI_LOCK(sc); | |||||
memset(&sc->sc_linkqual, 0, | memset(&sc->sc_linkqual, 0, | ||||
sizeof(struct iwi_notif_link_quality)); | sizeof(struct iwi_notif_link_quality)); | ||||
IWI_UNLOCK(sc); | |||||
error = 0; | error = 0; | ||||
break; | break; | ||||
default: | default: | ||||
error = EINVAL; | error = ENOTTY; | ||||
break; | break; | ||||
} | } | ||||
return error; | IWI_UNLOCK(sc); | ||||
return (error); | |||||
} | } | ||||
static void | static void | ||||
iwi_stop_master(struct iwi_softc *sc) | iwi_stop_master(struct iwi_softc *sc) | ||||
{ | { | ||||
uint32_t tmp; | uint32_t tmp; | ||||
int ntries; | int ntries; | ||||
▲ Show 20 Lines • Show All 462 Lines • ▼ Show 20 Lines | if (error != 0) | ||||
return error; | return error; | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
iwi_config(struct iwi_softc *sc) | iwi_config(struct iwi_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct iwi_configuration config; | struct iwi_configuration config; | ||||
struct iwi_rateset rs; | struct iwi_rateset rs; | ||||
struct iwi_txpower power; | struct iwi_txpower power; | ||||
uint32_t data; | uint32_t data; | ||||
int error, i; | int error, i; | ||||
IWI_LOCK_ASSERT(sc); | IWI_LOCK_ASSERT(sc); | ||||
DPRINTF(("Setting MAC address to %6D\n", IF_LLADDR(ifp), ":")); | DPRINTF(("Setting MAC address to %6D\n", ic->ic_macaddr, ":")); | ||||
error = iwi_cmd(sc, IWI_CMD_SET_MAC_ADDRESS, IF_LLADDR(ifp), | error = iwi_cmd(sc, IWI_CMD_SET_MAC_ADDRESS, ic->ic_macaddr, | ||||
IEEE80211_ADDR_LEN); | IEEE80211_ADDR_LEN); | ||||
if (error != 0) | if (error != 0) | ||||
return error; | return error; | ||||
memset(&config, 0, sizeof config); | memset(&config, 0, sizeof config); | ||||
config.bluetooth_coexistence = sc->bluetooth; | config.bluetooth_coexistence = sc->bluetooth; | ||||
config.silence_threshold = 0x1e; | config.silence_threshold = 0x1e; | ||||
config.antenna = sc->antenna; | config.antenna = sc->antenna; | ||||
▲ Show 20 Lines • Show All 103 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Start a scan on the current channel or all channels. | * Start a scan on the current channel or all channels. | ||||
*/ | */ | ||||
static int | static int | ||||
iwi_scanchan(struct iwi_softc *sc, unsigned long maxdwell, int allchan) | iwi_scanchan(struct iwi_softc *sc, unsigned long maxdwell, int allchan) | ||||
{ | { | ||||
struct ieee80211com *ic; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211_channel *chan; | struct ieee80211_channel *chan; | ||||
struct ieee80211_scan_state *ss; | struct ieee80211_scan_state *ss; | ||||
struct iwi_scan_ext scan; | struct iwi_scan_ext scan; | ||||
int error = 0; | int error = 0; | ||||
IWI_LOCK_ASSERT(sc); | IWI_LOCK_ASSERT(sc); | ||||
if (sc->fw_state == IWI_FW_SCANNING) { | if (sc->fw_state == IWI_FW_SCANNING) { | ||||
/* | /* | ||||
* This should not happen as we only trigger scan_next after | * This should not happen as we only trigger scan_next after | ||||
* completion | * completion | ||||
*/ | */ | ||||
DPRINTF(("%s: called too early - still scanning\n", __func__)); | DPRINTF(("%s: called too early - still scanning\n", __func__)); | ||||
return (EBUSY); | return (EBUSY); | ||||
} | } | ||||
IWI_STATE_BEGIN(sc, IWI_FW_SCANNING); | IWI_STATE_BEGIN(sc, IWI_FW_SCANNING); | ||||
ic = sc->sc_ifp->if_l2com; | |||||
ss = ic->ic_scan; | ss = ic->ic_scan; | ||||
memset(&scan, 0, sizeof scan); | memset(&scan, 0, sizeof scan); | ||||
scan.full_scan_index = htole32(++sc->sc_scangen); | scan.full_scan_index = htole32(++sc->sc_scangen); | ||||
scan.dwell_time[IWI_SCAN_TYPE_PASSIVE] = htole16(maxdwell); | scan.dwell_time[IWI_SCAN_TYPE_PASSIVE] = htole16(maxdwell); | ||||
if (ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) { | if (ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) { | ||||
/* | /* | ||||
* Use very short dwell times for when we send probe request | * Use very short dwell times for when we send probe request | ||||
▲ Show 20 Lines • Show All 370 Lines • ▼ Show 20 Lines | |||||
error: | error: | ||||
iwi_release_fw_dma(sc); | iwi_release_fw_dma(sc); | ||||
return 1; | return 1; | ||||
} | } | ||||
static void | static void | ||||
iwi_init_locked(struct iwi_softc *sc) | iwi_init_locked(struct iwi_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct iwi_rx_data *data; | struct iwi_rx_data *data; | ||||
int i; | int i; | ||||
IWI_LOCK_ASSERT(sc); | IWI_LOCK_ASSERT(sc); | ||||
if (sc->fw_state == IWI_FW_LOADING) { | if (sc->fw_state == IWI_FW_LOADING) { | ||||
device_printf(sc->sc_dev, "%s: already loading\n", __func__); | device_printf(sc->sc_dev, "%s: already loading\n", __func__); | ||||
return; /* XXX: condvar? */ | return; /* XXX: condvar? */ | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | iwi_init_locked(struct iwi_softc *sc) | ||||
IWI_STATE_END(sc, IWI_FW_LOADING); | IWI_STATE_END(sc, IWI_FW_LOADING); | ||||
if (iwi_config(sc) != 0) { | if (iwi_config(sc) != 0) { | ||||
device_printf(sc->sc_dev, "unable to enable adapter\n"); | device_printf(sc->sc_dev, "unable to enable adapter\n"); | ||||
goto fail2; | goto fail2; | ||||
} | } | ||||
callout_reset(&sc->sc_wdtimer, hz, iwi_watchdog, sc); | callout_reset(&sc->sc_wdtimer, hz, iwi_watchdog, sc); | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | sc->sc_running = 1; | ||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | |||||
return; | return; | ||||
fail: | fail: | ||||
IWI_STATE_END(sc, IWI_FW_LOADING); | IWI_STATE_END(sc, IWI_FW_LOADING); | ||||
fail2: | fail2: | ||||
iwi_stop_locked(sc); | iwi_stop_locked(sc); | ||||
} | } | ||||
static void | static void | ||||
iwi_init(void *priv) | iwi_init(void *priv) | ||||
{ | { | ||||
struct iwi_softc *sc = priv; | struct iwi_softc *sc = priv; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
IWI_LOCK_DECL; | IWI_LOCK_DECL; | ||||
IWI_LOCK(sc); | IWI_LOCK(sc); | ||||
iwi_init_locked(sc); | iwi_init_locked(sc); | ||||
IWI_UNLOCK(sc); | IWI_UNLOCK(sc); | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (sc->sc_running) | ||||
ieee80211_start_all(ic); | ieee80211_start_all(ic); | ||||
} | } | ||||
static void | static void | ||||
iwi_stop_locked(void *priv) | iwi_stop_locked(void *priv) | ||||
{ | { | ||||
struct iwi_softc *sc = priv; | struct iwi_softc *sc = priv; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
IWI_LOCK_ASSERT(sc); | IWI_LOCK_ASSERT(sc); | ||||
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); | sc->sc_running = 0; | ||||
if (sc->sc_softled) { | if (sc->sc_softled) { | ||||
callout_stop(&sc->sc_ledtimer); | callout_stop(&sc->sc_ledtimer); | ||||
sc->sc_blinking = 0; | sc->sc_blinking = 0; | ||||
} | } | ||||
callout_stop(&sc->sc_wdtimer); | callout_stop(&sc->sc_wdtimer); | ||||
callout_stop(&sc->sc_rftimer); | callout_stop(&sc->sc_rftimer); | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
return (CSR_READ_4(sc, IWI_CSR_IO) & IWI_IO_RADIO_ENABLED) == 0; | return (CSR_READ_4(sc, IWI_CSR_IO) & IWI_IO_RADIO_ENABLED) == 0; | ||||
} | } | ||||
static void | static void | ||||
iwi_radio_on(void *arg, int pending) | iwi_radio_on(void *arg, int pending) | ||||
{ | { | ||||
struct iwi_softc *sc = arg; | struct iwi_softc *sc = arg; | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
device_printf(sc->sc_dev, "radio turned on\n"); | device_printf(sc->sc_dev, "radio turned on\n"); | ||||
iwi_init(sc); | iwi_init(sc); | ||||
ieee80211_notify_radio(ic, 1); | ieee80211_notify_radio(ic, 1); | ||||
} | } | ||||
static void | static void | ||||
iwi_rfkill_poll(void *arg) | iwi_rfkill_poll(void *arg) | ||||
{ | { | ||||
struct iwi_softc *sc = arg; | struct iwi_softc *sc = arg; | ||||
IWI_LOCK_ASSERT(sc); | IWI_LOCK_ASSERT(sc); | ||||
/* | /* | ||||
* Check for a change in rfkill state. We get an | * Check for a change in rfkill state. We get an | ||||
* interrupt when a radio is disabled but not when | * interrupt when a radio is disabled but not when | ||||
* it is enabled so we must poll for the latter. | * it is enabled so we must poll for the latter. | ||||
*/ | */ | ||||
if (!iwi_getrfkill(sc)) { | if (!iwi_getrfkill(sc)) { | ||||
struct ifnet *ifp = sc->sc_ifp; | ieee80211_runtask(&sc->sc_ic, &sc->sc_radiontask); | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
ieee80211_runtask(ic, &sc->sc_radiontask); | |||||
return; | return; | ||||
} | } | ||||
callout_reset(&sc->sc_rftimer, 2*hz, iwi_rfkill_poll, sc); | callout_reset(&sc->sc_rftimer, 2*hz, iwi_rfkill_poll, sc); | ||||
} | } | ||||
static void | static void | ||||
iwi_radio_off(void *arg, int pending) | iwi_radio_off(void *arg, int pending) | ||||
{ | { | ||||
struct iwi_softc *sc = arg; | struct iwi_softc *sc = arg; | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
IWI_LOCK_DECL; | IWI_LOCK_DECL; | ||||
device_printf(sc->sc_dev, "radio turned off\n"); | device_printf(sc->sc_dev, "radio turned off\n"); | ||||
ieee80211_notify_radio(ic, 0); | ieee80211_notify_radio(ic, 0); | ||||
IWI_LOCK(sc); | IWI_LOCK(sc); | ||||
iwi_stop_locked(sc); | iwi_stop_locked(sc); | ||||
▲ Show 20 Lines • Show All 247 Lines • ▼ Show 20 Lines | |||||
iwi_scan_start(struct ieee80211com *ic) | iwi_scan_start(struct ieee80211com *ic) | ||||
{ | { | ||||
/* ignore */ | /* ignore */ | ||||
} | } | ||||
static void | static void | ||||
iwi_set_channel(struct ieee80211com *ic) | iwi_set_channel(struct ieee80211com *ic) | ||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | struct iwi_softc *sc = ic->ic_softc; | ||||
struct iwi_softc *sc = ifp->if_softc; | |||||
if (sc->fw_state == IWI_FW_IDLE) | if (sc->fw_state == IWI_FW_IDLE) | ||||
iwi_setcurchan(sc, ic->ic_curchan->ic_ieee); | iwi_setcurchan(sc, ic->ic_curchan->ic_ieee); | ||||
} | } | ||||
static void | static void | ||||
iwi_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) | iwi_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) | ||||
{ | { | ||||
struct ieee80211vap *vap = ss->ss_vap; | struct ieee80211vap *vap = ss->ss_vap; | ||||
struct ifnet *ifp = vap->iv_ic->ic_ifp; | struct iwi_softc *sc = vap->iv_ic->ic_softc; | ||||
struct iwi_softc *sc = ifp->if_softc; | |||||
IWI_LOCK_DECL; | IWI_LOCK_DECL; | ||||
IWI_LOCK(sc); | IWI_LOCK(sc); | ||||
if (iwi_scanchan(sc, maxdwell, 0)) | if (iwi_scanchan(sc, maxdwell, 0)) | ||||
ieee80211_cancel_scan(vap); | ieee80211_cancel_scan(vap); | ||||
IWI_UNLOCK(sc); | IWI_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
iwi_scan_mindwell(struct ieee80211_scan_state *ss) | iwi_scan_mindwell(struct ieee80211_scan_state *ss) | ||||
{ | { | ||||
/* 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 | ||||
iwi_scan_end(struct ieee80211com *ic) | iwi_scan_end(struct ieee80211com *ic) | ||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | struct iwi_softc *sc = ic->ic_softc; | ||||
struct iwi_softc *sc = ifp->if_softc; | |||||
IWI_LOCK_DECL; | IWI_LOCK_DECL; | ||||
IWI_LOCK(sc); | IWI_LOCK(sc); | ||||
sc->flags &= ~IWI_FLAG_CHANNEL_SCAN; | sc->flags &= ~IWI_FLAG_CHANNEL_SCAN; | ||||
/* NB: make sure we're still scanning */ | /* NB: make sure we're still scanning */ | ||||
if (sc->fw_state == IWI_FW_SCANNING) | if (sc->fw_state == IWI_FW_SCANNING) | ||||
iwi_cmd(sc, IWI_CMD_ABORT_SCAN, NULL, 0); | iwi_cmd(sc, IWI_CMD_ABORT_SCAN, NULL, 0); | ||||
IWI_UNLOCK(sc); | IWI_UNLOCK(sc); | ||||
} | } |