Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/usb make cdce(4) and ure(4) usb and mpsafe:
details: https://anonhg.NetBSD.org/src/rev/73da8cca0a69
branches: trunk
changeset: 452232:73da8cca0a69
user: mrg <mrg%NetBSD.org@localhost>
date: Sun Jun 23 02:14:14 2019 +0000
description:
make cdce(4) and ure(4) usb and mpsafe:
- introduce locking ala smsc(4)/axen(4) style
- convert to mpsafe interfaces
- add tick task to cdce(4) to deal with missing watchdog, and
actually make the watchdog do something
- convert DELAY() to usbd_delay_ms() in cdce(4) and don't increase
the time in a potentially unbounded way
- remove spl calls
tested with network cable and usb adapter pullouts, reboots and
many many GBs of data transferred in either direction under load.
diffstat:
sys/dev/usb/if_cdce.c | 266 +++++++++++++++++++++++++++++++++------------
sys/dev/usb/if_ure.c | 275 +++++++++++++++++++++++++++++++++--------------
sys/dev/usb/if_urevar.h | 11 +-
3 files changed, 395 insertions(+), 157 deletions(-)
diffs (truncated from 1180 to 300 lines):
diff -r 52d9508bcb9b -r 73da8cca0a69 sys/dev/usb/if_cdce.c
--- a/sys/dev/usb/if_cdce.c Sun Jun 23 01:46:56 2019 +0000
+++ b/sys/dev/usb/if_cdce.c Sun Jun 23 02:14:14 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: if_cdce.c,v 1.49 2019/06/22 04:45:04 mrg Exp $ */
+/* $NetBSD: if_cdce.c,v 1.50 2019/06/23 02:14:14 mrg Exp $ */
/*
* Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wpaul%windriver.com@localhost>
@@ -41,7 +41,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_cdce.c,v 1.49 2019/06/22 04:45:04 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_cdce.c,v 1.50 2019/06/23 02:14:14 mrg Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -71,6 +71,7 @@
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
#include <dev/usb/usbdi_util.h>
#include <dev/usb/usbdevs.h>
#include <dev/usb/usbcdc.h>
@@ -116,14 +117,23 @@
struct usbd_pipe * cdce_bulkin_pipe;
int cdce_bulkout_no;
struct usbd_pipe * cdce_bulkout_pipe;
- char cdce_dying;
int cdce_unit;
struct cdce_cdata cdce_cdata;
int cdce_rxeof_errors;
uint16_t cdce_flags;
- char cdce_attached;
+ uint16_t cdce_timer;
+
+ bool cdce_attached;
+ bool cdce_dying;
+ bool cdce_stopping;
- kmutex_t cdce_start_lock;
+ struct usb_task cdce_tick_task;
+ struct callout cdce_stat_ch;
+
+ kmutex_t cdce_lock;
+ kmutex_t cdce_mii_lock;
+ kmutex_t cdce_rxlock;
+ kmutex_t cdce_txlock;
};
static int cdce_tx_list_init(struct cdce_softc *);
@@ -138,6 +148,8 @@
static void cdce_init(void *);
static void cdce_watchdog(struct ifnet *);
static void cdce_stop(struct cdce_softc *);
+static void cdce_tick(void *);
+static void cdce_tick_task(void *);
static const struct cdce_type cdce_devs[] = {
{{ USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632 }, CDCE_NO_UNION },
@@ -184,7 +196,6 @@
struct cdce_softc *sc = device_private(self);
struct usbif_attach_arg *uiaa = aux;
char *devinfop;
- int s;
struct ifnet *ifp;
struct usbd_device *dev = uiaa->uiaa_device;
const struct cdce_type *t;
@@ -319,16 +330,20 @@
eaddr[5] = (uint8_t)(device_unit(sc->cdce_dev));
}
- s = splnet();
+ mutex_init(&sc->cdce_txlock, MUTEX_DEFAULT, IPL_SOFTUSB);
+ mutex_init(&sc->cdce_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB);
+ mutex_init(&sc->cdce_lock, MUTEX_DEFAULT, IPL_NONE);
+
+ usb_init_task(&sc->cdce_tick_task, cdce_tick_task, sc, USB_TASKQ_MPSAFE);
aprint_normal_dev(self, "address %s\n", ether_sprintf(eaddr));
ifp = GET_IFP(sc);
ifp->if_softc = sc;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_extflags = IFEF_MPSAFE;
ifp->if_ioctl = cdce_ioctl;
ifp->if_start = cdce_start;
- ifp->if_watchdog = cdce_watchdog;
strlcpy(ifp->if_xname, device_xname(sc->cdce_dev), IFNAMSIZ);
IFQ_SET_READY(&ifp->if_snd);
@@ -336,8 +351,10 @@
if_attach(ifp);
ether_ifattach(ifp, eaddr);
- sc->cdce_attached = 1;
- splx(s);
+ callout_init(&sc->cdce_stat_ch, CALLOUT_MPSAFE);
+ callout_setfunc(&sc->cdce_stat_ch, cdce_tick, sc);
+
+ sc->cdce_attached = true;
usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->cdce_udev,
sc->cdce_dev);
@@ -353,37 +370,46 @@
{
struct cdce_softc *sc = device_private(self);
struct ifnet *ifp = GET_IFP(sc);
- int s;
+
+ mutex_enter(&sc->cdce_lock);
+ sc->cdce_dying = true;
+ mutex_exit(&sc->cdce_lock);
+
+ if (!sc->cdce_attached)
+ return 0;
pmf_device_deregister(self);
- s = splusb();
-
- if (!sc->cdce_attached) {
- splx(s);
- return 0;
- }
+ callout_halt(&sc->cdce_stat_ch, NULL);
+ usb_rem_task_wait(sc->cdce_udev, &sc->cdce_tick_task,
+ USB_TASKQ_DRIVER, NULL);
if (ifp->if_flags & IFF_RUNNING)
cdce_stop(sc);
+ callout_destroy(&sc->cdce_stat_ch);
ether_ifdetach(ifp);
-
if_detach(ifp);
+ sc->cdce_attached = false;
- sc->cdce_attached = 0;
- splx(s);
+ usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->cdce_udev,sc->cdce_dev);
+
+ mutex_destroy(&sc->cdce_lock);
+ mutex_destroy(&sc->cdce_rxlock);
+ mutex_destroy(&sc->cdce_txlock);
return 0;
}
static void
-cdce_start(struct ifnet *ifp)
+cdce_start_locked(struct ifnet *ifp)
{
struct cdce_softc *sc = ifp->if_softc;
struct mbuf *m_head = NULL;
- if (sc->cdce_dying || (ifp->if_flags & IFF_OACTIVE))
+ KASSERT(mutex_owned(&sc->cdce_txlock));
+ if (sc->cdce_dying || sc->cdce_stopping ||
+ (ifp->if_flags & IFF_OACTIVE))
return;
IFQ_POLL(&ifp->if_snd, m_head);
@@ -401,9 +427,22 @@
ifp->if_flags |= IFF_OACTIVE;
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
ifp->if_timer = 6;
}
+static void
+cdce_start(struct ifnet *ifp)
+{
+ struct cdce_softc * const sc = ifp->if_softc;
+
+ mutex_enter(&sc->cdce_txlock);
+ cdce_start_locked(ifp);
+ mutex_exit(&sc->cdce_txlock);
+}
+
static int
cdce_encap(struct cdce_softc *sc, struct mbuf *m, int idx)
{
@@ -411,6 +450,8 @@
usbd_status err;
int extra = 0;
+ KASSERT(mutex_owned(&sc->cdce_txlock));
+
c = &sc->cdce_cdata.cdce_tx_chain[idx];
m_copydata(m, 0, m->m_pkthdr.len, c->cdce_buf);
@@ -444,7 +485,16 @@
struct ifnet *ifp = GET_IFP(sc);
int i;
+ mutex_enter(&sc->cdce_rxlock);
+ mutex_enter(&sc->cdce_txlock);
+ sc->cdce_stopping = true;
+ mutex_exit(&sc->cdce_txlock);
+ mutex_exit(&sc->cdce_rxlock);
+
ifp->if_timer = 0;
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+
+ callout_stop(&sc->cdce_stat_ch);
if (sc->cdce_bulkin_pipe != NULL) {
err = usbd_abort_pipe(sc->cdce_bulkin_pipe);
@@ -499,8 +549,7 @@
device_xname(sc->cdce_dev), usbd_errstr(err));
sc->cdce_bulkout_pipe = NULL;
}
-
- ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ mutex_exit(&sc->cdce_txlock);
}
static int
@@ -509,13 +558,11 @@
struct cdce_softc *sc = ifp->if_softc;
struct ifaddr *ifa = (struct ifaddr *)data;
struct ifreq *ifr = (struct ifreq *)data;
- int s, error = 0;
+ int error = 0;
if (sc->cdce_dying)
return EIO;
- s = splnet();
-
switch(command) {
case SIOCINITIFADDR:
ifp->if_flags |= IFF_UP;
@@ -557,8 +604,6 @@
break;
}
- splx(s);
-
if (error == ENETRESET)
error = 0;
@@ -569,12 +614,23 @@
cdce_watchdog(struct ifnet *ifp)
{
struct cdce_softc *sc = ifp->if_softc;
+ struct cdce_chain *c;
+ usbd_status stat;
+
+ KASSERT(mutex_owned(&sc->cdce_lock));
if (sc->cdce_dying)
return;
ifp->if_oerrors++;
- printf("%s: watchdog timeout\n", device_xname(sc->cdce_dev));
+ aprint_error_dev(sc->cdce_dev, "watchdog timeout\n");
+
+ c = &sc->cdce_cdata.cdce_rx_chain[0];
+ usbd_get_xfer_status(c->cdce_xfer, NULL, NULL, NULL, &stat);
+ cdce_txeof(c->cdce_xfer, c, stat);
+
+ if (!IFQ_IS_EMPTY(&ifp->if_snd))
+ cdce_start_locked(ifp);
}
static void
@@ -584,12 +640,11 @@
struct ifnet *ifp = GET_IFP(sc);
struct cdce_chain *c;
usbd_status err;
- int s, i;
+ int i;
+ mutex_enter(&sc->cdce_lock);
if (ifp->if_flags & IFF_RUNNING)
- return;
-
- s = splnet();
+ goto out;
/* Maybe set multicast / broadcast here??? */
@@ -598,8 +653,7 @@
if (err) {
printf("%s: open rx pipe failed: %s\n", device_xname(sc->cdce_dev),
usbd_errstr(err));
- splx(s);
- return;
+ goto out;
}
err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkout_no,
@@ -607,20 +661,17 @@
Home |
Main Index |
Thread Index |
Old Index