From owner-svn-src-all@FreeBSD.ORG Mon Jun 4 22:01:13 2012 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 14E7A1065678; Mon, 4 Jun 2012 22:01:13 +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 E963E8FC16; Mon, 4 Jun 2012 22:01: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 q54M1CpP069050; Mon, 4 Jun 2012 22:01:12 GMT (envelope-from adrian@svn.freebsd.org) Received: (from adrian@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q54M1Csx069045; Mon, 4 Jun 2012 22:01:12 GMT (envelope-from adrian@svn.freebsd.org) Message-Id: <201206042201.q54M1Csx069045@svn.freebsd.org> From: Adrian Chadd Date: Mon, 4 Jun 2012 22:01:12 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r236583 - head/sys/dev/ath X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 04 Jun 2012 22:01:13 -0000 Author: adrian Date: Mon Jun 4 22:01:12 2012 New Revision: 236583 URL: http://svn.freebsd.org/changeset/base/236583 Log: Migrate the TX path to a taskqueue for now, until a better way of implementing parallel TX and TX/RX completion can be done without simply abusing long-held locks. Right now, multiple concurrent ath_start() entries can result in frames being dequeued out of order. Well, they're dequeued in order fine, but if there's any preemption or race between CPUs between: * removing the frame from the ifnet, and * calling and runningath_tx_start(), until the frame is placed on a software or hardware TXQ Then although dequeueing the frame is in-order, queueing it to the hardware may be out of order. This is solved in a lot of other drivers by just holding a TX lock over a rather long period of time. This lets them continue to direct dispatch without races between dequeue and hardware queue. Note to observers: if_transmit() doesn't necessarily solve this. It removes the ifnet from the main path, but the same issue exists if there's some intermediary queue (eg a bufring, which as an aside also may pull in ifnet when you're using ALTQ.) So, until I can sit down and code up a much better way of doing parallel TX, I'm going to leave the TX path using a deferred taskqueue task. What I will likely head towards is doing a direct dispatch to hardware or software via if_transmit(), but it'll require some driver changes to allow queues to be made without using the really large ath_buf / ath_desc entries. TODO: * Look at how feasible it'll be to just do direct dispatch to ath_tx_start() from if_transmit(), avoiding doing _any_ intermediary serialisation into a global queue. This may break ALTQ for example, so I have to be delicate. * It's quite likely that I should break up ath_tx_start() so it deposits frames onto the software queues first, and then only fill in the 802.11 fields when it's being queued to the hardware. That will make the if_transmit() -> software queue path very quick and lightweight. * This has some very bad behaviour when using ACPI and Cx states. I'll do some subsequent analysis using KTR and schedgraph and file a follow-up PR or two. PR: kern/168649 Modified: head/sys/dev/ath/if_ath.c head/sys/dev/ath/if_ath_misc.h head/sys/dev/ath/if_ath_rx.c head/sys/dev/ath/if_athvar.h Modified: head/sys/dev/ath/if_ath.c ============================================================================== --- head/sys/dev/ath/if_ath.c Mon Jun 4 21:34:49 2012 (r236582) +++ head/sys/dev/ath/if_ath.c Mon Jun 4 22:01:12 2012 (r236583) @@ -373,6 +373,7 @@ ath_attach(u_int16_t devid, struct ath_s "%s taskq", ifp->if_xname); TASK_INIT(&sc->sc_rxtask, 0, ath_rx_tasklet, sc); + TASK_INIT(&sc->sc_txstarttask, 0, ath_tx_tasklet, 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); @@ -2325,6 +2326,15 @@ void ath_start(struct ifnet *ifp) { struct ath_softc *sc = ifp->if_softc; + + taskqueue_enqueue(sc->sc_tq, &sc->sc_txstarttask); +} + +void +ath_tx_tasklet(void *arg, int npending) +{ + struct ath_softc *sc = (struct ath_softc *) arg; + struct ifnet *ifp = sc->sc_ifp; struct ieee80211_node *ni; struct ath_buf *bf; struct mbuf *m, *next; @@ -3499,7 +3509,8 @@ ath_tx_proc_q0(void *arg, int npending) sc->sc_txproc_cnt--; ATH_PCU_UNLOCK(sc); - ath_start(ifp); + // ath_start(ifp); + ath_tx_tasklet(sc, 1); } /* @@ -3549,7 +3560,8 @@ ath_tx_proc_q0123(void *arg, int npendin sc->sc_txproc_cnt--; ATH_PCU_UNLOCK(sc); - ath_start(ifp); + //ath_start(ifp); + ath_tx_tasklet(sc, 1); } /* @@ -3592,7 +3604,8 @@ ath_tx_proc(void *arg, int npending) sc->sc_txproc_cnt--; ATH_PCU_UNLOCK(sc); - ath_start(ifp); + //ath_start(ifp); + ath_tx_tasklet(sc, 1); } #undef TXQACTIVE Modified: head/sys/dev/ath/if_ath_misc.h ============================================================================== --- head/sys/dev/ath/if_ath_misc.h Mon Jun 4 21:34:49 2012 (r236582) +++ head/sys/dev/ath/if_ath_misc.h Mon Jun 4 22:01:12 2012 (r236583) @@ -83,6 +83,7 @@ extern void ath_setslottime(struct ath_s * we can kill this. */ extern void ath_start(struct ifnet *ifp); +extern void ath_tx_tasklet(void *arg, int npending); #endif Modified: head/sys/dev/ath/if_ath_rx.c ============================================================================== --- head/sys/dev/ath/if_ath_rx.c Mon Jun 4 21:34:49 2012 (r236582) +++ head/sys/dev/ath/if_ath_rx.c Mon Jun 4 22:01:12 2012 (r236583) @@ -899,7 +899,8 @@ rx_proc_next: ieee80211_ff_age_all(ic, 100); #endif if (!IFQ_IS_EMPTY(&ifp->if_snd)) - ath_start(ifp); + ath_tx_tasklet(sc, 1); + //ath_start(ifp); } #undef PA2DESC Modified: head/sys/dev/ath/if_athvar.h ============================================================================== --- head/sys/dev/ath/if_athvar.h Mon Jun 4 21:34:49 2012 (r236582) +++ head/sys/dev/ath/if_athvar.h Mon Jun 4 22:01:12 2012 (r236583) @@ -476,6 +476,7 @@ struct ath_softc { struct mbuf *sc_rxpending; /* pending receive data */ u_int32_t *sc_rxlink; /* link ptr in last RX desc */ struct task sc_rxtask; /* rx int processing */ + struct task sc_txstarttask; /* ath_start() processing */ u_int8_t sc_defant; /* current default antenna */ u_int8_t sc_rxotherant; /* rx's on non-default antenna*/ u_int64_t sc_lastrx; /* tsf at last rx'd frame */