This legacy flag is a figment of userland's imagination. The actual
kernel state is ec->ec_flags & ETHER_F_ALLMULTI, protected by the
ETHER_LOCK, so that multicast filter updates -- which run without
IFNET_LOCK -- need not attempt to write racily to ifp->if_flags.
This operation only needs to update the hardware to reflect
SIOCADDMULTI/SIOCDELMULTI. Not clear that everything in aue(4) needs
to be reset -- in fact I'm pretty sure that's undesirable!
WARNING: I have not tested this with a real aue(4) device.
Every driver does this already. This will enable us to change the
lock that serializes access to the registers so we can go back to
doing this synchronously in SIOCADDMULTI/SIOCDELMULTI.
The only state this touches is unp_if_flags, and all paths touching
it also hold IFNET_LOCK -- not to mention this is the only path that
touches unp_if_flags in the first place!
After mii_detach, these have all completed and no new ones can be
made, and detach doesn't start destroying anything until after
mii_detach has returned, so there is no need to hang onto a reference
count here.
These run with IFNET_LOCK held, and the interface cannot be detached
until the IFNET_LOCK is released, so there is no need to hang onto a
reference count here.
usbnet_detach cannot run until the attach routine has finished
(unless a driver goes out of its way to tie its shoelaces together
and explicitly call it during the attach routine, which none of them
do), so there is no need to hang onto a reference count that we
release before attach returns.
This callback always runs with the IFNET_LOCK held, and the interface
cannot be detached until the IFNET_LOCK is released, so there is no
need to hang onto a reference count here. (None of the subnet
drivers touch the IFNET_LOCK except to verify it is held sometimes.)
This callback always runs with IFNET_LOCK held, and during a task
that usbnet_detach prevents scheduling anew and waits for finishing
before completing the detach, so there is no need to hang onto a
reference count here.
This callback always runs with the IFNET_LOCK held, and the interface
cannot be detached until the IFNET_LOCK is released, so there is no
need to hang onto a reference count here. (None of the usbnet
drivers touch the IFNET_LOCK except to verify it is held sometimes.)
Now that is tested and set with atomic_load/store, there is no need
to hold the lock -- which means we can set it while the core lock is
held during, e.g., a reset sequence, and use that to interrupt the
sequence so it doesn't get stuck waiting to time out when the device
is physically removed.
This way we don't need to hold the core lock to avoid upsetting
sanitizers (which probably find the current code upsetting), and we
can use it to exit early from timeout loops that run under the core
lock (which is probably not necessary for them to do anyway, but
let's worry about that later).
This reduces code in all drivers except urndis(4) and aue(4).
However, it's still safe for urndis to drop the core lock because the
ifnet is locked, and the ifnet lock covers the DOWN->UP (uno_init)
and UP->DOWN (uno_stop) transitions.
The hardware is most likely gone, so trying to write to its registers
(and, in some cases, wait until a timeout for a device to reset) is a
waste of time. Even if it was detached only in software with drvctl,
reattaching it will reset the device anyway.
No need to take the lock again -- which might not be necessary
because the callout and task have completed, but let's obviate the
need to think about that.
usbnet_stop waits for the task to complete before resetting the
hardware, and usbnet_detach waits for usbnet_stop to complete before
destroying anything, so there's no need for any of this.
It's harmless for us to schedule the tick task even if unp_dying or
unp_stopping is set by now, because usbnet_stop will just wait for it
to finish anyway, and the callout can't be scheduled again until the
interface is done stopping and is brought back up again.
No need for unp == NULL test -- un->un_pri is initialized well before
this callout can be scheduled, and is nulled out only at the end of
usbnet_detach, at which point we have already halted this callout.
We always hold IFNET_LOCK for ioctls that end up here -- the ones
that don't hold it are only SIOCADDMULTI/SIOCDELMULTI, which don't
end up here. However, urndis(4) throws a spanner in the works by
doing weird device initialization.
All outstanding software activity under usbnet's control -- which is
all that participates in the refcnting -- should be quiesced by
stopping and detaching everything.
Make this happen uniformly across all usbnet drivers, not on a
per-driver basis.
This ensures new activity on the interface can't happen by the time
we have stopped existing activity and waited for it to complete.
This ensures, if the device is being initialized or stopped,
usbnet_media_upd will not run until it's done, so the reset sequence
has exclusive access to the device registers used by mii.
Make sure all software activity is quiescent (callouts and tasks,
including ifmedia and mii callbacks -- anything that might trigger
register access) before asking the driver to stop the hardware. This
way, the driver uno_stop routine is guaranteed exclusive access to
the registers.
This will also enable us to simplify the callouts and tasks so they
don't have to check the software state -- to be done in a separate
commit.
This can only run after we start the pipes in usbnet_init_rx_tx, and
before we abort the pipes in usbnet_stop, during which time if_flags
& IFF_RUNNING is stably set.
Exception: urndis(4) abuses this API to start this logic before the
ifp is actually initialized. So for the sake of urndis(4), until
sense can be beaten into it, allow the !unp_ifp_attached case to run
without IFNET_LOCK.
This is not stable without IFNET_LOCK. Extraneous calls to
usbnet_stop arising from this race might be harmless, but let's
render it unnecessary to even think about that.
usbnet_detach (or its caller) stops all users before it returns.
If un->un_pri is null at this point, there's a bug -- something
didn't wait for everything to finish before calling usbnet_detach.
The unit-tests for meta mode do not depend on filemon.
Adding nofilemon to .MAKE.MODE allows these to pass on
a system that would use filemon_dev but does not have
the module loaded.