1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-14 14:55:41 +00:00

Migrate the ath_hal_filltxdesc() API to take a list of buffer/seglen values.

The existing API only exposes 'seglen' (the current buffer (segment) length)
with the data buffer pointer set in 'ds_data'.  This is fine for the legacy
DMA engine but it won't work for the EDMA engines.

The EDMA engine has a significantly different TX descriptor layout.

* The legacy DMA engine had a ds_data pointer at the same offset in the
  descriptor for both TX and RX buffers;
* The EDMA engine has no ds_data for RX - the data is DMAed after the
  descriptor;
* The EDMA engine has support for 4 TX buffer/segment pairs in the TX
  DMA descriptor;
* The EDMA TX completion is in a different FIFO, and the driver will
  'link' the status completion entry to a QCU by a "QCU ID".
  I don't know why it's just not filled in by the hardware, alas.

So given that, here are the changes:

* Instead of directly fondling 'ds_data' in ath_desc, change the
  ath_hal_filltxdesc() to take an array of buffer pointers as well
  as segment len pointers;
* The EDMA TX completion status wants a descriptor and queue id.
  This (for now) uses bf_state.bfs_txq and will extract the hardware QCU
  ID from that.
* .. and this is ugly and wasteful; it should change to just store
  the QCU in the bf_state and save 3/7 bytes in the process.

Now, the weird crap:

* The aggregate TX path was using bf_state->bfs_txq for the TXQ, rather than
  taking a function argument.  I've tidied that up.
* The multicast queue frames get put on a software TXQ and then that is
  appended to the hardware CABQ when appropriate.  So for now, make sure
  that bf_state->bfs_txq points at the CABQ when adding frames to the
  multicast queue.
* .. but the multicast queue TX path for now doesn't use the software
  queue and instead
  (a) directly sets up the descriptor contents at that point;
  (b) the frames on the vap->avp_mcastq are then just appended wholesale
      to the CABQ.
  So for now, I don't have to worry about making the multicast path
  work with aggregation or the per-TID software queue. Phew.

What's left to do:

* I need to modify the 11n ath_hal_chaintxdesc() API to do the same.
  I'll do that in a subsequent commit.
* Remove bf_state.bfs_txq entirely and store the QCU as appropriate.
* .. then do the runtime "is this going on the right HWQ?" checks using
  that, rather than comparing pointer values.

Tested on:

* AR9280 STA/AP
* AR5416 STA/AP
This commit is contained in:
Adrian Chadd 2012-08-05 10:12:27 +00:00
parent 7a27d904bd
commit 46634305f4
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=239051
13 changed files with 125 additions and 19 deletions

View File

@ -48,6 +48,12 @@ typedef void *HAL_SOFTC;
typedef bus_space_tag_t HAL_BUS_TAG;
typedef bus_space_handle_t HAL_BUS_HANDLE;
/*
* Although the underlying hardware may support 64 bit DMA, the
* current Atheros hardware only supports 32 bit addressing.
*/
typedef uint32_t HAL_DMA_ADDR;
/*
* Linker set writearounds for chip and RF backend registration.
*/

View File

@ -1081,7 +1081,8 @@ struct ath_hal {
u_int txRate2, u_int txTries2,
u_int txRate3, u_int txTries3);
HAL_BOOL __ahdecl(*ah_fillTxDesc)(struct ath_hal *, struct ath_desc *,
u_int segLen, HAL_BOOL firstSeg,
HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList,
u_int descId, u_int qcuId, HAL_BOOL firstSeg,
HAL_BOOL lastSeg, const struct ath_desc *);
HAL_STATUS __ahdecl(*ah_procTxDesc)(struct ath_hal *,
struct ath_desc *, struct ath_tx_status *);

View File

@ -171,7 +171,8 @@ extern HAL_BOOL ar5210SetupXTxDesc(struct ath_hal *, struct ath_desc *,
u_int txRate2, u_int txRetries2,
u_int txRate3, u_int txRetries3);
extern HAL_BOOL ar5210FillTxDesc(struct ath_hal *, struct ath_desc *,
u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList,
u_int descId, u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
const struct ath_desc *ds0);
extern HAL_STATUS ar5210ProcTxDesc(struct ath_hal *,
struct ath_desc *, struct ath_tx_status *);

View File

@ -546,13 +546,17 @@ ar5210IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds)
HAL_BOOL
ar5210FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int descId,
u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
const struct ath_desc *ds0)
{
struct ar5210_desc *ads = AR5210DESC(ds);
uint32_t segLen = segLenList[0];
HALASSERT((segLen &~ AR_BufLen) == 0);
ds->ds_data = bufAddrList[0];
if (firstSeg) {
/*
* First descriptor, don't clobber xmit control data

View File

@ -196,7 +196,8 @@ extern HAL_BOOL ar5211SetupXTxDesc(struct ath_hal *, struct ath_desc *,
u_int txRate2, u_int txRetries2,
u_int txRate3, u_int txRetries3);
extern HAL_BOOL ar5211FillTxDesc(struct ath_hal *, struct ath_desc *,
u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList,
u_int descId, u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
const struct ath_desc *ds0);
extern HAL_STATUS ar5211ProcTxDesc(struct ath_hal *,
struct ath_desc *, struct ath_tx_status *);

View File

@ -577,10 +577,14 @@ ar5211IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds)
HAL_BOOL
ar5211FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int qcuId,
u_int descId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
const struct ath_desc *ds0)
{
struct ar5211_desc *ads = AR5211DESC(ds);
uint32_t segLen = segLenList[0];
ds->ds_data = bufAddrList[0];
HALASSERT((segLen &~ AR_BufLen) == 0);

View File

@ -594,7 +594,8 @@ extern HAL_BOOL ar5212SetupXTxDesc(struct ath_hal *, struct ath_desc *,
u_int txRate2, u_int txRetries2,
u_int txRate3, u_int txRetries3);
extern HAL_BOOL ar5212FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList,
u_int descId, u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
const struct ath_desc *ds0);
extern HAL_STATUS ar5212ProcTxDesc(struct ath_hal *ah,
struct ath_desc *, struct ath_tx_status *);

View File

@ -802,13 +802,17 @@ ar5212IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds)
HAL_BOOL
ar5212FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int qcuId,
u_int descId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
const struct ath_desc *ds0)
{
struct ar5212_desc *ads = AR5212DESC(ds);
uint32_t segLen = segLenList[0];
HALASSERT((segLen &~ AR_BufLen) == 0);
ds->ds_data = bufAddrList[0];
if (firstSeg) {
/*
* First descriptor, don't clobber xmit control data

View File

@ -360,7 +360,8 @@ extern HAL_BOOL ar5416SetupXTxDesc(struct ath_hal *, struct ath_desc *,
u_int txRate2, u_int txRetries2,
u_int txRate3, u_int txRetries3);
extern HAL_BOOL ar5416FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList,
u_int descId, u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
const struct ath_desc *ds0);
extern HAL_STATUS ar5416ProcTxDesc(struct ath_hal *ah,
struct ath_desc *, struct ath_tx_status *);

View File

@ -277,13 +277,17 @@ ar5416SetupXTxDesc(struct ath_hal *ah, struct ath_desc *ds,
HAL_BOOL
ar5416FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int descId,
u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
const struct ath_desc *ds0)
{
struct ar5416_desc *ads = AR5416DESC(ds);
uint32_t segLen = segLenList[0];
HALASSERT((segLen &~ AR_BufLen) == 0);
ds->ds_data = bufAddrList[0];
if (firstSeg) {
/*
* First descriptor, don't clobber xmit control data

View File

@ -266,6 +266,8 @@ ath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf)
int flags, antenna;
const HAL_RATE_TABLE *rt;
u_int8_t rix, rate;
HAL_DMA_ADDR bufAddrList[4];
uint32_t segLenList[4];
DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s: m %p len %u\n",
__func__, m, m->m_len);
@ -300,7 +302,7 @@ ath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf)
KASSERT(bf->bf_nseg == 1,
("multi-segment beacon frame; nseg %u", bf->bf_nseg));
ds->ds_data = bf->bf_segs[0].ds_addr;
/*
* Calculate rate code.
* XXX everything at min xmit rate
@ -323,8 +325,15 @@ ath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf)
, 0 /* rts/cts duration */
);
/* NB: beacon's BufLen must be a multiple of 4 bytes */
segLenList[0] = roundup(m->m_len, 4);
segLenList[1] = segLenList[2] = segLenList[3] = 0;
bufAddrList[0] = bf->bf_segs[0].ds_addr;
bufAddrList[1] = bufAddrList[2] = bufAddrList[3] = 0;
ath_hal_filltxdesc(ah, ds
, roundup(m->m_len, 4) /* buffer length */
, bufAddrList
, segLenList
, 0 /* XXX desc id */
, sc->sc_bhalq /* hardware TXQ */
, AH_TRUE /* first segment */
, AH_TRUE /* last segment */
, ds /* first descriptor */

View File

@ -302,6 +302,9 @@ ath_tx_chaindesclist(struct ath_softc *sc, struct ath_buf *bf)
struct ath_hal *ah = sc->sc_ah;
struct ath_desc *ds, *ds0;
int i;
HAL_DMA_ADDR bufAddrList[4];
uint32_t segLenList[4];
/*
* XXX There's txdma and txdma_mgmt; the descriptor
* sizes must match.
@ -313,14 +316,30 @@ ath_tx_chaindesclist(struct ath_softc *sc, struct ath_buf *bf)
*/
ds0 = ds = bf->bf_desc;
for (i = 0; i < bf->bf_nseg; i++, ds++) {
ds->ds_data = bf->bf_segs[i].ds_addr;
bufAddrList[0] = bf->bf_segs[i].ds_addr;
segLenList[0] = bf->bf_segs[i].ds_len;
/* Blank this out until multi-buf support is added for AR9300 */
bufAddrList[1] = bufAddrList[2] = bufAddrList[3] = 0;
segLenList[1] = segLenList[2] = segLenList[3] = 0;
if (i == bf->bf_nseg - 1)
ath_hal_settxdesclink(ah, ds, 0);
else
ath_hal_settxdesclink(ah, ds,
bf->bf_daddr + dd->dd_descsize * (i + 1));
/*
* XXX this assumes that bfs_txq is the actual destination
* hardware queue at this point. It may not have been assigned,
* it may actually be pointing to the multicast software
* TXQ id. These must be fixed!
*/
ath_hal_filltxdesc(ah, ds
, bf->bf_segs[i].ds_len /* segment length */
, bufAddrList
, segLenList
, 0 /* XXX desc id */
, bf->bf_state.bfs_txq->axq_qnum /* XXX multicast? */
, i == 0 /* first segment */
, i == bf->bf_nseg - 1 /* last segment */
, ds0 /* first descriptor */
@ -526,6 +545,20 @@ ath_tx_setds_11n(struct ath_softc *sc, struct ath_buf *bf_first)
DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: end\n", __func__);
}
/*
* Hand-off a frame to the multicast TX queue.
*
* This is a software TXQ which will be appended to the CAB queue
* during the beacon setup code.
*
* XXX TODO: since the AR9300 EDMA TX queue support wants the QCU ID
* as part of the TX descriptor, bf_state.bfs_txq must be updated
* with the actual hardware txq, or all of this will fall apart.
*
* XXX It may not be a bad idea to just stuff the QCU ID into bf_state
* and retire bfs_txq; then make sure the CABQ QCU ID is populated
* correctly.
*/
static void
ath_tx_handoff_mcast(struct ath_softc *sc, struct ath_txq *txq,
struct ath_buf *bf)
@ -1065,6 +1098,11 @@ ath_tx_set_rtscts(struct ath_softc *sc, struct ath_buf *bf)
/*
* Setup the descriptor chain for a normal or fast-frame
* frame.
*
* XXX TODO: extend to include the destination hardware QCU ID.
* Make sure that is correct. Make sure that when being added
* to the mcastq, the CABQ QCUID is set or things will get a bit
* odd.
*/
static void
ath_tx_setds(struct ath_softc *sc, struct ath_buf *bf)
@ -1546,6 +1584,11 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni,
DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: tid=%d, ac=%d, is_ampdu=%d\n",
__func__, tid, pri, is_ampdu);
/* Set local packet state, used to queue packets to hardware */
bf->bf_state.bfs_tid = tid;
bf->bf_state.bfs_txq = txq;
bf->bf_state.bfs_pri = pri;
/*
* When servicing one or more stations in power-save mode
* (or) if there is some mcast data waiting on the mcast
@ -1554,8 +1597,15 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni,
*
* TODO: we should lock the mcastq before we check the length.
*/
if (ismcast && (vap->iv_ps_sta || avp->av_mcastq.axq_depth))
if (ismcast && (vap->iv_ps_sta || avp->av_mcastq.axq_depth)) {
txq = &avp->av_mcastq;
/*
* Mark the frame as eventually belonging on the CAB
* queue, so the descriptor setup functions will
* correctly initialise the descriptor 'qcuId' field.
*/
bf->bf_state.bfs_txq = sc->sc_cabq;
}
/* Do the generic frame setup */
/* XXX should just bzero the bf_state? */
@ -1564,6 +1614,10 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni,
/*
* Acquire the TXQ lock early, so both the encap and seqno
* are allocated together.
*
* XXX should TXQ for CABQ traffic be the multicast queue,
* or the TXQ the given PRI would allocate from? (eg for
* sequence number allocation locking.)
*/
ATH_TXQ_LOCK(txq);
@ -1809,6 +1863,11 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni,
bf->bf_state.bfs_shpream =
!! (params->ibp_flags & IEEE80211_BPF_SHORTPRE);
/* Set local packet state, used to queue packets to hardware */
bf->bf_state.bfs_tid = WME_AC_TO_TID(pri);
bf->bf_state.bfs_txq = sc->sc_ac2q[pri];
bf->bf_state.bfs_pri = pri;
/* XXX this should be done in ath_tx_setrate() */
bf->bf_state.bfs_ctsrate = 0;
bf->bf_state.bfs_ctsduration = 0;
@ -2380,12 +2439,20 @@ ath_tx_tid_seqno_assign(struct ath_softc *sc, struct ieee80211_node *ni,
* Otherwise, schedule it as a single frame.
*/
static void
ath_tx_xmit_aggr(struct ath_softc *sc, struct ath_node *an, struct ath_buf *bf)
ath_tx_xmit_aggr(struct ath_softc *sc, struct ath_node *an,
struct ath_txq *txq, struct ath_buf *bf)
{
struct ath_tid *tid = &an->an_tid[bf->bf_state.bfs_tid];
struct ath_txq *txq = bf->bf_state.bfs_txq;
// struct ath_txq *txq = bf->bf_state.bfs_txq;
struct ieee80211_tx_ampdu *tap;
if (txq != bf->bf_state.bfs_txq) {
device_printf(sc->sc_dev, "%s: txq %d != bfs_txq %d!\n",
__func__,
txq->axq_qnum,
bf->bf_state.bfs_txq->axq_qnum);
}
ATH_TXQ_LOCK_ASSERT(txq);
ATH_TID_LOCK_ASSERT(sc, tid);
@ -2464,6 +2531,8 @@ ath_tx_swq(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_txq *txq,
__func__, bf, pri, tid, IEEE80211_QOS_HAS_SEQ(wh));
/* Set local packet state, used to queue packets to hardware */
/* XXX potentially duplicate info, re-check */
/* XXX remember, txq must be the hardware queue, not the av_mcastq */
bf->bf_state.bfs_tid = tid;
bf->bf_state.bfs_txq = txq;
bf->bf_state.bfs_pri = pri;
@ -2501,7 +2570,7 @@ ath_tx_swq(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_txq *txq,
if (txq->axq_depth < sc->sc_hwq_limit) {
bf = TAILQ_FIRST(&atid->axq_q);
ATH_TXQ_REMOVE(atid, bf, bf_list);
ath_tx_xmit_aggr(sc, an, bf);
ath_tx_xmit_aggr(sc, an, txq, bf);
DPRINTF(sc, ATH_DEBUG_SW_TX,
"%s: xmit_aggr\n",
__func__);

View File

@ -1107,8 +1107,9 @@ void ath_intr(void *);
_txr1, _txtr1, _txr2, _txtr2, _txr3, _txtr3) \
((*(_ah)->ah_setupXTxDesc)((_ah), (_ds), \
(_txr1), (_txtr1), (_txr2), (_txtr2), (_txr3), (_txtr3)))
#define ath_hal_filltxdesc(_ah, _ds, _l, _first, _last, _ds0) \
((*(_ah)->ah_fillTxDesc)((_ah), (_ds), (_l), (_first), (_last), (_ds0)))
#define ath_hal_filltxdesc(_ah, _ds, _b, _l, _did, _qid, _first, _last, _ds0) \
((*(_ah)->ah_fillTxDesc)((_ah), (_ds), (_b), (_l), (_did), (_qid), \
(_first), (_last), (_ds0)))
#define ath_hal_txprocdesc(_ah, _ds, _ts) \
((*(_ah)->ah_procTxDesc)((_ah), (_ds), (_ts)))
#define ath_hal_gettxintrtxqs(_ah, _txqs) \