From owner-svn-src-user@FreeBSD.ORG Wed Aug 31 04:57:12 2011 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 850A3106566B; Wed, 31 Aug 2011 04:57:12 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 7333A8FC13; Wed, 31 Aug 2011 04:57:12 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id p7V4vCVf081632; Wed, 31 Aug 2011 04:57:12 GMT (envelope-from adrian@svn.freebsd.org) Received: (from adrian@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p7V4vCiq081626; Wed, 31 Aug 2011 04:57:12 GMT (envelope-from adrian@svn.freebsd.org) Message-Id: <201108310457.p7V4vCiq081626@svn.freebsd.org> From: Adrian Chadd Date: Wed, 31 Aug 2011 04:57:12 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r225279 - user/adrian/if_ath_tx/sys/dev/ath X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 31 Aug 2011 04:57:12 -0000 Author: adrian Date: Wed Aug 31 04:57:11 2011 New Revision: 225279 URL: http://svn.freebsd.org/changeset/base/225279 Log: As much as I dislike it, migrate the driver back to doing direct dispatch to hardware. This matches what the Linux/atheros reference code does. If the hardware txq isn't busy, start filling it with non-aggregate frames. If it's sufficiently busy, start aggregating frames in the background. The aim is to massage this code back to match the structure of the reference code in order to make porting/debugging easier. I may move it back to task-based TX at a later stage, but only once the rest of the TX path has been fully debugged. This drops the CPU use a little but there's still a problem breaking > 100mbit on the MIPS dev boards I'm using. (The same dev board can do 250mbit RX on the same NIC, so it's not necessarily unable to do it.) Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath.c user/adrian/if_ath_tx/sys/dev/ath/if_ath_sysctl.c user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c user/adrian/if_ath_tx/sys/dev/ath/if_athioctl.h user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath.c ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/if_ath.c Wed Aug 31 03:04:56 2011 (r225278) +++ user/adrian/if_ath_tx/sys/dev/ath/if_ath.c Wed Aug 31 04:57:11 2011 (r225279) @@ -176,7 +176,6 @@ static void ath_tx_cleanup(struct ath_so 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_tx_sched_proc(void *, int); static int ath_chan_set(struct ath_softc *, struct ieee80211_channel *); static void ath_draintxq(struct ath_softc *); static void ath_stoprecv(struct ath_softc *); @@ -399,7 +398,6 @@ ath_attach(u_int16_t devid, struct ath_s TASK_INIT(&sc->sc_rxtask, 0, ath_rx_proc, 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_txschedtask, 0, ath_tx_sched_proc, sc); /* * Allocate hardware transmit queues: one queue for @@ -2044,13 +2042,6 @@ ath_start(struct ifnet *ifp) sc->sc_wd_timer = 5; } - - /* - * Schedule the software TX process to occur - * if we transmitted at least one packet. - */ - if (tx) - ath_tx_sched_proc_sched(sc, NULL); } static int @@ -4523,41 +4514,6 @@ ath_tx_proc(void *arg, int npending) } /* - * TX scheduling - * - * This calls the per-TXQ TX queue packet scheduling code. - * - * Note: there's no need to handle the mcastq; it doesn't have - * a software TID queue attached (as it's a software queue in - * itself.) - */ -static void -ath_tx_sched_proc(void *arg, int npending) -{ - struct ath_softc *sc = arg; - struct ath_txq *txq; - int i; - - for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { - txq = &sc->sc_txq[i]; - if (ATH_TXQ_SETUP(sc, i)) { - ATH_TXQ_LOCK(txq); - ath_txq_sched(sc, txq); - ATH_TXQ_UNLOCK(txq); - } - } -} - -/* - * Schedule a TXQ scheduling task to occur. - */ -void -ath_tx_sched_proc_sched(struct ath_softc *sc, struct ath_txq *txq) -{ - taskqueue_enqueue(sc->sc_tq, &sc->sc_txschedtask); -} - -/* * Return a buffer to the pool. * The caller must free the mbuf and recycle the node reference. */ Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath_sysctl.c ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/if_ath_sysctl.c Wed Aug 31 03:04:56 2011 (r225278) +++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_sysctl.c Wed Aug 31 04:57:11 2011 (r225279) @@ -321,6 +321,8 @@ ath_sysctl_txagg(SYSCTL_HANDLER_ARGS) sc->sc_stats.tx_aggr.aggr_nonbaw_pkt); printf("aggr aggregate packet: %d\n", sc->sc_stats.tx_aggr.aggr_aggr_pkt); + printf("aggr single packet low hwq: %d\n", + sc->sc_stats.tx_aggr.aggr_low_hwq_single_pkt); for (i = 0; i < 64; i++) { printf("%2d: %10d ", i, sc->sc_stats.tx_aggr.aggr_pkts[i]); if (i % 4 == 3) Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c Wed Aug 31 03:04:56 2011 (r225278) +++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c Wed Aug 31 04:57:11 2011 (r225279) @@ -872,20 +872,27 @@ ath_tx_set_ratectrl(struct ath_softc *sc * * The frame must already be setup; rate control must already have * been done. + * + * XXX since the TXQ lock is being held here (and I dislike holding + * it for this long when not doing software aggregation), later on + * break this function into "setup_normal" and "xmit_normal". The + * lock only needs to be held for the ath_tx_handoff call. */ static void ath_tx_xmit_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf) { + + ATH_TXQ_LOCK_ASSERT(txq); + /* Setup the descriptor before handoff */ ath_tx_set_rtscts(sc, bf); ath_tx_setds(sc, bf); ath_tx_set_ratectrl(sc, bf->bf_node, bf); ath_tx_chaindesclist(sc, bf); - ATH_TXQ_LOCK(txq); + /* Hand off to hardware */ ath_tx_handoff(sc, txq, bf); - ATH_TXQ_UNLOCK(txq); } @@ -1371,26 +1378,24 @@ ath_tx_start(struct ath_softc *sc, struc * If it's a BAR frame, do a direct dispatch to the * destination hardware queue. Don't bother software * queuing it, as the TID will now be paused. + * Sending a BAR frame can occur from the net80211 txa timer + * (ie, retries) or from the ath txtask (completion call.) + * It queues directly to hardware because the TID is paused + * at this point (and won't be unpaused until the BAR has + * either been TXed successfully or max retries has been + * reached.) */ if (txq == &avp->av_mcastq) { + ATH_TXQ_LOCK(txq); ath_tx_xmit_normal(sc, txq, bf); + ATH_TXQ_UNLOCK(txq); } else if (type == IEEE80211_FC0_TYPE_CTL && subtype == IEEE80211_FC0_SUBTYPE_BAR) { - /* - * XXX The following is dirty but needed for now. - * - * Sending a BAR frame can occur from the net80211 txa timer - * (ie, retries) or from the ath txtask (completion call.) - * It queues directly to hardware because the TID is paused - * at this point (and won't be unpaused until the BAR has - * either been TXed successfully or max retries has been - * reached.) - * - * TODO: sending a BAR should be done at the management rate! - */ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: BAR: TX'ing direct\n", __func__); + ATH_TXQ_LOCK(txq); ath_tx_xmit_normal(sc, txq, bf); + ATH_TXQ_UNLOCK(txq); } else { /* add to software queue */ ath_tx_swq(sc, ni, txq, bf); @@ -1400,7 +1405,9 @@ ath_tx_start(struct ath_softc *sc, struc * For now, since there's no software queue, * direct-dispatch to the hardware. */ + ATH_TXQ_LOCK(txq); ath_tx_xmit_normal(sc, txq, bf); + ATH_TXQ_UNLOCK(txq); #endif return 0; @@ -1603,9 +1610,11 @@ ath_tx_raw_start(struct ath_softc *sc, s DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: dooverride=%d\n", __func__, do_override); - if (do_override) + if (do_override) { + ATH_TXQ_LOCK(sc->sc_ac2q[pri]); ath_tx_xmit_normal(sc, sc->sc_ac2q[pri], bf); - else { + ATH_TXQ_UNLOCK(sc->sc_ac2q[pri]); + } else { /* Queue to software queue */ ath_tx_swq(sc, ni, sc->sc_ac2q[pri], bf); } @@ -1670,9 +1679,6 @@ ath_raw_xmit(struct ieee80211_node *ni, ifp->if_opackets++; sc->sc_stats.ast_tx_raw++; - /* Schedule a TX scheduler task call to occur */ - ath_tx_sched_proc_sched(sc, NULL); - return 0; bad2: ATH_TXBUF_LOCK(sc); @@ -1965,9 +1971,63 @@ ath_tx_tid_seqno_assign(struct ath_softc } /* - * Queue the given packet on the relevant software queue. - * - * This however doesn't queue the packet to the hardware! + * Attempt to direct dispatch an aggregate frame to hardware. + * If the frame is out of BAW, queue. + * Otherwise, schedule it as a single frame. + */ +static void +ath_tx_xmit_aggr(struct ath_softc *sc, struct ath_node *an, struct ath_buf *bf) +{ + struct ath_tid *tid = &an->an_tid[bf->bf_state.bfs_tid]; + struct ath_txq *txq = bf->bf_state.bfs_txq; + struct ieee80211_tx_ampdu *tap; + + ATH_TXQ_LOCK_ASSERT(txq); + + tap = ath_tx_get_tx_tid(an, tid->tid); + + /* paused? queue */ + if (tid->paused) { + ATH_TXQ_INSERT_TAIL(tid, bf, bf_list); + return; + } + + /* outside baw? queue */ + if (bf->bf_state.bfs_dobaw && + (! BAW_WITHIN(tap->txa_start, tap->txa_wnd, + SEQNO(bf->bf_state.bfs_seqno)))) { + ATH_TXQ_INSERT_TAIL(tid, bf, bf_list); + return; + } + + /* Direct dispatch to hardware */ + ath_tx_set_rtscts(sc, bf); + ath_tx_setds(sc, bf); + ath_tx_set_ratectrl(sc, bf->bf_node, bf); + ath_tx_chaindesclist(sc, bf); + + /* Statistics */ + sc->sc_stats.tx_aggr.aggr_low_hwq_single_pkt++; + + /* Track per-TID hardware queue depth correctly */ + tid->hwq_depth++; + + /* Add to BAW */ + ath_tx_addto_baw(sc, an, tid, bf); + bf->bf_state.bfs_addedbaw = 1; + + /* Set completion handler, multi-frame aggregate or not */ + bf->bf_comp = ath_tx_aggr_comp; + + /* Hand off to hardware */ + ath_tx_handoff(sc, txq, bf); +} + +/* + * Attempt to send the packet. + * If the queue isn't busy, direct-dispatch. + * If the queue is busy enough, queue the given packet on the + * relevant software queue. */ void ath_tx_swq(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_txq *txq, @@ -1993,10 +2053,31 @@ ath_tx_swq(struct ath_softc *sc, struct bf->bf_state.bfs_txq = txq; bf->bf_state.bfs_pri = pri; - /* Queue frame to the tail of the software queue */ + /* + * If the hardware queue isn't busy, queue it directly. + * If the hardware queue is busy, queue it. + * If the TID is paused or the traffic it outside BAW, software + * queue it. + */ ATH_TXQ_LOCK(txq); - ATH_TXQ_INSERT_TAIL(atid, bf, bf_list); - ath_tx_tid_sched(sc, an, tid); + if (atid->paused) { + /* TID is paused, queue */ + ATH_TXQ_INSERT_TAIL(atid, bf, bf_list); + } else if (ath_tx_ampdu_pending(sc, an, tid)) { + /* AMPDU pending; queue */ + ATH_TXQ_INSERT_TAIL(atid, bf, bf_list); + } else if (txq->axq_depth < sc->sc_hwq_limit && + ath_tx_ampdu_running(sc, an, tid)) { + /* AMPDU running, attempt direct dispatch */ + ath_tx_xmit_aggr(sc, an, bf); + } else if (txq->axq_depth < sc->sc_hwq_limit) { + /* AMPDU not running, attempt direct dispatch */ + ath_tx_xmit_normal(sc, txq, bf); + } else { + /* Busy; queue */ + ATH_TXQ_INSERT_TAIL(atid, bf, bf_list); + ath_tx_tid_sched(sc, an, tid); + } ATH_TXQ_UNLOCK(txq); } @@ -2087,7 +2168,6 @@ ath_tx_tid_resume(struct ath_softc *sc, } ath_tx_tid_sched(sc, tid->an, tid->tid); - ath_tx_sched_proc_sched(sc, txq); } static void Modified: user/adrian/if_ath_tx/sys/dev/ath/if_athioctl.h ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/if_athioctl.h Wed Aug 31 03:04:56 2011 (r225278) +++ user/adrian/if_ath_tx/sys/dev/ath/if_athioctl.h Wed Aug 31 04:57:11 2011 (r225279) @@ -41,6 +41,7 @@ struct ath_tx_aggr_stats { u_int32_t aggr_nonbaw_pkt; u_int32_t aggr_aggr_pkt; u_int32_t aggr_baw_closed_single_pkt; + u_int32_t aggr_low_hwq_single_pkt; }; struct ath_stats { Modified: user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h Wed Aug 31 03:04:56 2011 (r225278) +++ user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h Wed Aug 31 04:57:11 2011 (r225279) @@ -445,7 +445,6 @@ 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_txschedtask; /* tx processing task */ 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;