ChangeSet 1.1722.83.19, 2004/06/04 15:13:47-07:00, stern@rowland.harvard.edu [PATCH] USB: Code cleanup for the UHCI driver This patch makes some simple cleanups in the UHCI driver: It introduces msecs_to_jiffies() conversions and uses msleep(). It wakes up threads waiting for an endpoint to be disabled in the oddball case where interrupts aren't working. (This should have been in a previous patch but I missed it.) It disables PCI interrupt generation whenever the controller is reset and enables it when the controller is started. This may possibly solve some people's problems with suspend/resume. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman drivers/usb/host/uhci-hcd.c | 45 +++++++++++++++++++++++++++----------------- 1 files changed, 28 insertions(+), 17 deletions(-) diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c --- a/drivers/usb/host/uhci-hcd.c Fri Jun 18 11:03:28 2004 +++ b/drivers/usb/host/uhci-hcd.c Fri Jun 18 11:03:28 2004 @@ -103,8 +103,8 @@ static void hc_state_transitions(struct uhci_hcd *uhci); /* If a transfer is still active after this much time, turn off FSBR */ -#define IDLE_TIMEOUT (HZ / 20) /* 50 ms */ -#define FSBR_DELAY (HZ / 20) /* 50 ms */ +#define IDLE_TIMEOUT msecs_to_jiffies(50) +#define FSBR_DELAY msecs_to_jiffies(50) /* When we timeout an idle transfer for FSBR, we'll switch it over to */ /* depth first traversal. We'll do it in groups of this number of TD's */ @@ -1611,6 +1611,7 @@ struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct list_head list, *tmp, *head; unsigned long flags; + int called_uhci_finish_completion = 0; INIT_LIST_HEAD(&list); @@ -1619,6 +1620,7 @@ uhci_get_current_frame_number(uhci) != uhci->urb_remove_age) { uhci_remove_pending_urbps(uhci); uhci_finish_completion(hcd, NULL); + called_uhci_finish_completion = 1; } head = &uhci->urb_list; @@ -1646,6 +1648,10 @@ } spin_unlock_irqrestore(&uhci->schedule_lock, flags); + /* Wake up anyone waiting for an URB to complete */ + if (called_uhci_finish_completion) + wake_up_all(&uhci->waitqh); + head = &list; tmp = head->next; while (tmp != head) { @@ -1676,7 +1682,7 @@ init_timer(&uhci->stall_timer); uhci->stall_timer.function = stall_callback; uhci->stall_timer.data = (unsigned long)hcd; - uhci->stall_timer.expires = jiffies + (HZ / 10); + uhci->stall_timer.expires = jiffies + msecs_to_jiffies(100); add_timer(&uhci->stall_timer); return 0; @@ -1831,16 +1837,20 @@ { unsigned int io_addr = uhci->io_addr; + /* Turn off PIRQ, SMI, and all interrupts. This also turns off + * the BIOS's USB Legacy Support. + */ + pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0); + outw(0, uhci->io_addr + USBINTR); + /* Global reset for 50ms */ uhci->state = UHCI_RESET; outw(USBCMD_GRESET, io_addr + USBCMD); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((HZ*50+999) / 1000); + msleep(50); outw(0, io_addr + USBCMD); /* Another 10ms delay */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((HZ*10+999) / 1000); + msleep(10); uhci->resume_detect = 0; } @@ -1865,7 +1875,7 @@ /* Global resume for >= 20ms */ outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD); uhci->state = UHCI_RESUMING_1; - uhci->state_end = jiffies + (20*HZ+999) / 1000; + uhci->state_end = jiffies + msecs_to_jiffies(20); break; case UHCI_RESUMING_1: /* End global resume */ @@ -1990,7 +2000,9 @@ } } - /* Turn on all interrupts */ + /* Turn on PIRQ and all interrupts */ + pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, + USBLEGSUP_DEFAULT); outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR); @@ -2054,15 +2066,10 @@ uhci->io_addr = (unsigned long) hcd->regs; - /* Turn off all interrupts */ - outw(0, uhci->io_addr + USBINTR); - - /* Maybe kick BIOS off this hardware. Then reset, so we won't get + /* Kick BIOS off this hardware and reset, so we won't get * interrupts from any previous setup. */ reset_hc(uhci); - pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, - USBLEGSUP_DEFAULT); return 0; } @@ -2369,14 +2376,18 @@ /* * Some systems don't maintain the UHCI register values * during a PM suspend/resume cycle, so reinitialize - * the Frame Number, the Framelist Base Address, and the - * Interrupt Enable registers. + * the Frame Number, Framelist Base Address, Interrupt + * Enable, and Legacy Support registers. */ + pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, + 0); outw(uhci->saved_framenumber, uhci->io_addr + USBFRNUM); outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD); outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, uhci->io_addr + USBINTR); uhci->resume_detect = 1; + pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, + USBLEGSUP_DEFAULT); } else { reset_hc(uhci); start_hc(uhci);