aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorGeoff Levand <geoff@infradead.org>2011-11-30 19:40:57 -0500
committerGeoff Levand <geoff@infradead.org>2011-12-08 12:38:53 -0500
commitdf7c1ca229ebffe14a6fb3f13d16b1dd2a1731cb (patch)
treeeb99177373815ded62106db7423a022520402fa7 /drivers/usb/host
parent9187bef2fa395e85d5e22c4792b553d98410ccd6 (diff)
usb: Fix PS3 EHCI suspend
The EHCI USB controller of the Cell Super Companion Chip used in the PS3 will stop the root hub after all root hub ports are suspended. When in this condition the ehci-hcd handshake routine will return -ETIMEDOUT and the USB runtime suspend sequence will fail. The STS_HLT bit will not be set, so inspection of the frame index is used to test for the condition. Add a new routine handshake_for_broken_root_hub() that is called after an unsuccessful -ETIMEDOUT handshake. On PS3 handshake_for_broken_root_hub() will test for the condition, and if found will return success to allow the USB suspend to complete. For all other platforms handshake_for_broken_root_hub() will return -ETIMEDOUT Signed-off-by: Geoff Levand <geoff@infradead.org> Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/ehci-hcd.c50
1 files changed, 50 insertions, 0 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 46dccbf85c1a..e0ca9955880b 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -48,6 +48,10 @@
48#include <asm/system.h> 48#include <asm/system.h>
49#include <asm/unaligned.h> 49#include <asm/unaligned.h>
50 50
51#if defined(CONFIG_PPC_PS3)
52#include <asm/firmware.h>
53#endif
54
51/*-------------------------------------------------------------------------*/ 55/*-------------------------------------------------------------------------*/
52 56
53/* 57/*
@@ -230,12 +234,58 @@ static int ehci_halt (struct ehci_hcd *ehci)
230 STS_HALT, STS_HALT, 16 * 125); 234 STS_HALT, STS_HALT, 16 * 125);
231} 235}
232 236
237#if defined(CONFIG_USB_SUSPEND) && defined(CONFIG_PPC_PS3)
238
239/*
240 * The EHCI controller of the Cell Super Companion Chip used in the
241 * PS3 will stop the root hub after all root hub ports are suspended.
242 * When in this condition handshake will return -ETIMEDOUT. The
243 * STS_HLT bit will not be set, so inspection of the frame index is
244 * used here to test for the condition. If the condition is found
245 * return success to allow the USB suspend to complete.
246 */
247
248static int handshake_for_broken_root_hub(struct ehci_hcd *ehci,
249 void __iomem *ptr, u32 mask, u32 done,
250 int usec)
251{
252 unsigned int old_index;
253 int error;
254
255 if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
256 return -ETIMEDOUT;
257
258 old_index = ehci_read_frame_index(ehci);
259
260 error = handshake(ehci, ptr, mask, done, usec);
261
262 if (error == -ETIMEDOUT && ehci_read_frame_index(ehci) == old_index)
263 return 0;
264
265 return error;
266}
267
268#else
269
270static int handshake_for_broken_root_hub(struct ehci_hcd *ehci,
271 void __iomem *ptr, u32 mask, u32 done,
272 int usec)
273{
274 return -ETIMEDOUT;
275}
276
277#endif
278
233static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr, 279static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
234 u32 mask, u32 done, int usec) 280 u32 mask, u32 done, int usec)
235{ 281{
236 int error; 282 int error;
237 283
238 error = handshake(ehci, ptr, mask, done, usec); 284 error = handshake(ehci, ptr, mask, done, usec);
285 if (error == -ETIMEDOUT)
286 error = handshake_for_broken_root_hub(ehci, ptr, mask, done,
287 usec);
288
239 if (error) { 289 if (error) {
240 ehci_halt(ehci); 290 ehci_halt(ehci);
241 ehci->rh_state = EHCI_RH_HALTED; 291 ehci->rh_state = EHCI_RH_HALTED;