Thu Mar 3 05:50:47 2022 UTC ()
usbnet: Omit needless locking around usbnet_isdying.

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.


(riastradh)
diff -r1.73 -r1.74 src/sys/dev/usb/usbnet.c

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

--- src/sys/dev/usb/usbnet.c 2022/03/03 05:50:39 1.73
+++ src/sys/dev/usb/usbnet.c 2022/03/03 05:50:47 1.74
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: usbnet.c,v 1.73 2022/03/03 05:50:39 riastradh Exp $ */ 1/* $NetBSD: usbnet.c,v 1.74 2022/03/03 05:50:47 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.73 2022/03/03 05:50:39 riastradh Exp $"); 34__KERNEL_RCSID(0, "$NetBSD: usbnet.c,v 1.74 2022/03/03 05:50:47 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;
@@ -1065,46 +1065,42 @@ usbnet_if_ioctl(struct ifnet *ifp, u_lon @@ -1065,46 +1065,42 @@ usbnet_if_ioctl(struct ifnet *ifp, u_lon
1065 default: 1065 default:
1066 error = uno_ioctl(un, ifp, cmd, data); 1066 error = uno_ioctl(un, ifp, cmd, data);
1067 } 1067 }
1068 } 1068 }
1069 1069
1070 return error; 1070 return error;
1071} 1071}
1072 1072
1073static void 1073static void
1074usbnet_mcast_task(void *arg) 1074usbnet_mcast_task(void *arg)
1075{ 1075{
1076 USBNETHIST_FUNC(); 1076 USBNETHIST_FUNC();
1077 struct usbnet * const un = arg; 1077 struct usbnet * const un = arg;
1078 struct usbnet_private * const unp = un->un_pri; 
1079 struct ifnet * const ifp = usbnet_ifp(un); 1078 struct ifnet * const ifp = usbnet_ifp(un);
1080 bool dying; 
1081 struct ifreq ifr; 1079 struct ifreq ifr;
1082 1080
1083 USBNETHIST_CALLARGSN(10, "%jd: enter", unp->unp_number, 0, 0, 0); 1081 USBNETHIST_CALLARGSN(10, "%jd: enter",
 1082 un->un_pri->unp_number, 0, 0, 0);
1084 1083
1085 /* 1084 /*
1086 * If we're detaching, we must check usbnet_isdying _before_ 1085 * If we're detaching, we must check usbnet_isdying _before_
1087 * touching IFNET_LOCK -- the ifnet may have been detached by 1086 * touching IFNET_LOCK -- the ifnet may have been detached by
1088 * the time this task runs. This is racy -- unp_dying may be 1087 * the time this task runs. This is racy -- unp_dying may be
1089 * set immediately after we test it -- but nevertheless safe, 1088 * set immediately after we test it -- but nevertheless safe,
1090 * because usbnet_detach waits for the task to complete before 1089 * because usbnet_detach waits for the task to complete before
1091 * issuing if_detach, and necessary, so that we don't touch 1090 * issuing if_detach, and necessary, so that we don't touch
1092 * IFNET_LOCK after if_detach. See usbnet_detach for details. 1091 * IFNET_LOCK after if_detach. See usbnet_detach for details.
1093 */ 1092 */
1094 mutex_enter(&unp->unp_core_lock); 1093 if (usbnet_isdying(un))
1095 dying = usbnet_isdying(un); 
1096 mutex_exit(&unp->unp_core_lock); 
1097 if (dying) 
1098 return; 1094 return;
1099 1095
1100 /* 1096 /*
1101 * Pass a bogus ifr with SIOCDELMULTI -- the goal is to just 1097 * Pass a bogus ifr with SIOCDELMULTI -- the goal is to just
1102 * notify the driver to reprogram any hardware multicast 1098 * notify the driver to reprogram any hardware multicast
1103 * filter, according to what's already stored in the ethercom. 1099 * filter, according to what's already stored in the ethercom.
1104 * None of the drivers actually examine this argument, so it 1100 * None of the drivers actually examine this argument, so it
1105 * doesn't change the ABI as far as they can tell. 1101 * doesn't change the ABI as far as they can tell.
1106 */ 1102 */
1107 IFNET_LOCK(ifp); 1103 IFNET_LOCK(ifp);
1108 if (ifp->if_flags & IFF_RUNNING) { 1104 if (ifp->if_flags & IFF_RUNNING) {
1109 memset(&ifr, 0, sizeof(ifr)); 1105 memset(&ifr, 0, sizeof(ifr));
1110 (void)uno_ioctl(un, ifp, SIOCDELMULTI, &ifr); 1106 (void)uno_ioctl(un, ifp, SIOCDELMULTI, &ifr);
@@ -1278,39 +1274,35 @@ usbnet_tick_task(void *arg) @@ -1278,39 +1274,35 @@ usbnet_tick_task(void *arg)
1278 uno_tick(un); 1274 uno_tick(un);
1279 1275
1280 mutex_enter(&unp->unp_core_lock); 1276 mutex_enter(&unp->unp_core_lock);
1281 if (!unp->unp_stopping && !usbnet_isdying(un)) 1277 if (!unp->unp_stopping && !usbnet_isdying(un))
1282 callout_schedule(&unp->unp_stat_ch, hz); 1278 callout_schedule(&unp->unp_stat_ch, hz);
1283 mutex_exit(&unp->unp_core_lock); 1279 mutex_exit(&unp->unp_core_lock);
1284} 1280}
1285 1281
1286static int 1282static int
1287usbnet_if_init(struct ifnet *ifp) 1283usbnet_if_init(struct ifnet *ifp)
1288{ 1284{
1289 USBNETHIST_FUNC(); USBNETHIST_CALLED(); 1285 USBNETHIST_FUNC(); USBNETHIST_CALLED();
1290 struct usbnet * const un = ifp->if_softc; 1286 struct usbnet * const un = ifp->if_softc;
1291 bool dying; 
1292 int error; 1287 int error;
1293 1288
1294 KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); 1289 KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
1295 1290
1296 /* 1291 /*
1297 * Prevent anyone from bringing the interface back up once 1292 * Prevent anyone from bringing the interface back up once
1298 * we're detaching. 1293 * we're detaching.
1299 */ 1294 */
1300 mutex_enter(&un->un_pri->unp_core_lock); 1295 if (usbnet_isdying(un))
1301 dying = usbnet_isdying(un); 
1302 mutex_exit(&un->un_pri->unp_core_lock); 
1303 if (dying) 
1304 return EIO; 1296 return EIO;
1305 1297
1306 mutex_enter(&un->un_pri->unp_core_lock); 1298 mutex_enter(&un->un_pri->unp_core_lock);
1307 error = uno_init(un, ifp); 1299 error = uno_init(un, ifp);
1308 mutex_exit(&un->un_pri->unp_core_lock); 1300 mutex_exit(&un->un_pri->unp_core_lock);
1309 1301
1310 return error; 1302 return error;
1311} 1303}
1312 1304
1313 1305
1314/* Various accessors. */ 1306/* Various accessors. */
1315 1307
1316void 1308void
@@ -1581,29 +1573,27 @@ usbnet_detach(device_t self, int flags) @@ -1581,29 +1573,27 @@ usbnet_detach(device_t self, int flags)
1581 struct usbnet_private * const unp = un->un_pri; 1573 struct usbnet_private * const unp = un->un_pri;
1582 1574
1583 /* Detached before attached finished, so just bail out. */ 1575 /* Detached before attached finished, so just bail out. */
1584 if (unp == NULL || !unp->unp_attached) 1576 if (unp == NULL || !unp->unp_attached)
1585 return 0; 1577 return 0;
1586 1578
1587 struct ifnet * const ifp = usbnet_ifp(un); 1579 struct ifnet * const ifp = usbnet_ifp(un);
1588 struct mii_data * const mii = usbnet_mii(un); 1580 struct mii_data * const mii = usbnet_mii(un);
1589 1581
1590 /* 1582 /*
1591 * Prevent new activity. After we stop the interface, it 1583 * Prevent new activity. After we stop the interface, it
1592 * cannot be brought back up. 1584 * cannot be brought back up.
1593 */ 1585 */
1594 mutex_enter(&unp->unp_core_lock); 
1595 atomic_store_relaxed(&unp->unp_dying, true); 1586 atomic_store_relaxed(&unp->unp_dying, true);
1596 mutex_exit(&unp->unp_core_lock); 
1597 1587
1598 /* 1588 /*
1599 * If we're still running on the network, stop and wait for all 1589 * If we're still running on the network, stop and wait for all
1600 * asynchronous activity to finish. 1590 * asynchronous activity to finish.
1601 * 1591 *
1602 * If usbnet_attach_ifp never ran, IFNET_LOCK won't work, but 1592 * If usbnet_attach_ifp never ran, IFNET_LOCK won't work, but
1603 * no activity is possible, so just skip this part. 1593 * no activity is possible, so just skip this part.
1604 */ 1594 */
1605 if (unp->unp_ifp_attached) { 1595 if (unp->unp_ifp_attached) {
1606 IFNET_LOCK(ifp); 1596 IFNET_LOCK(ifp);
1607 if (ifp->if_flags & IFF_RUNNING) { 1597 if (ifp->if_flags & IFF_RUNNING) {
1608 usbnet_if_stop(ifp, 1); 1598 usbnet_if_stop(ifp, 1);
1609 } 1599 }
@@ -1710,29 +1700,27 @@ usbnet_detach(device_t self, int flags) @@ -1710,29 +1700,27 @@ usbnet_detach(device_t self, int flags)
1710 1700
1711int 1701int
1712usbnet_activate(device_t self, devact_t act) 1702usbnet_activate(device_t self, devact_t act)
1713{ 1703{
1714 USBNETHIST_FUNC(); USBNETHIST_CALLED(); 1704 USBNETHIST_FUNC(); USBNETHIST_CALLED();
1715 struct usbnet * const un = device_private(self); 1705 struct usbnet * const un = device_private(self);
1716 struct usbnet_private * const unp = un->un_pri; 1706 struct usbnet_private * const unp = un->un_pri;
1717 struct ifnet * const ifp = usbnet_ifp(un); 1707 struct ifnet * const ifp = usbnet_ifp(un);
1718 1708
1719 switch (act) { 1709 switch (act) {
1720 case DVACT_DEACTIVATE: 1710 case DVACT_DEACTIVATE:
1721 if_deactivate(ifp); 1711 if_deactivate(ifp);
1722 1712
1723 mutex_enter(&unp->unp_core_lock); 
1724 atomic_store_relaxed(&unp->unp_dying, true); 1713 atomic_store_relaxed(&unp->unp_dying, true);
1725 mutex_exit(&unp->unp_core_lock); 
1726 1714
1727 mutex_enter(&unp->unp_rxlock); 1715 mutex_enter(&unp->unp_rxlock);
1728 mutex_enter(&unp->unp_txlock); 1716 mutex_enter(&unp->unp_txlock);
1729 unp->unp_stopping = true; 1717 unp->unp_stopping = true;
1730 mutex_exit(&unp->unp_txlock); 1718 mutex_exit(&unp->unp_txlock);
1731 mutex_exit(&unp->unp_rxlock); 1719 mutex_exit(&unp->unp_rxlock);
1732 1720
1733 return 0; 1721 return 0;
1734 default: 1722 default:
1735 return EOPNOTSUPP; 1723 return EOPNOTSUPP;
1736 } 1724 }
1737} 1725}
1738 1726