On Tue, Jul 26, 2022 at 11:19:27PM +0200, Mark Kettenis wrote:
> > Date: Tue, 26 Jul 2022 18:11:01 +0200
> > From: Alexander Bluhm <[email protected]>
> >
> > On Fri, Jul 22, 2022 at 06:13:04PM +0200, Alexander Bluhm wrote:
> > > But I am fine with committing ifmedia, gem(4) and bge(4) now. Then
> > > we can decide on a per driver basis. As long kernel lock is not
> > > removed from the ifmedia layer, this diff is not strictly necessary.
> > > I want to commit it anyway to show how MP in ifmedia should work.
> >
> > This is the part for gem(4) and bge(4). I have tested them.
> > ifmedia_current() is MP safe and provides the data which all the
> > drivers need.
> >
> > After commiting this, I can look for more hardware to test.
> >
> > ok?
>
> I still don't understand what this fixes. Most drivers create a list
> of media when the PHY attaches during autoconf. That list never
> changes, which means that the pointer to the ifmedia struct remains
> valid until the driver detaches.
>
> There is of course a race when you use ifconfig to change the media
> type. But your new interface doesn't really fix that race. Code that
> uses ifmedia_current() may still end up with the old information and
> use that at a point where that information is no longer accurate.
It does not fix a real bug. The diff tries to keep internal data
structures within a file, instead of spreading them over all drivers.
MP work is easier if each struct field has a clear lock that is
responsible for it. 70 drivers that should change it only during
attach is not that clear.
The ifmedia_list is protected by mutex. ifm_cur is a pointer to
an element of the list. It would be natural to protect it with the
same mutex. ifm_cur is changed by ifmedia_set() and ifmedia_ioctl()
and ifmedia_delete_instance().
Look at bnxt_hwrm_port_phy_qcfg(). There the list is changed by
bnxt_media_status() which is called from ifmedia_ioctl().
ixgbe_handle_msf() changes the list during SPF interrupt. But I
have to admit that these drivers do not access ifm_cur.
Why do you refuse to make the ifmedia layer MP safe by itself?
It is just one function and a mutex. I cannot see harm.
bluhm
> > Index: dev/ic/gem.c
> > ===================================================================
> > RCS file: /data/mirror/openbsd/cvs/src/sys/dev/ic/gem.c,v
> > retrieving revision 1.127
> > diff -u -p -r1.127 gem.c
> > --- dev/ic/gem.c 12 Jul 2022 22:08:17 -0000 1.127
> > +++ dev/ic/gem.c 26 Jul 2022 09:14:10 -0000
> > @@ -1348,16 +1348,18 @@ void
> > gem_mii_statchg(struct device *dev)
> > {
> > struct gem_softc *sc = (void *)dev;
> > -#ifdef GEM_DEBUG
> > - uint64_t instance = IFM_INST(sc->sc_mii.mii_media.ifm_cur->ifm_media);
> > -#endif
> > bus_space_tag_t t = sc->sc_bustag;
> > bus_space_handle_t mac = sc->sc_h1;
> > u_int32_t v;
> >
> > #ifdef GEM_DEBUG
> > - if (sc->sc_debug)
> > - printf("gem_mii_statchg: status change: phy = %lld\n",
> > instance);
> > + if (sc->sc_debug) {
> > + uint64_t media;
> > +
> > + ifmedia_current(&sc->sc_mii.mii_media, &media, NULL);
> > + printf("%s: status change: phy = %lld\n",
> > + __func__, IFM_INST(media));
> > + }
> > #endif
> >
> > /* Set tx full duplex options */
> > Index: dev/pci/if_bge.c
> > ===================================================================
> > RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/if_bge.c,v
> > retrieving revision 1.398
> > diff -u -p -r1.398 if_bge.c
> > --- dev/pci/if_bge.c 11 Mar 2022 18:00:45 -0000 1.398
> > +++ dev/pci/if_bge.c 26 Jul 2022 09:14:10 -0000
> > @@ -1054,12 +1054,15 @@ bge_miibus_statchg(struct device *dev)
> > {
> > struct bge_softc *sc = (struct bge_softc *)dev;
> > struct mii_data *mii = &sc->bge_mii;
> > + uint64_t media;
> > u_int32_t mac_mode, rx_mode, tx_mode;
> >
> > + ifmedia_current(&mii->mii_media, &media, NULL);
> > +
> > /*
> > * Get flow control negotiation result.
> > */
> > - if (IFM_SUBTYPE(mii->mii_media.ifm_cur->ifm_media) == IFM_AUTO &&
> > + if (IFM_SUBTYPE(media) == IFM_AUTO &&
> > (mii->mii_media_active & IFM_ETH_FMASK) != sc->bge_flowflags)
> > sc->bge_flowflags = mii->mii_media_active & IFM_ETH_FMASK;
> >
> > @@ -3095,7 +3098,8 @@ bge_attach(struct device *parent, struct
> > 0, NULL);
> > ifmedia_add(&sc->bge_ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
> > ifmedia_set(&sc->bge_ifmedia, IFM_ETHER|IFM_AUTO);
> > - sc->bge_ifmedia.ifm_media = sc->bge_ifmedia.ifm_cur->ifm_media;
> > + ifmedia_current(&sc->bge_ifmedia, &sc->bge_ifmedia.ifm_media,
> > + NULL);
> > } else {
> > int mii_flags;
> >
> > Index: net/if_media.c
> > ===================================================================
> > RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_media.c,v
> > retrieving revision 1.36
> > diff -u -p -r1.36 if_media.c
> > --- net/if_media.c 14 Jul 2022 13:46:25 -0000 1.36
> > +++ net/if_media.c 26 Jul 2022 09:14:10 -0000
> > @@ -430,6 +430,21 @@ ifmedia_get(struct ifmedia *ifm, uint64_
> > return (match);
> > }
> >
> > +void
> > +ifmedia_current(struct ifmedia *ifm, uint64_t *media, u_int *data)
> > +{
> > + struct ifmedia_entry *ife;
> > +
> > + mtx_enter(&ifmedia_mtx);
> > + ife = ifm->ifm_cur;
> > + KASSERT(ife != NULL);
> > + if (media != NULL)
> > + *media = ife->ifm_media;
> > + if (data != NULL)
> > + *data = ife->ifm_data;
> > + mtx_leave(&ifmedia_mtx);
> > +}
> > +
> > /*
> > * Delete all media for a given instance.
> > */
> > Index: net/if_media.h
> > ===================================================================
> > RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_media.h,v
> > retrieving revision 1.45
> > diff -u -p -r1.45 if_media.h
> > --- net/if_media.h 14 Jul 2022 13:46:25 -0000 1.45
> > +++ net/if_media.h 26 Jul 2022 09:14:10 -0000
> > @@ -131,6 +131,9 @@ int ifmedia_ioctl(struct ifnet *, struct
> > /* Locate a media entry */
> > int ifmedia_match(struct ifmedia *, uint64_t, uint64_t);
> >
> > +/* Get current media and data */
> > +void ifmedia_current(struct ifmedia *, uint64_t *, u_int *);
> > +
> > /* Delete all media for a given media instance */
> > void ifmedia_delete_instance(struct ifmedia *, uint64_t);
> >
> >