# HG changeset patch # User pengcheng chen - Sun Microsystems - Beijing China # Date 1246906976 -28800 # Node ID f8ab5da25490874e3d65f3328773b4197606e3a5 # Parent aeed618cdc998e8c2f65cce83068f827a213d07b 6836590 ehci driver fails to poll for reset completion, causing failures on high speed devices diff -r aeed618cdc99 -r f8ab5da25490 usr/src/uts/common/io/usb/hcd/ehci/ehci_hub.c --- a/usr/src/uts/common/io/usb/hcd/ehci/ehci_hub.c Mon Jul 06 10:15:58 2009 -0700 +++ b/usr/src/uts/common/io/usb/hcd/ehci/ehci_hub.c Tue Jul 07 03:02:56 2009 +0800 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -905,6 +905,7 @@ uint16_t port) { uint_t port_status; + int i; mutex_enter(&ehcip->ehci_int_mutex); @@ -941,8 +942,22 @@ mutex_exit(&ehcip->ehci_int_mutex); - /* Wait 2ms for port to return to high speed mode */ - delay(drv_usectohz(EHCI_PORT_RESUME_COMP_TIMEWAIT)); + /* + * Wait for port to return to high speed mode. It's necessary to poll + * for resume completion for some high-speed devices to work correctly. + */ + for (i = 0; i < EHCI_PORT_RESUME_RETRY_MAX; i++) { + delay(drv_usectohz(EHCI_PORT_RESUME_COMP_TIMEWAIT)); + + mutex_enter(&ehcip->ehci_int_mutex); + port_status = Get_OpReg(ehci_rh_port_status[port]) & + ~EHCI_RH_PORT_CLEAR_MASK; + mutex_exit(&ehcip->ehci_int_mutex); + + if (!(port_status & EHCI_RH_PORT_RESUME)) { + break; + } + } } @@ -958,6 +973,7 @@ { ehci_root_hub_t *rh; uint_t port_status; + int i; mutex_enter(&ehcip->ehci_int_mutex); @@ -999,7 +1015,7 @@ mutex_exit(&ehcip->ehci_int_mutex); - /* Wait 20ms for reset to complete */ + /* Wait 50ms for reset to complete */ delay(drv_usectohz(EHCI_PORT_RESET_TIMEWAIT)); mutex_enter(&ehcip->ehci_int_mutex); @@ -1013,10 +1029,23 @@ mutex_exit(&ehcip->ehci_int_mutex); /* - * Wait 2ms for hardware to enable this port - * if connected usb device is high speed. + * Wait for hardware to enable this port, if the connected + * usb device is high speed. It's necessary to poll for reset + * completion for some high-speed devices to recognized + * correctly. */ - delay(drv_usectohz(EHCI_PORT_RESET_COMP_TIMEWAIT)); + for (i = 0; i < EHCI_PORT_RESET_RETRY_MAX; i++) { + delay(drv_usectohz(EHCI_PORT_RESET_COMP_TIMEWAIT)); + + mutex_enter(&ehcip->ehci_int_mutex); + port_status = Get_OpReg(ehci_rh_port_status[port]) & + ~EHCI_RH_PORT_CLEAR_MASK; + mutex_exit(&ehcip->ehci_int_mutex); + + if (!(port_status & EHCI_RH_PORT_RESET)) { + break; + } + } mutex_enter(&ehcip->ehci_int_mutex); diff -r aeed618cdc99 -r f8ab5da25490 usr/src/uts/common/sys/usb/hcd/ehci/ehci_hub.h --- a/usr/src/uts/common/sys/usb/hcd/ehci/ehci_hub.h Mon Jul 06 10:15:58 2009 -0700 +++ b/usr/src/uts/common/sys/usb/hcd/ehci/ehci_hub.h Tue Jul 07 03:02:56 2009 +0800 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -100,11 +100,13 @@ * These timeout values are specified in terms of microseconds. */ #define EHCI_RH_POLL_TIME 256000 /* RH polling interval */ -#define EHCI_PORT_RESET_TIMEWAIT 20000 /* RH port reset time */ +#define EHCI_PORT_RESET_TIMEWAIT 50000 /* RH port reset time */ #define EHCI_PORT_RESET_COMP_TIMEWAIT 2000 /* RH port reset complete */ #define EHCI_PORT_SUSPEND_TIMEWAIT 10000 /* RH port suspend time */ #define EHCI_PORT_RESUME_TIMEWAIT 20000 /* RH port resume time */ #define EHCI_PORT_RESUME_COMP_TIMEWAIT 2000 /* RH port resume complete */ +#define EHCI_PORT_RESET_RETRY_MAX 10 /* RH port reset retry max */ +#define EHCI_PORT_RESUME_RETRY_MAX 10 /* RH port resume retry max */ #ifdef __cplusplus }