aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2008-10-06 11:25:53 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-10-17 17:41:03 -0400
commiteafe5b99f2135488b21cf17a262c54997c44f784 (patch)
tree648a1c93460c7ae9b12624989cb8aca21d789114
parent2da41d5f6c036e7a6e496a7e601a685f8b87acb0 (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>
-rw-r--r--drivers/usb/host/ehci-hcd.c14
-rw-r--r--drivers/usb/host/ehci-hub.c27
-rw-r--r--drivers/usb/host/ehci.h2
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");
739dead: 741dead:
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 */