git: b196276c20b5 - main - bus_generic_detach: Delete children after detaching them

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Thu, 02 Jan 2025 18:28:18 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=b196276c20b577b364372f1aa1a646b9ce34bf5c

commit b196276c20b577b364372f1aa1a646b9ce34bf5c
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2025-01-02 18:21:02 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2025-01-02 18:21:30 +0000

    bus_generic_detach: Delete children after detaching them
    
    This provides better semantics as a standalone DEVMETHOD for
    device_attach as bus drivers should remove child devices they created
    as part of detach cleanup.  The implementation calls
    bus_detach_children() first to permit child devices an opportunity to
    veto the detach operation.  If that succeeds, device_delete_children()
    is used to delete the child devices.
    
    This requires fixing various drivers that were deleting devices
    explicitly (via a device_t pointer cached in the softc) after calling
    bus_generic_detach to stop doing that and just rely on
    bus_generic_detach to remove child devices.
    
    Reviewed by:    imp
    Differential Revision:  https://reviews.freebsd.org/D47959
---
 sys/arm/broadcom/bcm2835/bcm2835_bsc.c       |  2 --
 sys/arm/freescale/imx/imx_i2c.c              |  3 ---
 sys/arm/freescale/imx/imx_spi.c              |  3 ---
 sys/arm/mv/a37x0_iic.c                       |  2 --
 sys/arm/nvidia/tegra_i2c.c                   |  2 --
 sys/arm/ti/am335x/am335x_ehrpwm.c            |  3 ---
 sys/arm/ti/cpsw/if_cpsw.c                    | 10 ++++------
 sys/arm/ti/ti_i2c.c                          |  4 ----
 sys/arm/xilinx/zy7_qspi.c                    |  4 ----
 sys/arm/xilinx/zy7_spi.c                     |  4 ----
 sys/dev/bce/if_bce.c                         |  1 -
 sys/dev/bfe/if_bfe.c                         |  2 --
 sys/dev/bge/if_bge.c                         |  1 -
 sys/dev/bhnd/bhndb/bhndb.c                   |  4 ----
 sys/dev/bhnd/cores/chipc/chipc.c             |  3 ---
 sys/dev/cxgbe/t4_main.c                      |  2 --
 sys/dev/dpaa2/dpaa2_mc.c                     |  2 --
 sys/dev/etherswitch/felix/felix.c            |  2 --
 sys/dev/firewire/fwohci_pci.c                |  5 -----
 sys/dev/glxiic/glxiic.c                      |  7 ++-----
 sys/dev/ichiic/ig4_iic.c                     | 10 +++-------
 sys/dev/ichsmb/ichsmb.c                      |  1 -
 sys/dev/iicbus/controller/cadence/cdnc_i2c.c |  7 +------
 sys/dev/iicbus/controller/rockchip/rk_i2c.c  |  4 ----
 sys/dev/iicbus/controller/twsi/twsi.c        |  4 ----
 sys/dev/iicbus/controller/vybrid/vf_i2c.c    |  6 ------
 sys/dev/ismt/ismt.c                          |  2 --
 sys/dev/lge/if_lge.c                         |  1 -
 sys/dev/ow/ow.c                              | 13 -------------
 sys/dev/pcf/pcf_isa.c                        |  3 ---
 sys/dev/pwm/controller/allwinner/aw_pwm.c    |  3 ---
 sys/dev/qcom_qup/qcom_spi.c                  |  2 --
 sys/dev/smbus/smbus.c                        |  1 -
 sys/dev/sound/pci/fm801.c                    |  6 ------
 sys/dev/spibus/controller/allwinner/aw_spi.c |  2 --
 sys/dev/spibus/controller/rockchip/rk_spi.c  |  2 --
 sys/dev/viapm/viapm.c                        |  6 ------
 sys/dev/vnic/thunder_mdio.c                  |  1 -
 sys/kern/subr_bus.c                          | 11 ++++++++---
 sys/sys/param.h                              |  2 +-
 40 files changed, 19 insertions(+), 134 deletions(-)

diff --git a/sys/arm/broadcom/bcm2835/bcm2835_bsc.c b/sys/arm/broadcom/bcm2835/bcm2835_bsc.c
index c7de4df0e8fb..a4cbef7d528f 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_bsc.c
+++ b/sys/arm/broadcom/bcm2835/bcm2835_bsc.c
@@ -361,8 +361,6 @@ bcm_bsc_detach(device_t dev)
 	bus_generic_detach(dev);
 
 	sc = device_get_softc(dev);
-	if (sc->sc_iicbus != NULL)
-		device_delete_child(dev, sc->sc_iicbus);
 	mtx_destroy(&sc->sc_mtx);
 	if (sc->sc_intrhand)
 		bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand);
diff --git a/sys/arm/freescale/imx/imx_i2c.c b/sys/arm/freescale/imx/imx_i2c.c
index c1d5c8c974a8..3190ec294ab4 100644
--- a/sys/arm/freescale/imx/imx_i2c.c
+++ b/sys/arm/freescale/imx/imx_i2c.c
@@ -494,9 +494,6 @@ i2c_detach(device_t dev)
 		return (error);
 	}
 
-	if (sc->iicbus != NULL)
-		device_delete_child(dev, sc->iicbus);
-
 	/* Release bus-recover pins; gpio_pin_release() handles NULL args. */
 	gpio_pin_release(sc->rb_sclpin);
 	gpio_pin_release(sc->rb_sdapin);
diff --git a/sys/arm/freescale/imx/imx_spi.c b/sys/arm/freescale/imx/imx_spi.c
index 53d9f739b97c..dac42a800e9e 100644
--- a/sys/arm/freescale/imx/imx_spi.c
+++ b/sys/arm/freescale/imx/imx_spi.c
@@ -473,9 +473,6 @@ spi_detach(device_t dev)
 	if ((error = bus_generic_detach(sc->dev)) != 0)
 		return (error);
 
-	if (sc->spibus != NULL)
-		device_delete_child(dev, sc->spibus);
-
 	for (idx = 0; idx < nitems(sc->cspins); ++idx) {
 		if (sc->cspins[idx] != NULL)
 			gpio_pin_release(sc->cspins[idx]);
diff --git a/sys/arm/mv/a37x0_iic.c b/sys/arm/mv/a37x0_iic.c
index f9a71b97240a..7d71cac23a40 100644
--- a/sys/arm/mv/a37x0_iic.c
+++ b/sys/arm/mv/a37x0_iic.c
@@ -249,8 +249,6 @@ a37x0_iic_detach(device_t dev)
 	bus_generic_detach(dev);
 
 	sc = device_get_softc(dev);
-	if (sc->sc_iicbus != NULL)
-		device_delete_child(dev, sc->sc_iicbus);
 	mtx_destroy(&sc->sc_mtx);
 	if (sc->sc_intrhand)
 		bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand);
diff --git a/sys/arm/nvidia/tegra_i2c.c b/sys/arm/nvidia/tegra_i2c.c
index bed1bf0ed7e3..6c4d20cb78ff 100644
--- a/sys/arm/nvidia/tegra_i2c.c
+++ b/sys/arm/nvidia/tegra_i2c.c
@@ -757,8 +757,6 @@ tegra_i2c_detach(device_t dev)
 		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
 
 	LOCK_DESTROY(sc);
-	if (sc->iicbus)
-		device_delete_child(dev, sc->iicbus);
 	return (0);
 }
 
diff --git a/sys/arm/ti/am335x/am335x_ehrpwm.c b/sys/arm/ti/am335x/am335x_ehrpwm.c
index 95301f9cfed3..59ef0931439d 100644
--- a/sys/arm/ti/am335x/am335x_ehrpwm.c
+++ b/sys/arm/ti/am335x/am335x_ehrpwm.c
@@ -542,9 +542,6 @@ am335x_ehrpwm_detach(device_t dev)
 
 	PWM_LOCK(sc);
 
-	if (sc->sc_busdev != NULL)
-		device_delete_child(dev, sc->sc_busdev);
-
 	if (sc->sc_mem_res)
 		bus_release_resource(dev, SYS_RES_MEMORY,
 		    sc->sc_mem_rid, sc->sc_mem_res);
diff --git a/sys/arm/ti/cpsw/if_cpsw.c b/sys/arm/ti/cpsw/if_cpsw.c
index 732b5a81857a..674a7ed8575a 100644
--- a/sys/arm/ti/cpsw/if_cpsw.c
+++ b/sys/arm/ti/cpsw/if_cpsw.c
@@ -923,13 +923,11 @@ cpsw_detach(device_t dev)
 	struct cpsw_softc *sc;
 	int error, i;
 
-	bus_generic_detach(dev);
- 	sc = device_get_softc(dev);
+	error = bus_generic_detach(dev);
+	if (error != 0)
+		return (error);
 
-	for (i = 0; i < CPSW_PORTS; i++) {
-		if (sc->port[i].dev)
-			device_delete_child(dev, sc->port[i].dev);
-	}
+	sc = device_get_softc(dev);
 
 	if (device_is_attached(dev)) {
 		callout_stop(&sc->watchdog.callout);
diff --git a/sys/arm/ti/ti_i2c.c b/sys/arm/ti/ti_i2c.c
index a6c397a87e8b..e2f114505015 100644
--- a/sys/arm/ti/ti_i2c.c
+++ b/sys/arm/ti/ti_i2c.c
@@ -913,10 +913,6 @@ ti_i2c_detach(device_t dev)
 		return (rv);
 	}
 
-    if (sc->sc_iicbus &&
-	    (rv = device_delete_child(dev, sc->sc_iicbus)) != 0)
-		return (rv);
-
 	ti_i2c_deactivate(dev);
 	TI_I2C_LOCK_DESTROY(sc);
 
diff --git a/sys/arm/xilinx/zy7_qspi.c b/sys/arm/xilinx/zy7_qspi.c
index c033fd29a7db..53559571f7db 100644
--- a/sys/arm/xilinx/zy7_qspi.c
+++ b/sys/arm/xilinx/zy7_qspi.c
@@ -616,10 +616,6 @@ zy7_qspi_detach(device_t dev)
 	if (device_is_attached(dev))
 		bus_generic_detach(dev);
 
-	/* Delete child bus. */
-	if (sc->child)
-		device_delete_child(dev, sc->child);
-
 	/* Disable hardware. */
 	if (sc->mem_res != NULL) {
 		/* Disable SPI. */
diff --git a/sys/arm/xilinx/zy7_spi.c b/sys/arm/xilinx/zy7_spi.c
index a24ce542a860..d032deabf8b7 100644
--- a/sys/arm/xilinx/zy7_spi.c
+++ b/sys/arm/xilinx/zy7_spi.c
@@ -452,10 +452,6 @@ zy7_spi_detach(device_t dev)
 	if (device_is_attached(dev))
 		bus_generic_detach(dev);
 
-	/* Delete child bus. */
-	if (sc->child)
-		device_delete_child(dev, sc->child);
-
 	/* Disable hardware. */
 	if (sc->mem_res != NULL) {
 		/* Disable SPI. */
diff --git a/sys/dev/bce/if_bce.c b/sys/dev/bce/if_bce.c
index 226fca16ac28..73af49015e52 100644
--- a/sys/dev/bce/if_bce.c
+++ b/sys/dev/bce/if_bce.c
@@ -1544,7 +1544,6 @@ bce_detach(device_t dev)
 		ifmedia_removeall(&sc->bce_ifmedia);
 	else {
 		bus_generic_detach(dev);
-		device_delete_child(dev, sc->bce_miibus);
 	}
 
 	/* Release all remaining resources. */
diff --git a/sys/dev/bfe/if_bfe.c b/sys/dev/bfe/if_bfe.c
index 817c867862d0..2fb6938fbdc5 100644
--- a/sys/dev/bfe/if_bfe.c
+++ b/sys/dev/bfe/if_bfe.c
@@ -551,8 +551,6 @@ bfe_detach(device_t dev)
 	BFE_UNLOCK(sc);
 
 	bus_generic_detach(dev);
-	if (sc->bfe_miibus != NULL)
-		device_delete_child(dev, sc->bfe_miibus);
 
 	bfe_release_resources(sc);
 	bfe_dma_free(sc);
diff --git a/sys/dev/bge/if_bge.c b/sys/dev/bge/if_bge.c
index 6c3301b1473a..cf3084f9b768 100644
--- a/sys/dev/bge/if_bge.c
+++ b/sys/dev/bge/if_bge.c
@@ -3949,7 +3949,6 @@ bge_detach(device_t dev)
 		ifmedia_removeall(&sc->bge_ifmedia);
 	else if (sc->bge_miibus != NULL) {
 		bus_generic_detach(dev);
-		device_delete_child(dev, sc->bge_miibus);
 	}
 
 	bge_release_resources(sc);
diff --git a/sys/dev/bhnd/bhndb/bhndb.c b/sys/dev/bhnd/bhndb/bhndb.c
index 511beae0cc25..f9d56a9b9226 100644
--- a/sys/dev/bhnd/bhndb/bhndb.c
+++ b/sys/dev/bhnd/bhndb/bhndb.c
@@ -624,10 +624,6 @@ bhndb_generic_detach(device_t dev)
 	if ((error = bus_generic_detach(dev)))
 		return (error);
 
-	/* Delete children */
-	if ((error = device_delete_children(dev)))
-		return (error);
-
 	/* Clean up our service registry */
 	if ((error = bhnd_service_registry_fini(&sc->services)))
 		return (error);
diff --git a/sys/dev/bhnd/cores/chipc/chipc.c b/sys/dev/bhnd/cores/chipc/chipc.c
index 09ca4d8884e6..24697a8f0b17 100644
--- a/sys/dev/bhnd/cores/chipc/chipc.c
+++ b/sys/dev/bhnd/cores/chipc/chipc.c
@@ -244,9 +244,6 @@ chipc_detach(device_t dev)
 	if ((error = bus_generic_detach(dev)))
 		return (error);
 
-	if ((error = device_delete_children(dev)))
-		return (error);
-
 	if ((error = bhnd_deregister_provider(dev, BHND_SERVICE_ANY)))
 		return (error);
 
diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c
index 755fd19a3c9c..024c97dcb78c 100644
--- a/sys/dev/cxgbe/t4_main.c
+++ b/sys/dev/cxgbe/t4_main.c
@@ -1807,8 +1807,6 @@ t4_detach_common(device_t dev)
 		pi = sc->port[i];
 		if (pi) {
 			t4_free_vi(sc, sc->mbox, sc->pf, 0, pi->vi[0].viid);
-			if (pi->dev)
-				device_delete_child(dev, pi->dev);
 
 			mtx_destroy(&pi->pi_lock);
 			free(pi->vi, M_CXGBE);
diff --git a/sys/dev/dpaa2/dpaa2_mc.c b/sys/dev/dpaa2/dpaa2_mc.c
index 1d0275127ced..c84b22d1d74d 100644
--- a/sys/dev/dpaa2/dpaa2_mc.c
+++ b/sys/dev/dpaa2/dpaa2_mc.c
@@ -286,8 +286,6 @@ dpaa2_mc_detach(device_t dev)
 		return (error);
 
 	sc = device_get_softc(dev);
-	if (sc->rcdev)
-		device_delete_child(dev, sc->rcdev);
 	bus_release_resources(dev, dpaa2_mc_spec, sc->res);
 
 	dinfo = device_get_ivars(dev);
diff --git a/sys/dev/etherswitch/felix/felix.c b/sys/dev/etherswitch/felix/felix.c
index 622cf3bca140..b6fb8cbb67c8 100644
--- a/sys/dev/etherswitch/felix/felix.c
+++ b/sys/dev/etherswitch/felix/felix.c
@@ -497,8 +497,6 @@ felix_detach(device_t dev)
 		felix_setup(sc);
 
 	for (i = 0; i < sc->info.es_nports; i++) {
-		if (sc->ports[i].miibus != NULL)
-			device_delete_child(dev, sc->ports[i].miibus);
 		if (sc->ports[i].ifp != NULL)
 			if_free(sc->ports[i].ifp);
 		if (sc->ports[i].ifname != NULL)
diff --git a/sys/dev/firewire/fwohci_pci.c b/sys/dev/firewire/fwohci_pci.c
index 591503728093..a6f9f50701f0 100644
--- a/sys/dev/firewire/fwohci_pci.c
+++ b/sys/dev/firewire/fwohci_pci.c
@@ -333,11 +333,6 @@ fwohci_pci_detach(device_t self)
 
 	bus_generic_detach(self);
 
-	if (sc->fc.bdev) {
-		device_delete_child(self, sc->fc.bdev);
-		sc->fc.bdev = NULL;
-	}
-
 	/* disable interrupts that might have been switched on */
 	if (sc->bst && sc->bsh)
 		bus_space_write_4(sc->bst, sc->bsh,
diff --git a/sys/dev/glxiic/glxiic.c b/sys/dev/glxiic/glxiic.c
index 5dfea9acbe4a..ddaa77b6b73c 100644
--- a/sys/dev/glxiic/glxiic.c
+++ b/sys/dev/glxiic/glxiic.c
@@ -451,11 +451,8 @@ glxiic_detach(device_t dev)
 
 	error = bus_generic_detach(dev);
 	if (error != 0)
-		goto out;
-	if (sc->iicbus != NULL)
-		error = device_delete_child(dev, sc->iicbus);
+		return (error);
 
-out:
 	callout_drain(&sc->callout);
 
 	if (sc->smb_res != NULL) {
@@ -479,7 +476,7 @@ out:
 
 	GLXIIC_LOCK_DESTROY(sc);
 
-	return (error);
+	return (0);
 }
 
 static uint8_t
diff --git a/sys/dev/ichiic/ig4_iic.c b/sys/dev/ichiic/ig4_iic.c
index 806b406af326..c9346ff12350 100644
--- a/sys/dev/ichiic/ig4_iic.c
+++ b/sys/dev/ichiic/ig4_iic.c
@@ -1080,13 +1080,9 @@ ig4iic_detach(ig4iic_softc_t *sc)
 {
 	int error;
 
-	if (device_is_attached(sc->dev)) {
-		error = bus_generic_detach(sc->dev);
-		if (error)
-			return (error);
-	}
-	if (sc->iicbus)
-		device_delete_child(sc->dev, sc->iicbus);
+	error = bus_generic_detach(sc->dev);
+	if (error)
+		return (error);
 	if (sc->intr_handle)
 		bus_teardown_intr(sc->dev, sc->intr_res, sc->intr_handle);
 
diff --git a/sys/dev/ichsmb/ichsmb.c b/sys/dev/ichsmb/ichsmb.c
index 063fbf66a75a..28503b9e574d 100644
--- a/sys/dev/ichsmb/ichsmb.c
+++ b/sys/dev/ichsmb/ichsmb.c
@@ -696,7 +696,6 @@ ichsmb_detach(device_t dev)
 	error = bus_generic_detach(dev);
 	if (error)
 		return (error);
-	device_delete_child(dev, sc->smb);
 	ichsmb_release_resources(sc);
 	mtx_destroy(&sc->mutex);
 	
diff --git a/sys/dev/iicbus/controller/cadence/cdnc_i2c.c b/sys/dev/iicbus/controller/cadence/cdnc_i2c.c
index 3bed24c36070..bf1f88ec9ca5 100644
--- a/sys/dev/iicbus/controller/cadence/cdnc_i2c.c
+++ b/sys/dev/iicbus/controller/cadence/cdnc_i2c.c
@@ -626,18 +626,13 @@ cdnc_i2c_detach(device_t dev)
 {
 	struct cdnc_i2c_softc *sc = device_get_softc(dev);
 
-	if (device_is_attached(dev))
-		bus_generic_detach(dev);
+	bus_generic_detach(dev);
 
 	if (sc->ref_clk != NULL) {
 		clk_release(sc->ref_clk);
 		sc->ref_clk = NULL;
 	}
 
-	/* Delete iic bus. */
-	if (sc->iicbus)
-		device_delete_child(dev, sc->iicbus);
-
 	/* Disable hardware. */
 	if (sc->mem_res != NULL) {
 		sc->cfg_reg_shadow = 0;
diff --git a/sys/dev/iicbus/controller/rockchip/rk_i2c.c b/sys/dev/iicbus/controller/rockchip/rk_i2c.c
index 0ef65d1121f5..9317adbcfd98 100644
--- a/sys/dev/iicbus/controller/rockchip/rk_i2c.c
+++ b/sys/dev/iicbus/controller/rockchip/rk_i2c.c
@@ -686,10 +686,6 @@ rk_i2c_detach(device_t dev)
 	if ((error = bus_generic_detach(dev)) != 0)
 		return (error);
 
-	if (sc->iicbus != NULL)
-		if ((error = device_delete_child(dev, sc->iicbus)) != 0)
-			return (error);
-
 	if (sc->sclk != NULL)
 		clk_release(sc->sclk);
 	if (sc->pclk != NULL)
diff --git a/sys/dev/iicbus/controller/twsi/twsi.c b/sys/dev/iicbus/controller/twsi/twsi.c
index 20d39aa7d93b..b5aefbae7d7e 100644
--- a/sys/dev/iicbus/controller/twsi/twsi.c
+++ b/sys/dev/iicbus/controller/twsi/twsi.c
@@ -835,10 +835,6 @@ twsi_detach(device_t dev)
 	if ((rv = bus_generic_detach(dev)) != 0)
 		return (rv);
 
-	if (sc->iicbus != NULL)
-		if ((rv = device_delete_child(dev, sc->iicbus)) != 0)
-			return (rv);
-
 	if (sc->intrhand != NULL)
 		bus_teardown_intr(sc->dev, sc->res[1], sc->intrhand);
 
diff --git a/sys/dev/iicbus/controller/vybrid/vf_i2c.c b/sys/dev/iicbus/controller/vybrid/vf_i2c.c
index f6d0eb4c2c59..4735a95cf5cd 100644
--- a/sys/dev/iicbus/controller/vybrid/vf_i2c.c
+++ b/sys/dev/iicbus/controller/vybrid/vf_i2c.c
@@ -213,12 +213,6 @@ i2c_detach(device_t dev)
 		return (error);
 	}
 
-	error = device_delete_child(dev, sc->iicbus);
-	if (error != 0) {
-		device_printf(dev, "could not delete iicbus child.\n");
-		return (error);
-	}
-
 	mtx_lock(&sc->mutex);
 
 	if (sc->freq == 0) {
diff --git a/sys/dev/ismt/ismt.c b/sys/dev/ismt/ismt.c
index 650353c75e9f..4aea93d1f435 100644
--- a/sys/dev/ismt/ismt.c
+++ b/sys/dev/ismt/ismt.c
@@ -532,8 +532,6 @@ ismt_detach(device_t dev)
 	if (error)
 		return (error);
 
-	device_delete_child(dev, sc->smbdev);
-
 	if (sc->intr_handle != NULL) {
 		bus_teardown_intr(dev, sc->intr_res, sc->intr_handle);
 		sc->intr_handle = NULL;
diff --git a/sys/dev/lge/if_lge.c b/sys/dev/lge/if_lge.c
index 7542b17e19eb..c5cfafc0bd22 100644
--- a/sys/dev/lge/if_lge.c
+++ b/sys/dev/lge/if_lge.c
@@ -583,7 +583,6 @@ lge_detach(device_t dev)
 	ether_ifdetach(ifp);
 
 	bus_generic_detach(dev);
-	device_delete_child(dev, sc->lge_miibus);
 
 	bus_teardown_intr(dev, sc->lge_irq, sc->lge_intrhand);
 	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lge_irq);
diff --git a/sys/dev/ow/ow.c b/sys/dev/ow/ow.c
index 9cbd05cd88b1..0325e6b324c8 100644
--- a/sys/dev/ow/ow.c
+++ b/sys/dev/ow/ow.c
@@ -565,8 +565,6 @@ ow_attach(device_t ndev)
 static int
 ow_detach(device_t ndev)
 {
-	device_t *children, child;
-	int nkid, i;
 	struct ow_softc *sc;
 
 	sc = device_get_softc(ndev);
@@ -576,17 +574,6 @@ ow_detach(device_t ndev)
 	 */
 	bus_generic_detach(ndev);
 
-	/*
-	 * We delete all the children, and free up the ivars 
-	 */
-	if (device_get_children(ndev, &children, &nkid) != 0)
-		return ENOMEM;
-	for (i = 0; i < nkid; i++) {
-		child = children[i];
-		device_delete_child(ndev, child);
-	}
-	free(children, M_TEMP);
-
 	OW_LOCK_DESTROY(sc);
 	return 0;
 }
diff --git a/sys/dev/pcf/pcf_isa.c b/sys/dev/pcf/pcf_isa.c
index 190554258c3a..f86caed87e6a 100644
--- a/sys/dev/pcf/pcf_isa.c
+++ b/sys/dev/pcf/pcf_isa.c
@@ -192,9 +192,6 @@ pcf_isa_detach(device_t dev)
 	if ((rv = bus_generic_detach(dev)) != 0)
 		return (rv);
 
-	if ((rv = device_delete_child(dev, sc->iicbus)) != 0)
-		return (rv);
-
 	if (sc->res_irq != 0) {
 		bus_teardown_intr(dev, sc->res_irq, sc->intr_cookie);
 		bus_release_resource(dev, SYS_RES_IRQ, sc->rid_irq, sc->res_irq);
diff --git a/sys/dev/pwm/controller/allwinner/aw_pwm.c b/sys/dev/pwm/controller/allwinner/aw_pwm.c
index 0f505957bb1a..117f3ae17e1b 100644
--- a/sys/dev/pwm/controller/allwinner/aw_pwm.c
+++ b/sys/dev/pwm/controller/allwinner/aw_pwm.c
@@ -211,9 +211,6 @@ aw_pwm_detach(device_t dev)
 		return (error);
 	}
 
-	if (sc->busdev != NULL)
-		device_delete_child(dev, sc->busdev);
-
 	if (sc->res != NULL)
 		bus_release_resources(dev, aw_pwm_spec, &sc->res);
 
diff --git a/sys/dev/qcom_qup/qcom_spi.c b/sys/dev/qcom_qup/qcom_spi.c
index d3f38dee041f..88341b4d2083 100644
--- a/sys/dev/qcom_qup/qcom_spi.c
+++ b/sys/dev/qcom_qup/qcom_spi.c
@@ -840,8 +840,6 @@ qcom_spi_detach(device_t dev)
 	int i;
 
 	bus_generic_detach(sc->sc_dev);
-	if (sc->spibus != NULL)
-		device_delete_child(dev, sc->spibus);
 
 	if (sc->sc_irq_h)
 		bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_h);
diff --git a/sys/dev/smbus/smbus.c b/sys/dev/smbus/smbus.c
index 28d1a16e8c96..9a37c482654b 100644
--- a/sys/dev/smbus/smbus.c
+++ b/sys/dev/smbus/smbus.c
@@ -83,7 +83,6 @@ smbus_detach(device_t dev)
 	error = bus_generic_detach(dev);
 	if (error)
 		return (error);
-	device_delete_children(dev);
 	mtx_destroy(&sc->lock);
 
 	return (0);
diff --git a/sys/dev/sound/pci/fm801.c b/sys/dev/sound/pci/fm801.c
index 72a476708aa7..3537c7807ded 100644
--- a/sys/dev/sound/pci/fm801.c
+++ b/sys/dev/sound/pci/fm801.c
@@ -676,12 +676,6 @@ fm801_pci_detach(device_t dev)
 	r = bus_generic_detach(dev);
 	if (r)
 		return r;
-	if (fm801->radio != NULL) {
-		r = device_delete_child(dev, fm801->radio);
-		if (r)
-			return r;
-		fm801->radio = NULL;
-	}
 
 	r = pcm_unregister(dev);
 	if (r)
diff --git a/sys/dev/spibus/controller/allwinner/aw_spi.c b/sys/dev/spibus/controller/allwinner/aw_spi.c
index e17152b054d7..34461ab2ba9c 100644
--- a/sys/dev/spibus/controller/allwinner/aw_spi.c
+++ b/sys/dev/spibus/controller/allwinner/aw_spi.c
@@ -253,8 +253,6 @@ aw_spi_detach(device_t dev)
 	sc = device_get_softc(dev);
 
 	bus_generic_detach(sc->dev);
-	if (sc->spibus != NULL)
-		device_delete_child(dev, sc->spibus);
 
 	if (sc->clk_mod != NULL)
 		clk_release(sc->clk_mod);
diff --git a/sys/dev/spibus/controller/rockchip/rk_spi.c b/sys/dev/spibus/controller/rockchip/rk_spi.c
index 2c8093c6dc82..db650763f6e1 100644
--- a/sys/dev/spibus/controller/rockchip/rk_spi.c
+++ b/sys/dev/spibus/controller/rockchip/rk_spi.c
@@ -354,8 +354,6 @@ rk_spi_detach(device_t dev)
 	sc = device_get_softc(dev);
 
 	bus_generic_detach(sc->dev);
-	if (sc->spibus != NULL)
-		device_delete_child(dev, sc->spibus);
 
 	if (sc->clk_spi != NULL)
 		clk_release(sc->clk_spi);
diff --git a/sys/dev/viapm/viapm.c b/sys/dev/viapm/viapm.c
index b19ad478a3ff..36c33422d5b3 100644
--- a/sys/dev/viapm/viapm.c
+++ b/sys/dev/viapm/viapm.c
@@ -444,9 +444,6 @@ viapm_586b_detach(device_t dev)
 	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
 
 	bus_generic_detach(dev);
-	if (viapm->iicbb) {
-		device_delete_child(dev, viapm->iicbb);
-	}
 
 	if (viapm->iores)
 		bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid,
@@ -462,9 +459,6 @@ viapm_pro_detach(device_t dev)
 	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
 
 	bus_generic_detach(dev);
-	if (viapm->smbus) {
-		device_delete_child(dev, viapm->smbus);
-	}
 
 	bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores);
 
diff --git a/sys/dev/vnic/thunder_mdio.c b/sys/dev/vnic/thunder_mdio.c
index 4545fe6658f5..a98e6aff05fd 100644
--- a/sys/dev/vnic/thunder_mdio.c
+++ b/sys/dev/vnic/thunder_mdio.c
@@ -494,7 +494,6 @@ thunder_mdio_phy_disconnect(device_t dev, int lmacid, int phy)
 
 	/* Detach miibus */
 	bus_generic_detach(dev);
-	device_delete_child(dev, pd->miibus);
 	/* Free fake ifnet */
 	if_free(pd->ifp);
 	/* Free memory under phy descriptor */
diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c
index 1d04ea496f08..0df0b883a32d 100644
--- a/sys/kern/subr_bus.c
+++ b/sys/kern/subr_bus.c
@@ -3496,8 +3496,13 @@ bus_delayed_attach_children(device_t dev)
  * @brief Helper function for implementing DEVICE_DETACH()
  *
  * This function can be used to help implement the DEVICE_DETACH() for
- * a bus. It calls device_detach() for each of the device's
- * children.
+ * a bus.  It detaches and deletes all children.  If an individual
+ * child fails to detach, this function stops and returns an error.
+ *
+ * @param dev		the parent device
+ *
+ * @retval 0		success
+ * @retval non-zero	a device would not detach
  */
 int
 bus_generic_detach(device_t dev)
@@ -3508,7 +3513,7 @@ bus_generic_detach(device_t dev)
 	if (error != 0)
 		return (error);
 
-	return (0);
+	return (device_delete_children(dev));
 }
 
 /**
diff --git a/sys/sys/param.h b/sys/sys/param.h
index f675dd024ee0..d2aad1ff98a1 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -73,7 +73,7 @@
  * cannot include sys/param.h and should only be updated here.
  */
 #undef __FreeBSD_version
-#define __FreeBSD_version 1500029
+#define __FreeBSD_version 1500030
 
 /*
  * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,