diff options
Diffstat (limited to 'drivers/usb/host/ehci-hub.c')
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 41 |
1 files changed, 29 insertions, 12 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 05490d387fd2..ffc5f27df725 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
@@ -59,6 +59,7 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci) | |||
59 | /* Give the connections some time to appear */ | 59 | /* Give the connections some time to appear */ |
60 | msleep(20); | 60 | msleep(20); |
61 | 61 | ||
62 | spin_lock_irq(&ehci->lock); | ||
62 | port = HCS_N_PORTS(ehci->hcs_params); | 63 | port = HCS_N_PORTS(ehci->hcs_params); |
63 | while (port--) { | 64 | while (port--) { |
64 | if (test_bit(port, &ehci->owned_ports)) { | 65 | if (test_bit(port, &ehci->owned_ports)) { |
@@ -70,23 +71,30 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci) | |||
70 | clear_bit(port, &ehci->owned_ports); | 71 | clear_bit(port, &ehci->owned_ports); |
71 | else if (test_bit(port, &ehci->companion_ports)) | 72 | else if (test_bit(port, &ehci->companion_ports)) |
72 | ehci_writel(ehci, status & ~PORT_PE, reg); | 73 | ehci_writel(ehci, status & ~PORT_PE, reg); |
73 | else | 74 | else { |
75 | spin_unlock_irq(&ehci->lock); | ||
74 | ehci_hub_control(hcd, SetPortFeature, | 76 | ehci_hub_control(hcd, SetPortFeature, |
75 | USB_PORT_FEAT_RESET, port + 1, | 77 | USB_PORT_FEAT_RESET, port + 1, |
76 | NULL, 0); | 78 | NULL, 0); |
79 | spin_lock_irq(&ehci->lock); | ||
80 | } | ||
77 | } | 81 | } |
78 | } | 82 | } |
83 | spin_unlock_irq(&ehci->lock); | ||
79 | 84 | ||
80 | if (!ehci->owned_ports) | 85 | if (!ehci->owned_ports) |
81 | return; | 86 | return; |
82 | msleep(90); /* Wait for resets to complete */ | 87 | msleep(90); /* Wait for resets to complete */ |
83 | 88 | ||
89 | spin_lock_irq(&ehci->lock); | ||
84 | port = HCS_N_PORTS(ehci->hcs_params); | 90 | port = HCS_N_PORTS(ehci->hcs_params); |
85 | while (port--) { | 91 | while (port--) { |
86 | if (test_bit(port, &ehci->owned_ports)) { | 92 | if (test_bit(port, &ehci->owned_ports)) { |
93 | spin_unlock_irq(&ehci->lock); | ||
87 | ehci_hub_control(hcd, GetPortStatus, | 94 | ehci_hub_control(hcd, GetPortStatus, |
88 | 0, port + 1, | 95 | 0, port + 1, |
89 | (char *) &buf, sizeof(buf)); | 96 | (char *) &buf, sizeof(buf)); |
97 | spin_lock_irq(&ehci->lock); | ||
90 | 98 | ||
91 | /* The companion should now own the port, | 99 | /* The companion should now own the port, |
92 | * but if something went wrong the port must not | 100 | * but if something went wrong the port must not |
@@ -105,6 +113,7 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci) | |||
105 | } | 113 | } |
106 | 114 | ||
107 | ehci->owned_ports = 0; | 115 | ehci->owned_ports = 0; |
116 | spin_unlock_irq(&ehci->lock); | ||
108 | } | 117 | } |
109 | 118 | ||
110 | static int ehci_port_change(struct ehci_hcd *ehci) | 119 | static int ehci_port_change(struct ehci_hcd *ehci) |
@@ -133,7 +142,6 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, | |||
133 | { | 142 | { |
134 | int port; | 143 | int port; |
135 | u32 temp; | 144 | u32 temp; |
136 | unsigned long flags; | ||
137 | 145 | ||
138 | /* If remote wakeup is enabled for the root hub but disabled | 146 | /* If remote wakeup is enabled for the root hub but disabled |
139 | * for the controller, we must adjust all the port wakeup flags | 147 | * for the controller, we must adjust all the port wakeup flags |
@@ -143,7 +151,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, | |||
143 | if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup) | 151 | if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup) |
144 | return; | 152 | return; |
145 | 153 | ||
146 | spin_lock_irqsave(&ehci->lock, flags); | 154 | spin_lock_irq(&ehci->lock); |
147 | 155 | ||
148 | /* clear phy low-power mode before changing wakeup flags */ | 156 | /* clear phy low-power mode before changing wakeup flags */ |
149 | if (ehci->has_hostpc) { | 157 | if (ehci->has_hostpc) { |
@@ -154,9 +162,9 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, | |||
154 | temp = ehci_readl(ehci, hostpc_reg); | 162 | temp = ehci_readl(ehci, hostpc_reg); |
155 | ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg); | 163 | ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg); |
156 | } | 164 | } |
157 | spin_unlock_irqrestore(&ehci->lock, flags); | 165 | spin_unlock_irq(&ehci->lock); |
158 | msleep(5); | 166 | msleep(5); |
159 | spin_lock_irqsave(&ehci->lock, flags); | 167 | spin_lock_irq(&ehci->lock); |
160 | } | 168 | } |
161 | 169 | ||
162 | port = HCS_N_PORTS(ehci->hcs_params); | 170 | port = HCS_N_PORTS(ehci->hcs_params); |
@@ -194,7 +202,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, | |||
194 | if (!suspending && ehci_port_change(ehci)) | 202 | if (!suspending && ehci_port_change(ehci)) |
195 | usb_hcd_resume_root_hub(ehci_to_hcd(ehci)); | 203 | usb_hcd_resume_root_hub(ehci_to_hcd(ehci)); |
196 | 204 | ||
197 | spin_unlock_irqrestore(&ehci->lock, flags); | 205 | spin_unlock_irq(&ehci->lock); |
198 | } | 206 | } |
199 | 207 | ||
200 | static int ehci_bus_suspend (struct usb_hcd *hcd) | 208 | static int ehci_bus_suspend (struct usb_hcd *hcd) |
@@ -209,6 +217,9 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
209 | if (time_before (jiffies, ehci->next_statechange)) | 217 | if (time_before (jiffies, ehci->next_statechange)) |
210 | msleep(5); | 218 | msleep(5); |
211 | 219 | ||
220 | /* stop the schedules */ | ||
221 | ehci_quiesce(ehci); | ||
222 | |||
212 | spin_lock_irq (&ehci->lock); | 223 | spin_lock_irq (&ehci->lock); |
213 | 224 | ||
214 | /* Once the controller is stopped, port resumes that are already | 225 | /* Once the controller is stopped, port resumes that are already |
@@ -224,10 +235,6 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
224 | } | 235 | } |
225 | } | 236 | } |
226 | 237 | ||
227 | /* stop schedules, clean any completed work */ | ||
228 | ehci_quiesce(ehci); | ||
229 | ehci_work(ehci); | ||
230 | |||
231 | /* Unlike other USB host controller types, EHCI doesn't have | 238 | /* Unlike other USB host controller types, EHCI doesn't have |
232 | * any notion of "global" or bus-wide suspend. The driver has | 239 | * any notion of "global" or bus-wide suspend. The driver has |
233 | * to manually suspend all the active unsuspended ports, and | 240 | * to manually suspend all the active unsuspended ports, and |
@@ -289,6 +296,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
289 | "succeeded" : "failed"); | 296 | "succeeded" : "failed"); |
290 | } | 297 | } |
291 | } | 298 | } |
299 | spin_unlock_irq(&ehci->lock); | ||
292 | 300 | ||
293 | /* Apparently some devices need a >= 1-uframe delay here */ | 301 | /* Apparently some devices need a >= 1-uframe delay here */ |
294 | if (ehci->bus_suspended) | 302 | if (ehci->bus_suspended) |
@@ -296,6 +304,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
296 | 304 | ||
297 | /* turn off now-idle HC */ | 305 | /* turn off now-idle HC */ |
298 | ehci_halt (ehci); | 306 | ehci_halt (ehci); |
307 | |||
308 | spin_lock_irq(&ehci->lock); | ||
299 | ehci->rh_state = EHCI_RH_SUSPENDED; | 309 | ehci->rh_state = EHCI_RH_SUSPENDED; |
300 | 310 | ||
301 | end_unlink_async(ehci); | 311 | end_unlink_async(ehci); |
@@ -424,13 +434,14 @@ static int ehci_bus_resume (struct usb_hcd *hcd) | |||
424 | } | 434 | } |
425 | 435 | ||
426 | ehci->next_statechange = jiffies + msecs_to_jiffies(5); | 436 | ehci->next_statechange = jiffies + msecs_to_jiffies(5); |
437 | spin_unlock_irq(&ehci->lock); | ||
438 | |||
439 | ehci_handover_companion_ports(ehci); | ||
427 | 440 | ||
428 | /* Now we can safely re-enable irqs */ | 441 | /* Now we can safely re-enable irqs */ |
429 | ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); | 442 | ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); |
430 | (void) ehci_readl(ehci, &ehci->regs->intr_enable); | 443 | (void) ehci_readl(ehci, &ehci->regs->intr_enable); |
431 | 444 | ||
432 | spin_unlock_irq (&ehci->lock); | ||
433 | ehci_handover_companion_ports(ehci); | ||
434 | return 0; | 445 | return 0; |
435 | } | 446 | } |
436 | 447 | ||
@@ -1018,7 +1029,9 @@ static int ehci_hub_control ( | |||
1018 | case USB_PORT_FEAT_TEST: | 1029 | case USB_PORT_FEAT_TEST: |
1019 | if (!selector || selector > 5) | 1030 | if (!selector || selector > 5) |
1020 | goto error; | 1031 | goto error; |
1032 | spin_unlock_irqrestore(&ehci->lock, flags); | ||
1021 | ehci_quiesce(ehci); | 1033 | ehci_quiesce(ehci); |
1034 | spin_lock_irqsave(&ehci->lock, flags); | ||
1022 | 1035 | ||
1023 | /* Put all enabled ports into suspend */ | 1036 | /* Put all enabled ports into suspend */ |
1024 | while (ports--) { | 1037 | while (ports--) { |
@@ -1030,7 +1043,11 @@ static int ehci_hub_control ( | |||
1030 | ehci_writel(ehci, temp | PORT_SUSPEND, | 1043 | ehci_writel(ehci, temp | PORT_SUSPEND, |
1031 | sreg); | 1044 | sreg); |
1032 | } | 1045 | } |
1046 | |||
1047 | spin_unlock_irqrestore(&ehci->lock, flags); | ||
1033 | ehci_halt(ehci); | 1048 | ehci_halt(ehci); |
1049 | spin_lock_irqsave(&ehci->lock, flags); | ||
1050 | |||
1034 | temp = ehci_readl(ehci, status_reg); | 1051 | temp = ehci_readl(ehci, status_reg); |
1035 | temp |= selector << 16; | 1052 | temp |= selector << 16; |
1036 | ehci_writel(ehci, temp, status_reg); | 1053 | ehci_writel(ehci, temp, status_reg); |