git: 0a12ff65b964 - main - iwm: add iwm_enable_ac_txq(); use it for command queue setup

From: Adrian Chadd <adrian_at_FreeBSD.org>
Date: Fri, 16 Oct 2026 03:54:19 UTC
The branch main has been updated by adrian:

URL: https://cgit.FreeBSD.org/src/commit/?id=0a12ff65b9647a6e31471e5d27a8692b4adb6803

commit 0a12ff65b9647a6e31471e5d27a8692b4adb6803
Author:     Adrian Chadd <adrian@FreeBSD.org>
AuthorDate: 2026-10-16 03:53:55 +0000
Commit:     Adrian Chadd <adrian@FreeBSD.org>
CommitDate: 2026-10-16 03:53:58 +0000

    iwm: add iwm_enable_ac_txq(); use it for command queue setup
    
    Port iwm_enable_ac_txq() from OpenBSD.  It's effictively the
    command FIFO path in the existing iwm_enable_txq().
    
    The OpenBSD driver does a bunch of TX aggregation queue setup in
    iwm_enable_txq() which isn't relevant here just quite yet and
    it doesn't currently hurt to leave the existing one here
    whilst I figure out the next steps.
    
    Locally tested:
    
    * 3160, 7260, 8260, 9260 - STA mode
    
    Obtained from: OpenBSD a6e25c727a2214219715b51ba6af2221d7e0d674
    
    Differential Revision:  https://reviews.freebsd.org/D60696
---
 sys/dev/iwm/if_iwm.c      | 52 +++++++++++++++++++++++++++++++++++++++++++++--
 sys/dev/iwm/if_iwm_sta.c  | 13 +++++++-----
 sys/dev/iwm/if_iwm_util.h |  1 +
 3 files changed, 59 insertions(+), 7 deletions(-)

diff --git a/sys/dev/iwm/if_iwm.c b/sys/dev/iwm/if_iwm.c
index fef762024c6f..5d911475b6e1 100644
--- a/sys/dev/iwm/if_iwm.c
+++ b/sys/dev/iwm/if_iwm.c
@@ -1701,6 +1701,55 @@ iwm_nic_init(struct iwm_softc *sc)
 	return 0;
 }
 
+int
+iwm_enable_ac_txq(struct iwm_softc *sc, int qid, int fifo)
+{
+	int err;
+
+	if (!sc->cmd_hold_nic_awake) {
+		device_printf(sc->sc_dev, "%s: NIC not awake\n", __func__);
+		return (ENXIO);
+	}
+
+	IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, qid << 8 | 0);
+
+	iwm_write_prph(sc, IWM_SCD_QUEUE_STATUS_BITS(qid),
+	    (0 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE)
+	    | (1 << IWM_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+
+	err = iwm_clear_bits_prph(sc, IWM_SCD_AGGR_SEL, (1 << qid));
+	if (err) {
+		return err;
+	}
+
+	iwm_write_prph(sc, IWM_SCD_QUEUE_RDPTR(qid), 0);
+
+	iwm_write_mem32(sc,
+	    sc->scd_base_addr + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid), 0);
+
+	/* Set scheduler window size and frame limit. */
+	iwm_write_mem32(sc,
+	    sc->scd_base_addr + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid) +
+	    sizeof(uint32_t),
+	    ((IWM_FRAME_LIMIT << IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
+	    IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
+	    ((IWM_FRAME_LIMIT
+		<< IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+	    IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
+
+	iwm_write_prph(sc, IWM_SCD_QUEUE_STATUS_BITS(qid),
+	    (1 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+	    (fifo << IWM_SCD_QUEUE_STTS_REG_POS_TXF) |
+	    (1 << IWM_SCD_QUEUE_STTS_REG_POS_WSL) |
+	    IWM_SCD_QUEUE_STTS_REG_MSK);
+
+	if (qid == sc->cmdqid)
+		iwm_write_prph(sc, IWM_SCD_EN_CTRL,
+		    iwm_read_prph(sc, IWM_SCD_EN_CTRL) | (1 << qid));
+
+	return 0;
+}
+
 int
 iwm_enable_txq(struct iwm_softc *sc, int sta_id, int qid, int fifo)
 {
@@ -1841,8 +1890,7 @@ iwm_trans_pcie_fw_alive(struct iwm_softc *sc, uint32_t scd_base_addr)
 	iwm_nic_unlock(sc);
 
 	/* enable command channel */
-	error = iwm_enable_txq(sc, 0 /* unused */, sc->cmdqid,
-	    IWM_TX_FIFO_CMD);
+	error = iwm_enable_ac_txq(sc, sc->cmdqid, IWM_TX_FIFO_CMD);
 	if (error)
 		return error;
 
diff --git a/sys/dev/iwm/if_iwm_sta.c b/sys/dev/iwm/if_iwm_sta.c
index 1c2725d33f90..902e33a8cc3a 100644
--- a/sys/dev/iwm/if_iwm_sta.c
+++ b/sys/dev/iwm/if_iwm_sta.c
@@ -365,18 +365,21 @@ iwm_add_aux_sta(struct iwm_softc *sc)
 	 * + non-DQA calls iwm_enable_ac_txq(), which does similar stuff to
 	 *   command setup but not the command scheduler
 	 */
-	if (iwm_fw_has_capa(sc, IWM_UCODE_TLV_CAPA_DQA_SUPPORT))
+	if (iwm_fw_has_capa(sc, IWM_UCODE_TLV_CAPA_DQA_SUPPORT)) {
 		qid = IWM_DQA_AUX_QUEUE;
-	else
+		ret = iwm_enable_txq(sc, IWM_AUX_STA_ID, qid,
+		    IWM_TX_FIFO_MCAST);
+	} else {
 		qid = IWM_AUX_QUEUE;
+		ret = iwm_enable_ac_txq(sc, qid, IWM_TX_FIFO_MCAST);
+	}
+	if (ret)
+		return ret;
 
 	sc->sc_aux_sta.sta_id = IWM_AUX_STA_ID;
 	sc->sc_aux_sta.tfd_queue_msk = (1 << qid);
 
 	/* Map Aux queue to fifo - needs to happen before adding Aux station */
-	ret = iwm_enable_txq(sc, IWM_AUX_STA_ID, qid, IWM_TX_FIFO_MCAST);
-	if (ret)
-		return ret;
 
 	ret = iwm_add_int_sta_common(sc, &sc->sc_aux_sta, NULL,
 					 IWM_MAC_INDEX_AUX, 0);
diff --git a/sys/dev/iwm/if_iwm_util.h b/sys/dev/iwm/if_iwm_util.h
index 3512b3bcf8d3..861bcfe95462 100644
--- a/sys/dev/iwm/if_iwm_util.h
+++ b/sys/dev/iwm/if_iwm_util.h
@@ -125,6 +125,7 @@ extern	int iwm_send_lq_cmd(struct iwm_softc *sc, struct iwm_lq_cmd *lq,
 extern	boolean_t iwm_rx_diversity_allowed(struct iwm_softc *sc);
 
 extern	uint8_t iwm_ridx2rate(struct ieee80211_rateset *rs, int ridx);
+extern	int iwm_enable_ac_txq(struct iwm_softc *sc, int qid, int fifo);
 extern	int iwm_enable_txq(struct iwm_softc *sc, int sta_id, int qid, int fifo);
 extern	int iwm_flush_tx_path(struct iwm_softc *sc, uint32_t tfd_msk,
 				  uint32_t flags);