Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/usb usbnet(9): Split unp_stopping into stopped/txsto...



details:   https://anonhg.NetBSD.org/src/rev/8d2ed65ebe0f
branches:  trunk
changeset: 369499:8d2ed65ebe0f
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Sat Aug 20 14:06:20 2022 +0000

description:
usbnet(9): Split unp_stopping into stopped/txstopped/rxstopped.

In practical terms this could be done with one variable and an atomic
store, but serializing all access with a lock makes reasoning easier,
and the locks have to be taken by the logic that queries the
variables anyway, and the variables are set only under heavy-weight
configuration changes anyway.

What this accomplishes is disentangling lock order between rxlock and
txlock: they are never taken at the same time, so no order is needed.

I renamed unp_stopping to unp_stopped for a compiler-assisted audit
to make sure I reviewed every case of it.

diffstat:

 sys/dev/usb/usbnet.c |  61 +++++++++++++++++++++++++++++++++++----------------
 1 files changed, 42 insertions(+), 19 deletions(-)

diffs (182 lines):

diff -r d676e776c957 -r 8d2ed65ebe0f sys/dev/usb/usbnet.c
--- a/sys/dev/usb/usbnet.c      Sat Aug 20 14:06:09 2022 +0000
+++ b/sys/dev/usb/usbnet.c      Sat Aug 20 14:06:20 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: usbnet.c,v 1.101 2022/08/20 14:06:09 riastradh Exp $   */
+/*     $NetBSD: usbnet.c,v 1.102 2022/08/20 14:06:20 riastradh Exp $   */
 
 /*
  * Copyright (c) 2019 Matthew R. Green
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usbnet.c,v 1.101 2022/08/20 14:06:09 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usbnet.c,v 1.102 2022/08/20 14:06:20 riastradh Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -58,7 +58,8 @@
         * - unp_txlock protects the tx path and its data
         *
         * the lock ordering is:
-        *      ifnet lock -> unp_core_lock -> unp_rxlock -> unp_txlock
+        *      ifnet lock -> unp_core_lock -> unp_rxlock
+        *                                  -> unp_txlock
         *                                  -> unp_mcastlock
         * - ifnet lock is not needed for unp_core_lock, but if ifnet lock is
         *   involved, it must be taken first
@@ -79,7 +80,9 @@
        struct usbd_pipe        *unp_ep[USBNET_ENDPT_MAX];
 
        volatile bool           unp_dying;
-       bool                    unp_stopping;
+       bool                    unp_stopped;
+       bool                    unp_rxstopped;
+       bool                    unp_txstopped;
        bool                    unp_attached;
        bool                    unp_ifp_attached;
        bool                    unp_link;
@@ -360,7 +363,7 @@
 
        mutex_enter(&unp->unp_rxlock);
 
-       if (usbnet_isdying(un) || unp->unp_stopping ||
+       if (usbnet_isdying(un) || unp->unp_rxstopped ||
            status == USBD_INVAL || status == USBD_NOT_STARTED ||
            status == USBD_CANCELLED)
                goto out;
@@ -387,7 +390,7 @@
        usbnet_isowned_rx(un);
 
 done:
-       if (usbnet_isdying(un) || unp->unp_stopping)
+       if (usbnet_isdying(un) || unp->unp_rxstopped)
                goto out;
 
        mutex_exit(&unp->unp_rxlock);
@@ -416,7 +419,7 @@
            unp->unp_number, status, (uintptr_t)xfer, 0);
 
        mutex_enter(&unp->unp_txlock);
-       if (unp->unp_stopping || usbnet_isdying(un)) {
+       if (unp->unp_txstopped || usbnet_isdying(un)) {
                mutex_exit(&unp->unp_txlock);
                return;
        }
@@ -588,11 +591,11 @@
        struct usbnet_private * const unp = un->un_pri;
 
        USBNETHIST_FUNC();
-       USBNETHIST_CALLARGS("%jd: stopping %jd",
-           unp->unp_number, unp->unp_stopping, 0, 0);
+       USBNETHIST_CALLARGS("%jd: txstopped %jd",
+           unp->unp_number, unp->unp_txstopped, 0, 0);
 
        mutex_enter(&unp->unp_txlock);
-       if (!unp->unp_stopping)
+       if (!unp->unp_txstopped)
                usbnet_start_locked(ifp);
        mutex_exit(&unp->unp_txlock);
 }
@@ -678,8 +681,8 @@
        struct usbnet_private * const unp = un->un_pri;
 
        mutex_enter(&unp->unp_rxlock);
-       mutex_enter(&unp->unp_txlock);
-       unp->unp_stopping = false;
+       KASSERT(unp->unp_rxstopped);
+       unp->unp_rxstopped = false;
 
        for (size_t i = 0; i < un->un_rx_list_cnt; i++) {
                struct usbnet_chain *c = &cd->uncd_rx_chain[i];
@@ -689,7 +692,6 @@
                usbd_transfer(c->unc_xfer);
        }
 
-       mutex_exit(&unp->unp_txlock);
        mutex_exit(&unp->unp_rxlock);
 }
 
@@ -874,9 +876,17 @@
                mutex_exit(&unp->unp_mcastlock);
        }
 
+       /* Allow transmit.  */
+       mutex_enter(&unp->unp_txlock);
+       KASSERT(unp->unp_txstopped);
+       unp->unp_txstopped = false;
+       mutex_exit(&unp->unp_txlock);
+
        /* Start up the receive pipe(s). */
        usbnet_rx_start_pipes(un);
 
+       /* Kick off the watchdog/stats/mii tick.  */
+       unp->unp_stopped = false;
        callout_schedule(&unp->unp_stat_ch, hz);
 
 out:
@@ -1094,17 +1104,21 @@
         * Prevent new activity (rescheduling ticks, xfers, &c.) and
         * clear the watchdog timer.
         */
+       unp->unp_stopped = true;
+
        mutex_enter(&unp->unp_rxlock);
+       unp->unp_rxstopped = true;
+       mutex_exit(&unp->unp_rxlock);
+
        mutex_enter(&unp->unp_txlock);
-       unp->unp_stopping = true;
+       unp->unp_txstopped = true;
        unp->unp_timer = 0;
        mutex_exit(&unp->unp_txlock);
-       mutex_exit(&unp->unp_rxlock);
 
        /*
         * Stop the timer first, then the task -- if the timer was
         * already firing, we stop the task or wait for it complete
-        * only after if last fired.  Setting unp_stopping prevents the
+        * only after if last fired.  Setting unp_stopped prevents the
         * timer task from being scheduled again.
         */
        callout_halt(&unp->unp_stat_ch, &unp->unp_core_lock);
@@ -1233,7 +1247,7 @@
        uno_tick(un);
 
        mutex_enter(&unp->unp_core_lock);
-       if (!unp->unp_stopping && !usbnet_isdying(un))
+       if (!unp->unp_stopped && !usbnet_isdying(un))
                callout_schedule(&unp->unp_stat_ch, hz);
        mutex_exit(&unp->unp_core_lock);
 }
@@ -1402,6 +1416,9 @@
 
        unp->unp_number = atomic_inc_uint_nv(&usbnet_number);
 
+       unp->unp_stopped = true;
+       unp->unp_rxstopped = true;
+       unp->unp_txstopped = true;
        unp->unp_attached = true;
 }
 
@@ -1591,11 +1608,17 @@
 
                atomic_store_relaxed(&unp->unp_dying, true);
 
+               mutex_enter(&unp->unp_core_lock);
+               unp->unp_stopped = true;
+               mutex_exit(&unp->unp_core_lock);
+
                mutex_enter(&unp->unp_rxlock);
+               unp->unp_rxstopped = true;
+               mutex_exit(&unp->unp_rxlock);
+
                mutex_enter(&unp->unp_txlock);
-               unp->unp_stopping = true;
+               unp->unp_txstopped = true;
                mutex_exit(&unp->unp_txlock);
-               mutex_exit(&unp->unp_rxlock);
 
                return 0;
        default:



Home | Main Index | Thread Index | Old Index