From owner-svn-src-head@FreeBSD.ORG Fri Jan 13 22:26:14 2012 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 27E84106564A; Fri, 13 Jan 2012 22:26:14 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 0B4D78FC08; Fri, 13 Jan 2012 22:26:14 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q0DMQDGB082919; Fri, 13 Jan 2012 22:26:13 GMT (envelope-from hselasky@svn.freebsd.org) Received: (from hselasky@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q0DMQDZC082916; Fri, 13 Jan 2012 22:26:13 GMT (envelope-from hselasky@svn.freebsd.org) Message-Id: <201201132226.q0DMQDZC082916@svn.freebsd.org> From: Hans Petter Selasky Date: Fri, 13 Jan 2012 22:26:13 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r230091 - head/sys/dev/usb X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 13 Jan 2012 22:26:14 -0000 Author: hselasky Date: Fri Jan 13 22:26:13 2012 New Revision: 230091 URL: http://svn.freebsd.org/changeset/base/230091 Log: 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 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 13 22:19:14 2012 (r230090) +++ head/sys/dev/usb/usb_hub.c Fri Jan 13 22:26:13 2012 (r230091) @@ -627,14 +627,15 @@ uhub_suspend_resume_port(struct uhub_sof } } 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 */ Modified: head/sys/dev/usb/usb_request.c ============================================================================== --- head/sys/dev/usb/usb_request.c Fri Jan 13 22:19:14 2012 (r230090) +++ head/sys/dev/usb/usb_request.c Fri Jan 13 22:26:13 2012 (r230091) @@ -785,12 +785,17 @@ usbd_req_reset_port(struct usb_device *u 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 *u #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 *u 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 *u /* 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 @@ done: * 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_devi 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_devi /* 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 @@ retry: } } + /* 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) {