aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2008-09-03 16:38:32 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-10-17 17:40:54 -0400
commit4a511bc3f5829bc18428bcf11c25417a79d09396 (patch)
treed2512a4e4cdf680f297e0af8be6566f9f95fdfb7 /drivers
parent8bfa24727087d7252f9ecfb5fea2dfc92d797fbd (diff)
OHCI: Allow broken controllers to auto-stop
This patch (as1134) attempts to improve the way we handle OHCI controllers with broken Root Hub Status Change interrupt support. In these controllers the RHSC interrupt bit essentially never turns off, making RHSC interrupts useless -- they have to remain permanently disabled. Such controllers should still be allowed to turn off their root hubs when no devices are attached. Polling for new connections can continue while the root hub is suspended. The patch implements this feature. (It won't have much effect unless CONFIG_PM is enabled and CONFIG_USB_SUSPEND is disabled, but since the overhead is very small we may as well do it.) Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/ohci-hub.c60
1 files changed, 32 insertions, 28 deletions
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 7ea9a7b31155..a150e85c901a 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -362,18 +362,23 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
362 int any_connected) 362 int any_connected)
363{ 363{
364 int poll_rh = 1; 364 int poll_rh = 1;
365 int rhsc; 365 int rhsc_status, rhsc_enable;
366 366
367 rhsc = ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC; 367 /* Some broken controllers never turn off RHCS in the interrupt
368 switch (ohci->hc_control & OHCI_CTRL_HCFS) { 368 * status register. For their sake we won't re-enable RHSC
369 * interrupts if the interrupt bit is already active.
370 */
371 rhsc_status = ohci_readl(ohci, &ohci->regs->intrstatus) &
372 OHCI_INTR_RHSC;
373 rhsc_enable = ohci_readl(ohci, &ohci->regs->intrenable) &
374 OHCI_INTR_RHSC;
369 375
376 switch (ohci->hc_control & OHCI_CTRL_HCFS) {
370 case OHCI_USB_OPER: 377 case OHCI_USB_OPER:
371 /* If no status changes are pending, enable status-change 378 /* If no status changes are pending, enable RHSC interrupts. */
372 * interrupts. 379 if (!rhsc_enable && !rhsc_status && !changed) {
373 */ 380 rhsc_enable = OHCI_INTR_RHSC;
374 if (!rhsc && !changed) { 381 ohci_writel(ohci, rhsc_enable, &ohci->regs->intrenable);
375 rhsc = OHCI_INTR_RHSC;
376 ohci_writel(ohci, rhsc, &ohci->regs->intrenable);
377 } 382 }
378 383
379 /* Keep on polling until we know a device is connected 384 /* Keep on polling until we know a device is connected
@@ -383,7 +388,7 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
383 if (any_connected || 388 if (any_connected ||
384 !device_may_wakeup(&ohci_to_hcd(ohci) 389 !device_may_wakeup(&ohci_to_hcd(ohci)
385 ->self.root_hub->dev)) { 390 ->self.root_hub->dev)) {
386 if (rhsc) 391 if (rhsc_enable)
387 poll_rh = 0; 392 poll_rh = 0;
388 } else { 393 } else {
389 ohci->autostop = 1; 394 ohci->autostop = 1;
@@ -396,34 +401,36 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
396 ohci->autostop = 0; 401 ohci->autostop = 0;
397 ohci->next_statechange = jiffies + 402 ohci->next_statechange = jiffies +
398 STATECHANGE_DELAY; 403 STATECHANGE_DELAY;
399 } else if (rhsc && time_after_eq(jiffies, 404 } else if (time_after_eq(jiffies,
400 ohci->next_statechange) 405 ohci->next_statechange)
401 && !ohci->ed_rm_list 406 && !ohci->ed_rm_list
402 && !(ohci->hc_control & 407 && !(ohci->hc_control &
403 OHCI_SCHED_ENABLES)) { 408 OHCI_SCHED_ENABLES)) {
404 ohci_rh_suspend(ohci, 1); 409 ohci_rh_suspend(ohci, 1);
405 poll_rh = 0; 410 if (rhsc_enable)
411 poll_rh = 0;
406 } 412 }
407 } 413 }
408 break; 414 break;
409 415
410 /* if there is a port change, autostart or ask to be resumed */
411 case OHCI_USB_SUSPEND: 416 case OHCI_USB_SUSPEND:
412 case OHCI_USB_RESUME: 417 case OHCI_USB_RESUME:
418 /* if there is a port change, autostart or ask to be resumed */
413 if (changed) { 419 if (changed) {
414 if (ohci->autostop) 420 if (ohci->autostop)
415 ohci_rh_resume(ohci); 421 ohci_rh_resume(ohci);
416 else 422 else
417 usb_hcd_resume_root_hub(ohci_to_hcd(ohci)); 423 usb_hcd_resume_root_hub(ohci_to_hcd(ohci));
418 } else { 424 } else {
419 if (!rhsc && (ohci->autostop || 425 if (!rhsc_enable && !rhsc_status && (ohci->autostop ||
420 ohci_to_hcd(ohci)->self.root_hub-> 426 ohci_to_hcd(ohci)->self.root_hub->
421 do_remote_wakeup)) 427 do_remote_wakeup)) {
422 ohci_writel(ohci, OHCI_INTR_RHSC, 428 rhsc_enable = OHCI_INTR_RHSC;
429 ohci_writel(ohci, rhsc_enable,
423 &ohci->regs->intrenable); 430 &ohci->regs->intrenable);
424 431 }
425 /* everything is idle, no need for polling */ 432 if (rhsc_enable)
426 poll_rh = 0; 433 poll_rh = 0;
427 } 434 }
428 break; 435 break;
429 } 436 }
@@ -443,12 +450,16 @@ static inline int ohci_rh_resume(struct ohci_hcd *ohci)
443static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, 450static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
444 int any_connected) 451 int any_connected)
445{ 452{
453 int rhsc_status;
454
446 /* If RHSC is enabled, don't poll */ 455 /* If RHSC is enabled, don't poll */
447 if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC) 456 if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
448 return 0; 457 return 0;
449 458
450 /* If no status changes are pending, enable status-change interrupts */ 459 /* If no status changes are pending, enable RHSC interrupts */
451 if (!changed) { 460 rhsc_status = ohci_readl(ohci, &ohci->regs->intrstatus) &
461 OHCI_INTR_RHSC;
462 if (!changed && !rhsc_status) {
452 ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); 463 ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
453 return 0; 464 return 0;
454 } 465 }
@@ -492,13 +503,6 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
492 length++; 503 length++;
493 } 504 }
494 505
495 /* Some broken controllers never turn off RHCS in the interrupt
496 * status register. For their sake we won't re-enable RHSC
497 * interrupts if the flag is already set.
498 */
499 if (ohci_readl(ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC)
500 changed = 1;
501
502 /* look at each port */ 506 /* look at each port */
503 for (i = 0; i < ohci->num_ports; i++) { 507 for (i = 0; i < ohci->num_ports; i++) {
504 u32 status = roothub_portstatus (ohci, i); 508 u32 status = roothub_portstatus (ohci, i);