Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 4 Jan 2019 21:09:38 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r342778 - head/sys/dev/usb
Message-ID:  <201901042109.x04L9ced054983@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Fri Jan  4 21:09:38 2019
New Revision: 342778
URL: https://svnweb.freebsd.org/changeset/base/342778

Log:
  Reduce timeout for reading the USB HUB port status to 1000ms and try to filter
  out dead USB HUB devices by implementing an error counter, so that the USB
  enumeration thread does not spend all its time reading from non-responding
  devices, blocking user-space access in the end.
  
  Tested by:	Matthias Apitz <guru@unixarea.de>
  MFC after:	1 week
  Sponsored by:	Mellanox Technologies

Modified:
  head/sys/dev/usb/usb_hub.c
  head/sys/dev/usb/usb_request.c

Modified: head/sys/dev/usb/usb_hub.c
==============================================================================
--- head/sys/dev/usb/usb_hub.c	Fri Jan  4 21:05:40 2019	(r342777)
+++ head/sys/dev/usb/usb_hub.c	Fri Jan  4 21:09:38 2019	(r342778)
@@ -129,6 +129,8 @@ struct uhub_softc {
 	int sc_disable_enumeration;
 	int sc_disable_port_power;
 #endif
+	uint8_t sc_usb_port_errors;	/* error counter */
+#define	UHUB_USB_PORT_ERRORS_MAX 4
 	uint8_t	sc_flags;
 #define	UHUB_FLAG_DID_EXPLORE 0x01
 };
@@ -587,13 +589,25 @@ uhub_read_port_status(struct uhub_softc *sc, uint8_t p
 	struct usb_port_status ps;
 	usb_error_t err;
 
+	if (sc->sc_usb_port_errors >= UHUB_USB_PORT_ERRORS_MAX) {
+		DPRINTFN(4, "port %d, HUB looks dead, too many errors\n", portno);
+		sc->sc_st.port_status = 0;
+		sc->sc_st.port_change = 0;
+		return (USB_ERR_TIMEOUT);
+	}
+
 	err = usbd_req_get_port_status(
 	    sc->sc_udev, NULL, &ps, portno);
 
-	/* update status regardless of error */
-
-	sc->sc_st.port_status = UGETW(ps.wPortStatus);
-	sc->sc_st.port_change = UGETW(ps.wPortChange);
+	if (err == 0) {
+		sc->sc_st.port_status = UGETW(ps.wPortStatus);
+		sc->sc_st.port_change = UGETW(ps.wPortChange);
+		sc->sc_usb_port_errors = 0;
+	} else {
+		sc->sc_st.port_status = 0;
+		sc->sc_st.port_change = 0;
+		sc->sc_usb_port_errors++;
+	}
 
 	/* debugging print */
 

Modified: head/sys/dev/usb/usb_request.c
==============================================================================
--- head/sys/dev/usb/usb_request.c	Fri Jan  4 21:05:40 2019	(r342777)
+++ head/sys/dev/usb/usb_request.c	Fri Jan  4 21:09:38 2019	(r342778)
@@ -1601,8 +1601,9 @@ usbd_req_get_port_status(struct usb_device *udev, stru
 	USETW(req.wValue, 0);
 	req.wIndex[0] = port;
 	req.wIndex[1] = 0;
-	USETW(req.wLength, sizeof *ps);
-	return (usbd_do_request(udev, mtx, &req, ps));
+	USETW(req.wLength, sizeof(*ps));
+
+	return (usbd_do_request_flags(udev, mtx, &req, ps, 0, NULL, 1000));
 }
 
 /*------------------------------------------------------------------------*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201901042109.x04L9ced054983>