aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-hub.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ehci-hub.c')
-rw-r--r--drivers/usb/host/ehci-hub.c122
1 files changed, 116 insertions, 6 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index f4d301bc83b9..0dcb4164dc83 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -28,6 +28,89 @@
28 28
29/*-------------------------------------------------------------------------*/ 29/*-------------------------------------------------------------------------*/
30 30
31#ifdef CONFIG_USB_PERSIST
32
33static int ehci_hub_control(
34 struct usb_hcd *hcd,
35 u16 typeReq,
36 u16 wValue,
37 u16 wIndex,
38 char *buf,
39 u16 wLength
40);
41
42/* After a power loss, ports that were owned by the companion must be
43 * reset so that the companion can still own them.
44 */
45static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
46{
47 u32 __iomem *reg;
48 u32 status;
49 int port;
50 __le32 buf;
51 struct usb_hcd *hcd = ehci_to_hcd(ehci);
52
53 if (!ehci->owned_ports)
54 return;
55
56 /* Give the connections some time to appear */
57 msleep(20);
58
59 port = HCS_N_PORTS(ehci->hcs_params);
60 while (port--) {
61 if (test_bit(port, &ehci->owned_ports)) {
62 reg = &ehci->regs->port_status[port];
63 status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
64
65 /* Port already owned by companion? */
66 if (status & PORT_OWNER)
67 clear_bit(port, &ehci->owned_ports);
68 else if (test_bit(port, &ehci->companion_ports))
69 ehci_writel(ehci, status & ~PORT_PE, reg);
70 else
71 ehci_hub_control(hcd, SetPortFeature,
72 USB_PORT_FEAT_RESET, port + 1,
73 NULL, 0);
74 }
75 }
76
77 if (!ehci->owned_ports)
78 return;
79 msleep(90); /* Wait for resets to complete */
80
81 port = HCS_N_PORTS(ehci->hcs_params);
82 while (port--) {
83 if (test_bit(port, &ehci->owned_ports)) {
84 ehci_hub_control(hcd, GetPortStatus,
85 0, port + 1,
86 (char *) &buf, sizeof(buf));
87
88 /* The companion should now own the port,
89 * but if something went wrong the port must not
90 * remain enabled.
91 */
92 reg = &ehci->regs->port_status[port];
93 status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
94 if (status & PORT_OWNER)
95 ehci_writel(ehci, status | PORT_CSC, reg);
96 else {
97 ehci_dbg(ehci, "failed handover port %d: %x\n",
98 port + 1, status);
99 ehci_writel(ehci, status & ~PORT_PE, reg);
100 }
101 }
102 }
103
104 ehci->owned_ports = 0;
105}
106
107#else /* CONFIG_USB_PERSIST */
108
109static inline void ehci_handover_companion_ports(struct ehci_hcd *ehci)
110{ }
111
112#endif
113
31#ifdef CONFIG_PM 114#ifdef CONFIG_PM
32 115
33static int ehci_bus_suspend (struct usb_hcd *hcd) 116static int ehci_bus_suspend (struct usb_hcd *hcd)
@@ -60,14 +143,16 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
60 * then manually resume them in the bus_resume() routine. 143 * then manually resume them in the bus_resume() routine.
61 */ 144 */
62 ehci->bus_suspended = 0; 145 ehci->bus_suspended = 0;
146 ehci->owned_ports = 0;
63 while (port--) { 147 while (port--) {
64 u32 __iomem *reg = &ehci->regs->port_status [port]; 148 u32 __iomem *reg = &ehci->regs->port_status [port];
65 u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; 149 u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
66 u32 t2 = t1; 150 u32 t2 = t1;
67 151
68 /* keep track of which ports we suspend */ 152 /* keep track of which ports we suspend */
69 if ((t1 & PORT_PE) && !(t1 & PORT_OWNER) && 153 if (t1 & PORT_OWNER)
70 !(t1 & PORT_SUSPEND)) { 154 set_bit(port, &ehci->owned_ports);
155 else if ((t1 & PORT_PE) && !(t1 & PORT_SUSPEND)) {
71 t2 |= PORT_SUSPEND; 156 t2 |= PORT_SUSPEND;
72 set_bit(port, &ehci->bus_suspended); 157 set_bit(port, &ehci->bus_suspended);
73 } 158 }
@@ -108,11 +193,16 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
108{ 193{
109 struct ehci_hcd *ehci = hcd_to_ehci (hcd); 194 struct ehci_hcd *ehci = hcd_to_ehci (hcd);
110 u32 temp; 195 u32 temp;
196 u32 power_okay;
111 int i; 197 int i;
112 198
113 if (time_before (jiffies, ehci->next_statechange)) 199 if (time_before (jiffies, ehci->next_statechange))
114 msleep(5); 200 msleep(5);
115 spin_lock_irq (&ehci->lock); 201 spin_lock_irq (&ehci->lock);
202 if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
203 spin_unlock_irq(&ehci->lock);
204 return -ESHUTDOWN;
205 }
116 206
117 /* Ideally and we've got a real resume here, and no port's power 207 /* Ideally and we've got a real resume here, and no port's power
118 * was lost. (For PCI, that means Vaux was maintained.) But we 208 * was lost. (For PCI, that means Vaux was maintained.) But we
@@ -120,8 +210,9 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
120 * the last user of the controller, not reset/pm hardware keeping 210 * the last user of the controller, not reset/pm hardware keeping
121 * state we gave to it. 211 * state we gave to it.
122 */ 212 */
123 temp = ehci_readl(ehci, &ehci->regs->intr_enable); 213 power_okay = ehci_readl(ehci, &ehci->regs->intr_enable);
124 ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss"); 214 ehci_dbg(ehci, "resume root hub%s\n",
215 power_okay ? "" : " after power loss");
125 216
126 /* at least some APM implementations will try to deliver 217 /* at least some APM implementations will try to deliver
127 * IRQs right away, so delay them until we're ready. 218 * IRQs right away, so delay them until we're ready.
@@ -184,6 +275,9 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
184 ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); 275 ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
185 276
186 spin_unlock_irq (&ehci->lock); 277 spin_unlock_irq (&ehci->lock);
278
279 if (!power_okay)
280 ehci_handover_companion_ports(ehci);
187 return 0; 281 return 0;
188} 282}
189 283
@@ -448,7 +542,8 @@ static int ehci_hub_control (
448) { 542) {
449 struct ehci_hcd *ehci = hcd_to_ehci (hcd); 543 struct ehci_hcd *ehci = hcd_to_ehci (hcd);
450 int ports = HCS_N_PORTS (ehci->hcs_params); 544 int ports = HCS_N_PORTS (ehci->hcs_params);
451 u32 __iomem *status_reg = &ehci->regs->port_status[wIndex - 1]; 545 u32 __iomem *status_reg = &ehci->regs->port_status[
546 (wIndex & 0xff) - 1];
452 u32 temp, status; 547 u32 temp, status;
453 unsigned long flags; 548 unsigned long flags;
454 int retval = 0; 549 int retval = 0;
@@ -556,9 +651,24 @@ static int ehci_hub_control (
556 status |= 1 << USB_PORT_FEAT_C_CONNECTION; 651 status |= 1 << USB_PORT_FEAT_C_CONNECTION;
557 if (temp & PORT_PEC) 652 if (temp & PORT_PEC)
558 status |= 1 << USB_PORT_FEAT_C_ENABLE; 653 status |= 1 << USB_PORT_FEAT_C_ENABLE;
559 if ((temp & PORT_OCC) && !ignore_oc) 654
655 if ((temp & PORT_OCC) && !ignore_oc){
560 status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT; 656 status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
561 657
658 /*
659 * Hubs should disable port power on over-current.
660 * However, not all EHCI implementations do this
661 * automatically, even if they _do_ support per-port
662 * power switching; they're allowed to just limit the
663 * current. khubd will turn the power back on.
664 */
665 if (HCS_PPC (ehci->hcs_params)){
666 ehci_writel(ehci,
667 temp & ~(PORT_RWC_BITS | PORT_POWER),
668 status_reg);
669 }
670 }
671
562 /* whoever resumes must GetPortStatus to complete it!! */ 672 /* whoever resumes must GetPortStatus to complete it!! */
563 if (temp & PORT_RESUME) { 673 if (temp & PORT_RESUME) {
564 674