Download raw body.
sys/qwz: initialize on Snapdragon but fails on scan
On Sun, Apr 12, 2026 at 01:22:28PM +0200, Marcus Glocker wrote:
> On Sat, Apr 11, 2026 at 09:32:46PM +0200, Marcus Glocker wrote:
>
> > On Thu, Apr 02, 2026 at 10:00:51PM +0200, Kirill A. Korinsky wrote:
> >
> > > May I ask you to try update from this email?
> > > https://marc.info/?l=openbsd-tech&m=177481501901011&w=2
> > >
> > > I haven't commited it yet
> >
> > That's what I'm getting on my Samsung Galaxy Book4 Edge.
> > Unfortunately by applying your diff, it makes no difference for me.
>
> With the linux-firmware-20260309 package and your diff I also can
> initialize the core now:
>
> qwz_wmi_tlv_op_rx: 0x16005: update fw mem dump
> qwz_wmi_tlv_op_rx: unsupported event id 0xb00b
> qwz_pull_reg_chan_list_ext_update_ev: not implemented
> qwz0: failed to extract regulatory info from received event
> qwz_pull_reg_chan_list_ext_update_ev: not implemented
> qwz0: failed to extract regulatory info from received event
> qwz_wmi_tlv_op_rx: unsupported event id 0x1d021
> qwz_dp_htt_htc_t2h_msg_handler: dp_htt rx msg type: 0x0
> --> qwz0: wcn7850 hw2.0 fw 0x110cffff address 00:03:7f:12:5b:c0
> qwz_dp_htt_htc_t2h_msg_handler: dp_htt rx msg type: 0x30
> qwz_dp_htt_htc_t2h_msg_handler: htt event 48 not handled
> qwz0: unhandled qrtr type 6
>
> That's some good progress! I'll try to review your diff next.
I'm OK with your diff, and I think we should get it in to make further
progress (re-attached your diff for reference).
ok mglocker@
Index: sys/dev/ic/qwz.c
===================================================================
RCS file: /home/cvs/src/sys/dev/ic/qwz.c,v
diff -u -p -r1.22 qwz.c
--- sys/dev/ic/qwz.c 18 Feb 2026 03:10:57 -0000 1.22
+++ sys/dev/ic/qwz.c 29 Mar 2026 19:09:10 -0000
@@ -1006,6 +1006,11 @@ qwz_wmi_init_wcn7850(struct qwz_softc *s
config->num_multicast_filter_entries = 0x20;
config->num_wow_filters = 0x16;
config->num_keep_alive_pattern = 0;
+
+ if (isset(sc->wmi.svc_map, WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT))
+ config->peer_metadata_ver = ATH12K_PEER_METADATA_V1A;
+ else
+ config->peer_metadata_ver = sc->dp.peer_metadata_ver;
}
void
@@ -1735,6 +1740,7 @@ static const struct ath12k_hw_params ath
.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) |
BIT(CNSS_PCIE_PERST_NO_PULL_V01),
.tx_ring_size = DP_TCL_DATA_RING_SIZE,
+ .rddm_size = 0x780000,
},
};
@@ -8340,6 +8346,9 @@ qwz_dp_cc_cleanup(struct qwz_softc *sc)
/* First ATH12K_NUM_RX_SPT_PAGES of allocated SPT pages are used for RX */
for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) {
rx_descs = dp->spt_info->rxbaddr[i];
+ if (!rx_descs)
+ continue;
+
for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) {
if (!rx_descs[j].m)
continue;
@@ -8364,6 +8373,8 @@ qwz_dp_cc_cleanup(struct qwz_softc *sc)
for (i = 0; i < ATH12K_TX_SPT_PAGES_PER_POOL; i++) {
tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL;
tx_descs = dp->spt_info->txbaddr[tx_spt_page];
+ if (!tx_descs)
+ continue;
for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) {
if (!tx_descs[j].m)
@@ -8381,6 +8392,17 @@ qwz_dp_cc_cleanup(struct qwz_softc *sc)
spin_unlock_bh(&dp->tx_desc_lock[pool_id]);
#endif
}
+
+ for (i = 0; i < dp->num_spt_pages; i++) {
+ if (!dp->spt_info[i].mem)
+ continue;
+ qwz_dmamem_free(sc->sc_dmat, dp->spt_info[i].mem);
+ dp->spt_info[i].mem = NULL;
+ }
+
+ free(dp->spt_info, M_DEVBUF, dp->num_spt_pages * sizeof(*dp->spt_info));
+ dp->spt_info = NULL;
+ dp->num_spt_pages = 0;
}
int
@@ -8543,7 +8565,7 @@ qwz_dp_rx_alloc(struct qwz_softc *sc)
for (i = 0; i < sc->hw_params.num_rxdma_dst_ring; i++) {
ret = qwz_dp_srng_setup(sc, &dp->rxdma_err_dst_ring[i],
- HAL_RXDMA_BUF, 0, i, DP_RXDMA_ERR_DST_RING_SIZE);
+ HAL_RXDMA_DST, 0, i, DP_RXDMA_ERR_DST_RING_SIZE);
if (ret) {
printf("%s: failed to setup "
"rxdma_err_dst_ring %d\n",
@@ -9913,9 +9935,19 @@ qwz_wmi_tlv_svc_rdy_ext2_parse(struct qw
uint16_t tag, uint16_t len, const void *ptr, void *data)
{
struct wmi_tlv_svc_rdy_ext2_parse *parse = data;
+ const struct wmi_service_ready_ext2_event *ev;
int ret;
switch (tag) {
+ case WMI_TAG_SERVICE_READY_EXT2_EVENT:
+ if (len < sizeof(*ev))
+ return EPROTO;
+
+ ev = ptr;
+ sc->dp.peer_metadata_ver = FIELD_GET(
+ WMI_TARGET_CAP_FLAGS_RX_PEER_METADATA_VERSION,
+ ev->target_cap_flags);
+ break;
case WMI_TAG_ARRAY_STRUCT:
if (!parse->dma_ring_cap_done) {
ret = qwz_wmi_tlv_dma_ring_caps(sc, len, ptr,
@@ -10476,6 +10508,56 @@ qwz_pull_reg_chan_list_ext_update_ev(str
}
void
+qwz_init_channels_world(struct qwz_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211_channel *chan;
+ uint32_t supported_bands = 0;
+ int i;
+
+ /* Same world fallback channels as ath12k reg.c. */
+ static const uint8_t channels_2ghz[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+ };
+ static const uint8_t channels_5ghz[] = {
+ 36, 40, 44, 48, 52, 56, 60, 64,
+ 149, 153, 157, 161, 165
+ };
+
+ for (i = 0; i < sc->num_radios; i++)
+ supported_bands |= sc->pdevs[i].cap.supported_bands;
+
+ if (!(supported_bands & (WMI_HOST_WLAN_2G_CAP | WMI_HOST_WLAN_5G_CAP)))
+ supported_bands = WMI_HOST_WLAN_2G_CAP | WMI_HOST_WLAN_5G_CAP;
+
+ memset(ic->ic_channels, 0, sizeof(ic->ic_channels));
+
+ if (supported_bands & WMI_HOST_WLAN_2G_CAP) {
+ for (i = 0; i < nitems(channels_2ghz); i++) {
+ chan = &ic->ic_channels[channels_2ghz[i]];
+ chan->ic_freq = ieee80211_ieee2mhz(channels_2ghz[i],
+ IEEE80211_CHAN_2GHZ);
+ chan->ic_flags = IEEE80211_CHAN_CCK |
+ IEEE80211_CHAN_OFDM |
+ IEEE80211_CHAN_DYN |
+ IEEE80211_CHAN_2GHZ;
+ }
+ }
+
+ if (supported_bands & WMI_HOST_WLAN_5G_CAP) {
+ for (i = 0; i < nitems(channels_5ghz); i++) {
+ chan = &ic->ic_channels[channels_5ghz[i]];
+ chan->ic_freq = ieee80211_ieee2mhz(channels_5ghz[i],
+ IEEE80211_CHAN_5GHZ);
+ chan->ic_flags = IEEE80211_CHAN_A |
+ IEEE80211_CHAN_PASSIVE;
+ }
+ }
+
+ ieee80211_channel_init(&ic->ic_if);
+}
+
+void
qwz_init_channels(struct qwz_softc *sc, struct cur_regulatory_info *reg_info)
{
struct ieee80211com *ic = &sc->sc_ic;
@@ -10587,6 +10669,7 @@ qwz_reg_chan_list_event(struct qwz_softc
if (ret) {
printf("%s: failed to extract regulatory info from "
"received event\n", sc->sc_dev.dv_xname);
+ qwz_init_channels_world(sc);
goto fallback;
}
@@ -10599,6 +10682,7 @@ qwz_reg_chan_list_event(struct qwz_softc
*/
printf("%s: Failed to set the requested Country "
"regulatory setting\n", __func__);
+ qwz_init_channels_world(sc);
goto mem_free;
}
@@ -11706,7 +11790,8 @@ qwz_wmi_tlv_op_rx(struct qwz_softc *sc,
DPRINTF("%s: 0x%x: update fw mem dump\n", __func__, id);
break;
case WMI_PDEV_SET_HW_MODE_RESP_EVENTID:
- DPRINTF("%s: 0x%x: set HW mode response event\n", __func__, id);
+ sc->wmi.hw_mode_ready = 1;
+ wakeup(&sc->wmi.hw_mode_ready);
break;
case WMI_WLAN_FREQ_AVOID_EVENTID:
DPRINTF("%s: 0x%x: wlan freq avoid event\n", __func__, id);
@@ -16815,6 +16900,8 @@ void
qwz_wmi_copy_resource_config(struct wmi_resource_config *wmi_cfg,
struct wmi_resource_config_arg *tg_cfg)
{
+ memset(wmi_cfg, 0, sizeof(*wmi_cfg));
+
wmi_cfg->num_vdevs = tg_cfg->num_vdevs;
wmi_cfg->num_peers = tg_cfg->num_peers;
wmi_cfg->num_offload_peers = tg_cfg->num_offload_peers;
@@ -16868,20 +16955,19 @@ qwz_wmi_copy_resource_config(struct wmi_
wmi_cfg->bpf_instruction_size = tg_cfg->bpf_instruction_size;
wmi_cfg->max_bssid_rx_filters = tg_cfg->max_bssid_rx_filters;
wmi_cfg->use_pdev_id = tg_cfg->use_pdev_id;
- wmi_cfg->flag1 = tg_cfg->atf_config | WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64;
+ wmi_cfg->flag1 = tg_cfg->atf_config | WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 |
+ WMI_RSRC_CFG_FLAG1_ACK_RSSI;
wmi_cfg->peer_map_unmap_version = tg_cfg->peer_map_unmap_version;
wmi_cfg->sched_params = tg_cfg->sched_params;
wmi_cfg->twt_ap_pdev_count = tg_cfg->twt_ap_pdev_count;
wmi_cfg->twt_ap_sta_count = tg_cfg->twt_ap_sta_count;
-#ifdef notyet /* 6 GHz support */
- wmi_cfg->host_service_flags &=
- ~(1 << WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT);
- wmi_cfg->host_service_flags |= (tg_cfg->is_reg_cc_ext_event_supported <<
- WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT);
- wmi_cfg->flags2 = WMI_RSRC_CFG_FLAG2_CALC_NEXT_DTIM_COUNT_SET;
+ wmi_cfg->flags2 = FIELD_PREP(WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION,
+ tg_cfg->peer_metadata_ver);
+ wmi_cfg->host_service_flags =
+ tg_cfg->is_reg_cc_ext_event_supported << WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT;
wmi_cfg->ema_max_vap_cnt = tg_cfg->ema_max_vap_cnt;
wmi_cfg->ema_max_profile_period = tg_cfg->ema_max_profile_period;
-#endif
+ wmi_cfg->flags2 |= WMI_RSRC_CFG_FLAG2_CALC_NEXT_DTIM_COUNT_SET;
}
int
@@ -17046,6 +17132,21 @@ qwz_wmi_wait_for_unified_ready(struct qw
}
int
+qwz_wmi_wait_for_hw_mode_ready(struct qwz_softc *sc)
+{
+ int ret;
+
+ while (!sc->wmi.hw_mode_ready) {
+ ret = tsleep_nsec(&sc->wmi.hw_mode_ready, 0, "qwzhwmode",
+ SEC_TO_NSEC(5));
+ if (ret)
+ return -1;
+ }
+
+ return 0;
+}
+
+int
qwz_wmi_set_hw_mode(struct qwz_softc *sc,
enum wmi_host_hw_mode_config_type mode)
{
@@ -17685,12 +17786,20 @@ qwz_core_start(struct qwz_softc *sc)
/* put hardware to DBS mode */
if (sc->hw_params.single_pdev_only) {
+ sc->wmi.hw_mode_ready = 0;
ret = qwz_wmi_set_hw_mode(sc, WMI_HOST_HW_MODE_DBS);
if (ret) {
printf("%s: failed to send dbs mode: %d\n",
__func__, ret);
goto err_hif_stop;
}
+
+ ret = qwz_wmi_wait_for_hw_mode_ready(sc);
+ if (ret) {
+ printf("%s: failed to receive dbs mode response: %d\n",
+ __func__, ret);
+ goto err_reo_cleanup;
+ }
}
ret = qwz_dp_tx_htt_h2t_ver_req_msg(sc);
@@ -20255,12 +20364,13 @@ qwz_reg_update_chan_list(struct qwz_soft
for (channel = &ic->ic_channels[1]; channel <= lastc; channel++) {
if (channel->ic_flags == 0)
continue;
-#ifdef notyet
- /* TODO: Set to true/false based on some condition? */
+ /*
+ * XXX We do not populate 6 GHz channels here yet.
+ * Linux sets these scan capability bits unconditionally too.
+ */
ch->allow_ht = true;
ch->allow_vht = true;
ch->allow_he = true;
-#endif
ch->dfs_set = !!(IEEE80211_IS_CHAN_5GHZ(channel) &&
(channel->ic_flags & IEEE80211_CHAN_PASSIVE));
ch->is_chan_passive = !!(channel->ic_flags &
@@ -21269,6 +21379,7 @@ qwz_mac_scan_finish(struct qwz_softc *sc
sc->scan.roc_freq = 0;
timeout_del(&sc->scan.timeout);
+ wakeup(&sc->scan.state);
if (!sc->scan.is_roc)
ieee80211_end_scan(ifp);
#if 0
@@ -22632,7 +22743,7 @@ qwz_wmi_start_scan_init(struct qwz_softc
/* fill bssid_list[0] with 0xff, otherwise bssid and RA will be
* ZEROs in probe request
*/
- IEEE80211_ADDR_COPY(arg->bssid_list[0].addr, etheranyaddr);
+ IEEE80211_ADDR_COPY(arg->bssid_list[0].addr, etherbroadcastaddr);
}
int
@@ -22834,6 +22945,9 @@ qwz_start_scan(struct qwz_softc *sc, str
break;
}
}
+
+ if (ret == 0 && sc->scan.state == ATH12K_SCAN_IDLE)
+ ret = EIO;
#ifdef notyet
spin_lock_bh(&ar->data_lock);
Index: sys/dev/ic/qwzreg.h
===================================================================
RCS file: /home/cvs/src/sys/dev/ic/qwzreg.h,v
diff -u -p -r1.11 qwzreg.h
--- sys/dev/ic/qwzreg.h 23 Dec 2024 00:12:44 -0000 1.11
+++ sys/dev/ic/qwzreg.h 29 Mar 2026 18:33:24 -0000
@@ -1957,6 +1957,8 @@ enum wmi_tlv_tag {
WMI_TAG_MAX
};
+#define WMI_TAG_SERVICE_READY_EXT2_EVENT 0x334
+
enum wmi_tlv_service {
WMI_TLV_SERVICE_BEACON_OFFLOAD = 0,
WMI_TLV_SERVICE_SCAN_OFFLOAD = 1,
@@ -2190,6 +2192,7 @@ enum wmi_tlv_service {
WMI_TLV_SERVICE_BIOS_SAR_SUPPORT = 326,
WMI_TLV_SERVICE_SUPPORT_11D_FOR_HOST_SCAN = 357,
WMI_TLV_SERVICE_WMSK_COMPACTION_RX_TLVS = 361,
+ WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT = 365,
/* The third 128 bits */
WMI_MAX_EXT2_SERVICE = 384
@@ -2479,6 +2482,7 @@ struct wmi_init_cmd {
#define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5)
#define WMI_RSRC_CFG_FLAG2_CALC_NEXT_DTIM_COUNT_SET BIT(9)
#define WMI_RSRC_CFG_FLAG1_ACK_RSSI BIT(18)
+#define WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION GENMASK(5, 4)
#define WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT 4
@@ -2541,7 +2545,6 @@ struct wmi_resource_config {
uint32_t sched_params;
uint32_t twt_ap_pdev_count;
uint32_t twt_ap_sta_count;
-#ifdef notyet /* 6 GHz support */
uint32_t max_nlo_ssids;
uint32_t num_pkt_filters;
uint32_t num_max_sta_vdevs;
@@ -2554,7 +2557,6 @@ struct wmi_resource_config {
uint32_t max_rnr_neighbours;
uint32_t ema_max_vap_cnt;
uint32_t ema_max_profile_period;
-#endif
} __packed;
struct wmi_service_ready_event {
@@ -2607,6 +2609,19 @@ struct wmi_service_ready_ext_event {
uint32_t max_nlo_ssids;
uint32_t max_bssid_indicator;
uint32_t he_cap_info_ext;
+} __packed;
+
+#define WMI_TARGET_CAP_FLAGS_RX_PEER_METADATA_VERSION GENMASK(1, 0)
+
+struct wmi_service_ready_ext2_event {
+ uint32_t reg_db_version;
+ uint32_t hw_min_max_tx_power_2ghz;
+ uint32_t hw_min_max_tx_power_5ghz;
+ uint32_t chwidth_num_peer_caps;
+ uint32_t preamble_puncture_bw;
+ uint32_t max_user_per_ppdu_ofdma;
+ uint32_t max_user_per_ppdu_mumimo;
+ uint32_t target_cap_flags;
} __packed;
struct wmi_soc_mac_phy_hw_mode_caps {
Index: sys/dev/ic/qwzvar.h
===================================================================
RCS file: /home/cvs/src/sys/dev/ic/qwzvar.h,v
diff -u -p -r1.12 qwzvar.h
--- sys/dev/ic/qwzvar.h 7 Jul 2025 00:55:15 -0000 1.12
+++ sys/dev/ic/qwzvar.h 29 Mar 2026 18:33:24 -0000
@@ -257,6 +257,7 @@ struct ath12k_hw_params {
bool tcl_ring_retry;
#endif
uint32_t tx_ring_size;
+ uint32_t rddm_size;
bool smp2p_wow_exit;
};
@@ -1378,6 +1379,7 @@ struct qwz_wmi_base {
uint32_t max_msg_len[QWZ_MAX_RADIOS];
int service_ready;
int unified_ready;
+ int hw_mode_ready;
uint8_t svc_map[howmany(WMI_MAX_EXT2_SERVICE, 8)];
int tx_credits;
const struct wmi_peer_flags_map *peer_flags;
Index: sys/dev/pci/if_qwz_pci.c
===================================================================
RCS file: /home/cvs/src/sys/dev/pci/if_qwz_pci.c,v
diff -u -p -r1.6 if_qwz_pci.c
--- sys/dev/pci/if_qwz_pci.c 9 Dec 2024 09:35:33 -0000 1.6
+++ sys/dev/pci/if_qwz_pci.c 29 Mar 2026 18:33:24 -0000
@@ -370,7 +370,6 @@ struct qwz_pci_softc {
struct qwz_dmamem *rddm_data;
int rddm_triggered;
struct task rddm_task;
-#define QWZ_RDDM_DUMP_SIZE 0x420000
struct qwz_dmamem *chan_ctxt;
struct qwz_dmamem *event_ctxt;
@@ -3287,7 +3286,7 @@ qwz_rddm_prepare(struct qwz_pci_softc *p
struct qwz_dmamem *data_adm, *vec_adm;
uint32_t seq, reg;
uint64_t paddr;
- const size_t len = QWZ_RDDM_DUMP_SIZE;
+ const size_t len = sc->hw_params.rddm_size;
const size_t chunk_size = MHI_DMA_VEC_CHUNK_SIZE;
size_t nseg, remain, vec_size;
int i;
@@ -3358,9 +3357,9 @@ qwz_rddm_task(void *arg)
struct qwz_pci_softc *psc = arg;
struct qwz_softc *sc = &psc->sc_sc;
uint32_t reg, state = MHI_BHIE_RXVECSTATUS_STATUS_RESET;
- const size_t len = QWZ_RDDM_DUMP_SIZE;
+ const size_t len = sc->hw_params.rddm_size;
int i, timeout;
- const uint32_t msecs = 100, retries = 20;
+ const uint32_t msecs = 2000, retries = 1000;
uint8_t *rddm;
struct nameidata nd;
struct vnode *vp = NULL;
sys/qwz: initialize on Snapdragon but fails on scan