Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/wpi/if_wpi.c
Show First 20 Lines • Show All 200 Lines • ▼ Show 20 Lines | |||||
static int wpi_tx_data(struct wpi_softc *, struct mbuf *, | static int wpi_tx_data(struct wpi_softc *, struct mbuf *, | ||||
struct ieee80211_node *); | struct ieee80211_node *); | ||||
static int wpi_tx_data_raw(struct wpi_softc *, struct mbuf *, | static int wpi_tx_data_raw(struct wpi_softc *, struct mbuf *, | ||||
struct ieee80211_node *, | struct ieee80211_node *, | ||||
const struct ieee80211_bpf_params *); | const struct ieee80211_bpf_params *); | ||||
static int wpi_raw_xmit(struct ieee80211_node *, struct mbuf *, | static int wpi_raw_xmit(struct ieee80211_node *, struct mbuf *, | ||||
const struct ieee80211_bpf_params *); | const struct ieee80211_bpf_params *); | ||||
static int wpi_transmit(struct ieee80211com *, struct mbuf *); | static int wpi_transmit(struct ieee80211com *, struct mbuf *); | ||||
static void wpi_start(void *, int); | |||||
static void wpi_watchdog_rfkill(void *); | static void wpi_watchdog_rfkill(void *); | ||||
static void wpi_scan_timeout(void *); | static void wpi_scan_timeout(void *); | ||||
static void wpi_tx_timeout(void *); | static void wpi_tx_timeout(void *); | ||||
static void wpi_parent(struct ieee80211com *); | static void wpi_parent(struct ieee80211com *); | ||||
static int wpi_cmd(struct wpi_softc *, int, const void *, size_t, int); | static int wpi_cmd(struct wpi_softc *, int, const void *, size_t, int); | ||||
static int wpi_mrr_setup(struct wpi_softc *); | static int wpi_mrr_setup(struct wpi_softc *); | ||||
static int wpi_add_node(struct wpi_softc *, struct ieee80211_node *); | static int wpi_add_node(struct wpi_softc *, struct ieee80211_node *); | ||||
static int wpi_add_broadcast_node(struct wpi_softc *, int); | static int wpi_add_broadcast_node(struct wpi_softc *, int); | ||||
▲ Show 20 Lines • Show All 302 Lines • ▼ Show 20 Lines | #endif | ||||
callout_init_mtx(&sc->calib_to, &sc->rxon_mtx, 0); | callout_init_mtx(&sc->calib_to, &sc->rxon_mtx, 0); | ||||
callout_init_mtx(&sc->scan_timeout, &sc->rxon_mtx, 0); | callout_init_mtx(&sc->scan_timeout, &sc->rxon_mtx, 0); | ||||
callout_init_mtx(&sc->tx_timeout, &sc->txq_state_mtx, 0); | callout_init_mtx(&sc->tx_timeout, &sc->txq_state_mtx, 0); | ||||
callout_init_mtx(&sc->watchdog_rfkill, &sc->sc_mtx, 0); | callout_init_mtx(&sc->watchdog_rfkill, &sc->sc_mtx, 0); | ||||
TASK_INIT(&sc->sc_reinittask, 0, wpi_hw_reset, sc); | TASK_INIT(&sc->sc_reinittask, 0, wpi_hw_reset, sc); | ||||
TASK_INIT(&sc->sc_radiooff_task, 0, wpi_radio_off, sc); | TASK_INIT(&sc->sc_radiooff_task, 0, wpi_radio_off, sc); | ||||
TASK_INIT(&sc->sc_radioon_task, 0, wpi_radio_on, sc); | TASK_INIT(&sc->sc_radioon_task, 0, wpi_radio_on, sc); | ||||
TASK_INIT(&sc->sc_start_task, 0, wpi_start, sc); | |||||
sc->sc_tq = taskqueue_create("wpi_taskq", M_WAITOK, | sc->sc_tq = taskqueue_create("wpi_taskq", M_WAITOK, | ||||
taskqueue_thread_enqueue, &sc->sc_tq); | taskqueue_thread_enqueue, &sc->sc_tq); | ||||
error = taskqueue_start_threads(&sc->sc_tq, 1, 0, "wpi_taskq"); | error = taskqueue_start_threads(&sc->sc_tq, 1, 0, "wpi_taskq"); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(dev, "can't start threads, error %d\n", error); | device_printf(dev, "can't start threads, error %d\n", error); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 143 Lines • ▼ Show 20 Lines | wpi_detach(device_t dev) | ||||
struct wpi_softc *sc = device_get_softc(dev); | struct wpi_softc *sc = device_get_softc(dev); | ||||
struct ieee80211com *ic = &sc->sc_ic; | struct ieee80211com *ic = &sc->sc_ic; | ||||
int qid; | int qid; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
if (ic->ic_vap_create == wpi_vap_create) { | if (ic->ic_vap_create == wpi_vap_create) { | ||||
ieee80211_draintask(ic, &sc->sc_radioon_task); | ieee80211_draintask(ic, &sc->sc_radioon_task); | ||||
ieee80211_draintask(ic, &sc->sc_start_task); | |||||
wpi_stop(sc); | wpi_stop(sc); | ||||
if (sc->sc_tq != NULL) { | if (sc->sc_tq != NULL) { | ||||
taskqueue_drain_all(sc->sc_tq); | taskqueue_drain_all(sc->sc_tq); | ||||
taskqueue_free(sc->sc_tq); | taskqueue_free(sc->sc_tq); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 463 Lines • ▼ Show 20 Lines | wpi_alloc_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring, int qid) | ||||
bus_addr_t paddr; | bus_addr_t paddr; | ||||
bus_size_t size; | bus_size_t size; | ||||
int i, error; | int i, error; | ||||
ring->qid = qid; | ring->qid = qid; | ||||
ring->queued = 0; | ring->queued = 0; | ||||
ring->cur = 0; | ring->cur = 0; | ||||
ring->update = 0; | ring->update = 0; | ||||
mbufq_init(&ring->snd, ifqmaxlen); | |||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
/* Allocate TX descriptors (16KB aligned.) */ | /* Allocate TX descriptors (16KB aligned.) */ | ||||
size = WPI_TX_RING_COUNT * sizeof (struct wpi_tx_desc); | size = WPI_TX_RING_COUNT * sizeof (struct wpi_tx_desc); | ||||
error = wpi_dma_contig_alloc(sc, &ring->desc_dma, (void **)&ring->desc, | error = wpi_dma_contig_alloc(sc, &ring->desc_dma, (void **)&ring->desc, | ||||
size, WPI_RING_DMA_ALIGN); | size, WPI_RING_DMA_ALIGN); | ||||
if (error != 0) { | if (error != 0) { | ||||
▲ Show 20 Lines • Show All 111 Lines • ▼ Show 20 Lines | if (data->ni != NULL) { | ||||
ieee80211_free_node(data->ni); | ieee80211_free_node(data->ni); | ||||
data->ni = NULL; | data->ni = NULL; | ||||
} | } | ||||
} | } | ||||
/* Clear TX descriptors. */ | /* Clear TX descriptors. */ | ||||
memset(ring->desc, 0, ring->desc_dma.size); | memset(ring->desc, 0, ring->desc_dma.size); | ||||
bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, | bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, | ||||
BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREWRITE); | ||||
mbufq_drain(&ring->snd); | |||||
sc->qfullmsk &= ~(1 << ring->qid); | |||||
ring->queued = 0; | ring->queued = 0; | ||||
ring->cur = 0; | ring->cur = 0; | ||||
ring->update = 0; | ring->update = 0; | ||||
} | } | ||||
static void | static void | ||||
wpi_free_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) | wpi_free_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 793 Lines • ▼ Show 20 Lines | ieee80211_ratectl_tx_complete(vap, ni, | ||||
IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); | IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); | ||||
} else | } else | ||||
ieee80211_ratectl_tx_complete(vap, ni, | ieee80211_ratectl_tx_complete(vap, ni, | ||||
IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); | IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); | ||||
ieee80211_tx_complete(ni, m, (status & WPI_TX_STATUS_FAIL) != 0); | ieee80211_tx_complete(ni, m, (status & WPI_TX_STATUS_FAIL) != 0); | ||||
WPI_TXQ_STATE_LOCK(sc); | WPI_TXQ_STATE_LOCK(sc); | ||||
ring->queued -= 1; | if (--ring->queued > 0) | ||||
if (ring->queued > 0) { | |||||
callout_reset(&sc->tx_timeout, 5*hz, wpi_tx_timeout, sc); | callout_reset(&sc->tx_timeout, 5*hz, wpi_tx_timeout, sc); | ||||
else | |||||
if ((sc->qfullmsk & (1 << ring->qid)) != 0 && | |||||
ring->queued < WPI_TX_RING_LOMARK) { | |||||
sc->qfullmsk &= ~(1 << ring->qid); | |||||
ieee80211_runtask(ic, &sc->sc_start_task); | |||||
} | |||||
} else | |||||
callout_stop(&sc->tx_timeout); | callout_stop(&sc->tx_timeout); | ||||
WPI_TXQ_STATE_UNLOCK(sc); | WPI_TXQ_STATE_UNLOCK(sc); | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | ||||
} | } | ||||
/* | /* | ||||
* Process a "command done" firmware notification. This is where we wakeup | * Process a "command done" firmware notification. This is where we wakeup | ||||
▲ Show 20 Lines • Show All 562 Lines • ▼ Show 20 Lines | wpi_cmd2(struct wpi_softc *sc, struct wpi_buf *buf) | ||||
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); | ||||
/* Kick TX ring. */ | /* Kick TX ring. */ | ||||
ring->cur = (ring->cur + 1) % WPI_TX_RING_COUNT; | ring->cur = (ring->cur + 1) % WPI_TX_RING_COUNT; | ||||
sc->sc_update_tx_ring(sc, ring); | sc->sc_update_tx_ring(sc, ring); | ||||
if (ring->qid < WPI_CMD_QUEUE_NUM) { | if (ring->qid < WPI_CMD_QUEUE_NUM) { | ||||
/* Mark TX ring as full if we reach a certain threshold. */ | |||||
WPI_TXQ_STATE_LOCK(sc); | WPI_TXQ_STATE_LOCK(sc); | ||||
if (++ring->queued > WPI_TX_RING_HIMARK) | ring->queued++; | ||||
sc->qfullmsk |= 1 << ring->qid; | |||||
callout_reset(&sc->tx_timeout, 5*hz, wpi_tx_timeout, sc); | callout_reset(&sc->tx_timeout, 5*hz, wpi_tx_timeout, sc); | ||||
WPI_TXQ_STATE_UNLOCK(sc); | WPI_TXQ_STATE_UNLOCK(sc); | ||||
} | } | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | ||||
WPI_TXQ_UNLOCK(sc); | WPI_TXQ_UNLOCK(sc); | ||||
▲ Show 20 Lines • Show All 351 Lines • ▼ Show 20 Lines | unlock: WPI_TX_UNLOCK(sc); | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
wpi_transmit(struct ieee80211com *ic, struct mbuf *m) | wpi_transmit(struct ieee80211com *ic, struct mbuf *m) | ||||
{ | { | ||||
struct wpi_softc *sc = ic->ic_softc; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct mbufq *sndq; | |||||
int ac, error; | int ac, error; | ||||
WPI_TX_LOCK(sc); | WPI_TX_LOCK(sc); | ||||
DPRINTF(sc, WPI_DEBUG_XMIT, "%s: called\n", __func__); | DPRINTF(sc, WPI_DEBUG_XMIT, "%s: called\n", __func__); | ||||
/* Check if interface is up & running. */ | /* Check if interface is up & running. */ | ||||
if (sc->sc_running == 0) { | if (sc->sc_running == 0) { | ||||
error = ENXIO; | error = ENXIO; | ||||
goto unlock; | goto unlock; | ||||
} | } | ||||
/* Check for available space. */ | /* Check for available space. */ | ||||
ac = M_WME_GETAC(m); | ac = M_WME_GETAC(m); | ||||
sndq = &sc->txq[ac].snd; | if (wpi_tx_ring_is_full(sc, ac)) { | ||||
if (wpi_tx_ring_is_full(sc, ac) || mbufq_len(sndq) != 0) { | error = ENOBUFS; | ||||
/* wpi_tx_done() will dequeue it. */ | |||||
error = mbufq_enqueue(sndq, m); | |||||
goto unlock; | goto unlock; | ||||
} | } | ||||
error = 0; | error = 0; | ||||
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; | ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; | ||||
if (wpi_tx_data(sc, m, ni) != 0) { | if (wpi_tx_data(sc, m, ni) != 0) { | ||||
wpi_handle_tx_failure(ni); | wpi_handle_tx_failure(ni); | ||||
} | } | ||||
DPRINTF(sc, WPI_DEBUG_XMIT, "%s: done\n", __func__); | DPRINTF(sc, WPI_DEBUG_XMIT, "%s: done\n", __func__); | ||||
unlock: WPI_TX_UNLOCK(sc); | unlock: WPI_TX_UNLOCK(sc); | ||||
return (error); | return (error); | ||||
} | |||||
/** | |||||
* Process data waiting to be sent on the output queue | |||||
*/ | |||||
static void | |||||
wpi_start(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; | |||||
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); | |||||
} | } | ||||
static void | static void | ||||
wpi_watchdog_rfkill(void *arg) | wpi_watchdog_rfkill(void *arg) | ||||
{ | { | ||||
struct wpi_softc *sc = arg; | struct wpi_softc *sc = arg; | ||||
struct ieee80211com *ic = &sc->sc_ic; | struct ieee80211com *ic = &sc->sc_ic; | ||||
▲ Show 20 Lines • Show All 2,485 Lines • Show Last 20 Lines |