Download raw body.
The 6th batch of qwz commits
Stefan,
here the 6th batch of qwz commits.
It is quite mechanical with exception of one commit where I fix REO layout
to that I had discovered in ath12k, and the next one fixes its lifetime.
It was tested on my device and makes it works better, but I may make typos.
Ok?
From d9ab1f87492f1fb420c1db383b1db95a49954bdf Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:54:40 +0200
Subject: [PATCH 1/7] sys/qwz: update RSSI from TX acknowledgments
Backport of sys/dev/ic/qwx.c,v 1.98
---
sys/dev/ic/qwz.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index 54f58f1f9ce..e517b9f417a 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -14561,6 +14561,16 @@ qwz_dp_tx_complete_msdu(struct qwz_softc *sc, struct dp_tx_ring *tx_ring,
} else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N)
tx_data->ni->ni_txmcs = mcs;
+ if (ts->status == HAL_WBM_TQM_REL_REASON_FRAME_ACKED &&
+ ts->ack_rssi != 0) {
+ int8_t rssi_dbm = (int8_t)ts->ack_rssi;
+
+ if (!isset(sc->wmi.svc_map,
+ WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT))
+ rssi_dbm += ATH12K_DEFAULT_NOISE_FLOOR;
+ tx_data->ni->ni_rssi = rssi_dbm;
+ }
+
ieee80211_release_node(ic, tx_data->ni);
tx_data->ni = NULL;
}
--
2.55.0
From 444ab6aeef335b30552052c536ad328ffcdac5f5 Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:56:21 +0200
Subject: [PATCH 2/7] sys/qwz: clear node flags during deauthentication
Backport of sys/dev/ic/qwx.c,v 1.113
---
sys/dev/ic/qwz.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index e517b9f417a..b018119e9ba 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -24388,11 +24388,18 @@ qwz_auth(struct qwz_softc *sc)
int
qwz_deauth(struct qwz_softc *sc)
{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct qwz_node *nq = (struct qwz_node *)ic->ic_bss;
struct qwz_vif *arvif = &sc->sc_vif;
uint8_t pdev_id = 0; /* TODO: derive pdev ID somehow? */
struct ath12k_peer *peer = TAILQ_FIRST(&sc->peers);
int ret;
+ if (ic->ic_opmode == IEEE80211_M_STA) {
+ ic->ic_bss->ni_txrate = 0;
+ nq->flags = 0;
+ }
+
ret = qwz_mac_vdev_stop(sc, arvif, pdev_id);
if (ret) {
printf("%s: unable to stop vdev vdev_id %d: %d\n",
--
2.55.0
From 941e13bb341b1f37d342a86ac75e363a05d24a4c Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:56:08 +0200
Subject: [PATCH 3/7] sys/qwz: keep data interrupts through association
Backport of sys/dev/ic/qwx.c,v 1.125
---
sys/dev/ic/qwz.c | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index b018119e9ba..cbe8ad6ff4e 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -250,6 +250,7 @@ qwz_init(struct ifnet *ifp)
refcnt_init(&sc->task_refs);
ifq_clr_oactive(&ifp->if_snd);
ifp->if_flags |= IFF_RUNNING;
+ sc->ops.irq_enable(sc);
ieee80211_begin_scan(ifp);
}
splx(s);
@@ -357,6 +358,7 @@ qwz_init(struct ifnet *ifp)
ifq_clr_oactive(&ifp->if_snd);
ifp->if_flags |= IFF_RUNNING;
+ sc->ops.irq_enable(sc);
ieee80211_begin_scan(ifp);
}
@@ -18969,10 +18971,6 @@ qwz_core_qmi_firmware_ready(struct qwz_softc *sc)
goto err_core_stop;
}
-#if 0 /* TODO: Is this in the right spot for OpenBSD? */
- sc->ops.irq_enable(sc);
-#endif
-
#if 0
mutex_unlock(&ab->core_lock);
#endif
@@ -24915,8 +24913,6 @@ qwz_run(struct qwz_softc *sc)
DNPRINTF(QWZ_D_MAC, "%s: vdev %d up (associated) bssid %s aid %d\n",
__func__, arvif->vdev_id, ether_sprintf(ni->ni_bssid), arvif->aid);
- /* Enable "ext" IRQs for datapath. */
- sc->ops.irq_enable(sc);
return 0;
}
@@ -24930,8 +24926,6 @@ qwz_run_stop(struct qwz_softc *sc)
struct qwz_node *nq = (void *)ic->ic_bss;
int ret;
- sc->ops.irq_disable(sc);
-
if (ic->ic_opmode == IEEE80211_M_STA) {
ic->ic_bss->ni_txrate = 0;
nq->flags = 0;
--
2.55.0
From 64f0e21feed6cafe1fd93688ed0737247cc467e3 Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:56:11 +0200
Subject: [PATCH 4/7] sys/qwz: prepare peers before association requests
Backport of sys/dev/ic/qwx.c,v 1.94, sys/dev/ic/qwx.c,v 1.118
---
sys/dev/ic/qwz.c | 60 +++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 52 insertions(+), 8 deletions(-)
diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index cbe8ad6ff4e..7eb5465f5d8 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -180,6 +180,7 @@ int qwz_scan(struct qwz_softc *);
void qwz_scan_abort(struct qwz_softc *);
int qwz_auth(struct qwz_softc *);
int qwz_deauth(struct qwz_softc *);
+int qwz_assoc(struct qwz_softc *);
int qwz_run(struct qwz_softc *);
int qwz_run_stop(struct qwz_softc *);
@@ -1114,6 +1115,7 @@ next_scan:
break;
case IEEE80211_S_ASSOC:
+ err = qwz_assoc(sc);
break;
case IEEE80211_S_RUN:
@@ -24408,13 +24410,6 @@ qwz_deauth(struct qwz_softc *sc)
if (peer == NULL)
return 0;
- ret = qwz_wmi_set_peer_param(sc, peer->addr, arvif->vdev_id,
- pdev_id, WMI_PEER_AUTHORIZE, 0);
- if (ret) {
- printf("%s: unable to deauthorize BSS peer: %d\n",
- sc->sc_dev.dv_xname, ret);
- return ret;
- }
ret = qwz_mac_station_remove(sc, arvif, pdev_id, peer);
if (ret)
@@ -24798,7 +24793,7 @@ qwz_ampdu_tx_start(struct ieee80211com *ic, struct ieee80211_node *ni,
}
int
-qwz_run(struct qwz_softc *sc)
+qwz_assoc(struct qwz_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_node *ni = ic->ic_bss;
@@ -24870,6 +24865,43 @@ qwz_run(struct qwz_softc *sc)
return ret;
}
}
+
+ return 0;
+}
+
+int
+qwz_run(struct qwz_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211_node *ni = ic->ic_bss;
+ struct qwz_vif *arvif = &sc->sc_vif;
+ uint8_t pdev_id = 0; /* TODO: derive pdev ID somehow? */
+ struct peer_assoc_params peer_arg;
+ int ret;
+
+ qwz_peer_assoc_prepare(sc, arvif, ni, &peer_arg, 1);
+
+ peer_arg.is_assoc = 1;
+
+ sc->peer_assoc_done = 0;
+ ret = qwz_wmi_send_peer_assoc_cmd(sc, pdev_id, &peer_arg);
+ if (ret) {
+ printf("%s: failed to run peer assoc for %s vdev %i: %d\n",
+ sc->sc_dev.dv_xname, ether_sprintf(ni->ni_macaddr),
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ while (!sc->peer_assoc_done) {
+ ret = tsleep_nsec(&sc->peer_assoc_done, 0, "qwzassoc",
+ SEC_TO_NSEC(1));
+ if (ret) {
+ printf("%s: failed to get peer assoc conf event "
+ "for %s vdev %i\n", sc->sc_dev.dv_xname,
+ ether_sprintf(ni->ni_macaddr), arvif->vdev_id);
+ return ret;
+ }
+ }
#if 0
ret = ath12k_setup_peer_smps(ar, arvif, sta->addr,
&sta->deflink.ht_cap,
@@ -24924,8 +24956,20 @@ qwz_run_stop(struct qwz_softc *sc)
struct qwz_vif *arvif = &sc->sc_vif;
uint8_t pdev_id = 0; /* TODO: derive pdev ID somehow? */
struct qwz_node *nq = (void *)ic->ic_bss;
+ struct ath12k_peer *peer = TAILQ_FIRST(&sc->peers);
int ret;
+ if (peer != NULL) {
+ ret = qwz_wmi_set_peer_param(sc, peer->addr, arvif->vdev_id,
+ pdev_id, WMI_PEER_AUTHORIZE, 0);
+ if (ret) {
+ printf("%s: unable to deauthorize BSS peer: %d\n",
+ sc->sc_dev.dv_xname, ret);
+ return ret;
+ }
+
+ }
+
if (ic->ic_opmode == IEEE80211_M_STA) {
ic->ic_bss->ni_txrate = 0;
nq->flags = 0;
--
2.55.0
From b46032b456e356b3befae341d4869c1dd09d5762 Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:56:14 +0200
Subject: [PATCH 5/7] sys/qwz: configure negotiated HT SMPS
Backport of sys/dev/ic/qwx.c,v 1.92
---
sys/dev/ic/qwz.c | 46 ++++++++++++++++++++++++++++++++++++----------
1 file changed, 36 insertions(+), 10 deletions(-)
diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index 7eb5465f5d8..24ca756e304 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -24792,6 +24792,33 @@ qwz_ampdu_tx_start(struct ieee80211com *ic, struct ieee80211_node *ni,
return 0;
}
+int
+qwz_setup_peer_smps(struct qwz_softc *sc, uint8_t pdev_id, struct qwz_vif *arvif,
+ uint8_t *addr, uint16_t htcaps)
+{
+ uint16_t smps;
+ uint32_t val;
+
+ smps = (htcaps & IEEE80211_HTCAP_SMPS_MASK) >>
+ IEEE80211_HTCAP_SMPS_SHIFT;
+
+ switch (smps) {
+ case IEEE80211_HTCAP_SMPS_STA:
+ val = WMI_PEER_SMPS_STATIC;
+ break;
+ case IEEE80211_HTCAP_SMPS_DYN:
+ val = WMI_PEER_SMPS_DYNAMIC;
+ break;
+ case IEEE80211_HTCAP_SMPS_DIS:
+ default:
+ val = WMI_PEER_SMPS_PS_NONE;
+ break;
+ }
+
+ return qwz_wmi_set_peer_param(sc, addr, arvif->vdev_id,
+ pdev_id, WMI_PEER_MIMO_PS_STATE, val);
+}
+
int
qwz_assoc(struct qwz_softc *sc)
{
@@ -24902,15 +24929,16 @@ qwz_run(struct qwz_softc *sc)
return ret;
}
}
-#if 0
- ret = ath12k_setup_peer_smps(ar, arvif, sta->addr,
- &sta->deflink.ht_cap,
- le16_to_cpu(sta->deflink.he_6ghz_capa.capa));
- if (ret) {
- ath12k_warn(ar->ab, "failed to setup peer SMPS for vdev %d: %d\n",
- arvif->vdev_id, ret);
- return ret;
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ ret = qwz_setup_peer_smps(sc, pdev_id, arvif, ni->ni_macaddr,
+ ni->ni_htcaps);
+ if (ret) {
+ printf("%s: failed to setup SMPS for vdev %d: %d\n",
+ sc->sc_dev.dv_xname, arvif->vdev_id, ret);
+ return ret;
+ }
}
+#if 0
if (!ath12k_mac_vif_recalc_sta_he_txbf(ar, vif, &he_cap)) {
ath12k_warn(ar->ab, "failed to recalc he txbf for vdev %i on bss %pM\n",
@@ -24945,7 +24973,6 @@ qwz_run(struct qwz_softc *sc)
DNPRINTF(QWZ_D_MAC, "%s: vdev %d up (associated) bssid %s aid %d\n",
__func__, arvif->vdev_id, ether_sprintf(ni->ni_bssid), arvif->aid);
-
return 0;
}
@@ -24967,7 +24994,6 @@ qwz_run_stop(struct qwz_softc *sc)
sc->sc_dev.dv_xname, ret);
return ret;
}
-
}
if (ic->ic_opmode == IEEE80211_M_STA) {
--
2.55.0
From 91870f9306624e78301f76272239208560e169e9 Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:57:39 +0200
Subject: [PATCH 6/7] sys/qwz: fix WCN7850 REO layout
Use WCN7850 REO tags and 64-bit TLV headers so commands and completions
use the correct offsets. Correct the status ring size and clear command
payloads before reuse.
The layout follows Linux ath12k's WCN7850 definitions.
---
sys/dev/ic/qwz.c | 165 ++++++++++++++++++++++++++------------------
sys/dev/ic/qwzreg.h | 32 ++++-----
2 files changed, 113 insertions(+), 84 deletions(-)
diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index 24ca756e304..6d79eec5376 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -8004,7 +8004,7 @@ void
qwz_hal_reo_init_cmd_ring(struct qwz_softc *sc, struct hal_srng *srng)
{
struct hal_srng_params params;
- struct hal_tlv_hdr *tlv;
+ struct hal_tlv_64_hdr *tlv;
struct hal_reo_get_queue_stats *desc;
int i, cmd_num = 1;
int entry_size;
@@ -8017,39 +8017,44 @@ qwz_hal_reo_init_cmd_ring(struct qwz_softc *sc, struct hal_srng *srng)
entry = (uint8_t *)params.ring_base_vaddr;
for (i = 0; i < params.num_entries; i++) {
- tlv = (struct hal_tlv_hdr *)entry;
+ tlv = (struct hal_tlv_64_hdr *)entry;
desc = (struct hal_reo_get_queue_stats *)tlv->value;
- desc->cmd.info0 = FIELD_PREP(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER,
- cmd_num++);
+ desc->cmd.info0 = htole32(FIELD_PREP(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER,
+ cmd_num++));
entry += entry_size;
}
}
int
-qwz_hal_reo_cmd_queue_stats(struct hal_tlv_hdr *tlv, struct ath12k_hal_reo_cmd *cmd)
+qwz_hal_reo_cmd_queue_stats(struct hal_tlv_64_hdr *tlv,
+ struct ath12k_hal_reo_cmd *cmd)
{
struct hal_reo_get_queue_stats *desc;
- tlv->tl = FIELD_PREP(HAL_TLV_HDR_TAG, HAL_REO_GET_QUEUE_STATS) |
- FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc));
+ tlv->tl = htole64(FIELD_PREP(HAL_TLV_HDR_TAG, HAL_REO_GET_QUEUE_STATS) |
+ FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc)));
desc = (struct hal_reo_get_queue_stats *)tlv->value;
+ memset(&desc->queue_addr_lo, 0,
+ sizeof(*desc) - offsetof(struct hal_reo_get_queue_stats, queue_addr_lo));
- desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
+ desc->cmd.info0 &= ~htole32(HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED);
if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS)
- desc->cmd.info0 |= HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
+ desc->cmd.info0 |= htole32(HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED);
- desc->queue_addr_lo = cmd->addr_lo;
+ desc->queue_addr_lo = htole32(cmd->addr_lo);
desc->info0 = FIELD_PREP(HAL_REO_GET_QUEUE_STATS_INFO0_QUEUE_ADDR_HI,
cmd->addr_hi);
if (cmd->flag & HAL_REO_CMD_FLG_STATS_CLEAR)
desc->info0 |= HAL_REO_GET_QUEUE_STATS_INFO0_CLEAR_STATS;
- return FIELD_GET(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER, desc->cmd.info0);
+ desc->info0 = htole32(desc->info0);
+ return FIELD_GET(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER,
+ le32toh(desc->cmd.info0));
}
int
-qwz_hal_reo_cmd_flush_cache(struct ath12k_hal *hal, struct hal_tlv_hdr *tlv,
+qwz_hal_reo_cmd_flush_cache(struct ath12k_hal *hal, struct hal_tlv_64_hdr *tlv,
struct ath12k_hal_reo_cmd *cmd)
{
struct hal_reo_flush_cache *desc;
@@ -8062,16 +8067,18 @@ qwz_hal_reo_cmd_flush_cache(struct ath12k_hal *hal, struct hal_tlv_hdr *tlv,
hal->current_blk_index = avail_slot;
}
- tlv->tl = FIELD_PREP(HAL_TLV_HDR_TAG, HAL_REO_FLUSH_CACHE) |
- FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc));
+ tlv->tl = htole64(FIELD_PREP(HAL_TLV_HDR_TAG, HAL_REO_FLUSH_CACHE) |
+ FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc)));
desc = (struct hal_reo_flush_cache *)tlv->value;
+ memset(&desc->cache_addr_lo, 0,
+ sizeof(*desc) - offsetof(struct hal_reo_flush_cache, cache_addr_lo));
- desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
+ desc->cmd.info0 &= ~htole32(HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED);
if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS)
- desc->cmd.info0 |= HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
+ desc->cmd.info0 |= htole32(HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED);
- desc->cache_addr_lo = cmd->addr_lo;
+ desc->cache_addr_lo = htole32(cmd->addr_lo);
desc->info0 = FIELD_PREP(HAL_REO_FLUSH_CACHE_INFO0_CACHE_ADDR_HI,
cmd->addr_hi);
@@ -8091,25 +8098,29 @@ qwz_hal_reo_cmd_flush_cache(struct ath12k_hal *hal, struct hal_tlv_hdr *tlv,
if (cmd->flag & HAL_REO_CMD_FLG_FLUSH_ALL)
desc->info0 |= HAL_REO_FLUSH_CACHE_INFO0_FLUSH_ALL;
- return FIELD_GET(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER, desc->cmd.info0);
+ desc->info0 = htole32(desc->info0);
+ return FIELD_GET(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER,
+ le32toh(desc->cmd.info0));
}
int
-qwz_hal_reo_cmd_update_rx_queue(struct hal_tlv_hdr *tlv,
+qwz_hal_reo_cmd_update_rx_queue(struct hal_tlv_64_hdr *tlv,
struct ath12k_hal_reo_cmd *cmd)
{
struct hal_reo_update_rx_queue *desc;
- tlv->tl = FIELD_PREP(HAL_TLV_HDR_TAG, HAL_REO_UPDATE_RX_REO_QUEUE) |
- FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc));
+ tlv->tl = htole64(FIELD_PREP(HAL_TLV_HDR_TAG, HAL_REO_UPDATE_RX_REO_QUEUE) |
+ FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc)));
desc = (struct hal_reo_update_rx_queue *)tlv->value;
+ memset(&desc->queue_addr_lo, 0,
+ sizeof(*desc) - offsetof(struct hal_reo_update_rx_queue, queue_addr_lo));
- desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
+ desc->cmd.info0 &= ~htole32(HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED);
if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS)
- desc->cmd.info0 |= HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
+ desc->cmd.info0 |= htole32(HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED);
- desc->queue_addr_lo = cmd->addr_lo;
+ desc->queue_addr_lo = htole32(cmd->addr_lo);
desc->info0 =
FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_QUEUE_ADDR_HI,
cmd->addr_hi) |
@@ -8215,20 +8226,25 @@ qwz_hal_reo_cmd_update_rx_queue(struct hal_tlv_hdr *tlv,
FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO2_PN_ERR,
!!(cmd->upd2 & HAL_REO_CMD_UPD2_PN_ERR));
- return FIELD_GET(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER, desc->cmd.info0);
+ desc->info0 = htole32(desc->info0);
+ desc->info1 = htole32(desc->info1);
+ desc->info2 = htole32(desc->info2);
+ return FIELD_GET(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER,
+ le32toh(desc->cmd.info0));
}
int
qwz_hal_reo_cmd_send(struct qwz_softc *sc, struct hal_srng *srng,
enum hal_reo_cmd_type type, struct ath12k_hal_reo_cmd *cmd)
{
- struct hal_tlv_hdr *reo_desc;
+ struct hal_tlv_64_hdr *reo_desc;
int ret;
#ifdef notyet
spin_lock_bh(&srng->lock);
#endif
qwz_hal_srng_access_begin(sc, srng);
- reo_desc = (struct hal_tlv_hdr *)qwz_hal_srng_src_get_next_entry(sc, srng);
+ reo_desc = (struct hal_tlv_64_hdr *)
+ qwz_hal_srng_src_get_next_entry(sc, srng);
if (!reo_desc) {
ret = ENOBUFS;
goto out;
@@ -16324,14 +16340,16 @@ void
qwz_hal_reo_status_queue_stats(struct qwz_softc *sc, uint32_t *reo_desc,
struct hal_reo_status *status)
{
- struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+ struct hal_tlv_64_hdr *tlv = (struct hal_tlv_64_hdr *)reo_desc;
struct hal_reo_get_queue_stats_status *desc =
(struct hal_reo_get_queue_stats_status *)tlv->value;
status->uniform_hdr.cmd_num =
- FIELD_GET(HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, desc->hdr.info0);
+ FIELD_GET(HAL_REO_STATUS_HDR_INFO0_STATUS_NUM,
+ le32toh(desc->hdr.info0));
status->uniform_hdr.cmd_status =
- FIELD_GET(HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, desc->hdr.info0);
+ FIELD_GET(HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS,
+ le32toh(desc->hdr.info0));
#if 0
ath12k_dbg(ab, ATH12K_DBG_HAL, "Queue stats status:\n");
ath12k_dbg(ab, ATH12K_DBG_HAL, "header: cmd_num %d status %d\n",
@@ -16390,16 +16408,16 @@ void
qwz_hal_reo_flush_queue_status(struct qwz_softc *sc, uint32_t *reo_desc,
struct hal_reo_status *status)
{
- struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+ struct hal_tlv_64_hdr *tlv = (struct hal_tlv_64_hdr *)reo_desc;
struct hal_reo_flush_queue_status *desc =
(struct hal_reo_flush_queue_status *)tlv->value;
status->uniform_hdr.cmd_num = FIELD_GET(
- HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, desc->hdr.info0);
+ HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, le32toh(desc->hdr.info0));
status->uniform_hdr.cmd_status = FIELD_GET(
- HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, desc->hdr.info0);
+ HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, le32toh(desc->hdr.info0));
status->u.flush_queue.err_detected = FIELD_GET(
- HAL_REO_FLUSH_QUEUE_INFO0_ERR_DETECTED, desc->info0);
+ HAL_REO_FLUSH_QUEUE_INFO0_ERR_DETECTED, le32toh(desc->info0));
}
void
@@ -16407,37 +16425,39 @@ qwz_hal_reo_flush_cache_status(struct qwz_softc *sc, uint32_t *reo_desc,
struct hal_reo_status *status)
{
struct ath12k_hal *hal = &sc->hal;
- struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+ struct hal_tlv_64_hdr *tlv = (struct hal_tlv_64_hdr *)reo_desc;
struct hal_reo_flush_cache_status *desc =
(struct hal_reo_flush_cache_status *)tlv->value;
status->uniform_hdr.cmd_num = FIELD_GET(
- HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, desc->hdr.info0);
+ HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, le32toh(desc->hdr.info0));
status->uniform_hdr.cmd_status = FIELD_GET(
- HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, desc->hdr.info0);
+ HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, le32toh(desc->hdr.info0));
status->u.flush_cache.err_detected = FIELD_GET(
- HAL_REO_FLUSH_CACHE_STATUS_INFO0_IS_ERR, desc->info0);
+ HAL_REO_FLUSH_CACHE_STATUS_INFO0_IS_ERR, le32toh(desc->info0));
status->u.flush_cache.err_code = FIELD_GET(
- HAL_REO_FLUSH_CACHE_STATUS_INFO0_BLOCK_ERR_CODE, desc->info0);
+ HAL_REO_FLUSH_CACHE_STATUS_INFO0_BLOCK_ERR_CODE,
+ le32toh(desc->info0));
if (!status->u.flush_cache.err_code)
hal->avail_blk_resource |= BIT(hal->current_blk_index);
status->u.flush_cache.cache_controller_flush_status_hit = FIELD_GET(
- HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_STATUS_HIT, desc->info0);
+ HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_STATUS_HIT,
+ le32toh(desc->info0));
status->u.flush_cache.cache_controller_flush_status_desc_type =
FIELD_GET(HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_DESC_TYPE,
- desc->info0);
+ le32toh(desc->info0));
status->u.flush_cache.cache_controller_flush_status_client_id =
FIELD_GET(HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_CLIENT_ID,
- desc->info0);
+ le32toh(desc->info0));
status->u.flush_cache.cache_controller_flush_status_err =
FIELD_GET(HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_ERR,
- desc->info0);
+ le32toh(desc->info0));
status->u.flush_cache.cache_controller_flush_status_cnt =
FIELD_GET(HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_COUNT,
- desc->info0);
+ le32toh(desc->info0));
}
void
@@ -16445,19 +16465,19 @@ qwz_hal_reo_unblk_cache_status(struct qwz_softc *sc, uint32_t *reo_desc,
struct hal_reo_status *status)
{
struct ath12k_hal *hal = &sc->hal;
- struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+ struct hal_tlv_64_hdr *tlv = (struct hal_tlv_64_hdr *)reo_desc;
struct hal_reo_unblock_cache_status *desc =
(struct hal_reo_unblock_cache_status *)tlv->value;
status->uniform_hdr.cmd_num = FIELD_GET(
- HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, desc->hdr.info0);
+ HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, le32toh(desc->hdr.info0));
status->uniform_hdr.cmd_status = FIELD_GET(
- HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, desc->hdr.info0);
+ HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, le32toh(desc->hdr.info0));
status->u.unblock_cache.err_detected = FIELD_GET(
- HAL_REO_UNBLOCK_CACHE_STATUS_INFO0_IS_ERR, desc->info0);
+ HAL_REO_UNBLOCK_CACHE_STATUS_INFO0_IS_ERR, le32toh(desc->info0));
status->u.unblock_cache.unblock_type = FIELD_GET(
- HAL_REO_UNBLOCK_CACHE_STATUS_INFO0_TYPE, desc->info0);
+ HAL_REO_UNBLOCK_CACHE_STATUS_INFO0_TYPE, le32toh(desc->info0));
if (!status->u.unblock_cache.err_detected &&
status->u.unblock_cache.unblock_type ==
@@ -16469,68 +16489,75 @@ void
qwz_hal_reo_flush_timeout_list_status(struct qwz_softc *ab, uint32_t *reo_desc,
struct hal_reo_status *status)
{
- struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+ struct hal_tlv_64_hdr *tlv = (struct hal_tlv_64_hdr *)reo_desc;
struct hal_reo_flush_timeout_list_status *desc =
(struct hal_reo_flush_timeout_list_status *)tlv->value;
status->uniform_hdr.cmd_num = FIELD_GET(
- HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, desc->hdr.info0);
+ HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, le32toh(desc->hdr.info0));
status->uniform_hdr.cmd_status = FIELD_GET(
- HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, desc->hdr.info0);
+ HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, le32toh(desc->hdr.info0));
status->u.timeout_list.err_detected = FIELD_GET(
- HAL_REO_FLUSH_TIMEOUT_STATUS_INFO0_IS_ERR, desc->info0);
+ HAL_REO_FLUSH_TIMEOUT_STATUS_INFO0_IS_ERR, le32toh(desc->info0));
status->u.timeout_list.list_empty = FIELD_GET(
- HAL_REO_FLUSH_TIMEOUT_STATUS_INFO0_LIST_EMPTY, desc->info0);
+ HAL_REO_FLUSH_TIMEOUT_STATUS_INFO0_LIST_EMPTY,
+ le32toh(desc->info0));
status->u.timeout_list.release_desc_cnt = FIELD_GET(
- HAL_REO_FLUSH_TIMEOUT_STATUS_INFO1_REL_DESC_COUNT, desc->info1);
+ HAL_REO_FLUSH_TIMEOUT_STATUS_INFO1_REL_DESC_COUNT,
+ le32toh(desc->info1));
status->u.timeout_list.fwd_buf_cnt = FIELD_GET(
- HAL_REO_FLUSH_TIMEOUT_STATUS_INFO1_FWD_BUF_COUNT, desc->info1);
+ HAL_REO_FLUSH_TIMEOUT_STATUS_INFO1_FWD_BUF_COUNT,
+ le32toh(desc->info1));
}
void
qwz_hal_reo_desc_thresh_reached_status(struct qwz_softc *sc, uint32_t *reo_desc,
struct hal_reo_status *status)
{
- struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+ struct hal_tlv_64_hdr *tlv = (struct hal_tlv_64_hdr *)reo_desc;
struct hal_reo_desc_thresh_reached_status *desc =
(struct hal_reo_desc_thresh_reached_status *)tlv->value;
status->uniform_hdr.cmd_num = FIELD_GET(
- HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, desc->hdr.info0);
+ HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, le32toh(desc->hdr.info0));
status->uniform_hdr.cmd_status = FIELD_GET(
- HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, desc->hdr.info0);
+ HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, le32toh(desc->hdr.info0));
status->u.desc_thresh_reached.threshold_idx = FIELD_GET(
- HAL_REO_DESC_THRESH_STATUS_INFO0_THRESH_INDEX, desc->info0);
+ HAL_REO_DESC_THRESH_STATUS_INFO0_THRESH_INDEX,
+ le32toh(desc->info0));
status->u.desc_thresh_reached.link_desc_counter0 = FIELD_GET(
- HAL_REO_DESC_THRESH_STATUS_INFO1_LINK_DESC_COUNTER0, desc->info1);
+ HAL_REO_DESC_THRESH_STATUS_INFO1_LINK_DESC_COUNTER0,
+ le32toh(desc->info1));
status->u.desc_thresh_reached.link_desc_counter1 = FIELD_GET(
- HAL_REO_DESC_THRESH_STATUS_INFO2_LINK_DESC_COUNTER1, desc->info2);
+ HAL_REO_DESC_THRESH_STATUS_INFO2_LINK_DESC_COUNTER1,
+ le32toh(desc->info2));
status->u.desc_thresh_reached.link_desc_counter2 = FIELD_GET(
- HAL_REO_DESC_THRESH_STATUS_INFO3_LINK_DESC_COUNTER2, desc->info3);
+ HAL_REO_DESC_THRESH_STATUS_INFO3_LINK_DESC_COUNTER2,
+ le32toh(desc->info3));
status->u.desc_thresh_reached.link_desc_counter_sum = FIELD_GET(
HAL_REO_DESC_THRESH_STATUS_INFO4_LINK_DESC_COUNTER_SUM,
- desc->info4);
+ le32toh(desc->info4));
}
void
qwz_hal_reo_update_rx_reo_queue_status(struct qwz_softc *ab, uint32_t *reo_desc,
struct hal_reo_status *status)
{
- struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+ struct hal_tlv_64_hdr *tlv = (struct hal_tlv_64_hdr *)reo_desc;
struct hal_reo_status_hdr *desc =
(struct hal_reo_status_hdr *)tlv->value;
status->uniform_hdr.cmd_num = FIELD_GET(
- HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, desc->info0);
+ HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, le32toh(desc->info0));
status->uniform_hdr.cmd_status = FIELD_GET(
- HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, desc->info0);
+ HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, le32toh(desc->info0));
}
int
@@ -16541,6 +16568,7 @@ qwz_dp_process_reo_status(struct qwz_softc *sc)
struct dp_reo_cmd *cmd, *tmp;
int found = 0, ret = 0;
uint32_t *reo_desc;
+ struct hal_tlv_64_hdr *tlv;
uint16_t tag;
struct hal_reo_status reo_status;
@@ -16554,7 +16582,8 @@ qwz_dp_process_reo_status(struct qwz_softc *sc)
while ((reo_desc = qwz_hal_srng_dst_get_next_entry(sc, srng))) {
ret = 1;
- tag = FIELD_GET(HAL_SRNG_TLV_HDR_TAG, *reo_desc);
+ tlv = (struct hal_tlv_64_hdr *)reo_desc;
+ tag = FIELD_GET(HAL_SRNG_TLV_HDR_TAG, le64toh(tlv->tl));
switch (tag) {
case HAL_REO_GET_QUEUE_STATS_STATUS:
qwz_hal_reo_status_queue_stats(sc, reo_desc,
diff --git a/sys/dev/ic/qwzreg.h b/sys/dev/ic/qwzreg.h
index 602fc4de356..a71db13cbb4 100644
--- a/sys/dev/ic/qwzreg.h
+++ b/sys/dev/ic/qwzreg.h
@@ -7888,7 +7888,7 @@ enum hal_tlv_tag {
HAL_MPDU_INFO = 150 /* 0x96 */,
HAL_PDG_USER_SETUP = 151 /* 0x97 */,
HAL_TX_11AH_SETUP = 152 /* 0x98 */,
- HAL_REO_UPDATE_RX_REO_QUEUE_STATUS = 153 /* 0x99 */,
+ HAL_REO_UPDATE_RX_REO_QUEUE_STATUS = 172 /* 0xac */,
HAL_TX_PEER_ENTRY = 154 /* 0x9a */,
HAL_TX_RAW_OR_NATIVE_FRAME_SETUP = 155 /* 0x9b */,
HAL_EXAMPLE_STRUCT_NAME = 156 /* 0x9c */,
@@ -8041,15 +8041,15 @@ enum hal_tlv_tag {
HAL_NO_ACK_REPORT = 303 /* 0x12f */,
HAL_ACK_REPORT = 304 /* 0x130 */,
HAL_UNIFORM_REO_CMD_HEADER = 305 /* 0x131 */,
- HAL_REO_GET_QUEUE_STATS = 306 /* 0x132 */,
- HAL_REO_FLUSH_QUEUE = 307 /* 0x133 */,
- HAL_REO_FLUSH_CACHE = 308 /* 0x134 */,
- HAL_REO_UNBLOCK_CACHE = 309 /* 0x135 */,
+ HAL_REO_GET_QUEUE_STATS = 281 /* 0x119 */,
+ HAL_REO_FLUSH_QUEUE = 282 /* 0x11a */,
+ HAL_REO_FLUSH_CACHE = 283 /* 0x11b */,
+ HAL_REO_UNBLOCK_CACHE = 284 /* 0x11c */,
HAL_UNIFORM_REO_STATUS_HEADER = 310 /* 0x136 */,
- HAL_REO_GET_QUEUE_STATS_STATUS = 311 /* 0x137 */,
- HAL_REO_FLUSH_QUEUE_STATUS = 312 /* 0x138 */,
- HAL_REO_FLUSH_CACHE_STATUS = 313 /* 0x139 */,
- HAL_REO_UNBLOCK_CACHE_STATUS = 314 /* 0x13a */,
+ HAL_REO_GET_QUEUE_STATS_STATUS = 285 /* 0x11d */,
+ HAL_REO_FLUSH_QUEUE_STATUS = 286 /* 0x11e */,
+ HAL_REO_FLUSH_CACHE_STATUS = 287 /* 0x11f */,
+ HAL_REO_UNBLOCK_CACHE_STATUS = 288 /* 0x120 */,
HAL_TQM_FLUSH_CACHE = 315 /* 0x13b */,
HAL_TQM_UNBLOCK_CACHE = 316 /* 0x13c */,
HAL_TQM_FLUSH_CACHE_STATUS = 317 /* 0x13d */,
@@ -8076,11 +8076,11 @@ enum hal_tlv_tag {
HAL_TQM_SYNC_CMD_STATUS = 338 /* 0x152 */,
HAL_TQM_THRESHOLD_DROP_NOTIFICATION_STATUS = 339 /* 0x153 */,
HAL_TQM_DESCRIPTOR_THRESHOLD_REACHED_STATUS = 340 /* 0x154 */,
- HAL_REO_FLUSH_TIMEOUT_LIST = 341 /* 0x155 */,
- HAL_REO_FLUSH_TIMEOUT_LIST_STATUS = 342 /* 0x156 */,
+ HAL_REO_FLUSH_TIMEOUT_LIST = 305 /* 0x131 */,
+ HAL_REO_FLUSH_TIMEOUT_LIST_STATUS = 306 /* 0x132 */,
HAL_REO_TO_PPE_RING = 343 /* 0x157 */,
HAL_RX_MPDU_INFO = 344 /* 0x158 */,
- HAL_REO_DESCRIPTOR_THRESHOLD_REACHED_STATUS = 345 /* 0x159 */,
+ HAL_REO_DESCRIPTOR_THRESHOLD_REACHED_STATUS = 307 /* 0x133 */,
HAL_SCHEDULER_RX_SIFS_RESPONSE_TRIGGER_STATUS = 346 /* 0x15a */,
HAL_EXAMPLE_USER_TLV_32_NAME = 347 /* 0x15b */,
HAL_RX_PPDU_START_USER_INFO = 348 /* 0x15c */,
@@ -8154,7 +8154,7 @@ enum hal_tlv_tag {
HAL_TQM_UPDATE_TX_MPDU_QUEUE_HEAD = 416 /* 0x1a0 */,
HAL_TQM_UPDATE_TX_MSDU_FLOW_STATUS = 417 /* 0x1a1 */,
HAL_TQM_UPDATE_TX_MPDU_QUEUE_HEAD_STATUS = 418 /* 0x1a2 */,
- HAL_REO_UPDATE_RX_REO_QUEUE = 419 /* 0x1a3 */,
+ HAL_REO_UPDATE_RX_REO_QUEUE = 339 /* 0x153 */,
HAL_CE_DST_DESC = 420 /* 0x1a4 */,
HAL_TLV_BASE = 511 /* 0x1ff */,
};
@@ -10163,7 +10163,7 @@ struct hal_reo_status_hdr {
* enum %HAL_REO_EXEC_STATUS_.
*/
#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO0_SSN GENMASK(11, 0)
-#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO0_CUR_IDX GENMASK(19, 12)
+#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO0_CUR_IDX GENMASK(21, 12)
#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO1_MPDU_COUNT GENMASK(6, 0)
#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO1_MSDU_COUNT GENMASK(31, 7)
@@ -10177,7 +10177,7 @@ struct hal_reo_status_hdr {
#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO4_LATE_RX_MPDU GENMASK(11, 0)
#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO4_WINDOW_JMP2K GENMASK(15, 12)
-#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO4_HOLE_COUNT GENMASK(31, 16)
+#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO4_HOLE_COUNT GENMASK(27, 12)
#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO5_LOOPING_CNT GENMASK(31, 28)
@@ -10187,7 +10187,7 @@ struct hal_reo_get_queue_stats_status {
uint32_t pn[4];
uint32_t last_rx_enqueue_timestamp;
uint32_t last_rx_dequeue_timestamp;
- uint32_t rx_bitmap[8];
+ uint32_t rx_bitmap[9];
uint32_t info1;
uint32_t info2;
uint32_t info3;
--
2.55.0
From c64ddb4c420cc7487c97acda497a0491099d6b1a Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
Date: Sun, 27 Sep 2026 12:57:48 +0200
Subject: [PATCH 7/7] sys/qwz: fix REO queue lifetime
Track REO completions before publication and wait for peer unmap,
deletion, and cache flushes before reusing queue DMA. Submission errors
and timeouts retain ownership; hardware failures block reuse until cold
cleanup. HAL error conventions and flush semantics follow ath12k;
tracking and the reuse barrier adapt qwz's retained pool.
---
sys/dev/ic/qwz.c | 328 +++++++++++++++++++++++---------------------
sys/dev/ic/qwzvar.h | 24 ++--
2 files changed, 181 insertions(+), 171 deletions(-)
diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c
index 6d79eec5376..3e93b6bb40d 100644
--- a/sys/dev/ic/qwz.c
+++ b/sys/dev/ic/qwz.c
@@ -169,6 +169,7 @@ int qwz_dp_rx_h_null_q_desc(struct qwz_softc *, struct qwz_rx_msdu *,
struct qwz_rx_msdu_list *);
void qwz_dp_service_mon_ring(void *);
void qwz_peer_frags_flush(struct qwz_softc *, struct ath12k_peer *);
+int qwz_peer_rx_tid_cleanup(struct qwz_softc *, struct ath12k_peer *);
int qwz_wmi_vdev_install_key(struct qwz_softc *,
struct wmi_vdev_install_key_arg *, uint8_t);
int qwz_dp_peer_rx_pn_replay_config(struct qwz_softc *, struct qwz_vif *,
@@ -8062,7 +8063,7 @@ qwz_hal_reo_cmd_flush_cache(struct ath12k_hal *hal, struct hal_tlv_64_hdr *tlv,
if (cmd->flag & HAL_REO_CMD_FLG_FLUSH_BLOCK_LATER) {
if (avail_slot >= HAL_MAX_AVAIL_BLK_RES)
- return ENOSPC;
+ return -ENOSPC;
hal->current_blk_index = avail_slot;
}
@@ -8235,18 +8236,23 @@ qwz_hal_reo_cmd_update_rx_queue(struct hal_tlv_64_hdr *tlv,
int
qwz_hal_reo_cmd_send(struct qwz_softc *sc, struct hal_srng *srng,
- enum hal_reo_cmd_type type, struct ath12k_hal_reo_cmd *cmd)
+ enum hal_reo_cmd_type type, struct ath12k_hal_reo_cmd *cmd,
+ struct dp_reo_cmd *dp_cmd)
{
struct hal_tlv_64_hdr *reo_desc;
+ struct dp_reo_cmd *pending;
+ uint32_t hp, reap_hp;
int ret;
#ifdef notyet
spin_lock_bh(&srng->lock);
#endif
qwz_hal_srng_access_begin(sc, srng);
+ hp = srng->u.src_ring.hp;
+ reap_hp = srng->u.src_ring.reap_hp;
reo_desc = (struct hal_tlv_64_hdr *)
qwz_hal_srng_src_get_next_entry(sc, srng);
if (!reo_desc) {
- ret = ENOBUFS;
+ ret = -ENOBUFS;
goto out;
}
@@ -8265,15 +8271,35 @@ qwz_hal_reo_cmd_send(struct qwz_softc *sc, struct hal_srng *srng,
case HAL_REO_CMD_FLUSH_TIMEOUT_LIST:
printf("%s: unsupported reo command %d\n",
sc->sc_dev.dv_xname, type);
- ret = ENOTSUP;
+ ret = -ENOTSUP;
break;
default:
printf("%s: unknown reo command %d\n",
sc->sc_dev.dv_xname, type);
- ret = EINVAL;
+ ret = -EINVAL;
break;
}
+ if (ret <= 0) {
+ if (ret == 0)
+ ret = -EINVAL;
+ goto rollback;
+ }
+ TAILQ_FOREACH(pending, &sc->dp.reo_cmd_list, entry) {
+ if (pending->cmd_num == ret) {
+ ret = -EBUSY;
+ goto rollback;
+ }
+ }
+ if (dp_cmd != NULL) {
+ dp_cmd->cmd_num = ret;
+ TAILQ_INSERT_TAIL(&sc->dp.reo_cmd_list, dp_cmd, entry);
+ }
+ goto out;
+
+rollback:
+ srng->u.src_ring.hp = hp;
+ srng->u.src_ring.reap_hp = reap_hp;
out:
qwz_hal_srng_access_end(sc, srng);
#ifdef notyet
@@ -8994,13 +9020,11 @@ qwz_dp_alloc(struct qwz_softc *sc)
dp->sc = sc;
TAILQ_INIT(&dp->reo_cmd_list);
- TAILQ_INIT(&dp->reo_cmd_cache_flush_list);
#if 0
INIT_LIST_HEAD(&dp->dp_full_mon_mpdu_list);
spin_lock_init(&dp->reo_cmd_lock);
#endif
- dp->reo_cmd_cache_flush_count = 0;
dp->idle_link_rbm = qwz_dp_get_idle_link_rbm(sc);
ret = qwz_wbm_idle_ring_setup(sc, &n_link_desc);
@@ -9108,7 +9132,6 @@ qwz_dp_reo_cmd_list_cleanup(struct qwz_softc *sc)
{
struct qwz_dp *dp = &sc->dp;
struct dp_reo_cmd *cmd, *tmp;
- struct dp_reo_cache_flush_elem *cmd_cache, *tmp_cache;
struct dp_rx_tid *rx_tid;
#ifdef notyet
spin_lock_bh(&dp->reo_cmd_lock);
@@ -9119,15 +9142,6 @@ qwz_dp_reo_cmd_list_cleanup(struct qwz_softc *sc)
qwz_dp_rx_tid_clear(sc, rx_tid);
free(cmd, M_DEVBUF, sizeof(*cmd));
}
-
- TAILQ_FOREACH_SAFE(cmd_cache, &dp->reo_cmd_cache_flush_list,
- entry, tmp_cache) {
- TAILQ_REMOVE(&dp->reo_cmd_cache_flush_list, cmd_cache, entry);
- dp->reo_cmd_cache_flush_count--;
- rx_tid = &cmd_cache->data;
- qwz_dp_rx_tid_clear(sc, rx_tid);
- free(cmd_cache, M_DEVBUF, sizeof(*cmd_cache));
- }
#ifdef notyet
spin_unlock_bh(&dp->reo_cmd_lock);
#endif
@@ -9169,6 +9183,8 @@ qwz_dp_free(struct qwz_softc *sc)
}
}
+ memset(dp->rx_tid_retire, 0, sizeof(dp->rx_tid_retire));
+
/* Deinit any SOC level resource */
}
@@ -16573,7 +16589,6 @@ qwz_dp_process_reo_status(struct qwz_softc *sc)
struct hal_reo_status reo_status;
srng = &sc->hal.srng_list[dp->reo_status_ring.ring_id];
- memset(&reo_status, 0, sizeof(reo_status));
#ifdef notyet
spin_lock_bh(&srng->lock);
#endif
@@ -16581,6 +16596,7 @@ qwz_dp_process_reo_status(struct qwz_softc *sc)
while ((reo_desc = qwz_hal_srng_dst_get_next_entry(sc, srng))) {
ret = 1;
+ memset(&reo_status, 0, sizeof(reo_status));
tlv = (struct hal_tlv_64_hdr *)reo_desc;
tag = FIELD_GET(HAL_SRNG_TLV_HDR_TAG, le64toh(tlv->tl));
@@ -16596,6 +16612,10 @@ qwz_dp_process_reo_status(struct qwz_softc *sc)
case HAL_REO_FLUSH_CACHE_STATUS:
qwz_hal_reo_flush_cache_status(sc, reo_desc,
&reo_status);
+ if (reo_status.u.flush_cache.err_detected ||
+ reo_status.u.flush_cache.err_code ||
+ reo_status.u.flush_cache.cache_controller_flush_status_err)
+ reo_status.uniform_hdr.cmd_status = HAL_REO_CMD_FAILED;
break;
case HAL_REO_UNBLOCK_CACHE_STATUS:
qwz_hal_reo_unblk_cache_status(sc, reo_desc,
@@ -16632,8 +16652,9 @@ qwz_dp_process_reo_status(struct qwz_softc *sc)
spin_unlock_bh(&dp->reo_cmd_lock);
#endif
if (found) {
- cmd->handler(dp, (void *)&cmd->data,
- reo_status.uniform_hdr.cmd_status);
+ if (cmd->handler != NULL)
+ cmd->handler(dp, (void *)&cmd->data,
+ reo_status.uniform_hdr.cmd_status);
free(cmd, M_DEVBUF, sizeof(*cmd));
}
found = 0;
@@ -22609,6 +22630,13 @@ qwz_peer_delete(struct qwz_softc *sc, uint32_t vdev_id, uint8_t pdev_id,
}
}
+ ret = qwz_peer_rx_tid_cleanup(sc, peer);
+ if (ret) {
+ printf("%s: failed to retire peer RX queues: %d\n",
+ sc->sc_dev.dv_xname, ret);
+ return ret;
+ }
+
TAILQ_REMOVE(&sc->peers, peer, entry);
qwz_node_clear_peer_id(sc, peer);
free(peer, M_DEVBUF, sizeof(*peer));
@@ -22673,44 +22701,27 @@ qwz_dp_tx_send_reo_cmd(struct qwz_softc *sc, struct dp_rx_tid *rx_tid,
void (*cb)(struct qwz_dp *, void *, enum hal_reo_cmd_status))
{
struct qwz_dp *dp = &sc->dp;
- struct dp_reo_cmd *dp_cmd;
+ struct dp_reo_cmd *dp_cmd = NULL;
struct hal_srng *cmd_ring;
int cmd_num;
if (test_bit(ATH12K_FLAG_CRASH_FLUSH, sc->sc_flags))
return ESHUTDOWN;
- cmd_ring = &sc->hal.srng_list[dp->reo_cmd_ring.ring_id];
- cmd_num = qwz_hal_reo_cmd_send(sc, cmd_ring, type, cmd);
- /* cmd_num should start from 1, during failure return the error code */
- if (cmd_num < 0)
- return cmd_num;
-
- /* reo cmd ring descriptors has cmd_num starting from 1 */
- if (cmd_num == 0)
- return EINVAL;
-
- if (!cb)
- return 0;
-
- /* Can this be optimized so that we keep the pending command list only
- * for tid delete command to free up the resource on the command status
- * indication?
- */
- dp_cmd = malloc(sizeof(*dp_cmd), M_DEVBUF, M_ZERO | M_NOWAIT);
- if (!dp_cmd)
- return ENOMEM;
+ if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS) {
+ dp_cmd = malloc(sizeof(*dp_cmd), M_DEVBUF, M_ZERO | M_NOWAIT);
+ if (dp_cmd == NULL)
+ return ENOMEM;
+ memcpy(&dp_cmd->data, rx_tid, sizeof(*rx_tid));
+ dp_cmd->handler = cb;
+ }
- memcpy(&dp_cmd->data, rx_tid, sizeof(struct dp_rx_tid));
- dp_cmd->cmd_num = cmd_num;
- dp_cmd->handler = cb;
-#ifdef notyet
- spin_lock_bh(&dp->reo_cmd_lock);
-#endif
- TAILQ_INSERT_TAIL(&dp->reo_cmd_list, dp_cmd, entry);
-#ifdef notyet
- spin_unlock_bh(&dp->reo_cmd_lock);
-#endif
+ cmd_ring = &sc->hal.srng_list[dp->reo_cmd_ring.ring_id];
+ cmd_num = qwz_hal_reo_cmd_send(sc, cmd_ring, type, cmd, dp_cmd);
+ if (cmd_num < 0) {
+ free(dp_cmd, M_DEVBUF, sizeof(*dp_cmd));
+ return -cmd_num;
+ }
return 0;
}
@@ -22825,141 +22836,131 @@ qwz_hal_reo_qdesc_setup(void *vaddr, int tid, uint32_t ba_window_size,
}
void
-qwz_dp_reo_cmd_free(struct qwz_dp *dp, void *ctx,
+qwz_dp_rx_tid_retire_done(struct qwz_dp *dp, void *ctx,
enum hal_reo_cmd_status status)
{
- struct qwz_softc *sc = dp->sc;
struct dp_rx_tid *rx_tid = ctx;
-
- if (status != HAL_REO_CMD_SUCCESS)
- printf("%s: failed to flush rx tid hw desc, tid %d status %d\n",
- sc->sc_dev.dv_xname, rx_tid->tid, status);
-
- qwz_dp_rx_tid_clear(sc, rx_tid);
+ struct qwz_rx_tid_retire *retire = &dp->rx_tid_retire[rx_tid->tid];
+
+ KASSERT(retire->data.mem == rx_tid->mem);
+ KASSERT(retire->state == QWZ_RX_TID_DELETE_PENDING ||
+ retire->state == QWZ_RX_TID_FLUSH_PENDING);
+
+ if (status != HAL_REO_CMD_SUCCESS) {
+ retire->state = QWZ_RX_TID_RETIRE_FAILED;
+ printf("%s: RX queue retirement failed, tid %u status %d\n",
+ dp->sc->sc_dev.dv_xname, rx_tid->tid, status);
+ } else if (retire->state == QWZ_RX_TID_DELETE_PENDING) {
+ retire->flush_offset = retire->data.size;
+ retire->state = QWZ_RX_TID_FLUSH_READY;
+ } else if (retire->flush_offset != 0) {
+ retire->state = QWZ_RX_TID_FLUSH_READY;
+ } else {
+ memset(retire, 0, sizeof(*retire));
+ }
+ wakeup(dp->rx_tid_retire);
}
-void
-qwz_dp_reo_cache_flush(struct qwz_softc *sc, struct dp_rx_tid *rx_tid)
+int
+qwz_dp_rx_tid_retire_submit(struct qwz_softc *sc,
+ struct qwz_rx_tid_retire *retire)
{
struct ath12k_hal_reo_cmd cmd = {0};
- unsigned long tot_desc_sz, desc_sz;
+ enum qwz_rx_tid_retire_state state = retire->state;
+ enum hal_reo_cmd_type type;
+ uint32_t offset = retire->flush_offset;
+ uint64_t paddr = retire->data.paddr;
int ret;
- tot_desc_sz = rx_tid->size;
- desc_sz = qwz_hal_reo_qdesc_size(0, HAL_DESC_REO_NON_QOS_TID);
-
- while (tot_desc_sz > desc_sz) {
- tot_desc_sz -= desc_sz;
- cmd.addr_lo = (rx_tid->paddr + tot_desc_sz) & 0xffffffff;
- cmd.addr_hi = rx_tid->paddr >> 32;
- ret = qwz_dp_tx_send_reo_cmd(sc, rx_tid,
- HAL_REO_CMD_FLUSH_CACHE, &cmd, NULL);
- if (ret) {
- printf("%s: failed to send HAL_REO_CMD_FLUSH_CACHE, "
- "tid %d (%d)\n", sc->sc_dev.dv_xname, rx_tid->tid,
- ret);
- }
- }
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.addr_lo = rx_tid->paddr & 0xffffffff;
- cmd.addr_hi = rx_tid->paddr >> 32;
- cmd.flag |= HAL_REO_CMD_FLG_NEED_STATUS;
- ret = qwz_dp_tx_send_reo_cmd(sc, rx_tid, HAL_REO_CMD_FLUSH_CACHE,
- &cmd, qwz_dp_reo_cmd_free);
+ cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS;
+ if (state == QWZ_RX_TID_DELETE_READY) {
+ /* WCN7850 requires VLD to remain set until the cache flush. */
+ cmd.upd0 = HAL_REO_CMD_UPD0_VLD;
+ cmd.upd1 = HAL_REO_CMD_UPD1_VLD;
+ type = HAL_REO_CMD_UPDATE_RX_QUEUE;
+ retire->state = QWZ_RX_TID_DELETE_PENDING;
+ } else {
+ KASSERT(state == QWZ_RX_TID_FLUSH_READY);
+ KASSERT(offset >= sizeof(struct hal_rx_reo_queue));
+ retire->flush_offset -= sizeof(struct hal_rx_reo_queue);
+ paddr += retire->flush_offset;
+ if (retire->flush_offset == 0)
+ cmd.flag |= HAL_REO_CMD_FLG_FLUSH_FWD_ALL_MPDUS;
+ type = HAL_REO_CMD_FLUSH_CACHE;
+ retire->state = QWZ_RX_TID_FLUSH_PENDING;
+ }
+ cmd.addr_lo = paddr & 0xffffffff;
+ cmd.addr_hi = paddr >> 32;
+ ret = qwz_dp_tx_send_reo_cmd(sc, &retire->data, type, &cmd,
+ qwz_dp_rx_tid_retire_done);
if (ret) {
- printf("%s: failed to send HAL_REO_CMD_FLUSH_CACHE cmd, "
- "tid %d (%d)\n", sc->sc_dev.dv_xname, rx_tid->tid, ret);
- qwz_dp_rx_tid_clear(sc, rx_tid);
+ retire->state = state;
+ retire->flush_offset = offset;
}
+ return ret;
}
-void
-qwz_dp_rx_tid_del_func(struct qwz_dp *dp, void *ctx,
- enum hal_reo_cmd_status status)
+int
+qwz_dp_rx_tid_retire_wait(struct qwz_softc *sc)
{
- struct qwz_softc *sc = dp->sc;
- struct dp_rx_tid *rx_tid = ctx;
- struct dp_reo_cache_flush_elem *elem, *tmp;
+ struct qwz_dp *dp = &sc->dp;
+ struct qwz_rx_tid_retire *retire;
+ uint64_t deadline = getnsecuptime() + SEC_TO_NSEC(3);
uint64_t now;
+ int i, pending, error, ret;
- if (status == HAL_REO_CMD_DRAIN) {
- qwz_dp_rx_tid_clear(sc, rx_tid);
- return;
- } else if (status != HAL_REO_CMD_SUCCESS) {
- /* Shouldn't happen! Cleanup in case of other failure? */
- printf("%s: failed to delete rx tid %d hw descriptor %d\n",
- sc->sc_dev.dv_xname, rx_tid->tid, status);
- return;
- }
-
- elem = malloc(sizeof(*elem), M_DEVBUF, M_ZERO | M_NOWAIT);
- if (!elem) {
- qwz_dp_rx_tid_clear(sc, rx_tid);
- return;
- }
-
- now = getnsecuptime();
- elem->ts = now;
- memcpy(&elem->data, rx_tid, sizeof(*rx_tid));
-
- qwz_dp_rx_tid_clear(sc, rx_tid);
-
-#ifdef notyet
- spin_lock_bh(&dp->reo_cmd_lock);
-#endif
- TAILQ_INSERT_TAIL(&dp->reo_cmd_cache_flush_list, elem, entry);
- dp->reo_cmd_cache_flush_count++;
-
- /* Flush and invalidate aged REO desc from HW cache */
- TAILQ_FOREACH_SAFE(elem, &dp->reo_cmd_cache_flush_list, entry, tmp) {
- if (dp->reo_cmd_cache_flush_count > DP_REO_DESC_FREE_THRESHOLD ||
- now >= elem->ts + MSEC_TO_NSEC(DP_REO_DESC_FREE_TIMEOUT_MS)) {
- TAILQ_REMOVE(&dp->reo_cmd_cache_flush_list, elem, entry);
- dp->reo_cmd_cache_flush_count--;
-#ifdef notyet
- spin_unlock_bh(&dp->reo_cmd_lock);
-#endif
- qwz_dp_reo_cache_flush(sc, &elem->data);
- free(elem, M_DEVBUF, sizeof(*elem));
-#ifdef notyet
- spin_lock_bh(&dp->reo_cmd_lock);
-#endif
+ for (;;) {
+ pending = 0;
+ error = 0;
+ for (i = 0; i < nitems(dp->rx_tid_retire); i++) {
+ retire = &dp->rx_tid_retire[i];
+ switch (retire->state) {
+ case QWZ_RX_TID_REUSABLE:
+ break;
+ case QWZ_RX_TID_DELETE_READY:
+ case QWZ_RX_TID_FLUSH_READY:
+ ret = qwz_dp_rx_tid_retire_submit(sc, retire);
+ if (ret && !error)
+ error = ret;
+ pending = 1;
+ break;
+ case QWZ_RX_TID_DELETE_PENDING:
+ case QWZ_RX_TID_FLUSH_PENDING:
+ pending = 1;
+ break;
+ case QWZ_RX_TID_RETIRE_FAILED:
+ error = EIO;
+ break;
+ }
}
+ if (error)
+ return error;
+ if (!pending)
+ return 0;
+ now = getnsecuptime();
+ if (now >= deadline)
+ return ETIMEDOUT;
+ ret = tsleep_nsec(dp->rx_tid_retire, 0, "qwzreo",
+ deadline - now);
+ if (ret)
+ return ret;
}
-#ifdef notyet
- spin_unlock_bh(&dp->reo_cmd_lock);
-#endif
}
void
qwz_peer_rx_tid_delete(struct qwz_softc *sc, struct ath12k_peer *peer,
uint8_t tid)
{
- struct ath12k_hal_reo_cmd cmd = {0};
struct dp_rx_tid *rx_tid = &peer->rx_tid[tid];
- int ret;
+ struct qwz_rx_tid_retire *retire = &sc->dp.rx_tid_retire[tid];
if (!rx_tid->active)
return;
+ KASSERT(retire->state == QWZ_RX_TID_REUSABLE);
+ retire->data = *rx_tid;
+ retire->state = QWZ_RX_TID_DELETE_READY;
rx_tid->active = 0;
-
- cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS;
- cmd.addr_lo = rx_tid->paddr & 0xffffffff;
- cmd.addr_hi = rx_tid->paddr >> 32;
- cmd.upd0 |= HAL_REO_CMD_UPD0_VLD;
- ret = qwz_dp_tx_send_reo_cmd(sc, rx_tid, HAL_REO_CMD_UPDATE_RX_QUEUE,
- &cmd, qwz_dp_rx_tid_del_func);
- if (ret) {
- if (ret != ESHUTDOWN) {
- printf("%s: failed to send "
- "HAL_REO_CMD_UPDATE_RX_QUEUE cmd, tid %d (%d)\n",
- sc->sc_dev.dv_xname, tid, ret);
- }
-
- qwz_dp_rx_tid_clear(sc, rx_tid);
- }
}
void
@@ -23006,11 +23007,11 @@ qwz_peer_frags_flush(struct qwz_softc *sc, struct ath12k_peer *peer)
}
}
-void
+int
qwz_peer_rx_tid_cleanup(struct qwz_softc *sc, struct ath12k_peer *peer)
{
struct dp_rx_tid *rx_tid;
- int i;
+ int i, ret;
#ifdef notyet
lockdep_assert_held(&ar->ab->base_lock);
#endif
@@ -23025,6 +23026,12 @@ qwz_peer_rx_tid_cleanup(struct qwz_softc *sc, struct ath12k_peer *peer)
spin_lock_bh(&ar->ab->base_lock);
#endif
}
+ ret = qwz_dp_rx_tid_retire_wait(sc);
+ if (ret)
+ return ret;
+ for (i = 0; i <= HAL_DESC_REO_NON_QOS_TID; i++)
+ qwz_dp_rx_tid_clear(sc, &peer->rx_tid[i]);
+ return 0;
}
int
@@ -23105,6 +23112,9 @@ qwz_peer_rx_tid_setup(struct qwz_softc *sc, struct ieee80211_node *ni,
peer = qwz_peer_find_by_id(sc, nq->peer_id);
if (peer == NULL)
return ENOENT;
+ if (peer->delete_pending || peer->unmapped ||
+ dp->rx_tid_retire[tid].state != QWZ_RX_TID_REUSABLE)
+ return EBUSY;
#ifdef notyet
spin_lock_bh(&ab->base_lock);
@@ -23712,8 +23722,6 @@ qwz_mac_station_remove(struct qwz_softc *sc, struct qwz_vif *arvif,
{
int ret;
- qwz_peer_rx_tid_cleanup(sc, peer);
-
ret = qwz_peer_delete(sc, arvif->vdev_id, pdev_id, peer);
if (ret) {
printf("%s: unable to delete BSS peer: %d\n",
diff --git a/sys/dev/ic/qwzvar.h b/sys/dev/ic/qwzvar.h
index 924adab0ce2..05984dd8697 100644
--- a/sys/dev/ic/qwzvar.h
+++ b/sys/dev/ic/qwzvar.h
@@ -1146,18 +1146,23 @@ struct dp_rx_tid {
#endif
};
-#define DP_REO_DESC_FREE_THRESHOLD 64
-#define DP_REO_DESC_FREE_TIMEOUT_MS 1000
#define DP_MON_PURGE_TIMEOUT_MS 100
#define DP_MON_SERVICE_BUDGET 128
-struct dp_reo_cache_flush_elem {
- TAILQ_ENTRY(dp_reo_cache_flush_elem) entry;
- struct dp_rx_tid data;
- uint64_t ts;
+enum qwz_rx_tid_retire_state {
+ QWZ_RX_TID_REUSABLE,
+ QWZ_RX_TID_DELETE_READY,
+ QWZ_RX_TID_DELETE_PENDING,
+ QWZ_RX_TID_FLUSH_READY,
+ QWZ_RX_TID_FLUSH_PENDING,
+ QWZ_RX_TID_RETIRE_FAILED,
};
-TAILQ_HEAD(dp_reo_cmd_cache_flush_head, dp_reo_cache_flush_elem);
+struct qwz_rx_tid_retire {
+ struct dp_rx_tid data;
+ enum qwz_rx_tid_retire_state state;
+ uint32_t flush_offset;
+};
struct dp_reo_cmd {
TAILQ_ENTRY(dp_reo_cmd) entry;
@@ -1257,18 +1262,14 @@ struct qwz_dp {
struct dp_tx_ring tx_ring[DP_TCL_NUM_RING_MAX];
struct hal_wbm_idle_scatter_list scatter_list[DP_IDLE_SCATTER_BUFS_MAX];
struct dp_reo_cmd_head reo_cmd_list;
- struct dp_reo_cmd_cache_flush_head reo_cmd_cache_flush_list;
#if 0
struct list_head dp_full_mon_mpdu_list;
#endif
- uint32_t reo_cmd_cache_flush_count;
enum hal_rx_buf_return_buf_manager idle_link_rbm;
#if 0
/**
* protects access to below fields,
* - reo_cmd_list
- * - reo_cmd_cache_flush_list
- * - reo_cmd_cache_flush_count
*/
spinlock_t reo_cmd_lock;
#endif
@@ -1302,6 +1303,7 @@ struct qwz_dp {
* support for HostAP mode gets added to the driver.
*/
struct qwz_dmamem *rx_tid_mem[HAL_DESC_REO_NON_QOS_TID + 1];
+ struct qwz_rx_tid_retire rx_tid_retire[HAL_DESC_REO_NON_QOS_TID + 1];
};
#define ATH12K_SHADOW_DP_TIMER_INTERVAL 20
--
2.55.0
--
wbr, Kirill
The 6th batch of qwz commits