aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/uhci-hcd.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2005-04-21 16:04:58 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-06-27 17:43:44 -0400
commit6c1b445c226dd82d0961725dec8051b95003723a (patch)
tree1e812a2e9e2d63879555bb48303a8bc344be3864 /drivers/usb/host/uhci-hcd.c
parent4daaa87c8f19c5f1978470e9e91b74d9e0fb0f8e (diff)
[PATCH] USB UHCI: Use root-hub IRQs while suspended
This patch, which has as478b as a prerequisite, enables the uhci-hcd driver to take advantage of root-hub IRQs rather than polling during the time it is suspended. (Unfortunately the hardware doesn't support port-change interrupts while the controller is running.) It also turns off the driver's private timer while the controller is suspended, as it isn't needed then. The combined elimination of polling interrupts and timer interrupts ought to be enough to allow some systems to save a noticeable amount of power while they are otherwise idle. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/uhci-hcd.c')
-rw-r--r--drivers/usb/host/uhci-hcd.c70
1 files changed, 23 insertions, 47 deletions
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 82e608a4bbd0..25a718eb1d0f 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -84,6 +84,8 @@ static char *errbuf;
84 84
85static kmem_cache_t *uhci_up_cachep; /* urb_priv */ 85static kmem_cache_t *uhci_up_cachep; /* urb_priv */
86 86
87static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state);
88static void wakeup_rh(struct uhci_hcd *uhci);
87static void uhci_get_current_frame_number(struct uhci_hcd *uhci); 89static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
88 90
89/* If a transfer is still active after this much time, turn off FSBR */ 91/* If a transfer is still active after this much time, turn off FSBR */
@@ -133,12 +135,12 @@ static void reset_hc(struct uhci_hcd *uhci)
133 outw(0, uhci->io_addr + USBINTR); 135 outw(0, uhci->io_addr + USBINTR);
134 outw(0, uhci->io_addr + USBCMD); 136 outw(0, uhci->io_addr + USBCMD);
135 137
136 uhci->resume_detect = 0;
137 uhci->port_c_suspend = uhci->suspended_ports = 138 uhci->port_c_suspend = uhci->suspended_ports =
138 uhci->resuming_ports = 0; 139 uhci->resuming_ports = 0;
139 uhci->rh_state = UHCI_RH_RESET; 140 uhci->rh_state = UHCI_RH_RESET;
140 uhci->is_stopped = UHCI_IS_STOPPED; 141 uhci->is_stopped = UHCI_IS_STOPPED;
141 uhci_to_hcd(uhci)->state = HC_STATE_HALT; 142 uhci_to_hcd(uhci)->state = HC_STATE_HALT;
143 uhci_to_hcd(uhci)->poll_rh = 0;
142} 144}
143 145
144/* 146/*
@@ -148,6 +150,7 @@ static void hc_died(struct uhci_hcd *uhci)
148{ 150{
149 reset_hc(uhci); 151 reset_hc(uhci);
150 uhci->hc_inaccessible = 1; 152 uhci->hc_inaccessible = 1;
153 del_timer(&uhci->stall_timer);
151} 154}
152 155
153/* 156/*
@@ -302,14 +305,14 @@ __acquires(uhci->lock)
302 305
303 uhci->rh_state = new_state; 306 uhci->rh_state = new_state;
304 uhci->is_stopped = UHCI_IS_STOPPED; 307 uhci->is_stopped = UHCI_IS_STOPPED;
305 uhci->resume_detect = 0; 308 del_timer(&uhci->stall_timer);
309 uhci_to_hcd(uhci)->poll_rh = !int_enable;
306 310
307 uhci_scan_schedule(uhci, NULL); 311 uhci_scan_schedule(uhci, NULL);
308} 312}
309 313
310static void start_rh(struct uhci_hcd *uhci) 314static void start_rh(struct uhci_hcd *uhci)
311{ 315{
312 uhci->rh_state = UHCI_RH_RUNNING;
313 uhci->is_stopped = 0; 316 uhci->is_stopped = 0;
314 smp_wmb(); 317 smp_wmb();
315 318
@@ -320,6 +323,9 @@ static void start_rh(struct uhci_hcd *uhci)
320 outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, 323 outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
321 uhci->io_addr + USBINTR); 324 uhci->io_addr + USBINTR);
322 mb(); 325 mb();
326 uhci->rh_state = UHCI_RH_RUNNING;
327 uhci_to_hcd(uhci)->poll_rh = 1;
328 restart_timer(uhci);
323} 329}
324 330
325static void wakeup_rh(struct uhci_hcd *uhci) 331static void wakeup_rh(struct uhci_hcd *uhci)
@@ -353,36 +359,9 @@ __acquires(uhci->lock)
353 } 359 }
354 360
355 start_rh(uhci); 361 start_rh(uhci);
356}
357
358static void rh_state_transitions(struct uhci_hcd *uhci)
359{
360 switch (uhci->rh_state) {
361 case UHCI_RH_RUNNING:
362 /* are any devices attached? */
363 if (!any_ports_active(uhci)) {
364 uhci->rh_state = UHCI_RH_RUNNING_NODEVS;
365 uhci->auto_stop_time = jiffies + HZ;
366 }
367 break;
368 362
369 case UHCI_RH_RUNNING_NODEVS: 363 /* Restart root hub polling */
370 /* auto-stop if nothing connected for 1 second */ 364 mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
371 if (any_ports_active(uhci))
372 uhci->rh_state = UHCI_RH_RUNNING;
373 else if (time_after_eq(jiffies, uhci->auto_stop_time))
374 suspend_rh(uhci, UHCI_RH_AUTO_STOPPED);
375 break;
376
377 case UHCI_RH_AUTO_STOPPED:
378 /* wakeup if requested by a device */
379 if (uhci->resume_detect)
380 wakeup_rh(uhci);
381 break;
382
383 default:
384 break;
385 }
386} 365}
387 366
388static void stall_callback(unsigned long _uhci) 367static void stall_callback(unsigned long _uhci)
@@ -394,14 +373,8 @@ static void stall_callback(unsigned long _uhci)
394 uhci_scan_schedule(uhci, NULL); 373 uhci_scan_schedule(uhci, NULL);
395 check_fsbr(uhci); 374 check_fsbr(uhci);
396 375
397 /* Poll for and perform state transitions */ 376 if (!uhci->is_stopped)
398 if (!uhci->hc_inaccessible) { 377 restart_timer(uhci);
399 rh_state_transitions(uhci);
400 if (uhci->suspended_ports)
401 uhci_check_ports(uhci);
402 }
403
404 restart_timer(uhci);
405 spin_unlock_irqrestore(&uhci->lock, flags); 378 spin_unlock_irqrestore(&uhci->lock, flags);
406} 379}
407 380
@@ -443,7 +416,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
443 } 416 }
444 417
445 if (status & USBSTS_RD) 418 if (status & USBSTS_RD)
446 uhci->resume_detect = 1; 419 usb_hcd_poll_rh_status(hcd);
447 420
448 spin_lock_irqsave(&uhci->lock, flags); 421 spin_lock_irqsave(&uhci->lock, flags);
449 uhci_scan_schedule(uhci, regs); 422 uhci_scan_schedule(uhci, regs);
@@ -542,6 +515,7 @@ static int uhci_start(struct usb_hcd *hcd)
542 struct dentry *dentry; 515 struct dentry *dentry;
543 516
544 io_size = (unsigned) hcd->rsrc_len; 517 io_size = (unsigned) hcd->rsrc_len;
518 hcd->uses_new_polling = 1;
545 if (pci_find_capability(to_pci_dev(uhci_dev(uhci)), PCI_CAP_ID_PM)) 519 if (pci_find_capability(to_pci_dev(uhci_dev(uhci)), PCI_CAP_ID_PM))
546 hcd->can_wakeup = 1; /* Assume it supports PME# */ 520 hcd->can_wakeup = 1; /* Assume it supports PME# */
547 521
@@ -714,8 +688,6 @@ static int uhci_start(struct usb_hcd *hcd)
714 configure_hc(uhci); 688 configure_hc(uhci);
715 start_rh(uhci); 689 start_rh(uhci);
716 690
717 restart_timer(uhci);
718
719 udev->speed = USB_SPEED_FULL; 691 udev->speed = USB_SPEED_FULL;
720 692
721 if (usb_hcd_register_root_hub(udev, hcd) != 0) { 693 if (usb_hcd_register_root_hub(udev, hcd) != 0) {
@@ -730,8 +702,8 @@ static int uhci_start(struct usb_hcd *hcd)
730 * error exits: 702 * error exits:
731 */ 703 */
732err_start_root_hub: 704err_start_root_hub:
733 del_timer_sync(&uhci->stall_timer);
734 reset_hc(uhci); 705 reset_hc(uhci);
706 del_timer_sync(&uhci->stall_timer);
735 707
736err_alloc_skelqh: 708err_alloc_skelqh:
737 for (i = 0; i < UHCI_NUM_SKELQH; i++) 709 for (i = 0; i < UHCI_NUM_SKELQH; i++)
@@ -771,13 +743,12 @@ static void uhci_stop(struct usb_hcd *hcd)
771{ 743{
772 struct uhci_hcd *uhci = hcd_to_uhci(hcd); 744 struct uhci_hcd *uhci = hcd_to_uhci(hcd);
773 745
774 del_timer_sync(&uhci->stall_timer);
775
776 spin_lock_irq(&uhci->lock); 746 spin_lock_irq(&uhci->lock);
777 reset_hc(uhci); 747 reset_hc(uhci);
778 uhci_scan_schedule(uhci, NULL); 748 uhci_scan_schedule(uhci, NULL);
779 spin_unlock_irq(&uhci->lock); 749 spin_unlock_irq(&uhci->lock);
780 750
751 del_timer_sync(&uhci->stall_timer);
781 release_uhci(uhci); 752 release_uhci(uhci);
782} 753}
783 754
@@ -844,6 +815,8 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
844 815
845done: 816done:
846 spin_unlock_irq(&uhci->lock); 817 spin_unlock_irq(&uhci->lock);
818 if (rc == 0)
819 del_timer_sync(&hcd->rh_timer);
847 return rc; 820 return rc;
848} 821}
849 822
@@ -875,6 +848,9 @@ static int uhci_resume(struct usb_hcd *hcd)
875 suspend_rh(uhci, UHCI_RH_SUSPENDED); 848 suspend_rh(uhci, UHCI_RH_SUSPENDED);
876 849
877 spin_unlock_irq(&uhci->lock); 850 spin_unlock_irq(&uhci->lock);
851
852 if (hcd->poll_rh)
853 usb_hcd_poll_rh_status(hcd);
878 return 0; 854 return 0;
879} 855}
880#endif 856#endif