Date: Fri, 12 Aug 2011 09:18:02 +0000 (UTC) From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r224792 - user/adrian/if_ath_tx/sys/dev/ath Message-ID: <201108120918.p7C9I251030777@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: adrian Date: Fri Aug 12 09:18:02 2011 New Revision: 224792 URL: http://svn.freebsd.org/changeset/base/224792 Log: Commit some (very untested) initial code to clean up after a DELBA. Once a DELBA is received, there may be: * packets in the software TX TID queue * packets in the hardware queue (aggregate or individual frames) The software TX queue is fine - those packets don't yet have a personality as they haven't been "scheduled". The packets in the hardware TX queues need to be completed or deleted. So the logic here is: * packets in the SWQ which are retries are discarded; * packets in the SWQ which aren't retries are modified to have their completion handler be the default, non-aggregate one * if there are any packets left in the hardware queue, mark the TID as "cleanup" and keep track of how many are outstanding * if the TID is "cleanup", pause the TID so no further traffic is scheduled. Then, when the packets are completed, the "incomplete" packet count is updated and when it hits 0 (ie, all packets on the hardware queue) it'll be unpaused and will begin running as a non-aggregate TID. To avoid races, pause the TID in the addba handler before disabling the addba state and calling ath_tx_cleanup(). Since the TXQ lock is held for the duration of queue operations, any packets that snuck in before the TID was paused will be downgraded to non-aggregate status by ath_tx_cleanup(). Obtained from: Atheros Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c 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 Fri Aug 12 07:04:16 2011 (r224791) +++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c Fri Aug 12 09:18:02 2011 (r224792) @@ -1916,53 +1916,121 @@ ath_tx_normal_comp(struct ath_softc *sc, } #endif -#ifdef notyet /* - * Handle cleanup of aggregate state packets that aren't + * Handle cleanup of aggregate session packets that aren't * an A-MPDU. */ static void ath_tx_comp_cleanup(struct ath_softc *sc, struct ath_buf *bf) { + struct ieee80211_node *ni = bf->bf_node; + struct ath_node *an = ATH_NODE(ni); + int tid = bf->bf_state.bfs_tid; + struct ath_tid *atid = &an->an_tid[tid]; + struct ath_txq *txq = sc->sc_ac2q[atid->ac]; + + device_printf(sc->sc_dev, "%s: TID %d: incomp=%d\n", + __func__, tid, atid->incomp); + + ATH_TXQ_LOCK_ASSERT(txq); + + atid->incomp--; + if (atid->incomp == 0) { + device_printf(sc->sc_dev, "%s: TID %d: cleaned up! resume!\n", + __func__, tid); + atid->cleanup_inprogress = 0; + ath_tx_tid_resume(sc, atid); + } + ath_tx_default_comp(sc, bf, 0); } -#endif /* * Performs transmit side cleanup when TID changes from aggregated to * unaggregated. + * * - Discard all retry frames from the s/w queue. * - Fix the tx completion function for all buffers in s/w queue. * - Count the number of unacked frames, and let transmit completion * handle it later. + * + * The caller is responsible for pausing the TID. + * The caller is responsible for locking TXQ. */ static void ath_tx_cleanup(struct ath_softc *sc, struct ath_node *an, int tid) { struct ath_tid *atid = &an->an_tid[tid]; struct ath_txq *txq = sc->sc_ac2q[atid->ac]; + struct ieee80211_tx_ampdu *tap; + struct ath_buf *bf, *bf_next; - ATH_TXQ_LOCK(txq); + device_printf(sc->sc_dev, "%s: TID %d: called\n", __func__, tid); + + ATH_TXQ_LOCK_ASSERT(txq); /* + * Update the frames in the software TX queue: + * * + Discard retry frames in the queue * + Fix the completion function to be non-aggregate */ + bf = STAILQ_FIRST(&atid->axq_q); + while (bf) { + if (bf->bf_state.bfs_isretried) { + bf_next = STAILQ_NEXT(bf, bf_list); + STAILQ_REMOVE(&atid->axq_q, bf, ath_buf, bf_list); + atid->axq_depth--; + ath_tx_update_baw(sc, an, atid, + SEQNO(bf->bf_state.bfs_seqno)); + /* + * Call the default completion handler with "fail" just + * so upper levels are suitably notified about this. + */ + ath_tx_default_comp(sc, bf, 1); + bf = bf_next; + continue; + } + /* Give these the default completion handler */ + bf->bf_comp = NULL; + bf = STAILQ_NEXT(bf, bf_list); + } + /* The caller is required to pause the TID */ +#if 0 /* Pause the TID */ + ath_tx_tid_pause(sc, atid); +#endif /* - * Calculate what incomplete frames exist, based on - * the current BAW size. Ie, what frames have been + * Calculate what hardware-queued frames exist based + * on the current BAW size. Ie, what frames have been * added to the TX hardware queue for this TID but * not yet ACKed. */ + tap = ath_tx_get_tx_tid(an, tid); + while (atid->baw_head != atid->baw_tail) { + if (atid->tx_buf[atid->baw_head]) { + atid->incomp++; + atid->cleanup_inprogress = 1; + atid->tx_buf[atid->baw_head] = NULL; + } + INCR(atid->baw_head, ATH_TID_MAX_BUFS); + INCR(tap->txa_start, IEEE80211_SEQ_RANGE); + } /* * If cleanup is required, defer TID scheduling * until all the HW queued packets have been * sent. */ + if (! atid->cleanup_inprogress) + ath_tx_tid_resume(sc, atid); + + if (atid->cleanup_inprogress) + device_printf(sc->sc_dev, + "%s: TID %d: cleanup needed: %d packets\n", + __func__, tid, atid->incomp); ATH_TXQ_UNLOCK(txq); } @@ -2051,15 +2119,13 @@ ath_tx_aggr_comp(struct ath_softc *sc, s /* * If a cleanup is in progress, punt to comp_cleanup; * rather than handling it here. It's thus their - * responsibility to do the BAW update, track the - * incomplete packet count, etc. + * responsibility to clean up, call the completion + * function in net80211, update rate control, etc. */ -#ifdef notyet if (atid->cleanup_inprogress) { ath_tx_comp_cleanup(sc, bf); return; } -#endif /* * Don't bother with the retry check if all frames @@ -2363,10 +2429,6 @@ ath_addba_response(struct ieee80211_node /* * Stop ADDBA on a queue. - * - * In theory, queued ath_bufs should be turned back into non-aggregate - * buffers. I'm not sure what to do about packets currently queued - * to the hardware. */ void ath_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap) @@ -2374,10 +2436,20 @@ ath_addba_stop(struct ieee80211_node *ni struct ath_softc *sc = ni->ni_ic->ic_ifp->if_softc; int tid = WME_AC_TO_TID(tap->txa_ac); struct ath_node *an = ATH_NODE(ni); -#if 0 - struct ath_tid *atid = an->an_tid[tid]; -#endif + struct ath_tid *atid = &an->an_tid[tid]; + struct ath_txq *txq = sc->sc_ac2q[atid->ac]; + DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: called\n", __func__); + + /* Pause TID traffic early, so there aren't any races */ + ATH_TXQ_LOCK(txq); + ath_tx_tid_pause(sc, atid); + ATH_TXQ_UNLOCK(txq); + + /* There's no need to hold the TXQ lock here */ sc->sc_addba_stop(ni, tap); + + ATH_TXQ_LOCK(txq); ath_tx_cleanup(sc, an, tid); + ATH_TXQ_UNLOCK(txq); } Modified: user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h Fri Aug 12 07:04:16 2011 (r224791) +++ user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h Fri Aug 12 09:18:02 2011 (r224792) @@ -115,6 +115,12 @@ struct ath_tid { * traffic will resume being TXed. */ int cleanup_inprogress; + /* + * How many hardware-queued packets are + * waiting to be cleaned up. + * This is only valid if cleanup_inprogress is 1. + */ + int incomp; /* * The following implements a ring representing
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201108120918.p7C9I251030777>