Index | Thread | Search

From:
Kirill A. Korinsky <kirill@korins.ky>
Subject:
The 6th batch of qwz commits
To:
Stefan Sperling <stsp@stsp.name>
Cc:
OpenBSD ports <ports@openbsd.org>
Date:
Thu, 01 Oct 2026 13:29:40 +0200

Download raw body.

Thread
  • Kirill A. Korinsky:

    The 6th batch of qwz commits

Stefan,

here the 6th batch of qwz commits.

It is quite mechanical with exception of one commit where I fix REO layout
to that I had discovered in ath12k, and the next one fixes its lifetime.

It was tested on my device and makes it works better, but I may make typos.

Ok?

From d9ab1f87492f1fb420c1db383b1db95a49954bdf Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:54:40 +0200
Subject: [PATCH 1/7] sys/qwz: update RSSI from TX acknowledgments

Backport of sys/dev/ic/qwx.c,v 1.98
---
 sys/dev/ic/qwz.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index 54f58f1f9ce..e517b9f417a 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -14561,6 +14561,16 @@ qwz_dp_tx_complete_msdu(struct qwz_softc *sc, struct dp_tx_ring *tx_ring,
 	} else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N)
 		tx_data->ni->ni_txmcs = mcs;
 
+	if (ts->status == HAL_WBM_TQM_REL_REASON_FRAME_ACKED &&
+	    ts->ack_rssi != 0) {
+		int8_t rssi_dbm = (int8_t)ts->ack_rssi;
+
+		if (!isset(sc->wmi.svc_map,
+		    WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT))
+			rssi_dbm += ATH12K_DEFAULT_NOISE_FLOOR;
+		tx_data->ni->ni_rssi = rssi_dbm;
+	}
+
 	ieee80211_release_node(ic, tx_data->ni);
 	tx_data->ni = NULL;
 }
-- 
2.55.0


From 444ab6aeef335b30552052c536ad328ffcdac5f5 Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:56:21 +0200
Subject: [PATCH 2/7] sys/qwz: clear node flags during deauthentication

Backport of sys/dev/ic/qwx.c,v 1.113
---
 sys/dev/ic/qwz.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index e517b9f417a..b018119e9ba 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -24388,11 +24388,18 @@ qwz_auth(struct qwz_softc *sc)
 int
 qwz_deauth(struct qwz_softc *sc)
 {
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct qwz_node *nq = (struct qwz_node *)ic->ic_bss;
 	struct qwz_vif *arvif = &sc->sc_vif;
 	uint8_t pdev_id = 0; /* TODO: derive pdev ID somehow? */
 	struct ath12k_peer *peer = TAILQ_FIRST(&sc->peers);
 	int ret;
 
+	if (ic->ic_opmode == IEEE80211_M_STA) {
+		ic->ic_bss->ni_txrate = 0;
+		nq->flags = 0;
+	}
+
 	ret = qwz_mac_vdev_stop(sc, arvif, pdev_id);
 	if (ret) {
 		printf("%s: unable to stop vdev vdev_id %d: %d\n",
-- 
2.55.0


From 941e13bb341b1f37d342a86ac75e363a05d24a4c Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:56:08 +0200
Subject: [PATCH 3/7] sys/qwz: keep data interrupts through association

Backport of sys/dev/ic/qwx.c,v 1.125
---
 sys/dev/ic/qwz.c | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index b018119e9ba..cbe8ad6ff4e 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -250,6 +250,7 @@ qwz_init(struct ifnet *ifp)
 			refcnt_init(&sc->task_refs);
 			ifq_clr_oactive(&ifp->if_snd);
 			ifp->if_flags |= IFF_RUNNING;
+			sc->ops.irq_enable(sc);
 			ieee80211_begin_scan(ifp);
 		}
 		splx(s);
@@ -357,6 +358,7 @@ qwz_init(struct ifnet *ifp)
 		ifq_clr_oactive(&ifp->if_snd);
 		ifp->if_flags |= IFF_RUNNING;
 
+		sc->ops.irq_enable(sc);
 		ieee80211_begin_scan(ifp);
 	}
 
@@ -18969,10 +18971,6 @@ qwz_core_qmi_firmware_ready(struct qwz_softc *sc)
 		goto err_core_stop;
 	}
 
-#if 0 /* TODO: Is this in the right spot for OpenBSD? */
-	sc->ops.irq_enable(sc);
-#endif
-
 #if 0
 	mutex_unlock(&ab->core_lock);
 #endif
@@ -24915,8 +24913,6 @@ qwz_run(struct qwz_softc *sc)
 	DNPRINTF(QWZ_D_MAC, "%s: vdev %d up (associated) bssid %s aid %d\n",
 	    __func__, arvif->vdev_id, ether_sprintf(ni->ni_bssid), arvif->aid);
 
-	/* Enable "ext" IRQs for datapath. */
-	sc->ops.irq_enable(sc);
 
 	return 0;
 }
@@ -24930,8 +24926,6 @@ qwz_run_stop(struct qwz_softc *sc)
 	struct qwz_node *nq = (void *)ic->ic_bss;
 	int ret;
 
-	sc->ops.irq_disable(sc);
-
 	if (ic->ic_opmode == IEEE80211_M_STA) {
 		ic->ic_bss->ni_txrate = 0;
 		nq->flags = 0;
-- 
2.55.0


From 64f0e21feed6cafe1fd93688ed0737247cc467e3 Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:56:11 +0200
Subject: [PATCH 4/7] sys/qwz: prepare peers before association requests

Backport of sys/dev/ic/qwx.c,v 1.94, sys/dev/ic/qwx.c,v 1.118
---
 sys/dev/ic/qwz.c | 60 +++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 52 insertions(+), 8 deletions(-)

diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index cbe8ad6ff4e..7eb5465f5d8 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -180,6 +180,7 @@ int qwz_scan(struct qwz_softc *);
 void qwz_scan_abort(struct qwz_softc *);
 int qwz_auth(struct qwz_softc *);
 int qwz_deauth(struct qwz_softc *);
+int qwz_assoc(struct qwz_softc *);
 int qwz_run(struct qwz_softc *);
 int qwz_run_stop(struct qwz_softc *);
 
@@ -1114,6 +1115,7 @@ next_scan:
 		break;
 
 	case IEEE80211_S_ASSOC:
+		err = qwz_assoc(sc);
 		break;
 
 	case IEEE80211_S_RUN:
@@ -24408,13 +24410,6 @@ qwz_deauth(struct qwz_softc *sc)
 	if (peer == NULL)
 		return 0;
 
-	ret = qwz_wmi_set_peer_param(sc, peer->addr, arvif->vdev_id,
-	    pdev_id, WMI_PEER_AUTHORIZE, 0);
-	if (ret) {
-		printf("%s: unable to deauthorize BSS peer: %d\n",
-		   sc->sc_dev.dv_xname, ret);
-		return ret;
-	}
 
 	ret = qwz_mac_station_remove(sc, arvif, pdev_id, peer);
 	if (ret)
@@ -24798,7 +24793,7 @@ qwz_ampdu_tx_start(struct ieee80211com *ic, struct ieee80211_node *ni,
 }
 
 int
-qwz_run(struct qwz_softc *sc)
+qwz_assoc(struct qwz_softc *sc)
 {
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct ieee80211_node *ni = ic->ic_bss;
@@ -24870,6 +24865,43 @@ qwz_run(struct qwz_softc *sc)
 			return ret;
 		}
 	}
+
+	return 0;
+}
+
+int
+qwz_run(struct qwz_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ieee80211_node *ni = ic->ic_bss;
+	struct qwz_vif *arvif = &sc->sc_vif;
+	uint8_t pdev_id = 0; /* TODO: derive pdev ID somehow? */
+	struct peer_assoc_params peer_arg;
+	int ret;
+
+	qwz_peer_assoc_prepare(sc, arvif, ni, &peer_arg, 1);
+
+	peer_arg.is_assoc = 1;
+
+	sc->peer_assoc_done = 0;
+	ret = qwz_wmi_send_peer_assoc_cmd(sc, pdev_id, &peer_arg);
+	if (ret) {
+		printf("%s: failed to run peer assoc for %s vdev %i: %d\n",
+		    sc->sc_dev.dv_xname, ether_sprintf(ni->ni_macaddr),
+		    arvif->vdev_id, ret);
+		return ret;
+	}
+
+	while (!sc->peer_assoc_done) {
+		ret = tsleep_nsec(&sc->peer_assoc_done, 0, "qwzassoc",
+		    SEC_TO_NSEC(1));
+		if (ret) {
+			printf("%s: failed to get peer assoc conf event "
+			    "for %s vdev %i\n", sc->sc_dev.dv_xname,
+			    ether_sprintf(ni->ni_macaddr), arvif->vdev_id);
+			return ret;
+		}
+	}
 #if 0
 	ret = ath12k_setup_peer_smps(ar, arvif, sta->addr,
 				     &sta->deflink.ht_cap,
@@ -24924,8 +24956,20 @@ qwz_run_stop(struct qwz_softc *sc)
 	struct qwz_vif *arvif = &sc->sc_vif;
 	uint8_t pdev_id = 0; /* TODO: derive pdev ID somehow? */
 	struct qwz_node *nq = (void *)ic->ic_bss;
+	struct ath12k_peer *peer = TAILQ_FIRST(&sc->peers);
 	int ret;
 
+	if (peer != NULL) {
+		ret = qwz_wmi_set_peer_param(sc, peer->addr, arvif->vdev_id,
+		    pdev_id, WMI_PEER_AUTHORIZE, 0);
+		if (ret) {
+			printf("%s: unable to deauthorize BSS peer: %d\n",
+			   sc->sc_dev.dv_xname, ret);
+			return ret;
+		}
+
+	}
+
 	if (ic->ic_opmode == IEEE80211_M_STA) {
 		ic->ic_bss->ni_txrate = 0;
 		nq->flags = 0;
-- 
2.55.0


From b46032b456e356b3befae341d4869c1dd09d5762 Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:56:14 +0200
Subject: [PATCH 5/7] sys/qwz: configure negotiated HT SMPS

Backport of sys/dev/ic/qwx.c,v 1.92
---
 sys/dev/ic/qwz.c | 46 ++++++++++++++++++++++++++++++++++++----------
 1 file changed, 36 insertions(+), 10 deletions(-)

diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index 7eb5465f5d8..24ca756e304 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -24792,6 +24792,33 @@ qwz_ampdu_tx_start(struct ieee80211com *ic, struct ieee80211_node *ni,
 	return 0;
 }
 
+int
+qwz_setup_peer_smps(struct qwz_softc *sc, uint8_t pdev_id, struct qwz_vif *arvif,
+    uint8_t *addr, uint16_t htcaps)
+{
+	uint16_t smps;
+	uint32_t val;
+
+	smps = (htcaps & IEEE80211_HTCAP_SMPS_MASK) >>
+	    IEEE80211_HTCAP_SMPS_SHIFT;
+
+	switch (smps) {
+	case IEEE80211_HTCAP_SMPS_STA:
+		val = WMI_PEER_SMPS_STATIC;
+		break;
+	case IEEE80211_HTCAP_SMPS_DYN:
+		val = WMI_PEER_SMPS_DYNAMIC;
+		break;
+	case IEEE80211_HTCAP_SMPS_DIS:
+	default:
+		val = WMI_PEER_SMPS_PS_NONE;
+		break;
+	}
+
+	return qwz_wmi_set_peer_param(sc, addr, arvif->vdev_id,
+	    pdev_id, WMI_PEER_MIMO_PS_STATE, val);
+}
+
 int
 qwz_assoc(struct qwz_softc *sc)
 {
@@ -24902,15 +24929,16 @@ qwz_run(struct qwz_softc *sc)
 			return ret;
 		}
 	}
-#if 0
-	ret = ath12k_setup_peer_smps(ar, arvif, sta->addr,
-				     &sta->deflink.ht_cap,
-				     le16_to_cpu(sta->deflink.he_6ghz_capa.capa));
-	if (ret) {
-		ath12k_warn(ar->ab, "failed to setup peer SMPS for vdev %d: %d\n",
-			    arvif->vdev_id, ret);
-		return ret;
+	if (ni->ni_flags & IEEE80211_NODE_HT) {
+		ret = qwz_setup_peer_smps(sc, pdev_id, arvif, ni->ni_macaddr,
+		    ni->ni_htcaps);
+		if (ret) {
+			printf("%s: failed to setup SMPS for vdev %d: %d\n",
+			    sc->sc_dev.dv_xname, arvif->vdev_id, ret);
+			return ret;
+		}
 	}
+#if 0
 
 	if (!ath12k_mac_vif_recalc_sta_he_txbf(ar, vif, &he_cap)) {
 		ath12k_warn(ar->ab, "failed to recalc he txbf for vdev %i on bss %pM\n",
@@ -24945,7 +24973,6 @@ qwz_run(struct qwz_softc *sc)
 	DNPRINTF(QWZ_D_MAC, "%s: vdev %d up (associated) bssid %s aid %d\n",
 	    __func__, arvif->vdev_id, ether_sprintf(ni->ni_bssid), arvif->aid);
 
-
 	return 0;
 }
 
@@ -24967,7 +24994,6 @@ qwz_run_stop(struct qwz_softc *sc)
 			   sc->sc_dev.dv_xname, ret);
 			return ret;
 		}
-
 	}
 
 	if (ic->ic_opmode == IEEE80211_M_STA) {
-- 
2.55.0


From 91870f9306624e78301f76272239208560e169e9 Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:57:39 +0200
Subject: [PATCH 6/7] sys/qwz: fix WCN7850 REO layout

Use WCN7850 REO tags and 64-bit TLV headers so commands and completions
use the correct offsets. Correct the status ring size and clear command
payloads before reuse.

The layout follows Linux ath12k's WCN7850 definitions.
---
 sys/dev/ic/qwz.c    | 165 ++++++++++++++++++++++++++------------------
 sys/dev/ic/qwzreg.h |  32 ++++-----
 2 files changed, 113 insertions(+), 84 deletions(-)

diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index 24ca756e304..6d79eec5376 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -8004,7 +8004,7 @@ void
 qwz_hal_reo_init_cmd_ring(struct qwz_softc *sc, struct hal_srng *srng)
 {
 	struct hal_srng_params params;
-	struct hal_tlv_hdr *tlv;
+	struct hal_tlv_64_hdr *tlv;
 	struct hal_reo_get_queue_stats *desc;
 	int i, cmd_num = 1;
 	int entry_size;
@@ -8017,39 +8017,44 @@ qwz_hal_reo_init_cmd_ring(struct qwz_softc *sc, struct hal_srng *srng)
 	entry = (uint8_t *)params.ring_base_vaddr;
 
 	for (i = 0; i < params.num_entries; i++) {
-		tlv = (struct hal_tlv_hdr *)entry;
+		tlv = (struct hal_tlv_64_hdr *)entry;
 		desc = (struct hal_reo_get_queue_stats *)tlv->value;
-		desc->cmd.info0 = FIELD_PREP(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER,
-		    cmd_num++);
+		desc->cmd.info0 = htole32(FIELD_PREP(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER,
+		    cmd_num++));
 		entry += entry_size;
 	}
 }
 
 int
-qwz_hal_reo_cmd_queue_stats(struct hal_tlv_hdr *tlv, struct ath12k_hal_reo_cmd *cmd)
+qwz_hal_reo_cmd_queue_stats(struct hal_tlv_64_hdr *tlv,
+    struct ath12k_hal_reo_cmd *cmd)
 {
 	struct hal_reo_get_queue_stats *desc;
 
-	tlv->tl = FIELD_PREP(HAL_TLV_HDR_TAG, HAL_REO_GET_QUEUE_STATS) |
-	    FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc));
+	tlv->tl = htole64(FIELD_PREP(HAL_TLV_HDR_TAG, HAL_REO_GET_QUEUE_STATS) |
+	    FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc)));
 
 	desc = (struct hal_reo_get_queue_stats *)tlv->value;
+	memset(&desc->queue_addr_lo, 0,
+	    sizeof(*desc) - offsetof(struct hal_reo_get_queue_stats, queue_addr_lo));
 
-	desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
+	desc->cmd.info0 &= ~htole32(HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED);
 	if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS)
-		desc->cmd.info0 |= HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
+		desc->cmd.info0 |= htole32(HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED);
 
-	desc->queue_addr_lo = cmd->addr_lo;
+	desc->queue_addr_lo = htole32(cmd->addr_lo);
 	desc->info0 = FIELD_PREP(HAL_REO_GET_QUEUE_STATS_INFO0_QUEUE_ADDR_HI,
 	    cmd->addr_hi);
 	if (cmd->flag & HAL_REO_CMD_FLG_STATS_CLEAR)
 		desc->info0 |= HAL_REO_GET_QUEUE_STATS_INFO0_CLEAR_STATS;
 
-	return FIELD_GET(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER, desc->cmd.info0);
+	desc->info0 = htole32(desc->info0);
+	return FIELD_GET(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER,
+	    le32toh(desc->cmd.info0));
 }
 
 int
-qwz_hal_reo_cmd_flush_cache(struct ath12k_hal *hal, struct hal_tlv_hdr *tlv,
+qwz_hal_reo_cmd_flush_cache(struct ath12k_hal *hal, struct hal_tlv_64_hdr *tlv,
     struct ath12k_hal_reo_cmd *cmd)
 {
 	struct hal_reo_flush_cache *desc;
@@ -8062,16 +8067,18 @@ qwz_hal_reo_cmd_flush_cache(struct ath12k_hal *hal, struct hal_tlv_hdr *tlv,
 		hal->current_blk_index = avail_slot;
 	}
 
-	tlv->tl = FIELD_PREP(HAL_TLV_HDR_TAG, HAL_REO_FLUSH_CACHE) |
-	    FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc));
+	tlv->tl = htole64(FIELD_PREP(HAL_TLV_HDR_TAG, HAL_REO_FLUSH_CACHE) |
+	    FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc)));
 
 	desc = (struct hal_reo_flush_cache *)tlv->value;
+	memset(&desc->cache_addr_lo, 0,
+	    sizeof(*desc) - offsetof(struct hal_reo_flush_cache, cache_addr_lo));
 
-	desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
+	desc->cmd.info0 &= ~htole32(HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED);
 	if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS)
-		desc->cmd.info0 |= HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
+		desc->cmd.info0 |= htole32(HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED);
 
-	desc->cache_addr_lo = cmd->addr_lo;
+	desc->cache_addr_lo = htole32(cmd->addr_lo);
 	desc->info0 = FIELD_PREP(HAL_REO_FLUSH_CACHE_INFO0_CACHE_ADDR_HI,
 	    cmd->addr_hi);
 
@@ -8091,25 +8098,29 @@ qwz_hal_reo_cmd_flush_cache(struct ath12k_hal *hal, struct hal_tlv_hdr *tlv,
 	if (cmd->flag & HAL_REO_CMD_FLG_FLUSH_ALL)
 		desc->info0 |= HAL_REO_FLUSH_CACHE_INFO0_FLUSH_ALL;
 
-	return FIELD_GET(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER, desc->cmd.info0);
+	desc->info0 = htole32(desc->info0);
+	return FIELD_GET(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER,
+	    le32toh(desc->cmd.info0));
 }
 
 int
-qwz_hal_reo_cmd_update_rx_queue(struct hal_tlv_hdr *tlv,
+qwz_hal_reo_cmd_update_rx_queue(struct hal_tlv_64_hdr *tlv,
     struct ath12k_hal_reo_cmd *cmd)
 {
 	struct hal_reo_update_rx_queue *desc;
 
-	tlv->tl = FIELD_PREP(HAL_TLV_HDR_TAG, HAL_REO_UPDATE_RX_REO_QUEUE) |
-	    FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc));
+	tlv->tl = htole64(FIELD_PREP(HAL_TLV_HDR_TAG, HAL_REO_UPDATE_RX_REO_QUEUE) |
+	    FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc)));
 
 	desc = (struct hal_reo_update_rx_queue *)tlv->value;
+	memset(&desc->queue_addr_lo, 0,
+	    sizeof(*desc) - offsetof(struct hal_reo_update_rx_queue, queue_addr_lo));
 
-	desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
+	desc->cmd.info0 &= ~htole32(HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED);
 	if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS)
-		desc->cmd.info0 |= HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
+		desc->cmd.info0 |= htole32(HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED);
 
-	desc->queue_addr_lo = cmd->addr_lo;
+	desc->queue_addr_lo = htole32(cmd->addr_lo);
 	desc->info0 =
 		FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_QUEUE_ADDR_HI,
 		    cmd->addr_hi) |
@@ -8215,20 +8226,25 @@ qwz_hal_reo_cmd_update_rx_queue(struct hal_tlv_hdr *tlv,
 	    FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO2_PN_ERR,
 	        !!(cmd->upd2 & HAL_REO_CMD_UPD2_PN_ERR));
 
-	return FIELD_GET(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER, desc->cmd.info0);
+	desc->info0 = htole32(desc->info0);
+	desc->info1 = htole32(desc->info1);
+	desc->info2 = htole32(desc->info2);
+	return FIELD_GET(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER,
+	    le32toh(desc->cmd.info0));
 }
 
 int
 qwz_hal_reo_cmd_send(struct qwz_softc *sc, struct hal_srng *srng,
     enum hal_reo_cmd_type type, struct ath12k_hal_reo_cmd *cmd)
 {
-	struct hal_tlv_hdr *reo_desc;
+	struct hal_tlv_64_hdr *reo_desc;
 	int ret;
 #ifdef notyet
 	spin_lock_bh(&srng->lock);
 #endif
 	qwz_hal_srng_access_begin(sc, srng);
-	reo_desc = (struct hal_tlv_hdr *)qwz_hal_srng_src_get_next_entry(sc, srng);
+	reo_desc = (struct hal_tlv_64_hdr *)
+	    qwz_hal_srng_src_get_next_entry(sc, srng);
 	if (!reo_desc) {
 		ret = ENOBUFS;
 		goto out;
@@ -16324,14 +16340,16 @@ void
 qwz_hal_reo_status_queue_stats(struct qwz_softc *sc, uint32_t *reo_desc,
     struct hal_reo_status *status)
 {
-	struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+	struct hal_tlv_64_hdr *tlv = (struct hal_tlv_64_hdr *)reo_desc;
 	struct hal_reo_get_queue_stats_status *desc =
 	    (struct hal_reo_get_queue_stats_status *)tlv->value;
 
 	status->uniform_hdr.cmd_num =
-	    FIELD_GET(HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, desc->hdr.info0);
+	    FIELD_GET(HAL_REO_STATUS_HDR_INFO0_STATUS_NUM,
+	    le32toh(desc->hdr.info0));
 	status->uniform_hdr.cmd_status =
-	    FIELD_GET(HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, desc->hdr.info0);
+	    FIELD_GET(HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS,
+	    le32toh(desc->hdr.info0));
 #if 0
 	ath12k_dbg(ab, ATH12K_DBG_HAL, "Queue stats status:\n");
 	ath12k_dbg(ab, ATH12K_DBG_HAL, "header: cmd_num %d status %d\n",
@@ -16390,16 +16408,16 @@ void
 qwz_hal_reo_flush_queue_status(struct qwz_softc *sc, uint32_t *reo_desc,
     struct hal_reo_status *status)
 {
-	struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+	struct hal_tlv_64_hdr *tlv = (struct hal_tlv_64_hdr *)reo_desc;
 	struct hal_reo_flush_queue_status *desc =
 	    (struct hal_reo_flush_queue_status *)tlv->value;
 
 	status->uniform_hdr.cmd_num = FIELD_GET(
-	   HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, desc->hdr.info0);
+	   HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, le32toh(desc->hdr.info0));
 	status->uniform_hdr.cmd_status = FIELD_GET(
-	    HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, desc->hdr.info0);
+	    HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, le32toh(desc->hdr.info0));
 	status->u.flush_queue.err_detected = FIELD_GET(
-	    HAL_REO_FLUSH_QUEUE_INFO0_ERR_DETECTED, desc->info0);
+	    HAL_REO_FLUSH_QUEUE_INFO0_ERR_DETECTED, le32toh(desc->info0));
 }
 
 void
@@ -16407,37 +16425,39 @@ qwz_hal_reo_flush_cache_status(struct qwz_softc *sc, uint32_t *reo_desc,
     struct hal_reo_status *status)
 {
 	struct ath12k_hal *hal = &sc->hal;
-	struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+	struct hal_tlv_64_hdr *tlv = (struct hal_tlv_64_hdr *)reo_desc;
 	struct hal_reo_flush_cache_status *desc =
 	    (struct hal_reo_flush_cache_status *)tlv->value;
 
 	status->uniform_hdr.cmd_num = FIELD_GET(
-	    HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, desc->hdr.info0);
+	    HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, le32toh(desc->hdr.info0));
 	status->uniform_hdr.cmd_status = FIELD_GET(
-	    HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, desc->hdr.info0);
+	    HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, le32toh(desc->hdr.info0));
 
 	status->u.flush_cache.err_detected = FIELD_GET(
-	    HAL_REO_FLUSH_CACHE_STATUS_INFO0_IS_ERR, desc->info0);
+	    HAL_REO_FLUSH_CACHE_STATUS_INFO0_IS_ERR, le32toh(desc->info0));
 	status->u.flush_cache.err_code = FIELD_GET(
-	    HAL_REO_FLUSH_CACHE_STATUS_INFO0_BLOCK_ERR_CODE, desc->info0);
+	    HAL_REO_FLUSH_CACHE_STATUS_INFO0_BLOCK_ERR_CODE,
+	    le32toh(desc->info0));
 	if (!status->u.flush_cache.err_code)
 		hal->avail_blk_resource |= BIT(hal->current_blk_index);
 
 	status->u.flush_cache.cache_controller_flush_status_hit = FIELD_GET(
-	    HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_STATUS_HIT, desc->info0);
+	    HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_STATUS_HIT,
+	    le32toh(desc->info0));
 
 	status->u.flush_cache.cache_controller_flush_status_desc_type =
 	    FIELD_GET(HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_DESC_TYPE,
-	    desc->info0);
+	    le32toh(desc->info0));
 	status->u.flush_cache.cache_controller_flush_status_client_id =
 	    FIELD_GET(HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_CLIENT_ID,
-	    desc->info0);
+	    le32toh(desc->info0));
 	status->u.flush_cache.cache_controller_flush_status_err =
 	    FIELD_GET(HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_ERR,
-	    desc->info0);
+	    le32toh(desc->info0));
 	status->u.flush_cache.cache_controller_flush_status_cnt =
 	    FIELD_GET(HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_COUNT,
-	    desc->info0);
+	    le32toh(desc->info0));
 }
 
 void
@@ -16445,19 +16465,19 @@ qwz_hal_reo_unblk_cache_status(struct qwz_softc *sc, uint32_t *reo_desc,
     struct hal_reo_status *status)
 {
 	struct ath12k_hal *hal = &sc->hal;
-	struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+	struct hal_tlv_64_hdr *tlv = (struct hal_tlv_64_hdr *)reo_desc;
 	struct hal_reo_unblock_cache_status *desc =
 	   (struct hal_reo_unblock_cache_status *)tlv->value;
 
 	status->uniform_hdr.cmd_num = FIELD_GET(
-	    HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, desc->hdr.info0);
+	    HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, le32toh(desc->hdr.info0));
 	status->uniform_hdr.cmd_status = FIELD_GET(
-	    HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, desc->hdr.info0);
+	    HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, le32toh(desc->hdr.info0));
 
 	status->u.unblock_cache.err_detected = FIELD_GET(
-	    HAL_REO_UNBLOCK_CACHE_STATUS_INFO0_IS_ERR, desc->info0);
+	    HAL_REO_UNBLOCK_CACHE_STATUS_INFO0_IS_ERR, le32toh(desc->info0));
 	status->u.unblock_cache.unblock_type = FIELD_GET(
-	    HAL_REO_UNBLOCK_CACHE_STATUS_INFO0_TYPE, desc->info0);
+	    HAL_REO_UNBLOCK_CACHE_STATUS_INFO0_TYPE, le32toh(desc->info0));
 
 	if (!status->u.unblock_cache.err_detected &&
 	    status->u.unblock_cache.unblock_type ==
@@ -16469,68 +16489,75 @@ void
 qwz_hal_reo_flush_timeout_list_status(struct qwz_softc *ab, uint32_t *reo_desc,
     struct hal_reo_status *status)
 {
-	struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+	struct hal_tlv_64_hdr *tlv = (struct hal_tlv_64_hdr *)reo_desc;
 	struct hal_reo_flush_timeout_list_status *desc =
 	    (struct hal_reo_flush_timeout_list_status *)tlv->value;
 
 	status->uniform_hdr.cmd_num = FIELD_GET(
-	    HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, desc->hdr.info0);
+	    HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, le32toh(desc->hdr.info0));
 	status->uniform_hdr.cmd_status = FIELD_GET(
-	    HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, desc->hdr.info0);
+	    HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, le32toh(desc->hdr.info0));
 
 	status->u.timeout_list.err_detected = FIELD_GET(
-	    HAL_REO_FLUSH_TIMEOUT_STATUS_INFO0_IS_ERR, desc->info0);
+	    HAL_REO_FLUSH_TIMEOUT_STATUS_INFO0_IS_ERR, le32toh(desc->info0));
 	status->u.timeout_list.list_empty = FIELD_GET(
-	    HAL_REO_FLUSH_TIMEOUT_STATUS_INFO0_LIST_EMPTY, desc->info0);
+	    HAL_REO_FLUSH_TIMEOUT_STATUS_INFO0_LIST_EMPTY,
+	    le32toh(desc->info0));
 
 	status->u.timeout_list.release_desc_cnt = FIELD_GET(
-	    HAL_REO_FLUSH_TIMEOUT_STATUS_INFO1_REL_DESC_COUNT, desc->info1);
+	    HAL_REO_FLUSH_TIMEOUT_STATUS_INFO1_REL_DESC_COUNT,
+	    le32toh(desc->info1));
 	status->u.timeout_list.fwd_buf_cnt = FIELD_GET(
-	    HAL_REO_FLUSH_TIMEOUT_STATUS_INFO1_FWD_BUF_COUNT, desc->info1);
+	    HAL_REO_FLUSH_TIMEOUT_STATUS_INFO1_FWD_BUF_COUNT,
+	    le32toh(desc->info1));
 }
 
 void
 qwz_hal_reo_desc_thresh_reached_status(struct qwz_softc *sc, uint32_t *reo_desc,
     struct hal_reo_status *status)
 {
-	struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+	struct hal_tlv_64_hdr *tlv = (struct hal_tlv_64_hdr *)reo_desc;
 	struct hal_reo_desc_thresh_reached_status *desc =
 	    (struct hal_reo_desc_thresh_reached_status *)tlv->value;
 
 	status->uniform_hdr.cmd_num = FIELD_GET(
-	    HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, desc->hdr.info0);
+	    HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, le32toh(desc->hdr.info0));
 	status->uniform_hdr.cmd_status = FIELD_GET(
-	    HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, desc->hdr.info0);
+	    HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, le32toh(desc->hdr.info0));
 
 	status->u.desc_thresh_reached.threshold_idx = FIELD_GET(
-	    HAL_REO_DESC_THRESH_STATUS_INFO0_THRESH_INDEX, desc->info0);
+	    HAL_REO_DESC_THRESH_STATUS_INFO0_THRESH_INDEX,
+	    le32toh(desc->info0));
 
 	status->u.desc_thresh_reached.link_desc_counter0 = FIELD_GET(
-	    HAL_REO_DESC_THRESH_STATUS_INFO1_LINK_DESC_COUNTER0, desc->info1);
+	    HAL_REO_DESC_THRESH_STATUS_INFO1_LINK_DESC_COUNTER0,
+	    le32toh(desc->info1));
 
 	status->u.desc_thresh_reached.link_desc_counter1 = FIELD_GET(
-	    HAL_REO_DESC_THRESH_STATUS_INFO2_LINK_DESC_COUNTER1, desc->info2);
+	    HAL_REO_DESC_THRESH_STATUS_INFO2_LINK_DESC_COUNTER1,
+	    le32toh(desc->info2));
 
 	status->u.desc_thresh_reached.link_desc_counter2 = FIELD_GET(
-	    HAL_REO_DESC_THRESH_STATUS_INFO3_LINK_DESC_COUNTER2, desc->info3);
+	    HAL_REO_DESC_THRESH_STATUS_INFO3_LINK_DESC_COUNTER2,
+	    le32toh(desc->info3));
 
 	status->u.desc_thresh_reached.link_desc_counter_sum = FIELD_GET(
 	    HAL_REO_DESC_THRESH_STATUS_INFO4_LINK_DESC_COUNTER_SUM,
-	    desc->info4);
+	    le32toh(desc->info4));
 }
 
 void
 qwz_hal_reo_update_rx_reo_queue_status(struct qwz_softc *ab, uint32_t *reo_desc,
     struct hal_reo_status *status)
 {
-	struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+	struct hal_tlv_64_hdr *tlv = (struct hal_tlv_64_hdr *)reo_desc;
 	struct hal_reo_status_hdr *desc =
 	    (struct hal_reo_status_hdr *)tlv->value;
 
 	status->uniform_hdr.cmd_num = FIELD_GET(
-	    HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, desc->info0);
+	    HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, le32toh(desc->info0));
 	status->uniform_hdr.cmd_status = FIELD_GET(
-	    HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, desc->info0);
+	    HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, le32toh(desc->info0));
 }
 
 int
@@ -16541,6 +16568,7 @@ qwz_dp_process_reo_status(struct qwz_softc *sc)
 	struct dp_reo_cmd *cmd, *tmp;
 	int found = 0, ret = 0;
 	uint32_t *reo_desc;
+	struct hal_tlv_64_hdr *tlv;
 	uint16_t tag;
 	struct hal_reo_status reo_status;
 
@@ -16554,7 +16582,8 @@ qwz_dp_process_reo_status(struct qwz_softc *sc)
 	while ((reo_desc = qwz_hal_srng_dst_get_next_entry(sc, srng))) {
 		ret = 1;
 
-		tag = FIELD_GET(HAL_SRNG_TLV_HDR_TAG, *reo_desc);
+		tlv = (struct hal_tlv_64_hdr *)reo_desc;
+		tag = FIELD_GET(HAL_SRNG_TLV_HDR_TAG, le64toh(tlv->tl));
 		switch (tag) {
 		case HAL_REO_GET_QUEUE_STATS_STATUS:
 			qwz_hal_reo_status_queue_stats(sc, reo_desc,
diff --git a/sys/dev/ic/qwzreg.h b/sys/dev/ic/qwzreg.h
index 602fc4de356..a71db13cbb4 100644
--- a/sys/dev/ic/qwzreg.h
+++ b/sys/dev/ic/qwzreg.h
@@ -7888,7 +7888,7 @@ enum hal_tlv_tag {
 	HAL_MPDU_INFO                          = 150 /* 0x96 */,
 	HAL_PDG_USER_SETUP                     = 151 /* 0x97 */,
 	HAL_TX_11AH_SETUP                      = 152 /* 0x98 */,
-	HAL_REO_UPDATE_RX_REO_QUEUE_STATUS     = 153 /* 0x99 */,
+	HAL_REO_UPDATE_RX_REO_QUEUE_STATUS     = 172 /* 0xac */,
 	HAL_TX_PEER_ENTRY                      = 154 /* 0x9a */,
 	HAL_TX_RAW_OR_NATIVE_FRAME_SETUP       = 155 /* 0x9b */,
 	HAL_EXAMPLE_STRUCT_NAME                = 156 /* 0x9c */,
@@ -8041,15 +8041,15 @@ enum hal_tlv_tag {
 	HAL_NO_ACK_REPORT                      = 303 /* 0x12f */,
 	HAL_ACK_REPORT                         = 304 /* 0x130 */,
 	HAL_UNIFORM_REO_CMD_HEADER             = 305 /* 0x131 */,
-	HAL_REO_GET_QUEUE_STATS                = 306 /* 0x132 */,
-	HAL_REO_FLUSH_QUEUE                    = 307 /* 0x133 */,
-	HAL_REO_FLUSH_CACHE                    = 308 /* 0x134 */,
-	HAL_REO_UNBLOCK_CACHE                  = 309 /* 0x135 */,
+	HAL_REO_GET_QUEUE_STATS                = 281 /* 0x119 */,
+	HAL_REO_FLUSH_QUEUE                    = 282 /* 0x11a */,
+	HAL_REO_FLUSH_CACHE                    = 283 /* 0x11b */,
+	HAL_REO_UNBLOCK_CACHE                  = 284 /* 0x11c */,
 	HAL_UNIFORM_REO_STATUS_HEADER          = 310 /* 0x136 */,
-	HAL_REO_GET_QUEUE_STATS_STATUS         = 311 /* 0x137 */,
-	HAL_REO_FLUSH_QUEUE_STATUS             = 312 /* 0x138 */,
-	HAL_REO_FLUSH_CACHE_STATUS             = 313 /* 0x139 */,
-	HAL_REO_UNBLOCK_CACHE_STATUS           = 314 /* 0x13a */,
+	HAL_REO_GET_QUEUE_STATS_STATUS         = 285 /* 0x11d */,
+	HAL_REO_FLUSH_QUEUE_STATUS             = 286 /* 0x11e */,
+	HAL_REO_FLUSH_CACHE_STATUS             = 287 /* 0x11f */,
+	HAL_REO_UNBLOCK_CACHE_STATUS           = 288 /* 0x120 */,
 	HAL_TQM_FLUSH_CACHE                    = 315 /* 0x13b */,
 	HAL_TQM_UNBLOCK_CACHE                  = 316 /* 0x13c */,
 	HAL_TQM_FLUSH_CACHE_STATUS             = 317 /* 0x13d */,
@@ -8076,11 +8076,11 @@ enum hal_tlv_tag {
 	HAL_TQM_SYNC_CMD_STATUS                = 338 /* 0x152 */,
 	HAL_TQM_THRESHOLD_DROP_NOTIFICATION_STATUS = 339 /* 0x153 */,
 	HAL_TQM_DESCRIPTOR_THRESHOLD_REACHED_STATUS = 340 /* 0x154 */,
-	HAL_REO_FLUSH_TIMEOUT_LIST             = 341 /* 0x155 */,
-	HAL_REO_FLUSH_TIMEOUT_LIST_STATUS      = 342 /* 0x156 */,
+	HAL_REO_FLUSH_TIMEOUT_LIST             = 305 /* 0x131 */,
+	HAL_REO_FLUSH_TIMEOUT_LIST_STATUS      = 306 /* 0x132 */,
 	HAL_REO_TO_PPE_RING                    = 343 /* 0x157 */,
 	HAL_RX_MPDU_INFO                       = 344 /* 0x158 */,
-	HAL_REO_DESCRIPTOR_THRESHOLD_REACHED_STATUS = 345 /* 0x159 */,
+	HAL_REO_DESCRIPTOR_THRESHOLD_REACHED_STATUS = 307 /* 0x133 */,
 	HAL_SCHEDULER_RX_SIFS_RESPONSE_TRIGGER_STATUS = 346 /* 0x15a */,
 	HAL_EXAMPLE_USER_TLV_32_NAME           = 347 /* 0x15b */,
 	HAL_RX_PPDU_START_USER_INFO            = 348 /* 0x15c */,
@@ -8154,7 +8154,7 @@ enum hal_tlv_tag {
 	HAL_TQM_UPDATE_TX_MPDU_QUEUE_HEAD      = 416 /* 0x1a0 */,
 	HAL_TQM_UPDATE_TX_MSDU_FLOW_STATUS     = 417 /* 0x1a1 */,
 	HAL_TQM_UPDATE_TX_MPDU_QUEUE_HEAD_STATUS = 418 /* 0x1a2 */,
-	HAL_REO_UPDATE_RX_REO_QUEUE            = 419 /* 0x1a3 */,
+	HAL_REO_UPDATE_RX_REO_QUEUE            = 339 /* 0x153 */,
 	HAL_CE_DST_DESC			       = 420 /* 0x1a4 */,
 	HAL_TLV_BASE                           = 511 /* 0x1ff */,
 };
@@ -10163,7 +10163,7 @@ struct hal_reo_status_hdr {
  *		enum %HAL_REO_EXEC_STATUS_.
  */
 #define HAL_REO_GET_QUEUE_STATS_STATUS_INFO0_SSN		GENMASK(11, 0)
-#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO0_CUR_IDX		GENMASK(19, 12)
+#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO0_CUR_IDX		GENMASK(21, 12)
 
 #define HAL_REO_GET_QUEUE_STATS_STATUS_INFO1_MPDU_COUNT		GENMASK(6, 0)
 #define HAL_REO_GET_QUEUE_STATS_STATUS_INFO1_MSDU_COUNT		GENMASK(31, 7)
@@ -10177,7 +10177,7 @@ struct hal_reo_status_hdr {
 
 #define HAL_REO_GET_QUEUE_STATS_STATUS_INFO4_LATE_RX_MPDU	GENMASK(11, 0)
 #define HAL_REO_GET_QUEUE_STATS_STATUS_INFO4_WINDOW_JMP2K	GENMASK(15, 12)
-#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO4_HOLE_COUNT		GENMASK(31, 16)
+#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO4_HOLE_COUNT		GENMASK(27, 12)
 
 #define HAL_REO_GET_QUEUE_STATS_STATUS_INFO5_LOOPING_CNT	GENMASK(31, 28)
 
@@ -10187,7 +10187,7 @@ struct hal_reo_get_queue_stats_status {
 	uint32_t pn[4];
 	uint32_t last_rx_enqueue_timestamp;
 	uint32_t last_rx_dequeue_timestamp;
-	uint32_t rx_bitmap[8];
+	uint32_t rx_bitmap[9];
 	uint32_t info1;
 	uint32_t info2;
 	uint32_t info3;
-- 
2.55.0


From c64ddb4c420cc7487c97acda497a0491099d6b1a Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:57:48 +0200
Subject: [PATCH 7/7] sys/qwz: fix REO queue lifetime

Track REO completions before publication and wait for peer unmap,
deletion, and cache flushes before reusing queue DMA. Submission errors
and timeouts retain ownership; hardware failures block reuse until cold
cleanup. HAL error conventions and flush semantics follow ath12k;
tracking and the reuse barrier adapt qwz's retained pool.
---
 sys/dev/ic/qwz.c    | 328 +++++++++++++++++++++++---------------------
 sys/dev/ic/qwzvar.h |  24 ++--
 2 files changed, 181 insertions(+), 171 deletions(-)

diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index 6d79eec5376..3e93b6bb40d 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -169,6 +169,7 @@ int qwz_dp_rx_h_null_q_desc(struct qwz_softc *, struct qwz_rx_msdu *,
     struct qwz_rx_msdu_list *);
 void qwz_dp_service_mon_ring(void *);
 void qwz_peer_frags_flush(struct qwz_softc *, struct ath12k_peer *);
+int qwz_peer_rx_tid_cleanup(struct qwz_softc *, struct ath12k_peer *);
 int qwz_wmi_vdev_install_key(struct qwz_softc *,
     struct wmi_vdev_install_key_arg *, uint8_t);
 int qwz_dp_peer_rx_pn_replay_config(struct qwz_softc *, struct qwz_vif *,
@@ -8062,7 +8063,7 @@ qwz_hal_reo_cmd_flush_cache(struct ath12k_hal *hal, struct hal_tlv_64_hdr *tlv,
 
 	if (cmd->flag & HAL_REO_CMD_FLG_FLUSH_BLOCK_LATER) {
 		if (avail_slot >= HAL_MAX_AVAIL_BLK_RES)
-			return ENOSPC;
+			return -ENOSPC;
 
 		hal->current_blk_index = avail_slot;
 	}
@@ -8235,18 +8236,23 @@ qwz_hal_reo_cmd_update_rx_queue(struct hal_tlv_64_hdr *tlv,
 
 int
 qwz_hal_reo_cmd_send(struct qwz_softc *sc, struct hal_srng *srng,
-    enum hal_reo_cmd_type type, struct ath12k_hal_reo_cmd *cmd)
+    enum hal_reo_cmd_type type, struct ath12k_hal_reo_cmd *cmd,
+    struct dp_reo_cmd *dp_cmd)
 {
 	struct hal_tlv_64_hdr *reo_desc;
+	struct dp_reo_cmd *pending;
+	uint32_t hp, reap_hp;
 	int ret;
 #ifdef notyet
 	spin_lock_bh(&srng->lock);
 #endif
 	qwz_hal_srng_access_begin(sc, srng);
+	hp = srng->u.src_ring.hp;
+	reap_hp = srng->u.src_ring.reap_hp;
 	reo_desc = (struct hal_tlv_64_hdr *)
 	    qwz_hal_srng_src_get_next_entry(sc, srng);
 	if (!reo_desc) {
-		ret = ENOBUFS;
+		ret = -ENOBUFS;
 		goto out;
 	}
 
@@ -8265,15 +8271,35 @@ qwz_hal_reo_cmd_send(struct qwz_softc *sc, struct hal_srng *srng,
 	case HAL_REO_CMD_FLUSH_TIMEOUT_LIST:
 		printf("%s: unsupported reo command %d\n",
 		   sc->sc_dev.dv_xname, type);
-		ret = ENOTSUP;
+		ret = -ENOTSUP;
 		break;
 	default:
 		printf("%s: unknown reo command %d\n",
 		    sc->sc_dev.dv_xname, type);
-		ret = EINVAL;
+		ret = -EINVAL;
 		break;
 	}
 
+	if (ret <= 0) {
+		if (ret == 0)
+			ret = -EINVAL;
+		goto rollback;
+	}
+	TAILQ_FOREACH(pending, &sc->dp.reo_cmd_list, entry) {
+		if (pending->cmd_num == ret) {
+			ret = -EBUSY;
+			goto rollback;
+		}
+	}
+	if (dp_cmd != NULL) {
+		dp_cmd->cmd_num = ret;
+		TAILQ_INSERT_TAIL(&sc->dp.reo_cmd_list, dp_cmd, entry);
+	}
+	goto out;
+
+rollback:
+	srng->u.src_ring.hp = hp;
+	srng->u.src_ring.reap_hp = reap_hp;
 out:
 	qwz_hal_srng_access_end(sc, srng);
 #ifdef notyet
@@ -8994,13 +9020,11 @@ qwz_dp_alloc(struct qwz_softc *sc)
 	dp->sc = sc;
 
 	TAILQ_INIT(&dp->reo_cmd_list);
-	TAILQ_INIT(&dp->reo_cmd_cache_flush_list);
 #if 0
 	INIT_LIST_HEAD(&dp->dp_full_mon_mpdu_list);
 	spin_lock_init(&dp->reo_cmd_lock);
 #endif
 
-	dp->reo_cmd_cache_flush_count = 0;
 	dp->idle_link_rbm = qwz_dp_get_idle_link_rbm(sc);
 
 	ret = qwz_wbm_idle_ring_setup(sc, &n_link_desc);
@@ -9108,7 +9132,6 @@ qwz_dp_reo_cmd_list_cleanup(struct qwz_softc *sc)
 {
 	struct qwz_dp *dp = &sc->dp;
 	struct dp_reo_cmd *cmd, *tmp;
-	struct dp_reo_cache_flush_elem *cmd_cache, *tmp_cache;
 	struct dp_rx_tid *rx_tid;
 #ifdef notyet
 	spin_lock_bh(&dp->reo_cmd_lock);
@@ -9119,15 +9142,6 @@ qwz_dp_reo_cmd_list_cleanup(struct qwz_softc *sc)
 		qwz_dp_rx_tid_clear(sc, rx_tid);
 		free(cmd, M_DEVBUF, sizeof(*cmd));
 	}
-
-	TAILQ_FOREACH_SAFE(cmd_cache, &dp->reo_cmd_cache_flush_list,
-	    entry, tmp_cache) {
-		TAILQ_REMOVE(&dp->reo_cmd_cache_flush_list, cmd_cache, entry);
-		dp->reo_cmd_cache_flush_count--;
-		rx_tid = &cmd_cache->data;
-		qwz_dp_rx_tid_clear(sc, rx_tid);
-		free(cmd_cache, M_DEVBUF, sizeof(*cmd_cache));
-	}
 #ifdef notyet
 	spin_unlock_bh(&dp->reo_cmd_lock);
 #endif
@@ -9169,6 +9183,8 @@ qwz_dp_free(struct qwz_softc *sc)
 		}
 	}
 
+	memset(dp->rx_tid_retire, 0, sizeof(dp->rx_tid_retire));
+
 	/* Deinit any SOC level resource */
 }
 
@@ -16573,7 +16589,6 @@ qwz_dp_process_reo_status(struct qwz_softc *sc)
 	struct hal_reo_status reo_status;
 
 	srng = &sc->hal.srng_list[dp->reo_status_ring.ring_id];
-	memset(&reo_status, 0, sizeof(reo_status));
 #ifdef notyet
 	spin_lock_bh(&srng->lock);
 #endif
@@ -16581,6 +16596,7 @@ qwz_dp_process_reo_status(struct qwz_softc *sc)
 
 	while ((reo_desc = qwz_hal_srng_dst_get_next_entry(sc, srng))) {
 		ret = 1;
+		memset(&reo_status, 0, sizeof(reo_status));
 
 		tlv = (struct hal_tlv_64_hdr *)reo_desc;
 		tag = FIELD_GET(HAL_SRNG_TLV_HDR_TAG, le64toh(tlv->tl));
@@ -16596,6 +16612,10 @@ qwz_dp_process_reo_status(struct qwz_softc *sc)
 		case HAL_REO_FLUSH_CACHE_STATUS:
 			qwz_hal_reo_flush_cache_status(sc, reo_desc,
 			    &reo_status);
+			if (reo_status.u.flush_cache.err_detected ||
+			    reo_status.u.flush_cache.err_code ||
+			    reo_status.u.flush_cache.cache_controller_flush_status_err)
+				reo_status.uniform_hdr.cmd_status = HAL_REO_CMD_FAILED;
 			break;
 		case HAL_REO_UNBLOCK_CACHE_STATUS:
 			qwz_hal_reo_unblk_cache_status(sc, reo_desc,
@@ -16632,8 +16652,9 @@ qwz_dp_process_reo_status(struct qwz_softc *sc)
 		spin_unlock_bh(&dp->reo_cmd_lock);
 #endif
 		if (found) {
-			cmd->handler(dp, (void *)&cmd->data,
-			    reo_status.uniform_hdr.cmd_status);
+			if (cmd->handler != NULL)
+				cmd->handler(dp, (void *)&cmd->data,
+				    reo_status.uniform_hdr.cmd_status);
 			free(cmd, M_DEVBUF, sizeof(*cmd));
 		}
 		found = 0;
@@ -22609,6 +22630,13 @@ qwz_peer_delete(struct qwz_softc *sc, uint32_t vdev_id, uint8_t pdev_id,
 		}
 	}
 
+	ret = qwz_peer_rx_tid_cleanup(sc, peer);
+	if (ret) {
+		printf("%s: failed to retire peer RX queues: %d\n",
+		    sc->sc_dev.dv_xname, ret);
+		return ret;
+	}
+
 	TAILQ_REMOVE(&sc->peers, peer, entry);
 	qwz_node_clear_peer_id(sc, peer);
 	free(peer, M_DEVBUF, sizeof(*peer));
@@ -22673,44 +22701,27 @@ qwz_dp_tx_send_reo_cmd(struct qwz_softc *sc, struct dp_rx_tid *rx_tid,
     void (*cb)(struct qwz_dp *, void *, enum hal_reo_cmd_status))
 {
 	struct qwz_dp *dp = &sc->dp;
-	struct dp_reo_cmd *dp_cmd;
+	struct dp_reo_cmd *dp_cmd = NULL;
 	struct hal_srng *cmd_ring;
 	int cmd_num;
 
 	if (test_bit(ATH12K_FLAG_CRASH_FLUSH, sc->sc_flags))
 		return ESHUTDOWN;
 
-	cmd_ring = &sc->hal.srng_list[dp->reo_cmd_ring.ring_id];
-	cmd_num = qwz_hal_reo_cmd_send(sc, cmd_ring, type, cmd);
-	/* cmd_num should start from 1, during failure return the error code */
-	if (cmd_num < 0)
-		return cmd_num;
-
-	/* reo cmd ring descriptors has cmd_num starting from 1 */
-	if (cmd_num == 0)
-		return EINVAL;
-
-	if (!cb)
-		return 0;
-
-	/* Can this be optimized so that we keep the pending command list only
-	 * for tid delete command to free up the resource on the command status
-	 * indication?
-	 */
-	dp_cmd = malloc(sizeof(*dp_cmd), M_DEVBUF, M_ZERO | M_NOWAIT);
-	if (!dp_cmd)
-		return ENOMEM;
+	if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS) {
+		dp_cmd = malloc(sizeof(*dp_cmd), M_DEVBUF, M_ZERO | M_NOWAIT);
+		if (dp_cmd == NULL)
+			return ENOMEM;
+		memcpy(&dp_cmd->data, rx_tid, sizeof(*rx_tid));
+		dp_cmd->handler = cb;
+	}
 
-	memcpy(&dp_cmd->data, rx_tid, sizeof(struct dp_rx_tid));
-	dp_cmd->cmd_num = cmd_num;
-	dp_cmd->handler = cb;
-#ifdef notyet
-	spin_lock_bh(&dp->reo_cmd_lock);
-#endif
-	TAILQ_INSERT_TAIL(&dp->reo_cmd_list, dp_cmd, entry);
-#ifdef notyet
-	spin_unlock_bh(&dp->reo_cmd_lock);
-#endif
+	cmd_ring = &sc->hal.srng_list[dp->reo_cmd_ring.ring_id];
+	cmd_num = qwz_hal_reo_cmd_send(sc, cmd_ring, type, cmd, dp_cmd);
+	if (cmd_num < 0) {
+		free(dp_cmd, M_DEVBUF, sizeof(*dp_cmd));
+		return -cmd_num;
+	}
 	return 0;
 }
 
@@ -22825,141 +22836,131 @@ qwz_hal_reo_qdesc_setup(void *vaddr, int tid, uint32_t ba_window_size,
 }
 
 void
-qwz_dp_reo_cmd_free(struct qwz_dp *dp, void *ctx,
+qwz_dp_rx_tid_retire_done(struct qwz_dp *dp, void *ctx,
     enum hal_reo_cmd_status status)
 {
-	struct qwz_softc *sc = dp->sc;
 	struct dp_rx_tid *rx_tid = ctx;
-
-	if (status != HAL_REO_CMD_SUCCESS)
-		printf("%s: failed to flush rx tid hw desc, tid %d status %d\n",
-		    sc->sc_dev.dv_xname, rx_tid->tid, status);
-
-	qwz_dp_rx_tid_clear(sc, rx_tid);
+	struct qwz_rx_tid_retire *retire = &dp->rx_tid_retire[rx_tid->tid];
+
+	KASSERT(retire->data.mem == rx_tid->mem);
+	KASSERT(retire->state == QWZ_RX_TID_DELETE_PENDING ||
+	    retire->state == QWZ_RX_TID_FLUSH_PENDING);
+
+	if (status != HAL_REO_CMD_SUCCESS) {
+		retire->state = QWZ_RX_TID_RETIRE_FAILED;
+		printf("%s: RX queue retirement failed, tid %u status %d\n",
+		    dp->sc->sc_dev.dv_xname, rx_tid->tid, status);
+	} else if (retire->state == QWZ_RX_TID_DELETE_PENDING) {
+		retire->flush_offset = retire->data.size;
+		retire->state = QWZ_RX_TID_FLUSH_READY;
+	} else if (retire->flush_offset != 0) {
+		retire->state = QWZ_RX_TID_FLUSH_READY;
+	} else {
+		memset(retire, 0, sizeof(*retire));
+	}
+	wakeup(dp->rx_tid_retire);
 }
 
-void
-qwz_dp_reo_cache_flush(struct qwz_softc *sc, struct dp_rx_tid *rx_tid)
+int
+qwz_dp_rx_tid_retire_submit(struct qwz_softc *sc,
+    struct qwz_rx_tid_retire *retire)
 {
 	struct ath12k_hal_reo_cmd cmd = {0};
-	unsigned long tot_desc_sz, desc_sz;
+	enum qwz_rx_tid_retire_state state = retire->state;
+	enum hal_reo_cmd_type type;
+	uint32_t offset = retire->flush_offset;
+	uint64_t paddr = retire->data.paddr;
 	int ret;
 
-	tot_desc_sz = rx_tid->size;
-	desc_sz = qwz_hal_reo_qdesc_size(0, HAL_DESC_REO_NON_QOS_TID);
-
-	while (tot_desc_sz > desc_sz) {
-		tot_desc_sz -= desc_sz;
-		cmd.addr_lo = (rx_tid->paddr + tot_desc_sz) & 0xffffffff;
-		cmd.addr_hi = rx_tid->paddr >> 32;
-		ret = qwz_dp_tx_send_reo_cmd(sc, rx_tid,
-		    HAL_REO_CMD_FLUSH_CACHE, &cmd, NULL);
-		if (ret) {
-			printf("%s: failed to send HAL_REO_CMD_FLUSH_CACHE, "
-			    "tid %d (%d)\n", sc->sc_dev.dv_xname, rx_tid->tid,
-			    ret);
-		}
-	}
-
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.addr_lo = rx_tid->paddr & 0xffffffff;
-	cmd.addr_hi = rx_tid->paddr >> 32;
-	cmd.flag |= HAL_REO_CMD_FLG_NEED_STATUS;
-	ret = qwz_dp_tx_send_reo_cmd(sc, rx_tid, HAL_REO_CMD_FLUSH_CACHE,
-	    &cmd, qwz_dp_reo_cmd_free);
+	cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS;
+	if (state == QWZ_RX_TID_DELETE_READY) {
+		/* WCN7850 requires VLD to remain set until the cache flush. */
+		cmd.upd0 = HAL_REO_CMD_UPD0_VLD;
+		cmd.upd1 = HAL_REO_CMD_UPD1_VLD;
+		type = HAL_REO_CMD_UPDATE_RX_QUEUE;
+		retire->state = QWZ_RX_TID_DELETE_PENDING;
+	} else {
+		KASSERT(state == QWZ_RX_TID_FLUSH_READY);
+		KASSERT(offset >= sizeof(struct hal_rx_reo_queue));
+		retire->flush_offset -= sizeof(struct hal_rx_reo_queue);
+		paddr += retire->flush_offset;
+		if (retire->flush_offset == 0)
+			cmd.flag |= HAL_REO_CMD_FLG_FLUSH_FWD_ALL_MPDUS;
+		type = HAL_REO_CMD_FLUSH_CACHE;
+		retire->state = QWZ_RX_TID_FLUSH_PENDING;
+	}
+	cmd.addr_lo = paddr & 0xffffffff;
+	cmd.addr_hi = paddr >> 32;
+	ret = qwz_dp_tx_send_reo_cmd(sc, &retire->data, type, &cmd,
+	    qwz_dp_rx_tid_retire_done);
 	if (ret) {
-		printf("%s: failed to send HAL_REO_CMD_FLUSH_CACHE cmd, "
-		    "tid %d (%d)\n", sc->sc_dev.dv_xname, rx_tid->tid, ret);
-		qwz_dp_rx_tid_clear(sc, rx_tid);
+		retire->state = state;
+		retire->flush_offset = offset;
 	}
+	return ret;
 }
 
-void
-qwz_dp_rx_tid_del_func(struct qwz_dp *dp, void *ctx,
-    enum hal_reo_cmd_status status)
+int
+qwz_dp_rx_tid_retire_wait(struct qwz_softc *sc)
 {
-	struct qwz_softc *sc = dp->sc;
-	struct dp_rx_tid *rx_tid = ctx;
-	struct dp_reo_cache_flush_elem *elem, *tmp;
+	struct qwz_dp *dp = &sc->dp;
+	struct qwz_rx_tid_retire *retire;
+	uint64_t deadline = getnsecuptime() + SEC_TO_NSEC(3);
 	uint64_t now;
+	int i, pending, error, ret;
 
-	if (status == HAL_REO_CMD_DRAIN) {
-		qwz_dp_rx_tid_clear(sc, rx_tid);
-		return;
-	} else if (status != HAL_REO_CMD_SUCCESS) {
-		/* Shouldn't happen! Cleanup in case of other failure? */
-		printf("%s: failed to delete rx tid %d hw descriptor %d\n",
-		    sc->sc_dev.dv_xname, rx_tid->tid, status);
-		return;
-	}
-
-	elem = malloc(sizeof(*elem), M_DEVBUF, M_ZERO | M_NOWAIT);
-	if (!elem) {
-		qwz_dp_rx_tid_clear(sc, rx_tid);
-		return;
-	}
-
-	now = getnsecuptime();
-	elem->ts = now;
-	memcpy(&elem->data, rx_tid, sizeof(*rx_tid));
-
-	qwz_dp_rx_tid_clear(sc, rx_tid);
-
-#ifdef notyet
-	spin_lock_bh(&dp->reo_cmd_lock);
-#endif
-	TAILQ_INSERT_TAIL(&dp->reo_cmd_cache_flush_list, elem, entry);
-	dp->reo_cmd_cache_flush_count++;
-
-	/* Flush and invalidate aged REO desc from HW cache */
-	TAILQ_FOREACH_SAFE(elem, &dp->reo_cmd_cache_flush_list, entry, tmp) {
-		if (dp->reo_cmd_cache_flush_count > DP_REO_DESC_FREE_THRESHOLD ||
-		    now >= elem->ts + MSEC_TO_NSEC(DP_REO_DESC_FREE_TIMEOUT_MS)) {
-			TAILQ_REMOVE(&dp->reo_cmd_cache_flush_list, elem, entry);
-			dp->reo_cmd_cache_flush_count--;
-#ifdef notyet
-			spin_unlock_bh(&dp->reo_cmd_lock);
-#endif
-			qwz_dp_reo_cache_flush(sc, &elem->data);
-			free(elem, M_DEVBUF, sizeof(*elem));
-#ifdef notyet
-			spin_lock_bh(&dp->reo_cmd_lock);
-#endif
+	for (;;) {
+		pending = 0;
+		error = 0;
+		for (i = 0; i < nitems(dp->rx_tid_retire); i++) {
+			retire = &dp->rx_tid_retire[i];
+			switch (retire->state) {
+			case QWZ_RX_TID_REUSABLE:
+				break;
+			case QWZ_RX_TID_DELETE_READY:
+			case QWZ_RX_TID_FLUSH_READY:
+				ret = qwz_dp_rx_tid_retire_submit(sc, retire);
+				if (ret && !error)
+					error = ret;
+				pending = 1;
+				break;
+			case QWZ_RX_TID_DELETE_PENDING:
+			case QWZ_RX_TID_FLUSH_PENDING:
+				pending = 1;
+				break;
+			case QWZ_RX_TID_RETIRE_FAILED:
+				error = EIO;
+				break;
+			}
 		}
+		if (error)
+			return error;
+		if (!pending)
+			return 0;
+		now = getnsecuptime();
+		if (now >= deadline)
+			return ETIMEDOUT;
+		ret = tsleep_nsec(dp->rx_tid_retire, 0, "qwzreo",
+		    deadline - now);
+		if (ret)
+			return ret;
 	}
-#ifdef notyet
-	spin_unlock_bh(&dp->reo_cmd_lock);
-#endif
 }
 
 void
 qwz_peer_rx_tid_delete(struct qwz_softc *sc, struct ath12k_peer *peer,
     uint8_t tid)
 {
-	struct ath12k_hal_reo_cmd cmd = {0};
 	struct dp_rx_tid *rx_tid = &peer->rx_tid[tid];
-	int ret;
+	struct qwz_rx_tid_retire *retire = &sc->dp.rx_tid_retire[tid];
 
 	if (!rx_tid->active)
 		return;
 
+	KASSERT(retire->state == QWZ_RX_TID_REUSABLE);
+	retire->data = *rx_tid;
+	retire->state = QWZ_RX_TID_DELETE_READY;
 	rx_tid->active = 0;
-
-	cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS;
-	cmd.addr_lo = rx_tid->paddr & 0xffffffff;
-	cmd.addr_hi = rx_tid->paddr >> 32;
-	cmd.upd0 |= HAL_REO_CMD_UPD0_VLD;
-	ret = qwz_dp_tx_send_reo_cmd(sc, rx_tid, HAL_REO_CMD_UPDATE_RX_QUEUE,
-	    &cmd, qwz_dp_rx_tid_del_func);
-	if (ret) {
-		if (ret != ESHUTDOWN) {
-			printf("%s: failed to send "
-			    "HAL_REO_CMD_UPDATE_RX_QUEUE cmd, tid %d (%d)\n",
-			    sc->sc_dev.dv_xname, tid, ret);
-		}
-
-		qwz_dp_rx_tid_clear(sc, rx_tid);
-	}
 }
 
 void
@@ -23006,11 +23007,11 @@ qwz_peer_frags_flush(struct qwz_softc *sc, struct ath12k_peer *peer)
 	}
 }
 
-void
+int
 qwz_peer_rx_tid_cleanup(struct qwz_softc *sc, struct ath12k_peer *peer)
 {
 	struct dp_rx_tid *rx_tid;
-	int i;
+	int i, ret;
 #ifdef notyet
 	lockdep_assert_held(&ar->ab->base_lock);
 #endif
@@ -23025,6 +23026,12 @@ qwz_peer_rx_tid_cleanup(struct qwz_softc *sc, struct ath12k_peer *peer)
 		spin_lock_bh(&ar->ab->base_lock);
 #endif
 	}
+	ret = qwz_dp_rx_tid_retire_wait(sc);
+	if (ret)
+		return ret;
+	for (i = 0; i <= HAL_DESC_REO_NON_QOS_TID; i++)
+		qwz_dp_rx_tid_clear(sc, &peer->rx_tid[i]);
+	return 0;
 }
 
 int
@@ -23105,6 +23112,9 @@ qwz_peer_rx_tid_setup(struct qwz_softc *sc, struct ieee80211_node *ni,
 	peer = qwz_peer_find_by_id(sc, nq->peer_id);
 	if (peer == NULL)
 		return ENOENT;
+	if (peer->delete_pending || peer->unmapped ||
+	    dp->rx_tid_retire[tid].state != QWZ_RX_TID_REUSABLE)
+		return EBUSY;
 
 #ifdef notyet
 	spin_lock_bh(&ab->base_lock);
@@ -23712,8 +23722,6 @@ qwz_mac_station_remove(struct qwz_softc *sc, struct qwz_vif *arvif,
 {
 	int ret;
 
-	qwz_peer_rx_tid_cleanup(sc, peer);
-
 	ret = qwz_peer_delete(sc, arvif->vdev_id, pdev_id, peer);
 	if (ret) {
 		printf("%s: unable to delete BSS peer: %d\n",
diff --git a/sys/dev/ic/qwzvar.h b/sys/dev/ic/qwzvar.h
index 924adab0ce2..05984dd8697 100644
--- a/sys/dev/ic/qwzvar.h
+++ b/sys/dev/ic/qwzvar.h
@@ -1146,18 +1146,23 @@ struct dp_rx_tid {
 #endif
 };
 
-#define DP_REO_DESC_FREE_THRESHOLD  64
-#define DP_REO_DESC_FREE_TIMEOUT_MS 1000
 #define DP_MON_PURGE_TIMEOUT_MS     100
 #define DP_MON_SERVICE_BUDGET       128
 
-struct dp_reo_cache_flush_elem {
-	TAILQ_ENTRY(dp_reo_cache_flush_elem) entry;
-	struct dp_rx_tid data;
-	uint64_t ts;
+enum qwz_rx_tid_retire_state {
+	QWZ_RX_TID_REUSABLE,
+	QWZ_RX_TID_DELETE_READY,
+	QWZ_RX_TID_DELETE_PENDING,
+	QWZ_RX_TID_FLUSH_READY,
+	QWZ_RX_TID_FLUSH_PENDING,
+	QWZ_RX_TID_RETIRE_FAILED,
 };
 
-TAILQ_HEAD(dp_reo_cmd_cache_flush_head, dp_reo_cache_flush_elem);
+struct qwz_rx_tid_retire {
+	struct dp_rx_tid data;
+	enum qwz_rx_tid_retire_state state;
+	uint32_t flush_offset;
+};
 
 struct dp_reo_cmd {
 	TAILQ_ENTRY(dp_reo_cmd) entry;
@@ -1257,18 +1262,14 @@ struct qwz_dp {
 	struct dp_tx_ring tx_ring[DP_TCL_NUM_RING_MAX];
 	struct hal_wbm_idle_scatter_list scatter_list[DP_IDLE_SCATTER_BUFS_MAX];
 	struct dp_reo_cmd_head reo_cmd_list;
-	struct dp_reo_cmd_cache_flush_head reo_cmd_cache_flush_list;
 #if 0
 	struct list_head dp_full_mon_mpdu_list;
 #endif
-	uint32_t reo_cmd_cache_flush_count;
 	enum hal_rx_buf_return_buf_manager idle_link_rbm;
 #if 0
 	/**
 	 * protects access to below fields,
 	 * - reo_cmd_list
-	 * - reo_cmd_cache_flush_list
-	 * - reo_cmd_cache_flush_count
 	 */
 	spinlock_t reo_cmd_lock;
 #endif
@@ -1302,6 +1303,7 @@ struct qwz_dp {
 	 * support for HostAP mode gets added to the driver.
 	 */
 	struct qwz_dmamem *rx_tid_mem[HAL_DESC_REO_NON_QOS_TID + 1];
+	struct qwz_rx_tid_retire rx_tid_retire[HAL_DESC_REO_NON_QOS_TID + 1];
 };
 
 #define ATH12K_SHADOW_DP_TIMER_INTERVAL 20
-- 
2.55.0



-- 
wbr, Kirill