diff options
| author | riastradh <riastradh@NetBSD.org> | 2022-08-14 20:34:26 +0000 |
|---|---|---|
| committer | riastradh <riastradh@NetBSD.org> | 2022-08-14 20:34:26 +0000 |
| commit | 604bc090e2600ddb4112787b4b06ceb3d54884b9 (patch) | |
| tree | 69f9e0d54f0fd3a27412758d1094d2d9c2d28dc7 /sys/dev | |
| parent | e5fb4d771fccd189b092bc635ee0e275cec3df57 (diff) | |
mii(4): Wait for MIIF_DOINGAUTO to clear with MIIF_AUTOTSLEEP too.
Otherwise mii_phy_detach may return while mii_phy_auto_timeout_locked
is still in progress in another thread.
Reuse the storage for mii_nway_ch, which is unused if MIIF_AUTOTSLEEP
is set, for a new condvar in a union. This doesn't change the kernel
ABI because sizeof(struct kcondvar) <= sizeof(struct callout) and
both have the same alignment, for an array of void *.
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/mii/mii.c | 9 | ||||
| -rw-r--r-- | sys/dev/mii/mii_physubr.c | 28 | ||||
| -rw-r--r-- | sys/dev/mii/miivar.h | 7 |
3 files changed, 32 insertions, 12 deletions
diff --git a/sys/dev/mii/mii.c b/sys/dev/mii/mii.c index e3b49b602c4..7824582bb40 100644 --- a/sys/dev/mii/mii.c +++ b/sys/dev/mii/mii.c @@ -1,4 +1,4 @@ -/* $NetBSD: mii.c,v 1.57 2021/08/07 16:19:13 thorpej Exp $ */ +/* $NetBSD: mii.c,v 1.58 2022/08/14 20:34:26 riastradh Exp $ */ /*- * Copyright (c) 1998, 2000, 2020 The NetBSD Foundation, Inc. @@ -36,7 +36,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: mii.c,v 1.57 2021/08/07 16:19:13 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mii.c,v 1.58 2022/08/14 20:34:26 riastradh Exp $"); #define __IFMEDIA_PRIVATE @@ -179,7 +179,10 @@ mii_attach(device_t parent, struct mii_data *mii, int capmask, .locators = locs))); if (child) { /* Link it up in the parent's MII data. */ - callout_init(&child->mii_nway_ch, 0); + if (child->mii_flags & MIIF_AUTOTSLEEP) + cv_init(&child->mii_nway_cv, "miiauto"); + else + callout_init(&child->mii_nway_ch, 0); mii_lock(mii); LIST_INSERT_HEAD(&mii->mii_phys, child, mii_list); child->mii_offset = offset; diff --git a/sys/dev/mii/mii_physubr.c b/sys/dev/mii/mii_physubr.c index 5731173c48e..d309ff4bcc9 100644 --- a/sys/dev/mii/mii_physubr.c +++ b/sys/dev/mii/mii_physubr.c @@ -1,4 +1,4 @@ -/* $NetBSD: mii_physubr.c,v 1.98 2022/08/14 20:33:57 riastradh Exp $ */ +/* $NetBSD: mii_physubr.c,v 1.99 2022/08/14 20:34:26 riastradh Exp $ */ /*- * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: mii_physubr.c,v 1.98 2022/08/14 20:33:57 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mii_physubr.c,v 1.99 2022/08/14 20:34:26 riastradh Exp $"); #include <sys/param.h> #include <sys/device.h> @@ -282,6 +282,8 @@ mii_phy_auto(struct mii_softc *sc) sc->mii_flags |= MIIF_DOINGAUTO; kpause("miiaut", false, hz >> 1, mii->mii_media.ifm_lock); mii_phy_auto_timeout_locked(sc); + KASSERT((sc->mii_flags & MIIF_DOINGAUTO) == 0); + cv_broadcast(&sc->mii_nway_cv); } else if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) { sc->mii_flags |= MIIF_DOINGAUTO; callout_reset(&sc->mii_nway_ch, hz >> 1, @@ -309,6 +311,7 @@ mii_phy_auto_timeout_locked(struct mii_softc *sc) { KASSERT(mii_locked(sc->mii_pdata)); + KASSERT(sc->mii_flags & MIIF_DOINGAUTO); if (!device_is_active(sc->mii_dev)) return; @@ -432,7 +435,8 @@ mii_phy_down(struct mii_softc *sc) KASSERT(mii_locked(sc->mii_pdata)); - if (sc->mii_flags & MIIF_DOINGAUTO) { + if ((sc->mii_flags & (MIIF_DOINGAUTO|MIIF_AUTOTSLEEP)) == + (MIIF_DOINGAUTO|MIIF_AUTOTSLEEP)) { /* * Try to stop it. * @@ -688,13 +692,23 @@ mii_phy_detach(device_t self, int flags) struct mii_softc *sc = device_private(self); mii_lock(sc->mii_pdata); - if (sc->mii_flags & MIIF_DOINGAUTO) { - callout_halt(&sc->mii_nway_ch, - sc->mii_pdata->mii_media.ifm_lock); + if (sc->mii_flags & MIIF_AUTOTSLEEP) { + while (sc->mii_flags & MIIF_DOINGAUTO) { + cv_wait(&sc->mii_nway_cv, + sc->mii_pdata->mii_media.ifm_lock); + } + } else { + if (sc->mii_flags & MIIF_DOINGAUTO) { + callout_halt(&sc->mii_nway_ch, + sc->mii_pdata->mii_media.ifm_lock); + } } mii_unlock(sc->mii_pdata); - callout_destroy(&sc->mii_nway_ch); + if (sc->mii_flags & MIIF_AUTOTSLEEP) + cv_destroy(&sc->mii_nway_cv); + else + callout_destroy(&sc->mii_nway_ch); mii_phy_delete_media(sc); diff --git a/sys/dev/mii/miivar.h b/sys/dev/mii/miivar.h index 99b2953e431..d96fa53b1dd 100644 --- a/sys/dev/mii/miivar.h +++ b/sys/dev/mii/miivar.h @@ -1,4 +1,4 @@ -/* $NetBSD: miivar.h,v 1.74 2021/06/29 21:03:36 pgoyette Exp $ */ +/* $NetBSD: miivar.h,v 1.75 2022/08/14 20:34:26 riastradh Exp $ */ /*- * Copyright (c) 1998, 1999, 2000, 2001, 2020 The NetBSD Foundation, Inc. @@ -150,7 +150,10 @@ struct mii_softc { int mii_ticks; /* m: MII_TICK counter */ int mii_anegticks; /* m: ticks before retrying aneg */ - struct callout mii_nway_ch; /* m: NWAY callout */ + union { + struct callout mii_nway_ch; /* m: NWAY callout */ + kcondvar_t mii_nway_cv; + }; u_int mii_media_active; /* m: last active media */ int mii_media_status; /* m: last active status */ |
