Thu Mar 3 05:48:23 2022 UTC ()
usbnet: Fix ordering of actions in usbnet_stop.

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.


(riastradh)
diff -r1.55 -r1.56 src/sys/dev/usb/usbnet.c

cvs diff -r1.55 -r1.56 src/sys/dev/usb/usbnet.c (expand / switch to unified diff)

--- src/sys/dev/usb/usbnet.c 2022/03/03 05:48:14 1.55
+++ src/sys/dev/usb/usbnet.c 2022/03/03 05:48:22 1.56
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: usbnet.c,v 1.55 2022/03/03 05:48:14 riastradh Exp $ */ 1/* $NetBSD: usbnet.c,v 1.56 2022/03/03 05:48:22 riastradh Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2019 Matthew R. Green 4 * Copyright (c) 2019 Matthew R. Green
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -21,27 +21,27 @@ @@ -21,27 +21,27 @@
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE. 26 * SUCH DAMAGE.
27 */ 27 */
28 28
29/* 29/*
30 * Common code shared between USB network drivers. 30 * Common code shared between USB network drivers.
31 */ 31 */
32 32
33#include <sys/cdefs.h> 33#include <sys/cdefs.h>
34__KERNEL_RCSID(0, "$NetBSD: usbnet.c,v 1.55 2022/03/03 05:48:14 riastradh Exp $"); 34__KERNEL_RCSID(0, "$NetBSD: usbnet.c,v 1.56 2022/03/03 05:48:22 riastradh Exp $");
35 35
36#include <sys/param.h> 36#include <sys/param.h>
37#include <sys/kernel.h> 37#include <sys/kernel.h>
38#include <sys/kmem.h> 38#include <sys/kmem.h>
39#include <sys/module.h> 39#include <sys/module.h>
40#include <sys/atomic.h> 40#include <sys/atomic.h>
41 41
42#include <dev/usb/usbnet.h> 42#include <dev/usb/usbnet.h>
43#include <dev/usb/usbhist.h> 43#include <dev/usb/usbhist.h>
44 44
45struct usbnet_cdata { 45struct usbnet_cdata {
46 struct usbnet_chain *uncd_tx_chain; 46 struct usbnet_chain *uncd_tx_chain;
47 struct usbnet_chain *uncd_rx_chain; 47 struct usbnet_chain *uncd_rx_chain;
@@ -1122,36 +1122,49 @@ usbnet_stop(struct usbnet *un, struct if @@ -1122,36 +1122,49 @@ usbnet_stop(struct usbnet *un, struct if
1122 1122
1123 KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), 1123 KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp),
1124 "%s", ifp->if_xname); 1124 "%s", ifp->if_xname);
1125 usbnet_isowned_core(un); 1125 usbnet_isowned_core(un);
1126 1126
1127 usbnet_busy(un); 1127 usbnet_busy(un);
1128 1128
1129 mutex_enter(&unp->unp_rxlock); 1129 mutex_enter(&unp->unp_rxlock);
1130 mutex_enter(&unp->unp_txlock); 1130 mutex_enter(&unp->unp_txlock);
1131 unp->unp_stopping = true; 1131 unp->unp_stopping = true;
1132 mutex_exit(&unp->unp_txlock); 1132 mutex_exit(&unp->unp_txlock);
1133 mutex_exit(&unp->unp_rxlock); 1133 mutex_exit(&unp->unp_rxlock);
1134 1134
 1135 /*
 1136 * Stop the timer first, then the task -- if the timer was
 1137 * already firing, we stop the task or wait for it complete
 1138 * only after if last fired. Setting unp_stopping prevents the
 1139 * timer task from being scheduled again.
 1140 */
 1141 callout_halt(&unp->unp_stat_ch, &unp->unp_core_lock);
 1142 usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER,
 1143 &unp->unp_core_lock);
 1144
 1145 /*
 1146 * Now that the software is quiescent, ask the driver to stop
 1147 * the hardware. The driver's uno_stop routine now has
 1148 * exclusive access to any registers that might previously have
 1149 * been used by to ifmedia, mii, or ioctl callbacks.
 1150 */
1135 uno_stop(un, ifp, disable); 1151 uno_stop(un, ifp, disable);
1136 1152
 1153 /* Clear the watchdog timer. */
1137 mutex_enter(&unp->unp_txlock); 1154 mutex_enter(&unp->unp_txlock);
1138 unp->unp_timer = 0; 1155 unp->unp_timer = 0;
1139 mutex_exit(&unp->unp_txlock); 1156 mutex_exit(&unp->unp_txlock);
1140 1157
1141 callout_halt(&unp->unp_stat_ch, &unp->unp_core_lock); 
1142 usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER, 
1143 &unp->unp_core_lock); 
1144 
1145 /* Stop transfers. */ 1158 /* Stop transfers. */
1146 usbnet_ep_stop_pipes(un); 1159 usbnet_ep_stop_pipes(un);
1147 1160
1148 /* Free RX/TX resources. */ 1161 /* Free RX/TX resources. */
1149 usbnet_rx_list_fini(un); 1162 usbnet_rx_list_fini(un);
1150 usbnet_tx_list_fini(un); 1163 usbnet_tx_list_fini(un);
1151 1164
1152 /* Close pipes. */ 1165 /* Close pipes. */
1153 usbnet_ep_close_pipes(un); 1166 usbnet_ep_close_pipes(un);
1154 1167
1155 /* Everything is quesced now. */ 1168 /* Everything is quesced now. */
1156 KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), 1169 KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp),
1157 "%s", ifp->if_xname); 1170 "%s", ifp->if_xname);