summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorriastradh <riastradh@NetBSD.org>2022-08-14 20:34:26 +0000
committerriastradh <riastradh@NetBSD.org>2022-08-14 20:34:26 +0000
commit604bc090e2600ddb4112787b4b06ceb3d54884b9 (patch)
tree69f9e0d54f0fd3a27412758d1094d2d9c2d28dc7 /sys/dev
parente5fb4d771fccd189b092bc635ee0e275cec3df57 (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.c9
-rw-r--r--sys/dev/mii/mii_physubr.c28
-rw-r--r--sys/dev/mii/miivar.h7
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 */