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" <[email protected]> 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" <[email protected]> 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" <[email protected]> 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" <[email protected]> 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" <[email protected]> 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" <[email protected]> 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" <[email protected]> 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
