From owner-svn-src-head@FreeBSD.ORG Wed Nov 9 18:24:20 2011 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id C2A2F1065672; Wed, 9 Nov 2011 18:24:20 +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 A86AD8FC16; Wed, 9 Nov 2011 18:24:20 +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 pA9IOK4x094189; Wed, 9 Nov 2011 18:24:20 GMT (envelope-from adrian@svn.freebsd.org) Received: (from adrian@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id pA9IOKBK094187; Wed, 9 Nov 2011 18:24:20 GMT (envelope-from adrian@svn.freebsd.org) Message-Id: <201111091824.pA9IOKBK094187@svn.freebsd.org> From: Adrian Chadd Date: Wed, 9 Nov 2011 18:24:20 +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: r227398 - head/sys/dev/ath X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 09 Nov 2011 18:24:21 -0000 Author: adrian Date: Wed Nov 9 18:24:20 2011 New Revision: 227398 URL: http://svn.freebsd.org/changeset/base/227398 Log: If software retransmit occurs with an ath_buf marked ATH_BUF_BUSY, it's cloned and that clone is retransmitted. This means that the ath_buf pointer squirreled away on the baw window array is suddenly wrong and was causing all kinds of console output. This updates the pointer in that particular BAW slot to the new ath_buf after ensuring that: * the new and old buffers have the same seqno; * the current slot pointer matches the old buffer pointer. This quietens the debugging output (again), restoring said debugging to only signify when a broken condition has occured. Sponsored by: Hobnob, Inc. Modified: head/sys/dev/ath/if_ath_tx.c Modified: head/sys/dev/ath/if_ath_tx.c ============================================================================== --- head/sys/dev/ath/if_ath_tx.c Wed Nov 9 18:12:42 2011 (r227397) +++ head/sys/dev/ath/if_ath_tx.c Wed Nov 9 18:24:20 2011 (r227398) @@ -1900,6 +1900,56 @@ ath_tx_addto_baw(struct ath_softc *sc, s } /* + * Flip the BAW buffer entry over from the existing one to the new one. + * + * When software retransmitting a (sub-)frame, it is entirely possible that + * the frame ath_buf is marked as BUSY and can't be immediately reused. + * In that instance the buffer is cloned and the new buffer is used for + * retransmit. We thus need to update the ath_buf slot in the BAW buf + * tracking array to maintain consistency. + */ +static void +ath_tx_switch_baw_buf(struct ath_softc *sc, struct ath_node *an, + struct ath_tid *tid, struct ath_buf *old_bf, struct ath_buf *new_bf) +{ + int index, cindex; + struct ieee80211_tx_ampdu *tap; + int seqno = SEQNO(old_bf->bf_state.bfs_seqno); + + ATH_TXQ_LOCK_ASSERT(sc->sc_ac2q[tid->ac]); + + tap = ath_tx_get_tx_tid(an, tid->tid); + index = ATH_BA_INDEX(tap->txa_start, seqno); + cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); + + /* + * Just warn for now; if it happens then we should find out + * about it. It's highly likely the aggregation session will + * soon hang. + */ + if (old_bf->bf_state.bfs_seqno != new_bf->bf_state.bfs_seqno) { + device_printf(sc->sc_dev, "%s: retransmitted buffer" + " has mismatching seqno's, BA session may hang.\n", + __func__); + device_printf(sc->sc_dev, "%s: old seqno=%d, new_seqno=%d\n", + __func__, + old_bf->bf_state.bfs_seqno, + new_bf->bf_state.bfs_seqno); + } + + if (tid->tx_buf[cindex] != old_bf) { + device_printf(sc->sc_dev, "%s: ath_buf pointer incorrect; " + " has m BA session may hang.\n", + __func__); + device_printf(sc->sc_dev, "%s: old bf=%p, new bf=%p\n", + __func__, + old_bf, new_bf); + } + + tid->tx_buf[cindex] = new_bf; +} + +/* * seq_start - left edge of BAW * seq_next - current/next sequence number to allocate * @@ -2619,7 +2669,8 @@ ath_tx_set_retry(struct ath_softc *sc, s } static struct ath_buf * -ath_tx_retry_clone(struct ath_softc *sc, struct ath_buf *bf) +ath_tx_retry_clone(struct ath_softc *sc, struct ath_node *an, + struct ath_tid *tid, struct ath_buf *bf) { struct ath_buf *nbf; int error; @@ -2657,6 +2708,10 @@ ath_tx_retry_clone(struct ath_softc *sc, return NULL; } + /* Update BAW if required, before we free the original buf */ + if (bf->bf_state.bfs_dobaw) + ath_tx_switch_baw_buf(sc, an, tid, bf, nbf); + /* Free current buffer; return the older buffer */ bf->bf_m = NULL; bf->bf_node = NULL; @@ -2699,7 +2754,7 @@ ath_tx_aggr_retry_unaggr(struct ath_soft if ((bf->bf_state.bfs_retries < SWMAX_RETRIES) && (bf->bf_flags & ATH_BUF_BUSY)) { struct ath_buf *nbf; - nbf = ath_tx_retry_clone(sc, bf); + nbf = ath_tx_retry_clone(sc, an, atid, bf); if (nbf) /* bf has been freed at this point */ bf = nbf; @@ -2791,7 +2846,7 @@ ath_tx_retry_subframe(struct ath_softc * if ((bf->bf_state.bfs_retries < SWMAX_RETRIES) && (bf->bf_flags & ATH_BUF_BUSY)) { struct ath_buf *nbf; - nbf = ath_tx_retry_clone(sc, bf); + nbf = ath_tx_retry_clone(sc, an, atid, bf); if (nbf) /* bf has been freed at this point */ bf = nbf;