When enabling Tx queues in iwx_enable_data_tx_queues() the driver computes
the Tx queue index as:
int qid = ac + IWX_DQA_AUX_QUEUE + 1;
with:
#define IWX_DQA_AUX_QUEUE 1
In iwx_tx(), we use a different way of computing the Tx queue index,
which is a leftover from iwm(4):
ring = &sc->txq[IWX_DQA_MIN_MGMT_QUEUE + ac];
with:
#define IWX_DQA_MIN_MGMT_QUEUE 5
This kind of bug would usually have severe consequences.
But in this case I got very lucky:
'ac' ranges from 0 to 3, and iwx_tx() always ends up picking Tx queue 5
from the range 5-8 because 'ac' is always passed in as 0 by the caller.
iwx_enable_data_tx_queues() enables Tx queues 2-5 inclusive.
So from the firmware's point of view, Tx queue 5 is enabled and is used
to send frames, and it all just works in spite of the bug.
With this fix, iwx_tx() uses Tx queue 2 and would work correctly for values
of 'ac' other than 0, as intended.
ok?
diff 6fed087d6e00a5c30641d2658d09ced7cb1e3090
1e58df09264b5ea64bbe8f02e26da8b4e738c867
blob - 2f41c5a7c8a943e38bbd69a81d46cf432d329607
blob + 831f4d766af8fbf4e00f3fc0ad1624838869d92e
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -1674,13 +1674,13 @@ iwx_alloc_tx_ring(struct iwx_softc *sc, struct iwx_tx_
*
* In DQA mode we use 1 command queue + 4 DQA mgmt/data queues.
* The command is queue 0 (sc->txq[0]), and 4 mgmt/data frame queues
- * are sc->tqx[IWX_DQA_MIN_MGMT_QUEUE + ac], i.e. sc->txq[5:8],
+ * are sc->tqx[ac + IWX_DQA_AUX_QUEUE + 1], i.e. sc->txq[2:5],
* in order to provide one queue per EDCA category.
*
* Tx aggregation will require additional queues (one queue per TID
* for which aggregation is enabled) but we do not implement this yet.
*/
- if (qid > IWX_DQA_MAX_MGMT_QUEUE)
+ if (qid > IWX_DQA_MIN_MGMT_QUEUE)
return 0;
err = iwx_dma_contig_alloc(sc->sc_dmat, &ring->bc_tbl,
@@ -4246,7 +4246,7 @@ iwx_tx(struct iwx_softc *sc, struct mbuf *m, struct ie
* Tx aggregation will require additional queues (one queue per TID
* for which aggregation is enabled) but we do not implement this yet.
*/
- ring = &sc->txq[IWX_DQA_MIN_MGMT_QUEUE + ac];
+ ring = &sc->txq[ac + IWX_DQA_AUX_QUEUE + 1];
desc = &ring->desc[ring->cur];
memset(desc, 0, sizeof(*desc));
data = &ring->data[ring->cur];