Index | Thread | Search

From:
Kirill A. Korinsky <kirill@korins.ky>
Subject:
sys/qwz: shutdown firmware after autoconf
To:
OpenBSD tech <tech@openbsd.org>
Date:
Mon, 01 Jun 2026 21:50:48 +0200

Download raw body.

Thread
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