--- a/sys/dev/netif/mii_layer/mii.c 2026-09-25 18:16:01.683350318 +0000 +++ b/sys/dev/netif/mii_layer/mii.c 2026-09-25 18:24:35.396634613 +0000 @@ -188,12 +188,31 @@ miibus_detach(device_t dev) { struct mii_data *mii; + device_t *children; + int count, i; + /* + * DF-5002: newbus never frees device ivars (subr_bus.c + * device_delete_child drops the pointer); the per-PHY + * mii_attach_args we kmalloc'ed in miibus_probe() are ours to + * release while the children are still enumerated. + */ + if (device_get_children(dev, &children, &count) == 0) { + for (i = 0; i < count; i++) { + kfree(device_get_ivars(children[i]), M_DEVBUF); + device_set_ivars(children[i], NULL); + } + kfree(children, M_TEMP); + } bus_generic_detach(dev); mii = device_get_softc(dev); ifmedia_removeall(&mii->mii_media); mii->mii_ifp = NULL; + /* ... and the mii_probe_args we attached to the bus itself. */ + kfree(device_get_ivars(dev), M_DEVBUF); + device_set_ivars(dev, NULL); + return 0; } @@ -272,6 +291,14 @@ } if (i == MII_NPHY) { + /* + * DF-5002: the child is deleted unattached; newbus does not + * free ivars, so release our mii_probe_args here instead of + * leaking them on every failed probe (bge retries this path + * up to 5 times per attach, if_bge.c). + */ + kfree(args, M_DEVBUF); + device_set_ivars(*child, NULL); device_delete_child(dev, *child); *child = NULL; return ENXIO;