aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorHans Petter Selasky <hselasky@FreeBSD.org>2019-01-04 21:09:38 +0000
committerHans Petter Selasky <hselasky@FreeBSD.org>2019-01-04 21:09:38 +0000
commit4604b6a18dfcc5774577f173ee8c254acb5949e5 (patch)
treeedc236886c3556c00f1ff4af0753a1371611e19f /sys
parent0fadd6731f1d072f9c6891f7b4f3fed0ba3436b0 (diff)
downloadsrc-4604b6a18dfcc5774577f173ee8c254acb5949e5.tar.gz
src-4604b6a18dfcc5774577f173ee8c254acb5949e5.zip
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
Notes
Notes: svn path=/head/; revision=342778
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/usb/usb_hub.c22
-rw-r--r--sys/dev/usb/usb_request.c5
2 files changed, 21 insertions, 6 deletions
diff --git a/sys/dev/usb/usb_hub.c b/sys/dev/usb/usb_hub.c
index 59d56e656979..63c870f33b57 100644
--- a/sys/dev/usb/usb_hub.c
+++ b/sys/dev/usb/usb_hub.c
@@ -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 portno)
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 */
diff --git a/sys/dev/usb/usb_request.c b/sys/dev/usb/usb_request.c
index fa5c469406cb..73e9874cb466 100644
--- a/sys/dev/usb/usb_request.c
+++ b/sys/dev/usb/usb_request.c
@@ -1601,8 +1601,9 @@ usbd_req_get_port_status(struct usb_device *udev, struct mtx *mtx,
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));
}
/*------------------------------------------------------------------------*