Improve support for USB 3.0 HUBs. In certain states we
should do a warm reset instead of the default reset. MFC after: 5 days
This commit is contained in:
parent
e02f894bbe
commit
93ee6e858b
@ -627,14 +627,15 @@ uhub_suspend_resume_port(struct uhub_softc *sc, uint8_t portno)
|
||||
}
|
||||
} else {
|
||||
switch (UPS_PORT_LINK_STATE_GET(sc->sc_st.port_status)) {
|
||||
case UPS_PORT_LS_U0:
|
||||
case UPS_PORT_LS_U1:
|
||||
case UPS_PORT_LS_U2:
|
||||
case UPS_PORT_LS_RESUME:
|
||||
case UPS_PORT_LS_U3:
|
||||
is_suspend = 1;
|
||||
break;
|
||||
case UPS_PORT_LS_SS_INA:
|
||||
usbd_req_warm_reset_port(udev, NULL, portno);
|
||||
is_suspend = 0;
|
||||
break;
|
||||
default:
|
||||
is_suspend = 1;
|
||||
is_suspend = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -793,7 +794,8 @@ uhub_explore(struct usb_device *udev)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sc->sc_st.port_change & (UPS_C_SUSPEND | UPS_C_PORT_LINK_STATE)) {
|
||||
if (sc->sc_st.port_change & (UPS_C_SUSPEND |
|
||||
UPS_C_PORT_LINK_STATE)) {
|
||||
err = uhub_suspend_resume_port(sc, portno);
|
||||
if (err) {
|
||||
/* most likely the HUB is gone */
|
||||
|
@ -785,12 +785,17 @@ usbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
|
||||
struct usb_port_status ps;
|
||||
usb_error_t err;
|
||||
uint16_t n;
|
||||
uint16_t status;
|
||||
uint16_t change;
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
uint16_t pr_poll_delay;
|
||||
uint16_t pr_recovery_delay;
|
||||
|
||||
#endif
|
||||
|
||||
DPRINTF("\n");
|
||||
|
||||
/* clear any leftover port reset changes first */
|
||||
usbd_req_clear_port_feature(
|
||||
udev, mtx, port, UHF_C_PORT_RESET);
|
||||
@ -817,9 +822,6 @@ usbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
|
||||
#endif
|
||||
n = 0;
|
||||
while (1) {
|
||||
uint16_t status;
|
||||
uint16_t change;
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
/* wait for the device to recover from reset */
|
||||
usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay));
|
||||
@ -830,9 +832,9 @@ usbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
|
||||
n += USB_PORT_RESET_DELAY;
|
||||
#endif
|
||||
err = usbd_req_get_port_status(udev, mtx, &ps, port);
|
||||
if (err) {
|
||||
if (err)
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = UGETW(ps.wPortStatus);
|
||||
change = UGETW(ps.wPortChange);
|
||||
|
||||
@ -862,9 +864,9 @@ usbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
|
||||
/* clear port reset first */
|
||||
err = usbd_req_clear_port_feature(
|
||||
udev, mtx, port, UHF_C_PORT_RESET);
|
||||
if (err) {
|
||||
if (err)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* check for timeout */
|
||||
if (n == 0) {
|
||||
err = USB_ERR_TIMEOUT;
|
||||
@ -898,21 +900,50 @@ usbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
|
||||
* disabled.
|
||||
*------------------------------------------------------------------------*/
|
||||
usb_error_t
|
||||
usbd_req_warm_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
|
||||
usbd_req_warm_reset_port(struct usb_device *udev, struct mtx *mtx,
|
||||
uint8_t port)
|
||||
{
|
||||
struct usb_port_status ps;
|
||||
usb_error_t err;
|
||||
uint16_t n;
|
||||
uint16_t status;
|
||||
uint16_t change;
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
uint16_t pr_poll_delay;
|
||||
uint16_t pr_recovery_delay;
|
||||
|
||||
#endif
|
||||
err = usbd_req_set_port_feature(udev, mtx, port, UHF_BH_PORT_RESET);
|
||||
if (err) {
|
||||
|
||||
DPRINTF("\n");
|
||||
|
||||
err = usbd_req_get_port_status(udev, mtx, &ps, port);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
status = UGETW(ps.wPortStatus);
|
||||
|
||||
switch (UPS_PORT_LINK_STATE_GET(status)) {
|
||||
case UPS_PORT_LS_U3:
|
||||
case UPS_PORT_LS_COMP_MODE:
|
||||
case UPS_PORT_LS_LOOPBACK:
|
||||
case UPS_PORT_LS_SS_INA:
|
||||
break;
|
||||
default:
|
||||
DPRINTF("Wrong state for warm reset\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* clear any leftover warm port reset changes first */
|
||||
usbd_req_clear_port_feature(udev, mtx,
|
||||
port, UHF_C_BH_PORT_RESET);
|
||||
|
||||
/* set warm port reset */
|
||||
err = usbd_req_set_port_feature(udev, mtx,
|
||||
port, UHF_BH_PORT_RESET);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
/* range check input parameters */
|
||||
pr_poll_delay = usb_pr_poll_delay;
|
||||
@ -938,17 +969,20 @@ usbd_req_warm_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
|
||||
n += USB_PORT_RESET_DELAY;
|
||||
#endif
|
||||
err = usbd_req_get_port_status(udev, mtx, &ps, port);
|
||||
if (err) {
|
||||
if (err)
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = UGETW(ps.wPortStatus);
|
||||
change = UGETW(ps.wPortChange);
|
||||
|
||||
/* if the device disappeared, just give up */
|
||||
if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) {
|
||||
if (!(status & UPS_CURRENT_CONNECT_STATUS))
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* check if reset is complete */
|
||||
if (UGETW(ps.wPortChange) & UPS_C_BH_PORT_RESET) {
|
||||
if (change & UPS_C_BH_PORT_RESET)
|
||||
break;
|
||||
}
|
||||
|
||||
/* check for timeout */
|
||||
if (n > 1000) {
|
||||
n = 0;
|
||||
@ -959,9 +993,9 @@ usbd_req_warm_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
|
||||
/* clear port reset first */
|
||||
err = usbd_req_clear_port_feature(
|
||||
udev, mtx, port, UHF_C_BH_PORT_RESET);
|
||||
if (err) {
|
||||
if (err)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* check for timeout */
|
||||
if (n == 0) {
|
||||
err = USB_ERR_TIMEOUT;
|
||||
@ -2004,6 +2038,10 @@ usbd_req_re_enumerate(struct usb_device *udev, struct mtx *mtx)
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to warm reset first */
|
||||
if (parent_hub->speed == USB_SPEED_SUPER)
|
||||
usbd_req_warm_reset_port(parent_hub, mtx, udev->port_no);
|
||||
|
||||
/* Try to reset the parent HUB port. */
|
||||
err = usbd_req_reset_port(parent_hub, mtx, udev->port_no);
|
||||
if (err) {
|
||||
|
Loading…
Reference in New Issue
Block a user