The holding buffer logic needs to be used for _all_ transmission, not

just "when the queue is busy."

After talking with the MAC team, it turns out that the linked list
implementation sometimes will not accept a TxDP update and will
instead re-read the link pointer.  So even if the hardware has
finished transmitting a chain and has hit EOL/VEOL, it may still
re-read the link pointer to begin transmitting again.

So, always set ATH_BUF_BUSY on the last buffer in the chain (to
mark the last descriptor as the holding descriptor) and never
blank the axq_link pointer.

Tested:

* AR5416, STA mode

TODO:

* much more thorough testing with the pre-11n NICs, just to verify
  that they behave the same way.
* test TDMA on the 11n and non-11n hardware.
This commit is contained in:
Adrian Chadd 2013-05-04 04:03:50 +00:00
parent a7880d59c9
commit 4136c09143

View File

@ -3928,19 +3928,20 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq, int dosched)
break;
}
ATH_TXQ_REMOVE(txq, bf, bf_list);
if (txq->axq_depth > 0) {
/*
* More frames follow. Mark the buffer busy
* so it's not re-used while the hardware may
* still re-read the link field in the descriptor.
*
* Use the last buffer in an aggregate as that
* is where the hardware may be - intermediate
* descriptors won't be "busy".
*/
bf->bf_last->bf_flags |= ATH_BUF_BUSY;
} else
txq->axq_link = NULL;
/*
* Always mark the last buffer in this list as busy.
*
* The hardware may re-read the holding descriptor
* even if we hit the end of the list and try writing
* a new TxDP.
*
* If there's no holding descriptor then this is the
* last buffer in the list of buffers after a fresh
* reset; it'll soon become the holding buffer.
*/
bf->bf_last->bf_flags |= ATH_BUF_BUSY;
if (bf->bf_state.bfs_aggr)
txq->axq_aggr_depth--;