Mercurial > illumos > illumos-gate
changeset 10039:f8ab5da25490
6836590 ehci driver fails to poll for reset completion, causing failures on high speed devices
author | pengcheng chen - Sun Microsystems - Beijing China <Pengcheng.Chen@Sun.COM> |
---|---|
date | Tue, 07 Jul 2009 03:02:56 +0800 |
parents | aeed618cdc99 |
children | 38b25aeeaf7a |
files | usr/src/uts/common/io/usb/hcd/ehci/ehci_hub.c usr/src/uts/common/sys/usb/hcd/ehci/ehci_hub.h |
diffstat | 2 files changed, 40 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- 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);
--- 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 }