Index | Thread | Search

From:
joshua stein <jcs@jcs.org>
Subject:
aq: support detaching
To:
tech@openbsd.org
Date:
Tue, 18 Aug 2026 10:04:12 -0500

Download raw body.

Thread
I bought an OWC 10gbit Thunderbolt adapter and it showed up as 
aq(4).  I unplugged it and the kernel panicked with "config_detach: 
forced detach of aq0 failed (45)".  This implements a detach routine 
that works for me.

aq0 at pci5 dev 0 function 0 "Aquantia AQC107S" rev 0x02: msix, 4 queues, Atlantic B1, F/W version 3.0.33, address 00:30:93:17:07:dc


Index: sys/dev/pci/if_aq_pci.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_aq_pci.c,v
diff -u -p -u -p -r1.37 if_aq_pci.c
--- sys/dev/pci/if_aq_pci.c	24 Jul 2026 02:31:43 -0000	1.37
+++ sys/dev/pci/if_aq_pci.c	18 Aug 2026 14:46:41 -0000
@@ -1001,6 +1001,7 @@ struct aq_softc {
 	void			*sc_ih;
 	bus_space_handle_t	sc_ioh;
 	bus_space_tag_t		sc_iot;
+	bus_size_t		sc_iosize;
 
 	uint32_t		sc_mbox_addr;
 	int			sc_rbl_enabled;
@@ -1130,6 +1131,7 @@ const struct aq_product {
 
 int	aq_match(struct device *, void *, void *);
 void	aq_attach(struct device *, struct device *, void *);
+int	aq_detach(struct device *, int);
 int	aq_activate(struct device *, int);
 int	aq_intr(void *);
 int	aq_intr_link(void *);
@@ -1230,7 +1232,7 @@ const struct aq_firmware_ops aq2_fw_ops 
 };
 
 const struct cfattach aq_ca = {
-	sizeof(struct aq_softc), aq_match, aq_attach, NULL,
+	sizeof(struct aq_softc), aq_match, aq_attach, aq_detach,
 	aq_activate
 };
 
@@ -1296,7 +1298,7 @@ aq_attach(struct device *parent, struct 
 
 	memtype = pci_mapreg_type(pc, tag, AQ_BAR0);
 	if (pci_mapreg_map(pa, AQ_BAR0, memtype, 0, &sc->sc_iot, &sc->sc_ioh,
-	    NULL, NULL, 0)) {
+	    NULL, &sc->sc_iosize, 0)) {
 		printf(": failed to map BAR0\n");
 		return;
 	}
@@ -1528,6 +1530,53 @@ aq_attach(struct device *parent, struct 
 
 	aq_enable_intr(sc, 1, 0);
 	printf("\n");
+}
+
+int
+aq_detach(struct device *self, int flags)
+{
+	struct aq_softc *sc = (struct aq_softc *)self;
+	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+	struct aq_queues *aq;
+	int i;
+
+	if (ifp->if_flags & IFF_RUNNING)
+		aq_down(sc);
+
+	aq_enable_intr(sc, 0, 0);
+
+	for (i = 0; i < sc->sc_nqueues; i++) {
+		aq = &sc->sc_queues[i];
+
+		if (aq->q_ihc != NULL) {
+			pci_intr_disestablish(sc->sc_pc, aq->q_ihc);
+			aq->q_ihc = NULL;
+		}
+		timeout_del(&aq->q_rx.rx_refill);
+	}
+
+	if (sc->sc_ih != NULL) {
+		pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
+		sc->sc_ih = NULL;
+	}
+
+	if (sc->sc_intrmap != NULL) {
+		intrmap_destroy(sc->sc_intrmap);
+		sc->sc_intrmap = NULL;
+	}
+
+	if (ifp->if_softc != NULL) {
+		ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
+		ether_ifdetach(ifp);
+		if_detach(ifp);
+	}
+
+	if (sc->sc_iosize != 0) {
+		bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize);
+		sc->sc_iosize = 0;
+	}
+
+	return 0;
 }
 
 int