From owner-svn-src-user@FreeBSD.ORG Sat Jun 11 10:35:54 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 8ED911065673; Sat, 11 Jun 2011 10:35:54 +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 7F21C8FC14; Sat, 11 Jun 2011 10:35:54 +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 p5BAZsln071751; Sat, 11 Jun 2011 10:35:54 GMT (envelope-from adrian@svn.freebsd.org) Received: (from adrian@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p5BAZsXQ071747; Sat, 11 Jun 2011 10:35:54 GMT (envelope-from adrian@svn.freebsd.org) Message-Id: <201106111035.p5BAZsXQ071747@svn.freebsd.org> From: Adrian Chadd Date: Sat, 11 Jun 2011 10:35:54 +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: r222981 - 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: Sat, 11 Jun 2011 10:35:54 -0000 Author: adrian Date: Sat Jun 11 10:35:53 2011 New Revision: 222981 URL: http://svn.freebsd.org/changeset/base/222981 Log: Flesh out some more software TX queue code ath_buf's now have both a destination tid and a destination txq. (I may end up also storing a destination AC, just to be complete.) The destination TXQ is pre-calculated at TID TXQ add time as that won't change. It's then added to the pre-determined hardware TXQ when the packet is ready to be scheduled. The routine to calculate the ath_node txq length is dirty. I shall fix soon. Packets should now be schedulable via a call to ath_tx_swq() and sit in the per-node queue until ath_txq_sched() is called. Packets then will be removed from the software queue and added to the relevant hardware queue. Next is writing a completion handler which looks a lot like what ath_tx_processq() does, but knows about the ath_node/tid involved. Eventually this is where the software aggregation retries will live. The TX packet scheduler isn't fair. It isn't pretending to be for now. Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.h user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h 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 Sat Jun 11 09:08:46 2011 (r222980) +++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c Sat Jun 11 10:35:53 2011 (r222981) @@ -1214,17 +1214,13 @@ bad: * Mark the current node/TID as ready to TX. * * This is done to make it easy for the software scheduler to - * find which nodes/TIDs have data to send. + * find which nodes have data to send. * * This must be called with the TX/ATH lock held. */ static void -ath_tx_node_sched(struct ath_softc *sc, struct ath_node *an, int tid) +ath_tx_node_sched(struct ath_softc *sc, struct ath_node *an) { - /* - * For now, the node is marked as ready; - * later code will also maintain a per-TID list. - */ if (an->sched) return; /* already scheduled */ @@ -1234,13 +1230,13 @@ ath_tx_node_sched(struct ath_softc *sc, } /* - * Mark the current node/TID as no longer needing to be polled for + * Mark the current node as no longer needing to be polled for * TX packets. * * This must be called with the TX/ATH lock held. */ static void -ath_tx_node_unsched(struct ath_softc *sc, struct ath_node *an, int tid) +ath_tx_node_unsched(struct ath_softc *sc, struct ath_node *an) { if (an->sched == 0) return; @@ -1259,20 +1255,42 @@ ath_tx_swq(struct ath_softc *sc, struct struct mbuf *m0) { struct ath_node *an = ATH_NODE(ni); + struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_frame *wh; + struct ath_vap *avp = ATH_VAP(vap); struct ath_tid *atid; + struct ath_txq *txq; /* eventual destination queue */ int tid; + int ismcast; + u_int pri; /* Fetch the TID - non-QoS frames get assigned to TID 16 */ wh = mtod(m0, struct ieee80211_frame *); tid = ieee80211_gettid(wh); atid = &an->an_tid[tid]; + /* Fetch the eventual destination queue */ + pri = M_WME_GETAC(m0); /* honor classification */ + ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); + txq = sc->sc_ac2q[pri]; + + /* Handle mcast, or PS STA */ + if (ismcast && (vap->iv_ps_sta || avp->av_mcastq.axq_depth)) + txq = &avp->av_mcastq; + + /* Set local packet state, used to queue packets to hardware */ + bf->bf_state.bfs_tid = tid; + bf->bf_state.bfs_txq = txq; + /* Queue frame to the tail of the software queue */ + ATH_TXQ_LOCK(atid); ATH_TXQ_INSERT_TAIL(atid, bf, bf_list); + ATH_TXQ_UNLOCK(atid); /* Mark the given node/tid as having packets to dequeue */ - ath_tx_node_sched(sc, an, tid); + ATH_LOCK(sc); + ath_tx_node_sched(sc, an); + ATH_UNLOCK(sc); } /* @@ -1374,9 +1392,105 @@ ath_tx_tid_cleanup(struct ath_softc *sc, ath_tx_tid_txq_unmark(sc, an, i); /* Remove any pending hardware TXQ scheduling */ - ath_tx_node_unsched(sc, an, i); + ath_tx_node_unsched(sc, an); /* Free mutex */ mtx_destroy(&atid->axq_lock); } } + +/* + * Schedule some packets from the given node/TID to the hardware. + * + * For non-aggregate packets, all packets can just be queued. + * Aggregate destinations will end up having limitations on + * what can actually be queued here (ie, not more than the + * block-ack window.) + */ +void +ath_tx_tid_hw_queue(struct ath_softc *sc, struct ath_node *an, int tid) +{ + struct ath_buf *bf; + struct ath_txq *txq; + struct ath_tid *atid = &an->an_tid[tid]; + + for (;;) { + ATH_TXQ_LOCK(atid); + bf = STAILQ_FIRST(&txq->axq_q); + if (bf == NULL) { + ATH_TXQ_UNLOCK(atid); + break; + } + ATH_TXQ_REMOVE_HEAD(atid, bf_list); + ATH_TXQ_UNLOCK(atid); + + txq = bf->bf_state.bfs_txq; + /* Sanity check! */ + if (tid != bf->bf_state.bfs_tid) { + device_printf(sc->sc_dev, "%s: bfs_tid %d !=" + " tid %d\n", + __func__, bf->bf_state.bfs_tid, tid); + } + + /* Punt to hardware or software txq */ + ath_tx_handoff(sc, txq, bf); + } +} + +/* + * Attempt to schedule packets from the given node to the hardware. + */ +void +ath_tx_hw_queue(struct ath_softc *sc, struct ath_node *an) +{ + struct ath_tid *atid; + int i; + + /* + * For now, just queue from all TIDs in order. + * This is very likely absolutely wrong from a QoS + * perspective but it'll do for now. + */ + for (i = 0; i < IEEE80211_TID_SIZE; i++) { + atid = &an->an_tid[i]; + ath_tx_tid_hw_queue(sc, an, i); + } +} + +/* + * This is pretty disgusting, but again it's just temporary. + */ +static int +ath_txq_node_qlen(struct ath_softc *sc, struct ath_node *an) +{ + int qlen = 0; + int i; + for (i = 0; i < IEEE80211_TID_SIZE; i++) { + ATH_TXQ_LOCK(&an->an_tid[i]); + qlen += an->an_tid[i].axq_depth; + ATH_TXQ_UNLOCK(&an->an_tid[i]); + } + return qlen; +} + +/* + * Handle scheduling some packets from whichever nodes have + * signaled they're (potentially) ready. + * + * This must be called with the ATH lock held. + */ +void +ath_txq_sched(struct ath_softc *sc) +{ + struct ath_node *an, *next; + + /* Iterate over the list of active nodes, queuing packets */ + STAILQ_FOREACH_SAFE(an, &sc->sc_txnodeq, an_list, next) { + /* Try dequeueing packets from the current node */ + ath_tx_hw_queue(sc, an); + + /* Are any packets left on the node software queue? Remove */ + if (! ath_txq_node_qlen(sc, an)) + ath_tx_node_unsched(sc, an); + } +} Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.h ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.h Sat Jun 11 09:08:46 2011 (r222980) +++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.h Sat Jun 11 10:35:53 2011 (r222981) @@ -46,6 +46,10 @@ extern void ath_tx_swq(struct ath_softc struct ath_buf *bf, struct mbuf *m0); extern void ath_tx_tid_init(struct ath_softc *sc, struct ath_node *an); extern void ath_tx_tid_cleanup(struct ath_softc *sc, struct ath_node *an); +extern void ath_tx_tid_hw_queue(struct ath_softc *sc, struct ath_node *an, + int tid); +extern void ath_tx_hw_queue(struct ath_softc *sc, struct ath_node *an); +extern void ath_txq_sched(struct ath_softc *sc); #endif Modified: user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h Sat Jun 11 09:08:46 2011 (r222980) +++ user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h Sat Jun 11 10:35:53 2011 (r222981) @@ -151,6 +151,7 @@ struct ath_buf { int bfs_seqno; /* sequence number of this packet */ int bfs_retries; /* retry count */ uint16_t bfs_tid; /* packet TID (or TID_MAX for no QoS) */ + struct ath_txq *bfs_txq; /* eventual dest hardware TXQ */ uint16_t bfs_al; /* length of aggregate */ uint16_t bfs_pktdur; /* packet duration (at current rate?) */ uint16_t bfs_nframes; /* number of frames in aggregate */