Commit 5609e1a2 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[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: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 84b8a97c
...@@ -103,8 +103,8 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci); ...@@ -103,8 +103,8 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci);
static void hc_state_transitions(struct uhci_hcd *uhci); static void hc_state_transitions(struct uhci_hcd *uhci);
/* If a transfer is still active after this much time, turn off FSBR */ /* If a transfer is still active after this much time, turn off FSBR */
#define IDLE_TIMEOUT (HZ / 20) /* 50 ms */ #define IDLE_TIMEOUT msecs_to_jiffies(50)
#define FSBR_DELAY (HZ / 20) /* 50 ms */ #define FSBR_DELAY msecs_to_jiffies(50)
/* When we timeout an idle transfer for FSBR, we'll switch it over to */ /* 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 */ /* depth first traversal. We'll do it in groups of this number of TD's */
...@@ -1611,6 +1611,7 @@ static void stall_callback(unsigned long ptr) ...@@ -1611,6 +1611,7 @@ static void stall_callback(unsigned long ptr)
struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
struct list_head list, *tmp, *head; struct list_head list, *tmp, *head;
unsigned long flags; unsigned long flags;
int called_uhci_finish_completion = 0;
INIT_LIST_HEAD(&list); INIT_LIST_HEAD(&list);
...@@ -1619,6 +1620,7 @@ static void stall_callback(unsigned long ptr) ...@@ -1619,6 +1620,7 @@ static void stall_callback(unsigned long ptr)
uhci_get_current_frame_number(uhci) != uhci->urb_remove_age) { uhci_get_current_frame_number(uhci) != uhci->urb_remove_age) {
uhci_remove_pending_urbps(uhci); uhci_remove_pending_urbps(uhci);
uhci_finish_completion(hcd, NULL); uhci_finish_completion(hcd, NULL);
called_uhci_finish_completion = 1;
} }
head = &uhci->urb_list; head = &uhci->urb_list;
...@@ -1646,6 +1648,10 @@ static void stall_callback(unsigned long ptr) ...@@ -1646,6 +1648,10 @@ static void stall_callback(unsigned long ptr)
} }
spin_unlock_irqrestore(&uhci->schedule_lock, flags); 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; head = &list;
tmp = head->next; tmp = head->next;
while (tmp != head) { while (tmp != head) {
...@@ -1676,7 +1682,7 @@ static int init_stall_timer(struct usb_hcd *hcd) ...@@ -1676,7 +1682,7 @@ static int init_stall_timer(struct usb_hcd *hcd)
init_timer(&uhci->stall_timer); init_timer(&uhci->stall_timer);
uhci->stall_timer.function = stall_callback; uhci->stall_timer.function = stall_callback;
uhci->stall_timer.data = (unsigned long)hcd; 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); add_timer(&uhci->stall_timer);
return 0; return 0;
...@@ -1831,16 +1837,20 @@ static void reset_hc(struct uhci_hcd *uhci) ...@@ -1831,16 +1837,20 @@ static void reset_hc(struct uhci_hcd *uhci)
{ {
unsigned int io_addr = uhci->io_addr; 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 */ /* Global reset for 50ms */
uhci->state = UHCI_RESET; uhci->state = UHCI_RESET;
outw(USBCMD_GRESET, io_addr + USBCMD); outw(USBCMD_GRESET, io_addr + USBCMD);
set_current_state(TASK_UNINTERRUPTIBLE); msleep(50);
schedule_timeout((HZ*50+999) / 1000);
outw(0, io_addr + USBCMD); outw(0, io_addr + USBCMD);
/* Another 10ms delay */ /* Another 10ms delay */
set_current_state(TASK_UNINTERRUPTIBLE); msleep(10);
schedule_timeout((HZ*10+999) / 1000);
uhci->resume_detect = 0; uhci->resume_detect = 0;
} }
...@@ -1865,7 +1875,7 @@ static void wakeup_hc(struct uhci_hcd *uhci) ...@@ -1865,7 +1875,7 @@ static void wakeup_hc(struct uhci_hcd *uhci)
/* Global resume for >= 20ms */ /* Global resume for >= 20ms */
outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD); outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD);
uhci->state = UHCI_RESUMING_1; uhci->state = UHCI_RESUMING_1;
uhci->state_end = jiffies + (20*HZ+999) / 1000; uhci->state_end = jiffies + msecs_to_jiffies(20);
break; break;
case UHCI_RESUMING_1: /* End global resume */ case UHCI_RESUMING_1: /* End global resume */
...@@ -1990,7 +2000,9 @@ static void start_hc(struct uhci_hcd *uhci) ...@@ -1990,7 +2000,9 @@ static void start_hc(struct uhci_hcd *uhci)
} }
} }
/* 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, outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
io_addr + USBINTR); io_addr + USBINTR);
...@@ -2054,15 +2066,10 @@ static int uhci_reset(struct usb_hcd *hcd) ...@@ -2054,15 +2066,10 @@ static int uhci_reset(struct usb_hcd *hcd)
uhci->io_addr = (unsigned long) hcd->regs; uhci->io_addr = (unsigned long) hcd->regs;
/* Turn off all interrupts */ /* Kick BIOS off this hardware and reset, so we won't get
outw(0, uhci->io_addr + USBINTR);
/* Maybe kick BIOS off this hardware. Then reset, so we won't get
* interrupts from any previous setup. * interrupts from any previous setup.
*/ */
reset_hc(uhci); reset_hc(uhci);
pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
USBLEGSUP_DEFAULT);
return 0; return 0;
} }
...@@ -2369,14 +2376,18 @@ static int uhci_resume(struct usb_hcd *hcd) ...@@ -2369,14 +2376,18 @@ static int uhci_resume(struct usb_hcd *hcd)
/* /*
* Some systems don't maintain the UHCI register values * Some systems don't maintain the UHCI register values
* during a PM suspend/resume cycle, so reinitialize * during a PM suspend/resume cycle, so reinitialize
* the Frame Number, the Framelist Base Address, and the * the Frame Number, Framelist Base Address, Interrupt
* Interrupt Enable registers. * 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); outw(uhci->saved_framenumber, uhci->io_addr + USBFRNUM);
outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD); outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC |
USBINTR_SP, uhci->io_addr + USBINTR); USBINTR_SP, uhci->io_addr + USBINTR);
uhci->resume_detect = 1; uhci->resume_detect = 1;
pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
USBLEGSUP_DEFAULT);
} else { } else {
reset_hc(uhci); reset_hc(uhci);
start_hc(uhci); start_hc(uhci);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment