From: Kirill A. Korinsky Subject: The 5th batch of qwz commits To: Stefan Sperling Cc: OpenBSD tech Date: Wed, 30 Sep 2026 20:59:37 +0200 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" 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" 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" 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" 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" 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" 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 @@ -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" 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" 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