ChangeSet 1.2181.4.44, 2005/03/21 22:27:09-08:00, [EMAIL PROTECTED]
[PATCH] UHCI updates
This is the second of five updates to the uhci-hcd driver:
Reimplement the port reset function by splitting it into two
parts like the other HC drivers do, where the second part is
triggered by a port status request when the reset finishes. Now
the entire hub_control routine can run without sleeping and can
hold the device spinlock.
Signed-off-by: Alan Stern <[EMAIL PROTECTED]>
Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>
uhci-hcd.c | 2 +-
uhci-hcd.h | 4 ++--
uhci-hub.c | 46 ++++++++++++++++++++++++++++++----------------
3 files changed, 33 insertions(+), 19 deletions(-)
diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c 2005-03-30 15:13:29 -08:00
+++ b/drivers/usb/host/uhci-hcd.c 2005-03-30 15:13:29 -08:00
@@ -149,7 +149,7 @@
/* Poll for and perform state transitions */
hc_state_transitions(uhci);
if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED))
- uhci_check_resume(uhci);
+ uhci_check_ports(uhci);
init_stall_timer(hcd);
}
diff -Nru a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
--- a/drivers/usb/host/uhci-hcd.h 2005-03-30 15:13:29 -08:00
+++ b/drivers/usb/host/uhci-hcd.h 2005-03-30 15:13:29 -08:00
@@ -368,11 +368,11 @@
int resume_detect; /* Need a Global Resume */
unsigned int saved_framenumber; /* Save during PM suspend */
- /* Support for port suspend/resume */
+ /* Support for port suspend/resume/reset */
unsigned long port_c_suspend; /* Bit-arrays of ports */
unsigned long suspended_ports;
unsigned long resuming_ports;
- unsigned long resume_timeout; /* Time to stop signalling */
+ unsigned long ports_timeout; /* Time to stop signalling */
/* Main list of URB's currently controlled by this HC */
struct list_head urb_list; /* P: uhci->lock */
diff -Nru a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
--- a/drivers/usb/host/uhci-hub.c 2005-03-30 15:13:29 -08:00
+++ b/drivers/usb/host/uhci-hub.c 2005-03-30 15:13:29 -08:00
@@ -66,7 +66,6 @@
/* UHCI controllers don't automatically stop resume signalling after 20 msec,
* so we have to poll and check timeouts in order to take care of it.
- * FIXME: Synchronize access to these fields by a spinlock.
*/
static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
unsigned long port_addr)
@@ -87,22 +86,37 @@
}
}
-static void uhci_check_resume(struct uhci_hcd *uhci)
+static void uhci_check_ports(struct uhci_hcd *uhci)
{
unsigned int port;
unsigned long port_addr;
+ int status;
for (port = 0; port < uhci->rh_numports; ++port) {
port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
- if (unlikely(inw(port_addr) & USBPORTSC_RD)) {
+ status = inw(port_addr);
+ if (unlikely(status & USBPORTSC_PR)) {
+ if (time_after_eq(jiffies, uhci->ports_timeout)) {
+ CLR_RH_PORTSTAT(USBPORTSC_PR);
+ udelay(10);
+
+ /* If the port was enabled before, turning
+ * reset on caused a port enable change.
+ * Turning reset off causes a port connect
+ * status change. Clear these changes. */
+ CLR_RH_PORTSTAT(USBPORTSC_CSC | USBPORTSC_PEC);
+ SET_RH_PORTSTAT(USBPORTSC_PE);
+ }
+ }
+ if (unlikely(status & USBPORTSC_RD)) {
if (!test_bit(port, &uhci->resuming_ports)) {
/* Port received a wakeup request */
set_bit(port, &uhci->resuming_ports);
- uhci->resume_timeout = jiffies +
+ uhci->ports_timeout = jiffies +
msecs_to_jiffies(20);
} else if (time_after_eq(jiffies,
- uhci->resume_timeout)) {
+ uhci->ports_timeout)) {
uhci_finish_suspend(uhci, port, port_addr);
}
}
@@ -118,7 +132,9 @@
unsigned int port = wIndex - 1;
unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
u16 wPortChange, wPortStatus;
+ unsigned long flags;
+ spin_lock_irqsave(&uhci->lock, flags);
switch (typeReq) {
case GetHubStatus:
@@ -128,9 +144,7 @@
if (port >= uhci->rh_numports)
goto err;
- if (uhci->resuming_ports)
- uhci_check_resume(uhci);
-
+ uhci_check_ports(uhci);
status = inw(port_addr);
/* Intel controllers report the OverCurrent bit active on.
@@ -203,15 +217,12 @@
OK(0);
case USB_PORT_FEAT_RESET:
SET_RH_PORTSTAT(USBPORTSC_PR);
- mdelay(50); /* USB v1.1 7.1.7.3 */
- CLR_RH_PORTSTAT(USBPORTSC_PR);
- udelay(10);
/* Reset terminates Resume signalling */
uhci_finish_suspend(uhci, port, port_addr);
- SET_RH_PORTSTAT(USBPORTSC_PE);
- mdelay(10);
- CLR_RH_PORTSTAT(USBPORTSC_PEC|USBPORTSC_CSC);
+
+ /* USB v2.0 7.1.7.5 */
+ uhci->ports_timeout = jiffies + msecs_to_jiffies(50);
OK(0);
case USB_PORT_FEAT_POWER:
/* UHCI has no power switching */
@@ -238,8 +249,6 @@
if (test_bit(port, &uhci->suspended_ports) &&
!test_and_set_bit(port,
&uhci->resuming_ports)) {
- uhci->resume_timeout = jiffies +
- msecs_to_jiffies(20);
SET_RH_PORTSTAT(USBPORTSC_RD);
/* The controller won't allow RD to be set
@@ -249,6 +258,10 @@
if (!(inw(port_addr) & USBPORTSC_RD))
uhci_finish_suspend(uhci, port,
port_addr);
+ else
+ /* USB v2.0 7.1.7.7 */
+ uhci->ports_timeout = jiffies +
+ msecs_to_jiffies(20);
}
OK(0);
case USB_PORT_FEAT_C_SUSPEND:
@@ -280,6 +293,7 @@
err:
retval = -EPIPE;
}
+ spin_unlock_irqrestore(&uhci->lock, flags);
return retval;
}
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html