diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2008-10-06 11:25:53 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-10-17 17:41:03 -0400 |
commit | eafe5b99f2135488b21cf17a262c54997c44f784 (patch) | |
tree | 648a1c93460c7ae9b12624989cb8aca21d789114 /drivers | |
parent | 2da41d5f6c036e7a6e496a7e601a685f8b87acb0 (diff) |
USB: EHCI: fix remote-wakeup support for ARC/TDI core
This patch (as1147) fixes the remote-wakeup support for EHCI
controllers using the ARC/TDI "embedded-TT" core. These controllers
turn off the RESUME bit by themselves when a port resume is complete;
hence we need to keep separate track of which ports are suspended or
in the process of resuming.
The patch also makes a couple of small improvements in ehci_irq(),
replacing reads of the command register with the value already stored
in a local variable.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Tested-by: Thomas Reitmayr <treitmayr@devbase.at>
CC: David Brownell <david-b@pacbell.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 14 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 27 | ||||
-rw-r--r-- | drivers/usb/host/ehci.h | 2 |
3 files changed, 29 insertions, 14 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 358df2a6c396..d343afacb0b0 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -706,7 +706,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) | |||
706 | pcd_status = status; | 706 | pcd_status = status; |
707 | 707 | ||
708 | /* resume root hub? */ | 708 | /* resume root hub? */ |
709 | if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN)) | 709 | if (!(cmd & CMD_RUN)) |
710 | usb_hcd_resume_root_hub(hcd); | 710 | usb_hcd_resume_root_hub(hcd); |
711 | 711 | ||
712 | while (i--) { | 712 | while (i--) { |
@@ -715,8 +715,11 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) | |||
715 | 715 | ||
716 | if (pstatus & PORT_OWNER) | 716 | if (pstatus & PORT_OWNER) |
717 | continue; | 717 | continue; |
718 | if (!(pstatus & PORT_RESUME) | 718 | if (!(test_bit(i, &ehci->suspended_ports) && |
719 | || ehci->reset_done [i] != 0) | 719 | ((pstatus & PORT_RESUME) || |
720 | !(pstatus & PORT_SUSPEND)) && | ||
721 | (pstatus & PORT_PE) && | ||
722 | ehci->reset_done[i] == 0)) | ||
720 | continue; | 723 | continue; |
721 | 724 | ||
722 | /* start 20 msec resume signaling from this port, | 725 | /* start 20 msec resume signaling from this port, |
@@ -731,9 +734,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) | |||
731 | 734 | ||
732 | /* PCI errors [4.15.2.4] */ | 735 | /* PCI errors [4.15.2.4] */ |
733 | if (unlikely ((status & STS_FATAL) != 0)) { | 736 | if (unlikely ((status & STS_FATAL) != 0)) { |
734 | dbg_cmd (ehci, "fatal", ehci_readl(ehci, | 737 | dbg_cmd(ehci, "fatal", cmd); |
735 | &ehci->regs->command)); | 738 | dbg_status(ehci, "fatal", status); |
736 | dbg_status (ehci, "fatal", status); | ||
737 | if (status & STS_HALT) { | 739 | if (status & STS_HALT) { |
738 | ehci_err (ehci, "fatal error\n"); | 740 | ehci_err (ehci, "fatal error\n"); |
739 | dead: | 741 | dead: |
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 740835bb8575..218f9660d7ee 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
@@ -236,10 +236,8 @@ static int ehci_bus_resume (struct usb_hcd *hcd) | |||
236 | temp = ehci_readl(ehci, &ehci->regs->port_status [i]); | 236 | temp = ehci_readl(ehci, &ehci->regs->port_status [i]); |
237 | temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); | 237 | temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); |
238 | if (test_bit(i, &ehci->bus_suspended) && | 238 | if (test_bit(i, &ehci->bus_suspended) && |
239 | (temp & PORT_SUSPEND)) { | 239 | (temp & PORT_SUSPEND)) |
240 | ehci->reset_done [i] = jiffies + msecs_to_jiffies (20); | ||
241 | temp |= PORT_RESUME; | 240 | temp |= PORT_RESUME; |
242 | } | ||
243 | ehci_writel(ehci, temp, &ehci->regs->port_status [i]); | 241 | ehci_writel(ehci, temp, &ehci->regs->port_status [i]); |
244 | } | 242 | } |
245 | i = HCS_N_PORTS (ehci->hcs_params); | 243 | i = HCS_N_PORTS (ehci->hcs_params); |
@@ -482,10 +480,9 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
482 | * controller by the user. | 480 | * controller by the user. |
483 | */ | 481 | */ |
484 | 482 | ||
485 | if ((temp & mask) != 0 | 483 | if ((temp & mask) != 0 || test_bit(i, &ehci->port_c_suspend) |
486 | || ((temp & PORT_RESUME) != 0 | 484 | || (ehci->reset_done[i] && time_after_eq( |
487 | && time_after_eq(jiffies, | 485 | jiffies, ehci->reset_done[i]))) { |
488 | ehci->reset_done[i]))) { | ||
489 | if (i < 7) | 486 | if (i < 7) |
490 | buf [0] |= 1 << (i + 1); | 487 | buf [0] |= 1 << (i + 1); |
491 | else | 488 | else |
@@ -688,6 +685,7 @@ static int ehci_hub_control ( | |||
688 | /* resume completed? */ | 685 | /* resume completed? */ |
689 | else if (time_after_eq(jiffies, | 686 | else if (time_after_eq(jiffies, |
690 | ehci->reset_done[wIndex])) { | 687 | ehci->reset_done[wIndex])) { |
688 | clear_bit(wIndex, &ehci->suspended_ports); | ||
691 | set_bit(wIndex, &ehci->port_c_suspend); | 689 | set_bit(wIndex, &ehci->port_c_suspend); |
692 | ehci->reset_done[wIndex] = 0; | 690 | ehci->reset_done[wIndex] = 0; |
693 | 691 | ||
@@ -734,6 +732,9 @@ static int ehci_hub_control ( | |||
734 | ehci_readl(ehci, status_reg)); | 732 | ehci_readl(ehci, status_reg)); |
735 | } | 733 | } |
736 | 734 | ||
735 | if (!(temp & (PORT_RESUME|PORT_RESET))) | ||
736 | ehci->reset_done[wIndex] = 0; | ||
737 | |||
737 | /* transfer dedicated ports to the companion hc */ | 738 | /* transfer dedicated ports to the companion hc */ |
738 | if ((temp & PORT_CONNECT) && | 739 | if ((temp & PORT_CONNECT) && |
739 | test_bit(wIndex, &ehci->companion_ports)) { | 740 | test_bit(wIndex, &ehci->companion_ports)) { |
@@ -757,8 +758,17 @@ static int ehci_hub_control ( | |||
757 | } | 758 | } |
758 | if (temp & PORT_PE) | 759 | if (temp & PORT_PE) |
759 | status |= 1 << USB_PORT_FEAT_ENABLE; | 760 | status |= 1 << USB_PORT_FEAT_ENABLE; |
760 | if (temp & (PORT_SUSPEND|PORT_RESUME)) | 761 | |
762 | /* maybe the port was unsuspended without our knowledge */ | ||
763 | if (temp & (PORT_SUSPEND|PORT_RESUME)) { | ||
761 | status |= 1 << USB_PORT_FEAT_SUSPEND; | 764 | status |= 1 << USB_PORT_FEAT_SUSPEND; |
765 | } else if (test_bit(wIndex, &ehci->suspended_ports)) { | ||
766 | clear_bit(wIndex, &ehci->suspended_ports); | ||
767 | ehci->reset_done[wIndex] = 0; | ||
768 | if (temp & PORT_PE) | ||
769 | set_bit(wIndex, &ehci->port_c_suspend); | ||
770 | } | ||
771 | |||
762 | if (temp & PORT_OC) | 772 | if (temp & PORT_OC) |
763 | status |= 1 << USB_PORT_FEAT_OVER_CURRENT; | 773 | status |= 1 << USB_PORT_FEAT_OVER_CURRENT; |
764 | if (temp & PORT_RESET) | 774 | if (temp & PORT_RESET) |
@@ -803,6 +813,7 @@ static int ehci_hub_control ( | |||
803 | || (temp & PORT_RESET) != 0) | 813 | || (temp & PORT_RESET) != 0) |
804 | goto error; | 814 | goto error; |
805 | ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); | 815 | ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); |
816 | set_bit(wIndex, &ehci->suspended_ports); | ||
806 | break; | 817 | break; |
807 | case USB_PORT_FEAT_POWER: | 818 | case USB_PORT_FEAT_POWER: |
808 | if (HCS_PPC (ehci->hcs_params)) | 819 | if (HCS_PPC (ehci->hcs_params)) |
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index a6fd550b6903..b11798d17ae5 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h | |||
@@ -99,6 +99,8 @@ struct ehci_hcd { /* one per controller */ | |||
99 | owned by the companion during a bus suspend */ | 99 | owned by the companion during a bus suspend */ |
100 | unsigned long port_c_suspend; /* which ports have | 100 | unsigned long port_c_suspend; /* which ports have |
101 | the change-suspend feature turned on */ | 101 | the change-suspend feature turned on */ |
102 | unsigned long suspended_ports; /* which ports are | ||
103 | suspended */ | ||
102 | 104 | ||
103 | /* per-HC memory pools (could be per-bus, but ...) */ | 105 | /* per-HC memory pools (could be per-bus, but ...) */ |
104 | struct dma_pool *qh_pool; /* qh per active urb */ | 106 | struct dma_pool *qh_pool; /* qh per active urb */ |