summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2012-03-29 17:39:18 +0000
committeradrian <adrian@FreeBSD.org>2012-03-29 17:39:18 +0000
commit9cb839a32c6a135485c4573a69c278031667e9c5 (patch)
treeecdb2e62cc341a90ea775e7e5b017085c860a417
parentc56f63e2badce01fac17bc5a106216ed15fcd003 (diff)
downloadFreeBSD-src-9cb839a32c6a135485c4573a69c278031667e9c5.zip
FreeBSD-src-9cb839a32c6a135485c4573a69c278031667e9c5.tar.gz
Defer the rescheduling of TID -> TXQ frames in some instances.
Right now ath_txq_sched() is mainly called from the TX ath_tx_processq() routine, which is (mostly) done as part of the taskqueue. It shouldn't be called outside the taskqueue. But now that I'm about to flip back on BAR TX, I'm going to start stressing the ath_tx_tid_pause() and ath_tx_tid_resume() paths. What I don't want to have happen is a reschedule of the TID traffic _during_ the completion of TX frames. Ideally I'd like to have a way to flag back up to the processing code that the current hardware queue should be rechecked for software TID queue frames. But for now, this should suffice for the BAR TX case. I may eventually delete this code once I've brought some further sanity to the general TX queue/completion path.
-rw-r--r--sys/dev/ath/if_ath.c34
-rw-r--r--sys/dev/ath/if_ath_tx.c3
-rw-r--r--sys/dev/ath/if_athvar.h1
3 files changed, 37 insertions, 1 deletions
diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c
index c886bc0..3c6043e 100644
--- a/sys/dev/ath/if_ath.c
+++ b/sys/dev/ath/if_ath.c
@@ -191,6 +191,7 @@ static void ath_tx_cleanup(struct ath_softc *);
static void ath_tx_proc_q0(void *, int);
static void ath_tx_proc_q0123(void *, int);
static void ath_tx_proc(void *, int);
+static void ath_txq_sched_tasklet(void *, int);
static int ath_chan_set(struct ath_softc *, struct ieee80211_channel *);
static void ath_draintxq(struct ath_softc *, ATH_RESET_TYPE reset_type);
static void ath_stoprecv(struct ath_softc *, int);
@@ -398,6 +399,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
TASK_INIT(&sc->sc_bmisstask, 0, ath_bmiss_proc, sc);
TASK_INIT(&sc->sc_bstucktask,0, ath_bstuck_proc, sc);
TASK_INIT(&sc->sc_resettask,0, ath_reset_proc, sc);
+ TASK_INIT(&sc->sc_txqtask,0, ath_txq_sched_tasklet, sc);
/*
* Allocate hardware transmit queues: one queue for
@@ -5132,6 +5134,38 @@ ath_tx_proc(void *arg, int npending)
#undef TXQACTIVE
/*
+ * Deferred processing of TXQ rescheduling.
+ */
+static void
+ath_txq_sched_tasklet(void *arg, int npending)
+{
+ struct ath_softc *sc = arg;
+ int i;
+
+ /* XXX is skipping ok? */
+ ATH_PCU_LOCK(sc);
+#if 0
+ if (sc->sc_inreset_cnt > 0) {
+ device_printf(sc->sc_dev,
+ "%s: sc_inreset_cnt > 0; skipping\n", __func__);
+ ATH_PCU_UNLOCK(sc);
+ return;
+ }
+#endif
+ sc->sc_txproc_cnt++;
+ ATH_PCU_UNLOCK(sc);
+
+ for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
+ if (ATH_TXQ_SETUP(sc, i))
+ ath_txq_sched(sc, &sc->sc_txq[i]);
+ }
+
+ ATH_PCU_LOCK(sc);
+ sc->sc_txproc_cnt--;
+ ATH_PCU_UNLOCK(sc);
+}
+
+/*
* Return a buffer to the pool and update the 'busy' flag on the
* previous 'tail' entry.
*
diff --git a/sys/dev/ath/if_ath_tx.c b/sys/dev/ath/if_ath_tx.c
index 57f3a13..6fb1fd2 100644
--- a/sys/dev/ath/if_ath_tx.c
+++ b/sys/dev/ath/if_ath_tx.c
@@ -2623,7 +2623,8 @@ ath_tx_tid_resume(struct ath_softc *sc, struct ath_tid *tid)
ath_tx_tid_sched(sc, tid);
/* Punt some frames to the hardware if needed */
- ath_txq_sched(sc, sc->sc_ac2q[tid->ac]);
+ //ath_txq_sched(sc, sc->sc_ac2q[tid->ac]);
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_txqtask);
}
/*
diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h
index a2c27f2..5d56159 100644
--- a/sys/dev/ath/if_athvar.h
+++ b/sys/dev/ath/if_athvar.h
@@ -490,6 +490,7 @@ struct ath_softc {
struct ath_txq sc_txq[HAL_NUM_TX_QUEUES];
struct ath_txq *sc_ac2q[5]; /* WME AC -> h/w q map */
struct task sc_txtask; /* tx int processing */
+ struct task sc_txqtask; /* tx proc processing */
int sc_wd_timer; /* count down for wd timer */
struct callout sc_wd_ch; /* tx watchdog timer */
struct ath_tx_radiotap_header sc_tx_th;
OpenPOWER on IntegriCloud