Download raw body.
The 5th batch of qwz commits
Stefan,
here the 5th batch of qwz commits, some backports were quite large and I
follow qwx code move.
Ok?
From 3a380b473e95f34156bef4f952b1d22042ce4812 Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:55:22 +0200
Subject: [PATCH 1/8] sys/qwz: report hardware RX aggregation
Based on sys/dev/ic/qwx.c,v 1.85 and sys/dev/ic/qwx.c,v 1.90
Report hardware deaggregation and reordering after successful RX
reconstruction; allow repaeted sequence numbers for later A-MSDU
subframes and clear the AMSDU QoS bit.
---
sys/dev/ic/qwz.c | 34 +++++++++++++++++++++++++++++-----
1 file changed, 29 insertions(+), 5 deletions(-)
diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index 94d3c5d8e9f..2148259098e 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -15433,19 +15433,43 @@ qwz_dp_rx_h_undecap(struct qwz_softc *sc, struct qwz_rx_msdu *msdu,
struct hal_rx_desc *rx_desc, enum hal_encrypt_type enctype,
int decrypted)
{
- uint8_t decap;
+ struct ieee80211_frame *wh;
+ uint8_t decap, *qos;
+ int ret;
decap = qwz_dp_rx_h_msdu_start_decap_type(sc, rx_desc);
switch (decap) {
case DP_RX_DECAP_TYPE_NATIVE_WIFI:
- return qwz_dp_rx_h_undecap_nwifi(sc, msdu, NULL, enctype);
- case DP_RX_DECAP_TYPE_RAW:
- qwz_dp_rx_h_undecap_raw(sc, msdu, enctype, decrypted);
+ ret = qwz_dp_rx_h_undecap_nwifi(sc, msdu, NULL, enctype);
break;
case DP_RX_DECAP_TYPE_ETHERNET2_DIX:
- return qwz_dp_rx_h_undecap_eth(sc, msdu, rx_desc);
+ ret = qwz_dp_rx_h_undecap_eth(sc, msdu, rx_desc);
+ break;
+ case DP_RX_DECAP_TYPE_RAW:
+ qwz_dp_rx_h_undecap_raw(sc, msdu, enctype, decrypted);
+ return 0;
+ default:
+ return 0;
}
+ if (ret)
+ return ret;
+
+ wh = mtod(msdu->m, struct ieee80211_frame *);
+ if (msdu->m->m_len < ieee80211_get_hdrlen(wh))
+ return EINVAL;
+ if (ieee80211_has_qos(wh)) {
+ if (ieee80211_has_addr4(wh))
+ qos = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos;
+ else
+ qos = ((struct ieee80211_qosframe *)wh)->i_qos;
+ qos[0] &= ~IEEE80211_QOS_AMSDU;
+ }
+
+ /* Hardware has deaggregated and reordered these frames. */
+ if (!msdu->is_first_msdu)
+ msdu->rxi.rxi_flags |= IEEE80211_RXI_SAME_SEQ;
+ msdu->rxi.rxi_flags |= IEEE80211_RXI_AMPDU_DONE;
return 0;
}
--
2.55.0
From 38680aa80d9c50ad66fe6962d641c3991e7ed45d Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:56:36 +0200
Subject: [PATCH 2/8] sys/qwz: handle WBM RX errors
Based on sys/dev/ic/qwx.c,v 1.35 and sys/dev/ic/qwxvar.h,v 1.18 ,
sys/dev/ic/qwx.c,v 1.89 , sys/dev/ic/qwx.c,v 1.121 and sys/dev/ic/qwxvar.h,v 1.36
Process WBM RX releases using WCN7850 descriptor and cookie formats.
Deliver valid null queue frames through existing RX processing, clear
mbuf pointers after delivery, and then replenish descriptors
---
sys/dev/ic/qwz.c | 252 ++++++++++++++++++++++++--------------------
sys/dev/ic/qwzreg.h | 23 ++++
sys/dev/ic/qwzvar.h | 3 +
3 files changed, 166 insertions(+), 112 deletions(-)
diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index 2148259098e..2b916eab0a8 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -154,6 +154,8 @@ int qwz_dp_tx_send_reo_cmd(struct qwz_softc *, struct dp_rx_tid *,
enum hal_reo_cmd_type , struct ath12k_hal_reo_cmd *,
void (*func)(struct qwz_dp *, void *, enum hal_reo_cmd_status));
void qwz_dp_rx_deliver_msdu(struct qwz_softc *, struct qwz_rx_msdu *);
+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_wmi_vdev_install_key(struct qwz_softc *,
@@ -8503,6 +8505,32 @@ qwz_dp_get_rx_desc(struct qwz_softc *sc, uint32_t cookie)
return *desc_addr_ptr;
}
+struct qwz_rx_msdu *
+qwz_dp_rx_reap_desc(struct qwz_softc *sc, uint32_t cookie, void *list)
+{
+ TAILQ_HEAD(, ath12k_rx_desc_info) *used_list = list;
+ struct ath12k_rx_desc_info *desc_info;
+ struct qwz_rx_msdu *msdu;
+
+ desc_info = qwz_dp_get_rx_desc(sc, cookie);
+ if (desc_info == NULL || desc_info->magic != ATH12K_DP_RX_DESC_MAGIC ||
+ !desc_info->in_use || desc_info->m == NULL)
+ return NULL;
+
+ bus_dmamap_sync(sc->sc_dmat, desc_info->map, 0,
+ desc_info->map->dm_mapsize, BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->sc_dmat, desc_info->map);
+
+ msdu = &desc_info->rx_msdu;
+ memset(msdu, 0, sizeof(*msdu));
+ msdu->m = desc_info->m;
+ msdu->rx_desc = mtod(msdu->m, struct hal_rx_desc *);
+ desc_info->m = NULL;
+ desc_info->in_use = 0;
+ TAILQ_INSERT_TAIL(used_list, desc_info, entry);
+ return msdu;
+}
+
int
qwz_dp_cc_desc_init(struct qwz_softc *sc)
{
@@ -14875,65 +14903,67 @@ qwz_dp_process_rx_err(struct qwz_softc *sc)
}
int
-qwz_hal_wbm_desc_parse_err(void *desc, struct hal_rx_wbm_rel_info *rel_info)
+qwz_hal_wbm_desc_parse_err(struct qwz_softc *sc, void *desc,
+ struct hal_rx_wbm_rel_info *rel_info)
{
- struct hal_wbm_release_ring *wbm_desc = desc;
+ struct hal_wbm_release_ring_rx *wbm_desc = desc;
+ struct hal_wbm_release_ring_cc_rx *cc_desc = desc;
enum hal_wbm_rel_desc_type type;
enum hal_wbm_rel_src_module rel_src;
- enum hal_rx_buf_return_buf_manager ret_buf_mgr;
-
- type = FIELD_GET(HAL_WBM_RELEASE_INFO0_DESC_TYPE, wbm_desc->info0);
+ enum hal_rx_buf_return_buf_manager rbm;
+ uint32_t info0 = le32toh(wbm_desc->info0);
+ uint32_t msdu_info = le32toh(wbm_desc->rx_msdu_info.info0);
- /* We expect only WBM_REL buffer type */
+ type = FIELD_GET(HAL_WBM_RELEASE_INFO0_DESC_TYPE, info0);
if (type != HAL_WBM_REL_DESC_TYPE_REL_MSDU)
- return -EINVAL;
+ return EINVAL;
- rel_src = FIELD_GET(HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE,
- wbm_desc->info0);
+ rel_src = FIELD_GET(HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE, info0);
if (rel_src != HAL_WBM_REL_SRC_MODULE_RXDMA &&
rel_src != HAL_WBM_REL_SRC_MODULE_REO)
return EINVAL;
- ret_buf_mgr = FIELD_GET(BUFFER_ADDR_INFO1_RET_BUF_MGR,
- wbm_desc->buf_addr_info.info1);
- if (ret_buf_mgr != HAL_RX_BUF_RBM_SW3_BM) {
-#if 0
- ab->soc_stats.invalid_rbm++;
-#endif
- return EINVAL;
+ /* Cookie conversion changes both the cookie and RBM locations. */
+ if (info0 & HAL_WBM_RELEASE_RX_INFO0_CC_STATUS) {
+ rbm = FIELD_GET(HAL_WBM_RELEASE_RX_CC_INFO0_RBM, info0);
+ rel_info->cookie = FIELD_GET(HAL_WBM_RELEASE_RX_CC_INFO1_COOKIE,
+ le32toh(cc_desc->info1));
+ } else {
+ rbm = FIELD_GET(BUFFER_ADDR_INFO1_RET_BUF_MGR,
+ le32toh(wbm_desc->buf_addr_info.info1));
+ rel_info->cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
+ le32toh(wbm_desc->buf_addr_info.info1));
}
+ if (rbm != HAL_RX_BUF_RBM_SW3_BM &&
+ rbm != sc->hw_params.hal_params->rx_buf_rbm)
+ return EINVAL;
- rel_info->cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
- wbm_desc->buf_addr_info.info1);
rel_info->err_rel_src = rel_src;
if (rel_src == HAL_WBM_REL_SRC_MODULE_REO) {
rel_info->push_reason = FIELD_GET(
- HAL_WBM_RELEASE_INFO0_REO_PUSH_REASON, wbm_desc->info0);
+ HAL_WBM_RELEASE_INFO0_REO_PUSH_REASON, info0);
rel_info->err_code = FIELD_GET(
- HAL_WBM_RELEASE_INFO0_REO_ERROR_CODE, wbm_desc->info0);
+ HAL_WBM_RELEASE_INFO0_REO_ERROR_CODE, info0);
} else {
rel_info->push_reason = FIELD_GET(
- HAL_WBM_RELEASE_INFO0_RXDMA_PUSH_REASON, wbm_desc->info0);
+ HAL_WBM_RELEASE_INFO0_RXDMA_PUSH_REASON, info0);
rel_info->err_code = FIELD_GET(
- HAL_WBM_RELEASE_INFO0_RXDMA_ERROR_CODE, wbm_desc->info0);
- }
-
- rel_info->first_msdu = FIELD_GET(HAL_WBM_RELEASE_INFO2_FIRST_MSDU,
- wbm_desc->info2);
- rel_info->last_msdu = FIELD_GET(HAL_WBM_RELEASE_INFO2_LAST_MSDU,
- wbm_desc->info2);
-
+ HAL_WBM_RELEASE_INFO0_RXDMA_ERROR_CODE, info0);
+ }
+
+ rel_info->first_msdu = !!(msdu_info &
+ RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU);
+ rel_info->last_msdu = !!(msdu_info &
+ RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU);
+ rel_info->continuation = !!(msdu_info &
+ RX_MSDU_DESC_INFO0_MSDU_CONTINUATION);
+ rel_info->peer_id = FIELD_GET(RX_MPDU_DESC_META_DATA_PEER_ID,
+ le32toh(wbm_desc->rx_mpdu_info.meta_data));
+ rel_info->seq_no = FIELD_GET(RX_MPDU_DESC_INFO0_SEQ_NUM,
+ le32toh(wbm_desc->rx_mpdu_info.info0));
return 0;
}
-int
-qwz_dp_rx_h_null_q_desc(struct qwz_softc *sc, struct qwz_rx_msdu *msdu,
- struct qwz_rx_msdu_list *msdu_list)
-{
- printf("%s: not implemented\n", __func__);
- return ENOTSUP;
-}
-
int
qwz_dp_rx_h_reo_err(struct qwz_softc *sc, struct qwz_rx_msdu *msdu,
struct qwz_rx_msdu_list *msdu_list)
@@ -15013,113 +15043,72 @@ qwz_dp_rx_wbm_err(struct qwz_softc *sc, struct qwz_rx_msdu *msdu,
}
qwz_dp_rx_deliver_msdu(sc, msdu);
+ msdu->m = NULL;
}
int
qwz_dp_rx_process_wbm_err(struct qwz_softc *sc)
{
-#if 0
- struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
+ struct ifnet *ifp = &sc->sc_ic.ic_if;
struct qwz_dp *dp = &sc->dp;
- struct dp_rxdma_ring *rx_ring;
struct hal_rx_wbm_rel_info err_info;
struct hal_srng *srng;
- struct qwz_rx_msdu_list msdu_list[MAX_RADIOS];
+ struct qwz_rx_msdu_list msdu_list;
+ TAILQ_HEAD(, ath12k_rx_desc_info) used_list;
struct qwz_rx_msdu *msdu;
- struct mbuf *m;
- struct qwz_rx_data *rx_data;
- uint32_t *rx_desc;
- int idx, mac_id;
- int num_buffs_reaped[MAX_RADIOS] = {0};
- int total_num_buffs_reaped = 0;
- int ret, i;
-
- for (i = 0; i < sc->num_radios; i++)
- TAILQ_INIT(&msdu_list[i]);
+ void *rx_desc;
+ int num_buffs_reaped = 0;
+ TAILQ_INIT(&msdu_list);
+ TAILQ_INIT(&used_list);
srng = &sc->hal.srng_list[dp->rx_rel_ring.ring_id];
-#ifdef notyet
- spin_lock_bh(&srng->lock);
-#endif
qwz_hal_srng_access_begin(sc, srng);
while ((rx_desc = qwz_hal_srng_dst_get_next_entry(sc, srng))) {
- ret = qwz_hal_wbm_desc_parse_err(rx_desc, &err_info);
- if (ret) {
- printf("%s: failed to parse rx error in wbm_rel "
- "ring desc %d\n", sc->sc_dev.dv_xname, ret);
+ if (qwz_hal_wbm_desc_parse_err(sc, rx_desc, &err_info)) {
+ ifp->if_ierrors++;
continue;
}
- idx = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, err_info.cookie);
- mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, err_info.cookie);
-
- if (mac_id >= MAX_RADIOS)
- continue;
-
- rx_ring = &sc->pdev_dp.rx_refill_buf_ring;
- if (idx >= rx_ring->bufs_max || isset(rx_ring->freemap, idx))
+ msdu = qwz_dp_rx_reap_desc(sc, err_info.cookie, &used_list);
+ if (msdu == NULL) {
+ ifp->if_ierrors++;
continue;
-
- rx_data = &rx_ring->rx_data[idx];
- bus_dmamap_unload(sc->sc_dmat, rx_data->map);
- m = rx_data->m;
- rx_data->m = NULL;
- setbit(rx_ring->freemap, idx);
-
- num_buffs_reaped[mac_id]++;
- total_num_buffs_reaped++;
+ }
+ num_buffs_reaped++;
if (err_info.push_reason !=
- HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED) {
- m_freem(m);
+ HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED ||
+ test_bit(ATH12K_CAC_RUNNING, sc->sc_flags)) {
+ m_freem(msdu->m);
+ msdu->m = NULL;
+ ifp->if_ierrors++;
continue;
}
- msdu = &rx_data->rx_msdu;
- memset(&msdu->rxi, 0, sizeof(msdu->rxi));
- msdu->m = m;
msdu->err_rel_src = err_info.err_rel_src;
msdu->err_code = err_info.err_code;
- msdu->rx_desc = mtod(m, struct hal_rx_desc *);
- TAILQ_INSERT_TAIL(&msdu_list[mac_id], msdu, entry);
+ msdu->is_first_msdu = err_info.first_msdu;
+ msdu->is_last_msdu = err_info.last_msdu;
+ msdu->is_continuation = err_info.continuation;
+ msdu->peer_id = err_info.peer_id;
+ msdu->seq_no = err_info.seq_no;
+ msdu->tid = sc->hal_rx_ops->rx_desc_get_mpdu_tid(msdu->rx_desc);
+ TAILQ_INSERT_TAIL(&msdu_list, msdu, entry);
}
qwz_hal_srng_access_end(sc, srng);
-#ifdef notyet
- spin_unlock_bh(&srng->lock);
-#endif
- if (!total_num_buffs_reaped)
- goto done;
- for (i = 0; i < sc->num_radios; i++) {
- if (!num_buffs_reaped[i])
- continue;
-
- rx_ring = &sc->pdev_dp.rx_refill_buf_ring;
- qwz_dp_rxbufs_replenish(sc, i, rx_ring, num_buffs_reaped[i],
- sc->hw_params.hal_params->rx_buf_rbm);
+ while ((msdu = TAILQ_FIRST(&msdu_list))) {
+ TAILQ_REMOVE(&msdu_list, msdu, entry);
+ qwz_dp_rx_wbm_err(sc, msdu, &msdu_list);
}
- for (i = 0; i < sc->num_radios; i++) {
- while ((msdu = TAILQ_FIRST(msdu_list))) {
- TAILQ_REMOVE(msdu_list, msdu, entry);
- if (test_bit(ATH12K_CAC_RUNNING, sc->sc_flags)) {
- m_freem(msdu->m);
- msdu->m = NULL;
- continue;
- }
- qwz_dp_rx_wbm_err(sc, msdu, &msdu_list[i]);
- msdu->m = NULL;
- }
- }
-done:
- ifp->if_ierrors += total_num_buffs_reaped;
+ if (num_buffs_reaped)
+ qwz_dp_rxbufs_replenish(sc, &dp->rx_refill_buf_ring,
+ &used_list, num_buffs_reaped);
- return total_num_buffs_reaped;
-#endif
- return 0;
+ return num_buffs_reaped;
}
struct qwz_rx_msdu *
@@ -15647,6 +15636,45 @@ qwz_dp_rx_process_msdu(struct qwz_softc *sc, struct qwz_rx_msdu *msdu,
return qwz_dp_rx_h_mpdu(sc, msdu, rx_desc);
}
+int
+qwz_dp_rx_h_null_q_desc(struct qwz_softc *sc, struct qwz_rx_msdu *msdu,
+ struct qwz_rx_msdu_list *msdu_list)
+{
+ struct qwz_rx_msdu *next, *tmp;
+ uint32_t desc_sz = sc->hal.hal_desc_sz;
+ uint16_t msdu_len;
+ uint8_t l3pad;
+ int nbufs;
+
+ msdu_len = qwz_dp_rx_h_msdu_start_msdu_len(sc, msdu->rx_desc);
+ if (msdu_len + desc_sz > DP_RX_BUFFER_SIZE) {
+ nbufs = howmany(msdu_len - (DP_RX_BUFFER_SIZE - desc_sz),
+ DP_RX_BUFFER_SIZE - desc_sz);
+ TAILQ_FOREACH_SAFE(next, msdu_list, entry, tmp) {
+ if (!nbufs)
+ break;
+ if (next->err_rel_src != HAL_WBM_REL_SRC_MODULE_REO ||
+ next->err_code !=
+ HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO)
+ continue;
+ TAILQ_REMOVE(msdu_list, next, entry);
+ m_freem(next->m);
+ next->m = NULL;
+ sc->sc_ic.ic_if.if_ierrors++;
+ nbufs--;
+ }
+ return EINVAL;
+ }
+ if (msdu->is_continuation)
+ return EINVAL;
+
+ l3pad = qwz_dp_rx_h_msdu_end_l3pad(sc, msdu->rx_desc);
+ if (desc_sz + l3pad + msdu_len > DP_RX_BUFFER_SIZE)
+ return EINVAL;
+
+ return qwz_dp_rx_process_msdu(sc, msdu, msdu_list);
+}
+
void
qwz_dp_rx_deliver_msdu(struct qwz_softc *sc, struct qwz_rx_msdu *msdu)
{
diff --git a/sys/dev/ic/qwzreg.h b/sys/dev/ic/qwzreg.h
index 35f1426525c..214db309aa4 100644
--- a/sys/dev/ic/qwzreg.h
+++ b/sys/dev/ic/qwzreg.h
@@ -9632,6 +9632,29 @@ struct hal_wbm_release_ring {
uint32_t info3;
} __packed;
+#define HAL_WBM_RELEASE_RX_INFO0_CC_STATUS BIT(16)
+#define HAL_WBM_RELEASE_RX_CC_INFO0_RBM GENMASK(12, 9)
+#define HAL_WBM_RELEASE_RX_CC_INFO1_COOKIE GENMASK(27, 8)
+
+struct hal_wbm_release_ring_rx {
+ struct ath12k_buffer_addr buf_addr_info;
+ uint32_t info0;
+ struct rx_mpdu_desc rx_mpdu_info;
+ struct rx_msdu_desc rx_msdu_info;
+ uint32_t info1;
+ uint32_t info2;
+} __packed;
+
+struct hal_wbm_release_ring_cc_rx {
+ uint32_t buf_va_lo;
+ uint32_t buf_va_hi;
+ uint32_t info0;
+ struct rx_mpdu_desc rx_mpdu_info;
+ struct rx_msdu_desc rx_msdu_info;
+ uint32_t buf_pa_lo;
+ uint32_t info1;
+} __packed;
+
/* hal_wbm_release_ring
*
* Producer: SW/TQM/RXDMA/REO/SWITCH
diff --git a/sys/dev/ic/qwzvar.h b/sys/dev/ic/qwzvar.h
index c21ad3ee860..f92bbeb2765 100644
--- a/sys/dev/ic/qwzvar.h
+++ b/sys/dev/ic/qwzvar.h
@@ -1644,6 +1644,9 @@ struct hal_rx_wbm_rel_info {
uint32_t err_code;
int first_msdu;
int last_msdu;
+ int continuation;
+ uint16_t peer_id;
+ uint16_t seq_no;
};
#define HAL_INVALID_PEERID 0xffff
--
2.55.0
From 86550cd54f0a1f8f9e135bf85ab9f7f9de021b61 Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:56:45 +0200
Subject: [PATCH 3/8] sys/qwz: read RX metadata from MPDU TLVs
Read sequence numbers and TIDs from WCN7850 MPDU descriptors.
---
sys/dev/ic/qwz.c | 12 ++++++------
sys/dev/ic/qwzvar.h | 1 -
2 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index 2b916eab0a8..a693d138e49 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -14959,8 +14959,6 @@ qwz_hal_wbm_desc_parse_err(struct qwz_softc *sc, void *desc,
RX_MSDU_DESC_INFO0_MSDU_CONTINUATION);
rel_info->peer_id = FIELD_GET(RX_MPDU_DESC_META_DATA_PEER_ID,
le32toh(wbm_desc->rx_mpdu_info.meta_data));
- rel_info->seq_no = FIELD_GET(RX_MPDU_DESC_INFO0_SEQ_NUM,
- le32toh(wbm_desc->rx_mpdu_info.info0));
return 0;
}
@@ -15092,7 +15090,8 @@ qwz_dp_rx_process_wbm_err(struct qwz_softc *sc)
msdu->is_last_msdu = err_info.last_msdu;
msdu->is_continuation = err_info.continuation;
msdu->peer_id = err_info.peer_id;
- msdu->seq_no = err_info.seq_no;
+ msdu->seq_no = sc->hal_rx_ops->rx_desc_get_mpdu_start_seq_no(
+ msdu->rx_desc);
msdu->tid = sc->hal_rx_ops->rx_desc_get_mpdu_tid(msdu->rx_desc);
TAILQ_INSERT_TAIL(&msdu_list, msdu, entry);
}
@@ -15813,9 +15812,10 @@ try_again:
RX_MSDU_DESC_INFO0_MSDU_CONTINUATION);
msdu->peer_id = FIELD_GET(RX_MPDU_DESC_META_DATA_PEER_ID,
desc->rx_mpdu_info.meta_data);
- msdu->seq_no = FIELD_GET(RX_MPDU_DESC_INFO0_SEQ_NUM,
- desc->rx_mpdu_info.info0);
- msdu->tid = 0; /* no RX_QUEUE_NUM in wifi7 */
+ msdu->rx_desc = mtod(m, struct hal_rx_desc *);
+ msdu->seq_no = sc->hal_rx_ops->rx_desc_get_mpdu_start_seq_no(
+ msdu->rx_desc);
+ msdu->tid = sc->hal_rx_ops->rx_desc_get_mpdu_tid(msdu->rx_desc);
msdu->mac_id = mac_id;
TAILQ_INSERT_TAIL(&msdu_list[mac_id], msdu, entry);
diff --git a/sys/dev/ic/qwzvar.h b/sys/dev/ic/qwzvar.h
index f92bbeb2765..b182f7001db 100644
--- a/sys/dev/ic/qwzvar.h
+++ b/sys/dev/ic/qwzvar.h
@@ -1646,7 +1646,6 @@ struct hal_rx_wbm_rel_info {
int last_msdu;
int continuation;
uint16_t peer_id;
- uint16_t seq_no;
};
#define HAL_INVALID_PEERID 0xffff
--
2.55.0
From 988802b1c4ce22c4f6581799954b7918f33b9b78 Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:56:42 +0200
Subject: [PATCH 4/8] sys/qwz: drain REO RX exceptions
Based on sys/dev/ic/qwx.c,v 1.33
Drain REO RX exceptions using descriptor layouts and qwz cookie.
Reclaim packet buffers, return link descriptors and replenish RX,
checking bank bounds and release ring space.
---
sys/dev/ic/qwz.c | 253 +++++++++++++++++---------------------------
sys/dev/ic/qwzreg.h | 5 +
2 files changed, 104 insertions(+), 154 deletions(-)
diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index a693d138e49..d5d6e230efd 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -14611,10 +14611,11 @@ qwz_hal_rx_reo_ent_paddr_get(struct qwz_softc *sc, void *desc, uint64_t *paddr,
struct ath12k_buffer_addr *buff_addr = desc;
*paddr = ((uint64_t)(FIELD_GET(BUFFER_ADDR_INFO1_ADDR,
- buff_addr->info1)) << 32) |
- FIELD_GET(BUFFER_ADDR_INFO0_ADDR, buff_addr->info0);
+ le32toh(buff_addr->info1))) << 32) |
+ FIELD_GET(BUFFER_ADDR_INFO0_ADDR, le32toh(buff_addr->info0));
- *desc_bank = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, buff_addr->info1);
+ *desc_bank = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
+ le32toh(buff_addr->info1));
}
int
@@ -14623,15 +14624,9 @@ qwz_hal_desc_reo_parse_err(struct qwz_softc *sc, uint32_t *rx_desc,
{
struct hal_reo_dest_ring *desc = (struct hal_reo_dest_ring *)rx_desc;
enum hal_reo_dest_ring_push_reason push_reason;
- enum hal_reo_dest_ring_error_code err_code;
push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON,
- desc->info0);
- err_code = FIELD_GET(HAL_REO_DEST_RING_INFO0_ERROR_CODE,
- desc->info0);
-#if 0
- ab->soc_stats.reo_error[err_code]++;
-#endif
+ le32toh(desc->info0));
if (push_reason != HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED &&
push_reason != HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) {
printf("%s: expected error push reason code, received %d\n",
@@ -14639,7 +14634,8 @@ qwz_hal_desc_reo_parse_err(struct qwz_softc *sc, uint32_t *rx_desc,
return EINVAL;
}
- if (FIELD_GET(HAL_REO_DEST_RING_INFO0_BUFFER_TYPE, desc->info0) !=
+ if (FIELD_GET(HAL_REO_DEST_RING_INFO0_BUFFER_TYPE,
+ le32toh(desc->info0)) !=
HAL_REO_DEST_RING_BUFFER_TYPE_LINK_DESC) {
printf("%s: expected buffer type link_desc",
sc->sc_dev.dv_xname);
@@ -14647,6 +14643,7 @@ qwz_hal_desc_reo_parse_err(struct qwz_softc *sc, uint32_t *rx_desc,
}
qwz_hal_rx_reo_ent_paddr_get(sc, rx_desc, paddr, desc_bank);
+ *desc_bank = FIELD_GET(DP_LINK_DESC_BANK_MASK, *desc_bank);
return 0;
}
@@ -14663,18 +14660,18 @@ qwz_hal_rx_msdu_link_info_get(void *link_desc, uint32_t *num_msdus,
msdu = &link->msdu_link[0];
*rbm = FIELD_GET(BUFFER_ADDR_INFO1_RET_BUF_MGR,
- msdu->buf_addr_info.info1);
+ le32toh(msdu->buf_addr_info.info1));
for (i = 0; i < *num_msdus; i++) {
msdu = &link->msdu_link[i];
if (!FIELD_GET(BUFFER_ADDR_INFO0_ADDR,
- msdu->buf_addr_info.info0)) {
+ le32toh(msdu->buf_addr_info.info0))) {
*num_msdus = i;
break;
}
*msdu_cookies = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
- msdu->buf_addr_info.info1);
+ le32toh(msdu->buf_addr_info.info1));
msdu_cookies++;
}
}
@@ -14686,12 +14683,13 @@ qwz_hal_rx_msdu_link_desc_set(struct qwz_softc *sc, void *desc,
struct hal_wbm_release_ring *dst_desc = desc;
struct hal_wbm_release_ring *src_desc = link_desc;
+ memset(dst_desc, 0, sizeof(*dst_desc));
dst_desc->buf_addr_info = src_desc->buf_addr_info;
- dst_desc->info0 |= FIELD_PREP(HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE,
+ dst_desc->info0 = htole32(FIELD_PREP(HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE,
HAL_WBM_REL_SRC_MODULE_SW) |
FIELD_PREP(HAL_WBM_RELEASE_INFO0_BM_ACTION, action) |
FIELD_PREP(HAL_WBM_RELEASE_INFO0_DESC_TYPE,
- HAL_WBM_REL_DESC_TYPE_MSDU_LINK);
+ HAL_WBM_REL_DESC_TYPE_MSDU_LINK));
}
int
@@ -14740,166 +14738,113 @@ qwz_dp_rx_h_msdu_start_msdu_len(struct qwz_softc *sc, struct hal_rx_desc *desc)
return sc->hal_rx_ops->rx_desc_get_msdu_len(desc);
}
-void
-qwz_dp_process_rx_err_buf(struct qwz_softc *sc, uint32_t *ring_desc,
- int buf_id, int drop)
+int
+qwz_dp_process_rx_err_buf(struct qwz_softc *sc, uint32_t cookie, void *list)
{
-#if 0
- struct qwz_pdev_dp *dp = &sc->pdev_dp;
- struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
- struct mbuf *m;
- struct qwz_rx_data *rx_data;
- struct hal_rx_desc *rx_desc;
- uint16_t msdu_len;
- uint32_t hal_rx_desc_sz = sc->hal.hal_desc_sz;
-
- if (buf_id >= rx_ring->bufs_max || isset(rx_ring->freemap, buf_id))
- return;
-
- rx_data = &rx_ring->rx_data[buf_id];
- bus_dmamap_unload(sc->sc_dmat, rx_data->map);
- m = rx_data->m;
- rx_data->m = NULL;
- setbit(rx_ring->freemap, buf_id);
-
- if (drop) {
- m_freem(m);
- return;
- }
-
- rx_desc = mtod(m, struct hal_rx_desc *);
- msdu_len = qwz_dp_rx_h_msdu_start_msdu_len(sc, rx_desc);
- if ((msdu_len + hal_rx_desc_sz) > DP_RX_BUFFER_SIZE) {
-#if 0
- uint8_t *hdr_status = ath12k_dp_rx_h_80211_hdr(ar->ab, rx_desc);
- ath12k_warn(ar->ab, "invalid msdu leng %u", msdu_len);
- ath12k_dbg_dump(ar->ab, ATH12K_DBG_DATA, NULL, "", hdr_status,
- sizeof(struct ieee80211_hdr));
- ath12k_dbg_dump(ar->ab, ATH12K_DBG_DATA, NULL, "", rx_desc,
- sizeof(struct hal_rx_desc));
-#endif
- m_freem(m);
- return;
- }
+ struct qwz_rx_msdu *msdu;
- if (qwz_dp_rx_frag_h_mpdu(sc, m, ring_desc)) {
- qwz_dp_rx_link_desc_return(sc, ring_desc,
- HAL_WBM_REL_BM_ACT_PUT_IN_IDLE);
- }
+ msdu = qwz_dp_rx_reap_desc(sc, cookie, list);
+ if (msdu == NULL)
+ return 0;
- m_freem(m);
-#endif
- printf("%s:%d\n", __func__, __LINE__);
+ m_freem(msdu->m);
+ msdu->m = NULL;
+ return 1;
}
int
qwz_dp_process_rx_err(struct qwz_softc *sc)
{
-#if 0
- struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
- uint32_t msdu_cookies[HAL_NUM_RX_MSDUS_PER_LINK_DESC];
- struct dp_link_desc_bank *link_desc_banks;
+ struct ifnet *ifp = &sc->sc_ic.ic_if;
+ struct qwz_dp *dp = &sc->dp;
+ TAILQ_HEAD(, ath12k_rx_desc_info) used_list;
+ struct hal_srng *srng, *release_srng;
+ struct hal_reo_dest_ring *reo_desc;
+ struct dp_link_desc_bank *bank;
+ struct hal_rx_msdu_link *link;
enum hal_rx_buf_return_buf_manager rbm;
- int tot_n_bufs_reaped, ret, i;
- int n_bufs_reaped[MAX_RADIOS] = {0};
- struct dp_rxdma_ring *rx_ring;
- struct dp_srng *reo_except;
- uint32_t desc_bank, num_msdus;
- struct hal_srng *srng;
- struct qwz_dp *dp;
- void *link_desc_va;
- int buf_id, mac_id;
+ enum hal_wbm_rel_bm_act action;
+ uint32_t cookies[HAL_NUM_RX_MSDUS_PER_LINK_DESC];
+ uint32_t desc_bank, num_msdus, cookie;
uint64_t paddr;
- uint32_t *desc;
- int is_frag;
- uint8_t drop = 0;
-
- tot_n_bufs_reaped = 0;
-
- dp = &sc->dp;
- reo_except = &dp->reo_except_ring;
- link_desc_banks = dp->link_desc_banks;
+ bus_size_t offset;
+ void *release_desc;
+ int num_buffs_reaped = 0;
+ int n, i;
- srng = &sc->hal.srng_list[reo_except->ring_id];
-#ifdef notyet
- spin_lock_bh(&srng->lock);
-#endif
+ TAILQ_INIT(&used_list);
+ srng = &sc->hal.srng_list[dp->reo_except_ring.ring_id];
+ release_srng = &sc->hal.srng_list[dp->wbm_desc_rel_ring.ring_id];
qwz_hal_srng_access_begin(sc, srng);
+ qwz_hal_srng_access_begin(sc, release_srng);
- while ((desc = qwz_hal_srng_dst_get_next_entry(sc, srng))) {
- struct hal_reo_dest_ring *reo_desc =
- (struct hal_reo_dest_ring *)desc;
-#if 0
- ab->soc_stats.err_ring_pkts++;
-#endif
- ret = qwz_hal_desc_reo_parse_err(sc, desc, &paddr, &desc_bank);
- if (ret) {
- printf("%s: failed to parse error reo desc %d\n",
- sc->sc_dev.dv_xname, ret);
- continue;
- }
- link_desc_va = link_desc_banks[desc_bank].vaddr +
- (paddr - link_desc_banks[desc_bank].paddr);
- qwz_hal_rx_msdu_link_info_get(link_desc_va, &num_msdus,
- msdu_cookies, &rbm);
- if (rbm != HAL_RX_BUF_RBM_WBM_DEV0_IDLE_DESC_LIST &&
- rbm != HAL_RX_BUF_RBM_SW3_BM) {
-#if 0
- ab->soc_stats.invalid_rbm++;
-#endif
- printf("%s: invalid return buffer manager %d\n",
- sc->sc_dev.dv_xname, rbm);
- qwz_dp_rx_link_desc_return(sc, desc,
- HAL_WBM_REL_BM_ACT_REL_MSDU);
+ while (qwz_hal_srng_src_num_free(sc, release_srng, 1) > 0 &&
+ (reo_desc = (struct hal_reo_dest_ring *)
+ qwz_hal_srng_dst_get_next_entry(sc, srng))) {
+ if (FIELD_GET(HAL_REO_DEST_RING_INFO0_BUFFER_TYPE,
+ le32toh(reo_desc->info0)) ==
+ HAL_REO_DEST_RING_BUFFER_TYPE_MSDU) {
+ cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
+ le32toh(reo_desc->buf_addr_info.info1));
+ n = qwz_dp_process_rx_err_buf(sc, cookie, &used_list);
+ num_buffs_reaped += n;
+ if (!n)
+ ifp->if_ierrors++;
continue;
}
- is_frag = !!(reo_desc->rx_mpdu_info.info0 &
- RX_MPDU_DESC_INFO0_FRAG_FLAG);
-
- /* Process only rx fragments with one msdu per link desc below,
- * and drop msdu's indicated due to error reasons.
- */
- if (!is_frag || num_msdus > 1) {
- drop = 1;
- /* Return the link desc back to wbm idle list */
- qwz_dp_rx_link_desc_return(sc, desc,
- HAL_WBM_REL_BM_ACT_PUT_IN_IDLE);
+ if (qwz_hal_desc_reo_parse_err(sc, (uint32_t *)reo_desc,
+ &paddr, &desc_bank)) {
+ ifp->if_ierrors++;
+ continue;
}
-
- for (i = 0; i < num_msdus; i++) {
- buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID,
- msdu_cookies[i]);
-
- mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID,
- msdu_cookies[i]);
-
- qwz_dp_process_rx_err_buf(sc, desc, buf_id, drop);
- n_bufs_reaped[mac_id]++;
- tot_n_bufs_reaped++;
+ if (desc_bank >= nitems(dp->link_desc_banks)) {
+ ifp->if_ierrors++;
+ continue;
}
- }
-
- qwz_hal_srng_access_end(sc, srng);
-#ifdef notyet
- spin_unlock_bh(&srng->lock);
-#endif
- for (i = 0; i < sc->num_radios; i++) {
- if (!n_bufs_reaped[i])
+ bank = &dp->link_desc_banks[desc_bank];
+ if (bank->mem == NULL || bank->size < sizeof(*link) ||
+ paddr < bank->paddr ||
+ paddr - bank->paddr > bank->size - sizeof(*link)) {
+ ifp->if_ierrors++;
continue;
+ }
+ offset = paddr - bank->paddr;
+ link = (struct hal_rx_msdu_link *)
+ ((uint8_t *)bank->vaddr + offset);
+ bus_dmamap_sync(sc->sc_dmat, bank->mem->map, offset,
+ sizeof(*link), BUS_DMASYNC_POSTREAD);
+ qwz_hal_rx_msdu_link_info_get(link, &num_msdus, cookies, &rbm);
+ action = HAL_WBM_REL_BM_ACT_PUT_IN_IDLE;
+ if (rbm != dp->idle_link_rbm && rbm != HAL_RX_BUF_RBM_SW3_BM &&
+ rbm != sc->hw_params.hal_params->rx_buf_rbm) {
+ action = HAL_WBM_REL_BM_ACT_REL_MSDU;
+ ifp->if_ierrors++;
+ } else {
+ /* Fragment reassembly is not implemented. */
+ for (i = 0; i < num_msdus; i++) {
+ n = qwz_dp_process_rx_err_buf(sc, cookies[i],
+ &used_list);
+ num_buffs_reaped += n;
+ if (!n)
+ ifp->if_ierrors++;
+ }
+ }
+ bus_dmamap_sync(sc->sc_dmat, bank->mem->map, offset,
+ sizeof(*link), BUS_DMASYNC_PREREAD);
- rx_ring = &sc->pdev_dp.rx_refill_buf_ring;
-
- qwz_dp_rxbufs_replenish(sc, i, rx_ring, n_bufs_reaped[i],
- sc->hw_params.hal_params->rx_buf_rbm);
+ release_desc = qwz_hal_srng_src_get_next_entry(sc, release_srng);
+ KASSERT(release_desc != NULL);
+ qwz_hal_rx_msdu_link_desc_set(sc, release_desc, reo_desc, action);
}
- ifp->if_ierrors += tot_n_bufs_reaped;
-
- return tot_n_bufs_reaped;
-#endif
- return 0;
+ qwz_hal_srng_access_end(sc, release_srng);
+ qwz_hal_srng_access_end(sc, srng);
+ if (num_buffs_reaped)
+ qwz_dp_rxbufs_replenish(sc, &dp->rx_refill_buf_ring,
+ &used_list, num_buffs_reaped);
+ ifp->if_ierrors += num_buffs_reaped;
+ return num_buffs_reaped;
}
int
diff --git a/sys/dev/ic/qwzreg.h b/sys/dev/ic/qwzreg.h
index 214db309aa4..602fc4de356 100644
--- a/sys/dev/ic/qwzreg.h
+++ b/sys/dev/ic/qwzreg.h
@@ -9881,9 +9881,14 @@ struct hal_rx_mpdu_link_ptr {
struct ath12k_buffer_addr addr_info;
} __packed;
+struct rx_msdu_ext_desc {
+ uint32_t info0;
+} __packed;
+
struct hal_rx_msdu_details {
struct ath12k_buffer_addr buf_addr_info;
struct rx_msdu_desc rx_msdu_info;
+ struct rx_msdu_ext_desc rx_msdu_ext_info;
} __packed;
#define HAL_RX_MSDU_LNK_INFO0_RX_QUEUE_NUMBER GENMASK(15, 0)
--
2.55.0
From efb0bc2bc6857d147e4241dc6dd9b6d7bf9aebc8 Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:56:39 +0200
Subject: [PATCH 5/8] sys/qwz: count discarded RX packets
Backport of sys/dev/ic/qwx.c,v 1.91 and sys/dev/ic/qwx.c,v 1.95
---
sys/dev/ic/qwz.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index d5d6e230efd..f963445d8d9 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -14982,6 +14982,7 @@ qwz_dp_rx_wbm_err(struct qwz_softc *sc, struct qwz_rx_msdu *msdu,
if (drop) {
m_freem(msdu->m);
msdu->m = NULL;
+ sc->sc_ic.ic_if.if_ierrors++;
return;
}
@@ -15656,6 +15657,7 @@ qwz_dp_rx_process_received_packets(struct qwz_softc *sc,
DNPRINTF(QWZ_D_MAC, "Unable to process msdu: %d", ret);
m_freem(msdu->m);
msdu->m = NULL;
+ sc->sc_ic.ic_if.if_ierrors++;
continue;
}
--
2.55.0
From 9f3f11dc694dab0f0da30f94bd1796e97841a26b Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:54:46 +0200
Subject: [PATCH 6/8] sys/qwz: report radiotap channels and rates
Based on sys/dev/ic/qwx.c,v 1.93 and sys/dev/ic/qwxvar.h,v 1.31
Populate radiotap channel and rate fields with WCN7850 RX rate decoding.
Use QWZ presence masks and omit unavailable timestamps, noise and
signal strength for data frames.
Correct 54 Mb/s encoding from 104 to 108 in 500 kb/s.
---
sys/dev/ic/qwz.c | 99 +++++++++++++++++++++++++++++++++++++++++++--
sys/dev/ic/qwzvar.h | 22 ++++++++--
2 files changed, 114 insertions(+), 7 deletions(-)
diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index f963445d8d9..e6a08bdc2e7 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -105,6 +105,17 @@
const __typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
+#if NBPFILTER > 0
+static inline uint8_t
+hweight8(uint8_t x)
+{
+ x = (x & 0x55) + ((x & 0xaa) >> 1);
+ x = (x & 0x33) + ((x & 0xcc) >> 2);
+ x = (x + (x >> 4)) & 0x0f;
+ return (x);
+}
+#endif
+
/* #define QWZ_DEBUG */
#include <dev/ic/qwzreg.h>
@@ -515,6 +526,33 @@ qwz_tx(struct qwz_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
#if NBPFILTER > 0
if (sc->sc_drvbpf != NULL) {
struct qwz_tx_radiotap_header *tap = &sc->sc_txtap;
+ struct ieee80211com *ic = &sc->sc_ic;
+ uint16_t chan_flags;
+
+ tap->wt_flags = 0;
+ tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq);
+ chan_flags = ni->ni_chan->ic_flags;
+ if (ic->ic_curmode != IEEE80211_MODE_11N &&
+ ic->ic_curmode != IEEE80211_MODE_11AC) {
+ chan_flags &= ~IEEE80211_CHAN_HT;
+ chan_flags &= ~IEEE80211_CHAN_40MHZ;
+ }
+ if (ic->ic_curmode != IEEE80211_MODE_11AC)
+ chan_flags &= ~IEEE80211_CHAN_VHT;
+ tap->wt_chan_flags = htole16(chan_flags);
+ if ((ni->ni_flags & IEEE80211_NODE_HT) &&
+ !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+ frame_type == IEEE80211_FC0_TYPE_DATA) {
+ tap->wt_rate = (0x80 | ni->ni_txmcs);
+ } else {
+ struct ieee80211_rateset *rs = &ni->ni_rates;
+ uint8_t rate = rs->rs_rates[ni->ni_txrate];
+
+ tap->wt_rate = rate & IEEE80211_RATE_VAL;
+ }
+ if ((ic->ic_flags & IEEE80211_F_WEPON) &&
+ (wh->i_fc[1] & IEEE80211_FC1_PROTECTED))
+ tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
bpf_mtap_hdr(sc->sc_drvbpf, tap, sc->sc_txtap_len,
m, BPF_DIRECTION_OUT);
@@ -1806,9 +1844,9 @@ const struct hal_rx_ops hal_rx_wcn7850_ops = {
.rx_desc_get_msdu_len = qwz_hw_wcn7850_rx_desc_get_msdu_len,
#ifdef notyet
.rx_desc_get_msdu_sgi = qwz_hw_wcn7850_rx_desc_get_msdu_sgi,
- .rx_desc_get_msdu_rate_mcs = qwz_hw_wcn7850_rx_desc_get_msdu_rate_mcs,
.rx_desc_get_msdu_rx_bw = qwz_hw_wcn7850_rx_desc_get_msdu_rx_bw,
#endif
+ .rx_desc_get_msdu_rate_mcs = qwz_hw_wcn7850_rx_desc_get_msdu_rate_mcs,
.rx_desc_get_msdu_freq = qwz_hw_wcn7850_rx_desc_get_msdu_freq,
.rx_desc_get_msdu_pkt_type = qwz_hw_wcn7850_rx_desc_get_msdu_pkt_type,
.rx_desc_get_msdu_nss = qwz_hw_wcn7850_rx_desc_get_msdu_nss,
@@ -11858,6 +11896,23 @@ qwz_mgmt_rx_event(struct qwz_softc *sc, struct mbuf *m)
#if NBPFILTER > 0
if (sc->sc_drvbpf != NULL) {
struct qwz_rx_radiotap_header *tap = &sc->sc_rxtap;
+ uint16_t chan_flags;
+ uint32_t freq;
+
+ tap->wr_ihdr.it_present = htole32(QWZ_RX_RADIOTAP_PRESENT);
+ tap->wr_flags = 0;
+ freq = le32toh(rx_ev.chan_freq);
+ tap->wr_chan_freq = htole16(freq);
+ chan_flags = ic->ic_channels[rx_ev.channel & 0xff].ic_flags;
+ if (ic->ic_curmode != IEEE80211_MODE_11N &&
+ ic->ic_curmode != IEEE80211_MODE_11AC) {
+ chan_flags &= ~IEEE80211_CHAN_HT;
+ chan_flags &= ~IEEE80211_CHAN_VHT;
+ chan_flags &= ~IEEE80211_CHAN_40MHZ;
+ }
+ tap->wr_rate = rx_ev.rate / 500;
+ tap->wr_chan_flags = htole16(chan_flags);
+ tap->wr_dbm_antsignal = rxi.rxi_rssi;
bpf_mtap_hdr(sc->sc_drvbpf, tap, sc->sc_rxtap_len,
m, BPF_DIRECTION_IN);
@@ -14450,7 +14505,7 @@ qwz_mac_hw_ratecode_to_legacy_rate(struct ieee80211_node *ni, uint8_t hw_rc,
*rate = 96;
break;
case ATH12K_HW_RATE_OFDM_54M:
- *rate = 104;
+ *rate = 108;
break;
default:
return EINVAL;
@@ -15634,6 +15689,42 @@ qwz_dp_rx_deliver_msdu(struct qwz_softc *sc, struct qwz_rx_msdu *msdu)
#if NBPFILTER > 0
if (sc->sc_drvbpf != NULL) {
struct qwz_rx_radiotap_header *tap = &sc->sc_rxtap;
+ uint8_t mcs, pkt_type, nss;
+ uint16_t chan_flags;
+ uint32_t freq;
+
+ mcs = sc->hal_rx_ops->rx_desc_get_msdu_rate_mcs(msdu->rx_desc);
+ pkt_type = sc->hal_rx_ops->rx_desc_get_msdu_pkt_type(
+ msdu->rx_desc);
+ nss = hweight8(sc->hal_rx_ops->rx_desc_get_msdu_nss(
+ msdu->rx_desc));
+ freq = qwz_dp_rx_h_msdu_start_freq(sc, msdu->rx_desc);
+
+ tap->wr_ihdr.it_present = htole32(QWZ_RX_RADIOTAP_PRESENT &
+ ~(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL));
+ tap->wr_flags = 0;
+ tap->wr_chan_freq = htole16(ic->ic_channels[freq & 0xff].ic_freq);
+ chan_flags = ic->ic_channels[freq & 0xff].ic_flags;
+ if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) {
+ if (nss > 1)
+ mcs += 8 * (nss - 1);
+ tap->wr_rate = (0x80 | mcs);
+ } else {
+ uint8_t rateidx;
+ uint16_t rate;
+
+ if (qwz_mac_hw_ratecode_to_legacy_rate(ni, mcs,
+ pkt_type, &rateidx, &rate) == 0)
+ tap->wr_rate = rate;
+ else
+ tap->wr_rate = 0;
+
+ chan_flags &= ~IEEE80211_CHAN_HT;
+ chan_flags &= ~IEEE80211_CHAN_VHT;
+ chan_flags &= ~IEEE80211_CHAN_40MHZ;
+ }
+ tap->wr_chan_flags = htole16(chan_flags);
+ tap->wr_dbm_antsignal = 0;
bpf_mtap_hdr(sc->sc_drvbpf, tap, sc->sc_rxtap_len,
msdu->m, BPF_DIRECTION_IN);
@@ -24849,11 +24940,11 @@ qwz_radiotap_attach(struct qwz_softc *sc)
sc->sc_rxtap_len = sizeof(sc->sc_rxtapu);
sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
- sc->sc_rxtap.wr_ihdr.it_present = htole32(IWX_RX_RADIOTAP_PRESENT);
+ sc->sc_rxtap.wr_ihdr.it_present = htole32(QWZ_RX_RADIOTAP_PRESENT);
sc->sc_txtap_len = sizeof(sc->sc_txtapu);
sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
- sc->sc_txtap.wt_ihdr.it_present = htole32(IWX_TX_RADIOTAP_PRESENT);
+ sc->sc_txtap.wt_ihdr.it_present = htole32(QWZ_TX_RADIOTAP_PRESENT);
}
#endif
diff --git a/sys/dev/ic/qwzvar.h b/sys/dev/ic/qwzvar.h
index b182f7001db..924adab0ce2 100644
--- a/sys/dev/ic/qwzvar.h
+++ b/sys/dev/ic/qwzvar.h
@@ -289,9 +289,9 @@ struct hal_rx_ops {
uint16_t (*rx_desc_get_msdu_len)(struct hal_rx_desc *desc);
#ifdef notyet
uint8_t (*rx_desc_get_msdu_sgi)(struct hal_rx_desc *desc);
- uint8_t (*rx_desc_get_msdu_rate_mcs)(struct hal_rx_desc *desc);
uint8_t (*rx_desc_get_msdu_rx_bw)(struct hal_rx_desc *desc);
#endif
+ uint8_t (*rx_desc_get_msdu_rate_mcs)(struct hal_rx_desc *desc);
uint32_t (*rx_desc_get_msdu_freq)(struct hal_rx_desc *desc);
uint8_t (*rx_desc_get_msdu_pkt_type)(struct hal_rx_desc *desc);
uint8_t (*rx_desc_get_msdu_nss)(struct hal_rx_desc *desc);
@@ -1889,15 +1889,31 @@ struct qwz_ext_irq_grp {
struct qwz_rx_radiotap_header {
struct ieee80211_radiotap_header wr_ihdr;
+ uint8_t wr_flags;
+ uint8_t wr_rate;
+ uint16_t wr_chan_freq;
+ uint16_t wr_chan_flags;
+ int8_t wr_dbm_antsignal;
} __packed;
-#define IWX_RX_RADIOTAP_PRESENT 0 /* TODO add more information */
+#define QWZ_RX_RADIOTAP_PRESENT \
+ ((1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_CHANNEL) | \
+ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL))
struct qwz_tx_radiotap_header {
struct ieee80211_radiotap_header wt_ihdr;
+ uint8_t wt_flags;
+ uint8_t wt_rate;
+ uint16_t wt_chan_freq;
+ uint16_t wt_chan_flags;
} __packed;
-#define IWX_TX_RADIOTAP_PRESENT 0 /* TODO add more information */
+#define QWZ_TX_RADIOTAP_PRESENT \
+ ((1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_CHANNEL))
struct qwz_setkey_task_arg {
struct ieee80211_node *ni;
--
2.55.0
From 8db03414d84b4bc2ab6cee6304232abce91a9e16 Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:56:51 +0200
Subject: [PATCH 7/8] sys/qwz: preserve decoded radiotap frequency
Management RX parameters already contain a hostorder chanel
frequency. Avoid decoding it again before writing the little endian
radiotap field.
---
sys/dev/ic/qwz.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index e6a08bdc2e7..54f58f1f9ce 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -11901,7 +11901,7 @@ qwz_mgmt_rx_event(struct qwz_softc *sc, struct mbuf *m)
tap->wr_ihdr.it_present = htole32(QWZ_RX_RADIOTAP_PRESENT);
tap->wr_flags = 0;
- freq = le32toh(rx_ev.chan_freq);
+ freq = rx_ev.chan_freq;
tap->wr_chan_freq = htole16(freq);
chan_flags = ic->ic_channels[rx_ev.channel & 0xff].ic_flags;
if (ic->ic_curmode != IEEE80211_MODE_11N &&
--
2.55.0
From 5bf6ecff371848346ab02d43a599f5e9d4394a08 Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:57:06 +0200
Subject: [PATCH 8/8] sys/qwz: retain cached firmware filenames
Backport of sys/dev/pci/if_qwx_pci.c,v 1.29
---
sys/dev/pci/if_qwz_pci.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/sys/dev/pci/if_qwz_pci.c b/sys/dev/pci/if_qwz_pci.c
index 1c7c3895c72..e1997e2671c 100644
--- a/sys/dev/pci/if_qwz_pci.c
+++ b/sys/dev/pci/if_qwz_pci.c
@@ -3033,16 +3033,15 @@ qwz_mhi_fw_load_handler(struct qwz_pci_softc *psc)
u_char *data;
size_t len;
- amss_path[0] = '\0';
+ ret = snprintf(amss_path, sizeof(amss_path), "%s-%s-%s",
+ ATH12K_FW_DIR, sc->hw_params.fw.dir, ATH12K_AMSS_FILE);
+ if (ret < 0 || ret >= sizeof(amss_path))
+ return ENOSPC;
+
if (sc->fw_img[QWZ_FW_AMSS].data) {
data = sc->fw_img[QWZ_FW_AMSS].data;
len = sc->fw_img[QWZ_FW_AMSS].size;
} else {
- ret = snprintf(amss_path, sizeof(amss_path), "%s-%s-%s",
- ATH12K_FW_DIR, sc->hw_params.fw.dir, ATH12K_AMSS_FILE);
- if (ret < 0 || ret >= sizeof(amss_path))
- return ENOSPC;
-
ret = loadfirmware(amss_path, &data, &len);
if (ret) {
printf("%s: could not read %s (error %d)\n",
--
2.55.0
--
wbr, Kirill
The 5th batch of qwz commits