From: Kirill A. Korinsky Subject: sys/qwz: shutdown firmware after autoconf To: OpenBSD tech Date: Mon, 01 Jun 2026 21:50:48 +0200 tech@, seems that I had figured out why we need a hack to keep qwz running after autoconf. So, here I reset pending MHI transfers and the command ring queue counter during shutdown, and remove fw_initialized so the next ifconfig up performs a full firmware boot. Thoughts? Ok? Index: sys/dev/ic/qwz.c =================================================================== RCS file: /home/cvs/src/sys/dev/ic/qwz.c,v diff -u -p -r1.38 qwz.c --- sys/dev/ic/qwz.c 26 May 2026 14:55:16 -0000 1.38 +++ sys/dev/ic/qwz.c 1 Jun 2026 19:26:04 -0000 @@ -159,6 +159,7 @@ int qwz_wmi_vdev_install_key(struct qwz_ int qwz_dp_peer_rx_pn_replay_config(struct qwz_softc *, struct qwz_vif *, struct ieee80211_node *, struct ieee80211_key *, int); void qwz_setkey_clear(struct qwz_softc *); +void qwz_vif_free_all(struct qwz_softc *); int qwz_scan(struct qwz_softc *); void qwz_scan_abort(struct qwz_softc *); @@ -185,20 +186,6 @@ qwz_init(struct ifnet *ifp) struct qwz_softc *sc = ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; - /* Firmware stays running across ifconfig down/up; only re-scan. */ - if (sc->fw_initialized) { - ic->ic_state = IEEE80211_S_INIT; - sc->ns_nstate = IEEE80211_S_INIT; - sc->scan.state = ATH12K_SCAN_IDLE; - if (ifp->if_flags & IFF_UP) { - refcnt_init(&sc->task_refs); - ifq_clr_oactive(&ifp->if_snd); - ifp->if_flags |= IFF_RUNNING; - ieee80211_begin_scan(ifp); - } - return 0; - } - sc->fw_mode = ATH12K_FIRMWARE_MODE_NORMAL; /* * There are several known hardware/software crypto issues @@ -300,7 +287,6 @@ qwz_init(struct ifnet *ifp) ieee80211_begin_scan(ifp); } - sc->fw_initialized = 1; return 0; } @@ -370,12 +356,10 @@ qwz_stop(struct ifnet *ifp) sc->scan.state = ATH12K_SCAN_IDLE; sc->vdev_id_11d_scan = QWZ_11D_INVALID_VDEV_ID; - /* - * Firmware stays running across ifconfig down/up; the chip is - * only released on driver detach. Do not clear pdevs_active - * or call qwz_core_deinit() here. - */ + sc->pdevs_active = 0; + qwz_core_deinit(sc); + qwz_vif_free_all(sc); splx(s); } @@ -18703,8 +18687,6 @@ qwz_core_deinit(struct qwz_softc *sc) hal->num_shadow_reg_configured = 0; - sc->fw_initialized = 0; - splx(s); } @@ -21787,6 +21769,18 @@ qwz_vif_free(struct qwz_softc *sc, struc } free(arvif, M_DEVBUF, sizeof(*arvif)); +} + +void +qwz_vif_free_all(struct qwz_softc *sc) +{ + struct qwz_vif *arvif; + + while (!TAILQ_EMPTY(&sc->vif_list)) { + arvif = TAILQ_FIRST(&sc->vif_list); + TAILQ_REMOVE(&sc->vif_list, arvif, entry); + qwz_vif_free(sc, arvif); + } } struct qwz_vif * Index: sys/dev/ic/qwzvar.h =================================================================== RCS file: /home/cvs/src/sys/dev/ic/qwzvar.h,v diff -u -p -r1.18 qwzvar.h --- sys/dev/ic/qwzvar.h 26 May 2026 14:55:16 -0000 1.18 +++ sys/dev/ic/qwzvar.h 1 Jun 2026 19:26:14 -0000 @@ -1971,7 +1971,6 @@ struct qwz_softc { struct qwz_survey_info survey[IEEE80211_CHAN_MAX]; int attached; - int fw_initialized; struct { u_char *data; size_t size; 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.13 if_qwz_pci.c --- sys/dev/pci/if_qwz_pci.c 26 May 2026 14:55:16 -0000 1.13 +++ sys/dev/pci/if_qwz_pci.c 1 Jun 2026 19:30:15 -0000 @@ -430,6 +430,7 @@ void qwz_mhi_init_xfer_rings(struct qwz_ void qwz_mhi_init_event_rings(struct qwz_pci_softc *); void qwz_mhi_init_cmd_ring(struct qwz_pci_softc *); void qwz_mhi_init_dev_ctxt(struct qwz_pci_softc *); +void qwz_mhi_reset_xfer_rings(struct qwz_pci_softc *); int qwz_mhi_send_cmd(struct qwz_pci_softc *psc, uint32_t, uint32_t); void * qwz_pci_xfer_ring_get_elem(struct qwz_pci_xfer_ring *, uint64_t); struct qwz_xfer_data *qwz_pci_xfer_ring_get_data(struct qwz_pci_xfer_ring *, @@ -2445,6 +2446,7 @@ qwz_mhi_init_cmd_ring(struct qwz_pci_sof len = ring->size; ring->rp = ring->wp = paddr; + ring->queued = 0; c = (struct qwz_mhi_cmd_ctxt *)QWZ_DMA_KVA(psc->cmd_ctxt); c->rbase = htole64(paddr); @@ -2464,6 +2466,58 @@ qwz_mhi_init_dev_ctxt(struct qwz_pci_sof qwz_mhi_init_cmd_ring(psc); } +void +qwz_mhi_reset_xfer_rings(struct qwz_pci_softc *psc) +{ + struct qwz_softc *sc = &psc->sc_sc; + struct qwz_pci_xfer_ring *ring; + struct qwz_xfer_data *xfer; + uint64_t paddr; + int i, j; + + for (i = 0; i < nitems(psc->xfer_rings); i++) { + ring = &psc->xfer_rings[i]; + if (ring->dmamem == NULL) + continue; + + for (j = 0; j < ring->num_elements; j++) { + xfer = &ring->data[j]; + if (ring->mhi_chan_direction == MHI_CHAN_TYPE_OUTBOUND) { + if (xfer->m == NULL) + continue; + bus_dmamap_sync(sc->sc_dmat, xfer->map, 0, + xfer->map->dm_mapsize, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmat, xfer->map); + m_freem(xfer->m); + xfer->m = NULL; + } else if (xfer->m != NULL) { + bus_dmamap_sync(sc->sc_dmat, xfer->map, 0, + QWZ_PCI_XFER_MAX_DATA_SIZE, + BUS_DMASYNC_POSTREAD); + xfer->m->m_len = xfer->m->m_pkthdr.len = + QWZ_PCI_XFER_MAX_DATA_SIZE; + bus_dmamap_sync(sc->sc_dmat, xfer->map, 0, + QWZ_PCI_XFER_MAX_DATA_SIZE, + BUS_DMASYNC_PREREAD); + } + } + + paddr = QWZ_DMA_DVA(ring->dmamem); + ring->rp = ring->wp = paddr; + ring->queued = 0; + ring->cmd_status = MHI_EV_CC_INVALID; + if (ring->chan_ctxt != NULL) { + ring->chan_ctxt->rp = htole64(paddr); + ring->chan_ctxt->wp = htole64(paddr); + } + } + + if (psc->chan_ctxt != NULL) + bus_dmamap_sync(sc->sc_dmat, QWZ_DMA_MAP(psc->chan_ctxt), 0, + QWZ_DMA_LEN(psc->chan_ctxt), BUS_DMASYNC_PREWRITE); +} + void * qwz_pci_cmd_ring_get_elem(struct qwz_pci_cmd_ring *ring, uint64_t ptr) { @@ -2847,6 +2901,7 @@ void qwz_mhi_stop(struct qwz_softc *sc) { qwz_mhi_reset_device(sc, 1); + qwz_mhi_reset_xfer_rings((struct qwz_pci_softc *)sc); } int -- wbr, Kirill