Date: Thu, 12 Jan 2012 21:21:20 +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: r230032 - in head/sys/dev/usb: . controller Message-ID: <201201122121.q0CLLKig026956@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: hselasky Date: Thu Jan 12 21:21:20 2012 New Revision: 230032 URL: http://svn.freebsd.org/changeset/base/230032 Log: - Try to fix support for USB 3.0 HUBs. - Try to fix support for USB 3.0 suspend and resume. MFC after: 1 week Modified: head/sys/dev/usb/controller/xhci.c head/sys/dev/usb/usb.h head/sys/dev/usb/usb_hub.c head/sys/dev/usb/usb_request.c head/sys/dev/usb/usb_request.h Modified: head/sys/dev/usb/controller/xhci.c ============================================================================== --- head/sys/dev/usb/controller/xhci.c Thu Jan 12 21:12:16 2012 (r230031) +++ head/sys/dev/usb/controller/xhci.c Thu Jan 12 21:21:20 2012 (r230032) @@ -2211,9 +2211,10 @@ xhci_configure_device(struct usb_device struct usb_device *hubdev; uint32_t temp; uint32_t route; + uint32_t rh_port; uint8_t is_hub; uint8_t index; - uint8_t rh_port; + uint8_t depth; index = udev->controller_slot_id; @@ -2235,6 +2236,8 @@ xhci_configure_device(struct usb_device if (hubdev->parent_hub == NULL) break; + depth = hubdev->parent_hub->depth; + /* * NOTE: HS/FS/LS devices and the SS root HUB can have * more than 15 ports @@ -2242,17 +2245,18 @@ xhci_configure_device(struct usb_device rh_port = hubdev->port_no; - if (hubdev->parent_hub->parent_hub == NULL) + if (depth == 0) break; - route *= 16; - if (rh_port > 15) - route |= 15; - else - route |= rh_port; + rh_port = 15; + + if (depth < 6) + route |= rh_port << (4 * (depth - 1)); } + DPRINTF("Route=0x%08x\n", route); + temp = XHCI_SCTX_0_ROUTE_SET(route); switch (sc->sc_hw.devs[index].state) { @@ -3063,6 +3067,7 @@ xhci_roothub_exec(struct usb_device *ude case UHF_C_PORT_CONFIG_ERROR: XWRITE4(sc, oper, port, v | XHCI_PS_CEC); break; + case UHF_C_PORT_SUSPEND: case UHF_C_PORT_LINK_STATE: XWRITE4(sc, oper, port, v | XHCI_PS_PLC); break; @@ -3190,7 +3195,7 @@ xhci_roothub_exec(struct usb_device *ude if (v & XHCI_PS_PR) i |= UPS_RESET; if (v & XHCI_PS_PP) - i |= UPS_PORT_POWER; + i |= UPS_PORT_POWER_SS; USETW(sc->sc_hub_desc.ps.wPortStatus, i); i = 0; Modified: head/sys/dev/usb/usb.h ============================================================================== --- head/sys/dev/usb/usb.h Thu Jan 12 21:12:16 2012 (r230031) +++ head/sys/dev/usb/usb.h Thu Jan 12 21:21:20 2012 (r230032) @@ -688,6 +688,7 @@ struct usb_port_status { #define UPS_PORT_LS_LOOPBACK 0x0B #define UPS_PORT_LS_RESUME 0x0F #define UPS_PORT_POWER 0x0100 +#define UPS_PORT_POWER_SS 0x0200 /* super-speed only */ #define UPS_LOW_SPEED 0x0200 #define UPS_HIGH_SPEED 0x0400 #define UPS_OTHER_SPEED 0x0600 /* currently FreeBSD specific */ Modified: head/sys/dev/usb/usb_hub.c ============================================================================== --- head/sys/dev/usb/usb_hub.c Thu Jan 12 21:12:16 2012 (r230031) +++ head/sys/dev/usb/usb_hub.c Thu Jan 12 21:21:20 2012 (r230032) @@ -369,10 +369,25 @@ repeat: } /* check if there is no power on the port and print a warning */ - if (!(sc->sc_st.port_status & UPS_PORT_POWER)) { - DPRINTF("WARNING: strange, connected port %d " - "has no power\n", portno); + switch (udev->speed) { + case USB_SPEED_HIGH: + case USB_SPEED_FULL: + case USB_SPEED_LOW: + if (!(sc->sc_st.port_status & UPS_PORT_POWER)) { + DPRINTF("WARNING: strange, connected port %d " + "has no power\n", portno); + } + break; + case USB_SPEED_SUPER: + if (!(sc->sc_st.port_status & UPS_PORT_POWER_SS)) { + DPRINTF("WARNING: strange, connected port %d " + "has no power\n", portno); + } + break; + default: + break; } + /* check if the device is in Host Mode */ if (!(sc->sc_st.port_status & UPS_PORT_MODE_DEVICE)) { @@ -611,6 +626,7 @@ uhub_suspend_resume_port(struct uhub_sof 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: is_suspend = 0; break; @@ -632,8 +648,7 @@ uhub_suspend_resume_port(struct uhub_sof */ if (is_suspend == 0) usb_dev_resume_peer(child); - else if ((child->flags.usb_mode == USB_MODE_DEVICE) || - (usb_device_20_compatible(child) == 0)) + else if (child->flags.usb_mode == USB_MODE_DEVICE) usb_dev_suspend_peer(child); } done: @@ -2064,7 +2079,6 @@ usb_peer_should_wakeup(struct usb_device (udev->pwr_save.write_refs != 0) || ((udev->pwr_save.read_refs != 0) && (udev->flags.usb_mode == USB_MODE_HOST) && - (usb_device_20_compatible(udev) != 0) && (usb_peer_can_wakeup(udev) == 0))); } @@ -2244,6 +2258,14 @@ usb_dev_resume_peer(struct usb_device *u DPRINTFN(0, "Resuming port failed\n"); return; } + } else { + /* resume current port (Valid in Host and Device Mode) */ + err = usbd_req_set_port_link_state(udev->parent_hub, + NULL, udev->port_no, UPS_PORT_LS_U0); + if (err) { + DPRINTFN(0, "Resuming port failed\n"); + return; + } } /* resume settle time */ @@ -2285,8 +2307,7 @@ usb_dev_resume_peer(struct usb_device *u usbd_sr_unlock(udev); /* check if peer has wakeup capability */ - if (usb_peer_can_wakeup(udev) && - usb_device_20_compatible(udev)) { + if (usb_peer_can_wakeup(udev)) { /* clear remote wakeup */ err = usbd_req_clear_device_feature(udev, NULL, UF_DEVICE_REMOTE_WAKEUP); @@ -2347,8 +2368,7 @@ repeat: } } - if (usb_peer_can_wakeup(udev) && - usb_device_20_compatible(udev)) { + if (usb_peer_can_wakeup(udev)) { /* * This request needs to be done before we set * "udev->flags.self_suspended": @@ -2380,8 +2400,7 @@ repeat: USB_BUS_UNLOCK(udev->bus); if (err != 0) { - if (usb_peer_can_wakeup(udev) && - usb_device_20_compatible(udev)) { + if (usb_peer_can_wakeup(udev)) { /* allow device to do remote wakeup */ err = usbd_req_clear_device_feature(udev, NULL, UF_DEVICE_REMOTE_WAKEUP); @@ -2437,6 +2456,14 @@ repeat: DPRINTFN(0, "Suspending port failed\n"); return; } + } else { + /* suspend current port */ + err = usbd_req_set_port_link_state(udev->parent_hub, + NULL, udev->port_no, UPS_PORT_LS_U3); + if (err) { + DPRINTFN(0, "Suspending port failed\n"); + return; + } } udev = udev->parent_hub; Modified: head/sys/dev/usb/usb_request.c ============================================================================== --- head/sys/dev/usb/usb_request.c Thu Jan 12 21:12:16 2012 (r230031) +++ head/sys/dev/usb/usb_request.c Thu Jan 12 21:21:20 2012 (r230032) @@ -2164,3 +2164,27 @@ usbd_req_clear_tt_buffer(struct usb_devi USETW(req.wLength, 0); return (usbd_do_request(udev, mtx, &req, 0)); } + +/*------------------------------------------------------------------------* + * usbd_req_set_port_link_state + * + * USB 3.0 specific request + * + * Returns: + * 0: Success + * Else: Failure + *------------------------------------------------------------------------*/ +usb_error_t +usbd_req_set_port_link_state(struct usb_device *udev, struct mtx *mtx, + uint8_t port, uint8_t link_state) +{ + struct usb_device_request req; + + req.bmRequestType = UT_WRITE_CLASS_OTHER; + req.bRequest = UR_SET_FEATURE; + USETW(req.wValue, UHF_PORT_LINK_STATE); + req.wIndex[0] = port; + req.wIndex[1] = link_state; + USETW(req.wLength, 0); + return (usbd_do_request(udev, mtx, &req, 0)); +} Modified: head/sys/dev/usb/usb_request.h ============================================================================== --- head/sys/dev/usb/usb_request.h Thu Jan 12 21:12:16 2012 (r230031) +++ head/sys/dev/usb/usb_request.h Thu Jan 12 21:21:20 2012 (r230032) @@ -89,5 +89,7 @@ usb_error_t usbd_req_reset_tt(struct usb uint8_t port); usb_error_t usbd_req_clear_tt_buffer(struct usb_device *udev, struct mtx *mtx, uint8_t port, uint8_t addr, uint8_t type, uint8_t endpoint); +usb_error_t usbd_req_set_port_link_state(struct usb_device *udev, + struct mtx *mtx, uint8_t port, uint8_t link_state); #endif /* _USB_REQUEST_H_ */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201201122121.q0CLLKig026956>