diff options
| author | Adrian Chadd <adrian@FreeBSD.org> | 2015-08-08 01:10:17 +0000 |
|---|---|---|
| committer | Adrian Chadd <adrian@FreeBSD.org> | 2015-08-08 01:10:17 +0000 |
| commit | ba2c1fbc03f312b978f76f7b6c67eec6afa80bf8 (patch) | |
| tree | 5973a9059f73ed5abf84d6d98e44f1953e764064 /sys/dev/wpi | |
| parent | 721b581722c3a383f02036d009db4473590e3f88 (diff) | |
Notes
Diffstat (limited to 'sys/dev/wpi')
| -rw-r--r-- | sys/dev/wpi/if_wpi.c | 481 | ||||
| -rw-r--r-- | sys/dev/wpi/if_wpivar.h | 7 |
2 files changed, 256 insertions, 232 deletions
diff --git a/sys/dev/wpi/if_wpi.c b/sys/dev/wpi/if_wpi.c index 01ce3e467695..34406059b437 100644 --- a/sys/dev/wpi/if_wpi.c +++ b/sys/dev/wpi/if_wpi.c @@ -205,12 +205,12 @@ static int wpi_tx_data_raw(struct wpi_softc *, struct mbuf *, const struct ieee80211_bpf_params *); static int wpi_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); -static int wpi_transmit(struct ieee80211com *, struct mbuf *); -static void wpi_start(void *, int); +static void wpi_start(struct ifnet *); +static void wpi_start_task(void *, int); static void wpi_watchdog_rfkill(void *); static void wpi_scan_timeout(void *); static void wpi_tx_timeout(void *); -static void wpi_parent(struct ieee80211com *); +static int wpi_ioctl(struct ifnet *, u_long, caddr_t); static int wpi_cmd(struct wpi_softc *, int, const void *, size_t, int); static int wpi_mrr_setup(struct wpi_softc *); static int wpi_add_node(struct wpi_softc *, struct ieee80211_node *); @@ -272,7 +272,7 @@ static int wpi_hw_init(struct wpi_softc *); static void wpi_hw_stop(struct wpi_softc *); static void wpi_radio_on(void *, int); static void wpi_radio_off(void *, int); -static int wpi_init(struct wpi_softc *); +static void wpi_init(void *); static void wpi_stop_locked(struct wpi_softc *); static void wpi_stop(struct wpi_softc *); static void wpi_scan_start(struct ieee80211com *); @@ -329,11 +329,13 @@ wpi_attach(device_t dev) { struct wpi_softc *sc = (struct wpi_softc *)device_get_softc(dev); struct ieee80211com *ic; + struct ifnet *ifp; int i, error, rid; #ifdef WPI_DEBUG int supportsa = 1; const struct wpi_ident *ident; #endif + uint8_t macaddr[IEEE80211_ADDR_LEN]; sc->sc_dev = dev; @@ -443,7 +445,14 @@ wpi_attach(device_t dev) /* Clear pending interrupts. */ WPI_WRITE(sc, WPI_INT, 0xffffffff); - ic = &sc->sc_ic; + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + 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_name = device_get_nameunit(dev); ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ @@ -472,7 +481,7 @@ wpi_attach(device_t dev) * Read in the eeprom and also setup the channels for * net80211. We don't set the rates as net80211 does this for us */ - if ((error = wpi_read_eeprom(sc, ic->ic_macaddr)) != 0) { + if ((error = wpi_read_eeprom(sc, macaddr)) != 0) { device_printf(dev, "could not read EEPROM, error %d\n", error); goto fail; @@ -494,12 +503,20 @@ wpi_attach(device_t dev) } #endif - ieee80211_ifattach(ic); + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_softc = sc; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = wpi_init; + ifp->if_ioctl = wpi_ioctl; + ifp->if_start = wpi_start; + IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); + ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; + IFQ_SET_READY(&ifp->if_snd); + + ieee80211_ifattach(ic, macaddr); ic->ic_vap_create = wpi_vap_create; ic->ic_vap_delete = wpi_vap_delete; - ic->ic_parent = wpi_parent; ic->ic_raw_xmit = wpi_raw_xmit; - ic->ic_transmit = wpi_transmit; ic->ic_node_alloc = wpi_node_alloc; sc->sc_node_free = ic->ic_node_free; ic->ic_node_free = wpi_node_free; @@ -526,7 +543,7 @@ wpi_attach(device_t dev) TASK_INIT(&sc->sc_reinittask, 0, wpi_hw_reset, sc); TASK_INIT(&sc->sc_radiooff_task, 0, wpi_radio_off, sc); TASK_INIT(&sc->sc_radioon_task, 0, wpi_radio_on, sc); - TASK_INIT(&sc->sc_start_task, 0, wpi_start, sc); + TASK_INIT(&sc->sc_start_task, 0, wpi_start_task, sc); sc->sc_tq = taskqueue_create("wpi_taskq", M_WAITOK, taskqueue_thread_enqueue, &sc->sc_tq); @@ -571,13 +588,14 @@ fail: wpi_detach(dev); static void wpi_radiotap_attach(struct wpi_softc *sc) { - struct wpi_rx_radiotap_header *rxtap = &sc->sc_rxtap; - struct wpi_tx_radiotap_header *txtap = &sc->sc_txtap; - + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); - ieee80211_radiotap_attach(&sc->sc_ic, - &txtap->wt_ihdr, sizeof(*txtap), WPI_TX_RADIOTAP_PRESENT, - &rxtap->wr_ihdr, sizeof(*rxtap), WPI_RX_RADIOTAP_PRESENT); + ieee80211_radiotap_attach(ic, + &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), + WPI_TX_RADIOTAP_PRESENT, + &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), + WPI_RX_RADIOTAP_PRESENT); DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); } @@ -628,9 +646,12 @@ wpi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ return NULL; - wvp = malloc(sizeof(struct wpi_vap), M_80211_VAP, M_WAITOK | M_ZERO); + wvp = (struct wpi_vap *) malloc(sizeof(struct wpi_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (wvp == NULL) + return NULL; vap = &wvp->wv_vap; - ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); + ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); if (opmode == IEEE80211_M_IBSS || opmode == IEEE80211_M_HOSTAP) { WPI_VAP_LOCK_INIT(wvp); @@ -650,7 +671,7 @@ wpi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, ieee80211_ratectl_init(vap); /* Complete setup. */ ieee80211_vap_attach(vap, ieee80211_media_change, - ieee80211_media_status, mac); + ieee80211_media_status); ic->ic_opmode = opmode; return vap; } @@ -679,21 +700,22 @@ static int wpi_detach(device_t dev) { struct wpi_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic; int qid; DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); - if (ic->ic_vap_create == wpi_vap_create) { + if (ifp != NULL) { + ic = ifp->if_l2com; + ieee80211_draintask(ic, &sc->sc_radioon_task); ieee80211_draintask(ic, &sc->sc_start_task); wpi_stop(sc); - if (sc->sc_tq != NULL) { - taskqueue_drain_all(sc->sc_tq); - taskqueue_free(sc->sc_tq); - } + taskqueue_drain_all(sc->sc_tq); + taskqueue_free(sc->sc_tq); callout_drain(&sc->watchdog_rfkill); callout_drain(&sc->tx_timeout); @@ -726,6 +748,9 @@ wpi_detach(device_t dev) bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->mem), sc->mem); + if (ifp != NULL) + if_free(ifp); + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); WPI_TXQ_STATE_LOCK_DESTROY(sc); WPI_TXQ_LOCK_DESTROY(sc); @@ -749,7 +774,7 @@ static int wpi_suspend(device_t dev) { struct wpi_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; ieee80211_suspend_all(ic); return 0; @@ -759,7 +784,7 @@ static int wpi_resume(device_t dev) { struct wpi_softc *sc = device_get_softc(dev); - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; /* Clear device-specific "PCI retry timeout" register (41h). */ pci_write_config(dev, 0x41, 0, 1); @@ -1166,7 +1191,6 @@ wpi_alloc_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring, int qid) ring->queued = 0; ring->cur = 0; ring->update = 0; - mbufq_init(&ring->snd, ifqmaxlen); DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); @@ -1294,7 +1318,6 @@ wpi_reset_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) memset(ring->desc, 0, ring->desc_dma.size); bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); - mbufq_drain(&ring->snd); sc->qfullmsk &= ~(1 << ring->qid); ring->queued = 0; ring->cur = 0; @@ -1425,7 +1448,8 @@ wpi_eeprom_channel_flags(struct wpi_eeprom_chan *channel) static void wpi_read_eeprom_band(struct wpi_softc *sc, int n) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct wpi_eeprom_chan *channels = sc->eeprom_channels[n]; const struct wpi_chan_band *band = &wpi_bands[n]; struct ieee80211_channel *c; @@ -1482,7 +1506,8 @@ wpi_read_eeprom_band(struct wpi_softc *sc, int n) static int wpi_read_eeprom_channels(struct wpi_softc *sc, int n) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; const struct wpi_chan_band *band = &wpi_bands[n]; int error; @@ -1524,7 +1549,8 @@ static int wpi_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *rd, int nchan, struct ieee80211_channel chans[]) { - struct wpi_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct wpi_softc *sc = ifp->if_softc; int i; for (i = 0; i < nchan; i++) { @@ -1533,7 +1559,8 @@ wpi_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *rd, channel = wpi_find_eeprom_channel(sc, c); if (channel == NULL) { - ic_printf(ic, "%s: invalid channel %u freq %u/0x%x\n", + if_printf(ic->ic_ifp, + "%s: invalid channel %u freq %u/0x%x\n", __func__, c->ic_ieee, c->ic_freq, c->ic_flags); return EINVAL; } @@ -1645,7 +1672,8 @@ wpi_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) static void wpi_node_free(struct ieee80211_node *ni) { - struct wpi_softc *sc = ni->ni_ic->ic_softc; + struct ieee80211com *ic = ni->ni_ic; + struct wpi_softc *sc = ic->ic_ifp->if_softc; struct wpi_node *wn = WPI_NODE(ni); if (wn->id != WPI_ID_UNDEFINED) { @@ -1672,7 +1700,7 @@ wpi_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, int rssi, int nf) { struct ieee80211vap *vap = ni->ni_vap; - struct wpi_softc *sc = vap->iv_ic->ic_softc; + struct wpi_softc *sc = vap->iv_ic->ic_ifp->if_softc; struct wpi_vap *wvp = WPI_VAP(vap); uint64_t ni_tstamp, rx_tstamp; @@ -1716,7 +1744,7 @@ wpi_restore_node(void *arg, struct ieee80211_node *ni) static void wpi_restore_node_table(struct wpi_softc *sc, struct wpi_vap *wvp) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; /* Set group keys once. */ WPI_NT_LOCK(sc); @@ -1735,20 +1763,12 @@ wpi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct wpi_vap *wvp = WPI_VAP(vap); struct ieee80211com *ic = vap->iv_ic; - struct wpi_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct wpi_softc *sc = ifp->if_softc; int error = 0; DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); - WPI_TXQ_LOCK(sc); - if (nstate > IEEE80211_S_INIT && sc->sc_running == 0) { - DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); - WPI_TXQ_UNLOCK(sc); - - return ENXIO; - } - WPI_TXQ_UNLOCK(sc); - DPRINTF(sc, WPI_DEBUG_STATE, "%s: %s -> %s\n", __func__, ieee80211_state_name[vap->iv_state], ieee80211_state_name[nstate]); @@ -1917,7 +1937,8 @@ static void wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, struct wpi_rx_data *data) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct wpi_rx_ring *ring = &sc->rxq; struct wpi_rx_stat *stat; struct wpi_rx_head *head; @@ -1998,6 +2019,7 @@ wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, BUS_DMASYNC_PREWRITE); /* Finalize mbuf. */ + m->m_pkthdr.rcvif = ifp; m->m_data = (caddr_t)(head + 1); m->m_pkthdr.len = m->m_len = len; @@ -2051,7 +2073,7 @@ wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, fail2: m_freem(m); -fail1: counter_u64_add(ic->ic_ierrors, 1); +fail1: if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); } static void @@ -2064,6 +2086,7 @@ wpi_rx_statistics(struct wpi_softc *sc, struct wpi_rx_desc *desc, static void wpi_tx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc) { + struct ifnet *ifp = sc->sc_ifp; struct wpi_tx_ring *ring = &sc->txq[desc->qid & 0x3]; struct wpi_tx_data *data = &ring->data[desc->idx]; struct wpi_tx_stat *stat = (struct wpi_tx_stat *)(desc + 1); @@ -2096,11 +2119,14 @@ wpi_tx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc) * Update rate control statistics for the node. */ if (status & WPI_TX_STATUS_FAIL) { + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); - } else + } else { + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); + } ieee80211_tx_complete(ni, m, (status & WPI_TX_STATUS_FAIL) != 0); @@ -2109,10 +2135,17 @@ wpi_tx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc) if (ring->queued > 0) { callout_reset(&sc->tx_timeout, 5*hz, wpi_tx_timeout, sc); - if ((sc->qfullmsk & (1 << ring->qid)) != 0 && - ring->queued < WPI_TX_RING_LOMARK) { + if (sc->qfullmsk != 0 && + ring->queued < WPI_TX_RING_LOMARK) { sc->qfullmsk &= ~(1 << ring->qid); - ieee80211_runtask(ic, &sc->sc_start_task); + IF_LOCK(&ifp->if_snd); + if (sc->qfullmsk == 0 && + (ifp->if_drv_flags & IFF_DRV_OACTIVE)) { + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + IF_UNLOCK(&ifp->if_snd); + ieee80211_runtask(ic, &sc->sc_start_task); + } else + IF_UNLOCK(&ifp->if_snd); } } else callout_stop(&sc->tx_timeout); @@ -2170,7 +2203,8 @@ wpi_cmd_done(struct wpi_softc *sc, struct wpi_rx_desc *desc) static void wpi_notif_intr(struct wpi_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); uint32_t hw; @@ -2205,7 +2239,7 @@ wpi_notif_intr(struct wpi_softc *sc) /* An 802.11 frame has been received. */ wpi_rx_done(sc, desc, data); - if (sc->sc_running == 0) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { /* wpi_stop() was called. */ return; } @@ -2294,7 +2328,6 @@ wpi_notif_intr(struct wpi_softc *sc) device_printf(sc->sc_dev, "microcontroller initialization failed\n"); wpi_stop_locked(sc); - return; } /* Save the address of the error log in SRAM. */ sc->errptr = le32toh(uc->errptr); @@ -2525,6 +2558,7 @@ static void wpi_intr(void *arg) { struct wpi_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; uint32_t r1, r2; WPI_LOCK(sc); @@ -2574,7 +2608,7 @@ wpi_intr(void *arg) done: /* Re-enable interrupts. */ - if (sc->sc_running) + if (ifp->if_flags & IFF_UP) WPI_WRITE(sc, WPI_INT_MASK, WPI_INT_MASK_DEF); end: WPI_UNLOCK(sc); @@ -2583,6 +2617,7 @@ end: WPI_UNLOCK(sc); static int wpi_cmd2(struct wpi_softc *sc, struct wpi_buf *buf) { + struct ifnet *ifp = sc->sc_ifp; struct ieee80211_frame *wh; struct wpi_tx_cmd *cmd; struct wpi_tx_data *data; @@ -2598,7 +2633,7 @@ wpi_cmd2(struct wpi_softc *sc, struct wpi_buf *buf) DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); - if (sc->sc_running == 0) { + if (sc->txq_active == 0) { /* wpi_stop() was called */ error = ENETDOWN; goto fail; @@ -2695,8 +2730,14 @@ wpi_cmd2(struct wpi_softc *sc, struct wpi_buf *buf) if (ring->qid < WPI_CMD_QUEUE_NUM) { /* Mark TX ring as full if we reach a certain threshold. */ WPI_TXQ_STATE_LOCK(sc); - if (++ring->queued > WPI_TX_RING_HIMARK) + if (++ring->queued > WPI_TX_RING_HIMARK) { sc->qfullmsk |= 1 << ring->qid; + + IF_LOCK(&ifp->if_snd); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + IF_UNLOCK(&ifp->if_snd); + } + callout_reset(&sc->tx_timeout, 5*hz, wpi_tx_timeout, sc); WPI_TXQ_STATE_UNLOCK(sc); } @@ -2990,47 +3031,24 @@ wpi_tx_data_raw(struct wpi_softc *sc, struct mbuf *m, return wpi_cmd2(sc, &tx_data); } -static __inline int -wpi_tx_ring_is_full(struct wpi_softc *sc, int ac) -{ - struct wpi_tx_ring *ring = &sc->txq[ac]; - int retval; - - WPI_TXQ_STATE_LOCK(sc); - retval = (ring->queued > WPI_TX_RING_HIMARK); - WPI_TXQ_STATE_UNLOCK(sc); - - return retval; -} - -static __inline void -wpi_handle_tx_failure(struct ieee80211_node *ni) -{ - /* NB: m is reclaimed on tx failure */ - if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); - ieee80211_free_node(ni); -} - static int wpi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; - struct wpi_softc *sc = ic->ic_softc; - int ac, error = 0; + struct ifnet *ifp = ic->ic_ifp; + struct wpi_softc *sc = ifp->if_softc; + int error = 0; DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); - ac = M_WME_GETAC(m); - - WPI_TX_LOCK(sc); - - if (sc->sc_running == 0 || wpi_tx_ring_is_full(sc, ac)) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + ieee80211_free_node(ni); m_freem(m); - error = sc->sc_running ? ENOBUFS : ENETDOWN; - goto unlock; + return ENETDOWN; } + WPI_TX_LOCK(sc); if (params == NULL) { /* * Legacy path; interpret frame contents to decide @@ -3044,11 +3062,13 @@ wpi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, */ error = wpi_tx_data_raw(sc, m, ni, params); } - -unlock: WPI_TX_UNLOCK(sc); + WPI_TX_UNLOCK(sc); if (error != 0) { - wpi_handle_tx_failure(ni); + /* NB: m is reclaimed on tx failure */ + ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); return error; @@ -3059,88 +3079,57 @@ unlock: WPI_TX_UNLOCK(sc); return 0; } -static int -wpi_transmit(struct ieee80211com *ic, struct mbuf *m) +/** + * Process data waiting to be sent on the IFNET output queue + */ +static void +wpi_start(struct ifnet *ifp) { - struct wpi_softc *sc = ic->ic_softc; + struct wpi_softc *sc = ifp->if_softc; struct ieee80211_node *ni; - struct mbufq *sndq; - int ac, error; + struct mbuf *m; WPI_TX_LOCK(sc); DPRINTF(sc, WPI_DEBUG_XMIT, "%s: called\n", __func__); - /* Check if interface is up & running. */ - if (sc->sc_running == 0) { - error = ENXIO; - goto unlock; - } - - /* Check for available space. */ - ac = M_WME_GETAC(m); - sndq = &sc->txq[ac].snd; - if (wpi_tx_ring_is_full(sc, ac) || mbufq_len(sndq) != 0) { - /* wpi_tx_done() will dequeue it. */ - error = mbufq_enqueue(sndq, m); - goto unlock; - } + for (;;) { + IF_LOCK(&ifp->if_snd); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || + (ifp->if_drv_flags & IFF_DRV_OACTIVE)) { + IF_UNLOCK(&ifp->if_snd); + break; + } + IF_UNLOCK(&ifp->if_snd); - error = 0; - ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; - if (wpi_tx_data(sc, m, ni) != 0) { - wpi_handle_tx_failure(ni); + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; + ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; + if (wpi_tx_data(sc, m, ni) != 0) { + ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + } } DPRINTF(sc, WPI_DEBUG_XMIT, "%s: done\n", __func__); - -unlock: WPI_TX_UNLOCK(sc); - - return (error); + WPI_TX_UNLOCK(sc); } -/** - * Process data waiting to be sent on the output queue - */ static void -wpi_start(void *arg0, int pending) +wpi_start_task(void *arg0, int pending) { struct wpi_softc *sc = arg0; - struct ieee80211_node *ni; - struct mbuf *m; - uint8_t i; - - WPI_TX_LOCK(sc); - if (sc->sc_running == 0) - goto unlock; + struct ifnet *ifp = sc->sc_ifp; - DPRINTF(sc, WPI_DEBUG_XMIT, "%s: called\n", __func__); - - for (i = 0; i < WPI_CMD_QUEUE_NUM; i++) { - struct mbufq *sndq = &sc->txq[i].snd; - - for (;;) { - if (wpi_tx_ring_is_full(sc, i)) - break; - - if ((m = mbufq_dequeue(sndq)) == NULL) - break; - - ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; - if (wpi_tx_data(sc, m, ni) != 0) { - wpi_handle_tx_failure(ni); - } - } - } - - DPRINTF(sc, WPI_DEBUG_XMIT, "%s: done\n", __func__); -unlock: WPI_TX_UNLOCK(sc); + wpi_start(ifp); } static void wpi_watchdog_rfkill(void *arg) { struct wpi_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; DPRINTF(sc, WPI_DEBUG_WATCHDOG, "RFkill Watchdog: tick\n"); @@ -3157,9 +3146,9 @@ static void wpi_scan_timeout(void *arg) { struct wpi_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; - ic_printf(ic, "scan timeout\n"); + if_printf(ifp, "scan timeout\n"); taskqueue_enqueue(sc->sc_tq, &sc->sc_reinittask); } @@ -3167,28 +3156,44 @@ static void wpi_tx_timeout(void *arg) { struct wpi_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; - ic_printf(ic, "device timeout\n"); + if_printf(ifp, "device timeout\n"); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); taskqueue_enqueue(sc->sc_tq, &sc->sc_reinittask); } -static void -wpi_parent(struct ieee80211com *ic) +static int +wpi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct wpi_softc *sc = ic->ic_softc; + struct wpi_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ifreq *ifr = (struct ifreq *) data; + int error = 0; - if (ic->ic_nrunning > 0) { - if (wpi_init(sc) == 0) { - ieee80211_notify_radio(ic, 1); - ieee80211_start_all(ic); - } else { - ieee80211_notify_radio(ic, 0); - ieee80211_stop(vap); - } - } else - wpi_stop(sc); + switch (cmd) { + case SIOCGIFADDR: + error = ether_ioctl(ifp, cmd, data); + break; + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + wpi_init(sc); + + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 && + vap != NULL) + ieee80211_stop(vap); + } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + wpi_stop(sc); + break; + case SIOCGIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); + break; + default: + error = EINVAL; + break; + } + return error; } /* @@ -3210,13 +3215,9 @@ wpi_cmd(struct wpi_softc *sc, int code, const void *buf, size_t size, DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); - if (sc->sc_running == 0) { + if (sc->txq_active == 0) { /* wpi_stop() was called */ - if (code == WPI_CMD_SCAN) - error = ENETDOWN; - else - error = 0; - + error = 0; goto fail; } @@ -3282,7 +3283,10 @@ wpi_cmd(struct wpi_softc *sc, int code, const void *buf, size_t size, WPI_TXQ_UNLOCK(sc); - return async ? 0 : mtx_sleep(cmd, &sc->sc_mtx, PCATCH, "wpicmd", hz); + if (async) + return 0; + + return mtx_sleep(cmd, &sc->sc_mtx, PCATCH, "wpicmd", hz); fail: DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); @@ -3297,7 +3301,8 @@ fail: DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); static int wpi_mrr_setup(struct wpi_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct wpi_mrr_setup mrr; int i, error; @@ -3394,13 +3399,14 @@ wpi_add_node(struct wpi_softc *sc, struct ieee80211_node *ni) static int wpi_add_broadcast_node(struct wpi_softc *sc, int async) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct wpi_node_info node; DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); memset(&node, 0, sizeof node); - IEEE80211_ADDR_COPY(node.macaddr, ieee80211broadcastaddr); + IEEE80211_ADDR_COPY(node.macaddr, ifp->if_broadcastaddr); node.id = WPI_ID_BROADCAST; node.plcp = (ic->ic_curmode == IEEE80211_MODE_11A) ? wpi_ridx_to_plcp[WPI_RIDX_OFDM6] : wpi_ridx_to_plcp[WPI_RIDX_CCK1]; @@ -3486,7 +3492,7 @@ static int wpi_updateedca(struct ieee80211com *ic) { #define WPI_EXP2(x) ((1 << (x)) - 1) /* CWmin = 2^ECWmin - 1 */ - struct wpi_softc *sc = ic->ic_softc; + struct wpi_softc *sc = ic->ic_ifp->if_softc; struct wpi_edca_params cmd; int aci, error; @@ -3520,7 +3526,8 @@ wpi_updateedca(struct ieee80211com *ic) static void wpi_set_promisc(struct wpi_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); uint32_t promisc_filter; @@ -3528,7 +3535,7 @@ wpi_set_promisc(struct wpi_softc *sc) if (vap != NULL && vap->iv_opmode != IEEE80211_M_HOSTAP) promisc_filter |= WPI_FILTER_PROMISC; - if (ic->ic_promisc > 0) + if (ifp->if_flags & IFF_PROMISC) sc->rxon.filter |= htole32(promisc_filter); else sc->rxon.filter &= ~htole32(promisc_filter); @@ -3893,7 +3900,8 @@ wpi_send_rxon(struct wpi_softc *sc, int assoc, int async) static int wpi_config(struct wpi_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct ieee80211_channel *c = ic->ic_curchan; int error; @@ -4003,7 +4011,7 @@ wpi_get_active_dwell_time(struct wpi_softc *sc, static uint16_t wpi_limit_dwell(struct wpi_softc *sc, uint16_t dwell_time) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); int bintval = 0; @@ -4060,7 +4068,8 @@ wpi_get_scan_pause_time(uint32_t time, uint16_t bintval) static int wpi_scan(struct wpi_softc *sc, struct ieee80211_channel *c) { - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_scan_state *ss = ic->ic_scan; struct ieee80211vap *vap = ss->ss_vap; struct wpi_scan_hdr *hdr; @@ -4162,9 +4171,11 @@ wpi_scan(struct wpi_softc *sc, struct ieee80211_channel *c) wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; - IEEE80211_ADDR_COPY(wh->i_addr1, ieee80211broadcastaddr); + IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); - IEEE80211_ADDR_COPY(wh->i_addr3, ieee80211broadcastaddr); + IEEE80211_ADDR_COPY(wh->i_addr3, ifp->if_broadcastaddr); + *(uint16_t *)&wh->i_dur[0] = 0; /* filled by h/w */ + *(uint16_t *)&wh->i_seq[0] = 0; /* filled by h/w */ frm = (uint8_t *)(wh + 1); frm = ieee80211_add_ssid(frm, NULL, 0); @@ -4195,6 +4206,7 @@ wpi_scan(struct wpi_softc *sc, struct ieee80211_channel *c) /* * Calculate the active/passive dwell times. */ + dwell_active = wpi_get_active_dwell_time(sc, c, nssid); dwell_passive = wpi_get_passive_dwell_time(sc, c); @@ -4312,7 +4324,7 @@ wpi_config_beacon(struct wpi_vap *wvp) struct ieee80211com *ic = wvp->wv_vap.iv_ic; struct ieee80211_beacon_offsets *bo = &wvp->wv_boff; struct wpi_buf *bcn = &wvp->wv_bcbuf; - struct wpi_softc *sc = ic->ic_softc; + struct wpi_softc *sc = ic->ic_ifp->if_softc; struct wpi_cmd_beacon *cmd = (struct wpi_cmd_beacon *)&bcn->data; struct ieee80211_tim_ie *tie; struct mbuf *m; @@ -4394,7 +4406,7 @@ wpi_setup_beacon(struct wpi_softc *sc, struct ieee80211_node *ni) static void wpi_update_beacon(struct ieee80211vap *vap, int item) { - struct wpi_softc *sc = vap->iv_ic->ic_softc; + struct wpi_softc *sc = vap->iv_ic->ic_ifp->if_softc; struct wpi_vap *wvp = WPI_VAP(vap); struct wpi_buf *bcn = &wvp->wv_bcbuf; struct ieee80211_beacon_offsets *bo = &wvp->wv_boff; @@ -4436,7 +4448,7 @@ static void wpi_newassoc(struct ieee80211_node *ni, int isnew) { struct ieee80211vap *vap = ni->ni_vap; - struct wpi_softc *sc = ni->ni_ic->ic_softc; + struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; struct wpi_node *wn = WPI_NODE(ni); int error; @@ -4563,7 +4575,7 @@ wpi_load_key(struct ieee80211_node *ni, const struct ieee80211_key *k) { const struct ieee80211_cipher *cip = k->wk_cipher; struct ieee80211vap *vap = ni->ni_vap; - struct wpi_softc *sc = ni->ni_ic->ic_softc; + struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; struct wpi_node *wn = WPI_NODE(ni); struct wpi_node_info node; uint16_t kflags; @@ -4627,7 +4639,7 @@ wpi_load_key_cb(void *arg, struct ieee80211_node *ni) { const struct ieee80211_key *k = arg; struct ieee80211vap *vap = ni->ni_vap; - struct wpi_softc *sc = ni->ni_ic->ic_softc; + struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; struct wpi_node *wn = WPI_NODE(ni); int error; @@ -4662,7 +4674,7 @@ static int wpi_del_key(struct ieee80211_node *ni, const struct ieee80211_key *k) { struct ieee80211vap *vap = ni->ni_vap; - struct wpi_softc *sc = ni->ni_ic->ic_softc; + struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; struct wpi_node *wn = WPI_NODE(ni); struct wpi_node_info node; uint16_t kflags; @@ -4712,7 +4724,7 @@ wpi_del_key_cb(void *arg, struct ieee80211_node *ni) { const struct ieee80211_key *k = arg; struct ieee80211vap *vap = ni->ni_vap; - struct wpi_softc *sc = ni->ni_ic->ic_softc; + struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; struct wpi_node *wn = WPI_NODE(ni); int error; @@ -4734,7 +4746,7 @@ wpi_process_key(struct ieee80211vap *vap, const struct ieee80211_key *k, int set) { struct ieee80211com *ic = vap->iv_ic; - struct wpi_softc *sc = ic->ic_softc; + struct wpi_softc *sc = ic->ic_ifp->if_softc; struct wpi_vap *wvp = WPI_VAP(vap); struct ieee80211_node *ni; int error, ni_ref = 0; @@ -5384,29 +5396,34 @@ static void wpi_radio_on(void *arg0, int pending) { struct wpi_softc *sc = arg0; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); device_printf(sc->sc_dev, "RF switch: radio enabled\n"); - WPI_LOCK(sc); - callout_stop(&sc->watchdog_rfkill); - WPI_UNLOCK(sc); - - if (vap != NULL) + if (vap != NULL) { + wpi_init(sc); ieee80211_init(vap); + } + + if (WPI_READ(sc, WPI_GP_CNTRL) & WPI_GP_CNTRL_RFKILL) { + WPI_LOCK(sc); + callout_stop(&sc->watchdog_rfkill); + WPI_UNLOCK(sc); + } } static void wpi_radio_off(void *arg0, int pending) { struct wpi_softc *sc = arg0; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); device_printf(sc->sc_dev, "RF switch: radio disabled\n"); - ieee80211_notify_radio(ic, 0); wpi_stop(sc); if (vap != NULL) ieee80211_stop(vap); @@ -5416,16 +5433,19 @@ wpi_radio_off(void *arg0, int pending) WPI_UNLOCK(sc); } -static int -wpi_init(struct wpi_softc *sc) +static void +wpi_init(void *arg) { - int error = 0; + struct wpi_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + int error; WPI_LOCK(sc); DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); - if (sc->sc_running != 0) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) goto end; /* Check that the radio is not disabled by hardware switch. */ @@ -5434,7 +5454,6 @@ wpi_init(struct wpi_softc *sc) "RF switch: radio disabled (%s)\n", __func__); callout_reset(&sc->watchdog_rfkill, hz, wpi_watchdog_rfkill, sc); - error = EINPROGRESS; goto end; } @@ -5443,11 +5462,9 @@ wpi_init(struct wpi_softc *sc) device_printf(sc->sc_dev, "%s: could not read firmware, error %d\n", __func__, error); - goto end; + goto fail; } - sc->sc_running = 1; - /* Initialize hardware and upload firmware. */ error = wpi_hw_init(sc); wpi_unload_firmware(sc); @@ -5459,6 +5476,7 @@ wpi_init(struct wpi_softc *sc) } /* Configure adapter now that it is ready. */ + sc->txq_active = 1; if ((error = wpi_config(sc)) != 0) { device_printf(sc->sc_dev, "%s: could not configure device, error %d\n", __func__, @@ -5466,34 +5484,34 @@ wpi_init(struct wpi_softc *sc) goto fail; } + IF_LOCK(&ifp->if_snd); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; + IF_UNLOCK(&ifp->if_snd); + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); WPI_UNLOCK(sc); - return 0; + ieee80211_start_all(ic); -fail: wpi_stop_locked(sc); + return; +fail: wpi_stop_locked(sc); end: DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); WPI_UNLOCK(sc); - - return error; } static void wpi_stop_locked(struct wpi_softc *sc) { + struct ifnet *ifp = sc->sc_ifp; WPI_LOCK_ASSERT(sc); - if (sc->sc_running == 0) - return; - - WPI_TX_LOCK(sc); WPI_TXQ_LOCK(sc); - sc->sc_running = 0; + sc->txq_active = 0; WPI_TXQ_UNLOCK(sc); - WPI_TX_UNLOCK(sc); WPI_TXQ_STATE_LOCK(sc); callout_stop(&sc->tx_timeout); @@ -5504,6 +5522,10 @@ wpi_stop_locked(struct wpi_softc *sc) callout_stop(&sc->calib_to); WPI_RXON_UNLOCK(sc); + IF_LOCK(&ifp->if_snd); + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + IF_UNLOCK(&ifp->if_snd); + /* Power OFF hardware. */ wpi_hw_stop(sc); } @@ -5522,7 +5544,7 @@ wpi_stop(struct wpi_softc *sc) static void wpi_scan_start(struct ieee80211com *ic) { - struct wpi_softc *sc = ic->ic_softc; + struct wpi_softc *sc = ic->ic_ifp->if_softc; wpi_set_led(sc, WPI_LED_LINK, 20, 2); } @@ -5533,7 +5555,8 @@ wpi_scan_start(struct ieee80211com *ic) static void wpi_scan_end(struct ieee80211com *ic) { - struct wpi_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct wpi_softc *sc = ifp->if_softc; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); if (vap->iv_state == IEEE80211_S_RUN) @@ -5548,7 +5571,8 @@ static void wpi_set_channel(struct ieee80211com *ic) { const struct ieee80211_channel *c = ic->ic_curchan; - struct wpi_softc *sc = ic->ic_softc; + struct ifnet *ifp = ic->ic_ifp; + struct wpi_softc *sc = ifp->if_softc; int error; DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); @@ -5594,7 +5618,7 @@ wpi_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) { struct ieee80211vap *vap = ss->ss_vap; struct ieee80211com *ic = vap->iv_ic; - struct wpi_softc *sc = ic->ic_softc; + struct wpi_softc *sc = ic->ic_ifp->if_softc; int error; WPI_RXON_LOCK(sc); @@ -5620,18 +5644,19 @@ static void wpi_hw_reset(void *arg, int pending) { struct wpi_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); - ieee80211_notify_radio(ic, 0); if (vap != NULL && (ic->ic_flags & IEEE80211_F_SCAN)) ieee80211_cancel_scan(vap); wpi_stop(sc); - if (vap != NULL) { + if (vap != NULL) ieee80211_stop(vap); + wpi_init(sc); + if (vap != NULL) ieee80211_init(vap); - } } diff --git a/sys/dev/wpi/if_wpivar.h b/sys/dev/wpi/if_wpivar.h index 4e1baa5fdc50..b7835281fb39 100644 --- a/sys/dev/wpi/if_wpivar.h +++ b/sys/dev/wpi/if_wpivar.h @@ -72,7 +72,6 @@ struct wpi_tx_ring { struct wpi_tx_cmd *cmd; struct wpi_tx_data data[WPI_TX_RING_COUNT]; bus_dma_tag_t data_dmat; - struct mbufq snd; int qid; int queued; int cur; @@ -165,15 +164,14 @@ struct wpi_fw_info { struct wpi_softc { device_t sc_dev; + + struct ifnet *sc_ifp; int sc_debug; int sc_flags; #define WPI_PS_PATH (1 << 0) - int sc_running; struct mtx sc_mtx; - struct ieee80211com sc_ic; - struct mtx tx_mtx; /* Shared area. */ @@ -183,6 +181,7 @@ struct wpi_softc { struct wpi_tx_ring txq[WPI_NTXQUEUES]; struct mtx txq_mtx; struct mtx txq_state_mtx; + uint32_t txq_active; struct wpi_rx_ring rxq; uint64_t rx_tstamp; |
