Commit 5c549937 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] USB: ohci-hcd PM fixes

This patch primarily fixes PM-related bugs in the OHCI driver.

It gets rid of some flags that duplicated state between usbcore
and the HCD.  The duplication wasn't correct, and wasn't tested
correctly ... this fixes both issues.  So now the driver avoids
writing to hardware when it's suspended (as required by older
PowerBook hardware) or halted, and treats all non-running states
the same (as required by all hardware).

This includes the last generic parts of a patch sent a while back
by Benjamin Herrenschmidt, which weren't at that time testable on a
x86 kernel because the generic PM code was in flux (and broken).
There may still be some PMAC-specific issues to resolve.

With this patch, and a device_resume() deadlock fix, I've seen
OHCI suspend/resume work on hardware it's not worked on since the
PM changes started to merge into the 2.6.0-test kernels.
parent 752d7202
...@@ -102,14 +102,8 @@ ...@@ -102,14 +102,8 @@
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
/*
* TO DO:
*
* - "disabled" and "sleeping" should be in hcd->state
* - lots more testing!!
*/
#define DRIVER_VERSION "2003 Feb 24" #define DRIVER_VERSION "2003 Oct 13"
#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell" #define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver" #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
...@@ -131,7 +125,6 @@ static const char hcd_name [] = "ohci_hcd"; ...@@ -131,7 +125,6 @@ static const char hcd_name [] = "ohci_hcd";
static inline void disable (struct ohci_hcd *ohci) static inline void disable (struct ohci_hcd *ohci)
{ {
ohci->disabled = 1;
ohci->hcd.state = USB_STATE_HALT; ohci->hcd.state = USB_STATE_HALT;
} }
...@@ -222,7 +215,7 @@ static int ohci_urb_enqueue ( ...@@ -222,7 +215,7 @@ static int ohci_urb_enqueue (
spin_lock_irqsave (&ohci->lock, flags); spin_lock_irqsave (&ohci->lock, flags);
/* don't submit to a dead HC */ /* don't submit to a dead HC */
if (ohci->disabled || ohci->sleeping) { if (!HCD_IS_RUNNING(ohci->hcd.state)) {
retval = -ENODEV; retval = -ENODEV;
goto fail; goto fail;
} }
...@@ -278,7 +271,7 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) ...@@ -278,7 +271,7 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
#endif #endif
spin_lock_irqsave (&ohci->lock, flags); spin_lock_irqsave (&ohci->lock, flags);
if (!ohci->disabled) { if (HCD_IS_RUNNING(ohci->hcd.state)) {
urb_priv_t *urb_priv; urb_priv_t *urb_priv;
/* Unless an IRQ completed the unlink while it was being /* Unless an IRQ completed the unlink while it was being
...@@ -287,7 +280,6 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) ...@@ -287,7 +280,6 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
*/ */
urb_priv = urb->hcpriv; urb_priv = urb->hcpriv;
if (urb_priv) { if (urb_priv) {
urb_priv->state = URB_DEL;
if (urb_priv->ed->state == ED_OPER) if (urb_priv->ed->state == ED_OPER)
start_urb_unlink (ohci, urb_priv->ed); start_urb_unlink (ohci, urb_priv->ed);
} }
...@@ -334,7 +326,7 @@ ohci_endpoint_disable (struct usb_hcd *hcd, struct hcd_dev *dev, int ep) ...@@ -334,7 +326,7 @@ ohci_endpoint_disable (struct usb_hcd *hcd, struct hcd_dev *dev, int ep)
if (!ed) if (!ed)
goto done; goto done;
if (!HCD_IS_RUNNING (ohci->hcd.state) || ohci->disabled) if (!HCD_IS_RUNNING (ohci->hcd.state))
ed->state = ED_IDLE; ed->state = ED_IDLE;
switch (ed->state) { switch (ed->state) {
case ED_UNLINK: /* wait for hw to finish? */ case ED_UNLINK: /* wait for hw to finish? */
...@@ -355,9 +347,9 @@ ohci_endpoint_disable (struct usb_hcd *hcd, struct hcd_dev *dev, int ep) ...@@ -355,9 +347,9 @@ ohci_endpoint_disable (struct usb_hcd *hcd, struct hcd_dev *dev, int ep)
/* caller was supposed to have unlinked any requests; /* caller was supposed to have unlinked any requests;
* that's not our job. can't recover; must leak ed. * that's not our job. can't recover; must leak ed.
*/ */
ohci_err (ohci, "ed %p (#%d) state %d%s\n", ohci_err (ohci, "leak ed %p (#%d) state %d%s\n",
ed, epnum, ed->state, ed, epnum, ed->state,
list_empty (&ed->td_list) ? "" : "(has tds)"); list_empty (&ed->td_list) ? "" : " (has tds)");
td_free (ohci, ed->dummy); td_free (ohci, ed->dummy);
break; break;
} }
...@@ -466,8 +458,7 @@ static int hc_start (struct ohci_hcd *ohci) ...@@ -466,8 +458,7 @@ static int hc_start (struct ohci_hcd *ohci)
struct usb_bus *bus; struct usb_bus *bus;
spin_lock_init (&ohci->lock); spin_lock_init (&ohci->lock);
ohci->disabled = 1; disable (ohci);
ohci->sleeping = 0;
/* Tell the controller where the control and bulk lists are /* Tell the controller where the control and bulk lists are
* The lists are empty now. */ * The lists are empty now. */
...@@ -496,8 +487,8 @@ static int hc_start (struct ohci_hcd *ohci) ...@@ -496,8 +487,8 @@ static int hc_start (struct ohci_hcd *ohci)
/* start controller operations */ /* start controller operations */
ohci->hc_control &= OHCI_CTRL_RWC; ohci->hc_control &= OHCI_CTRL_RWC;
ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER; ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
ohci->disabled = 0;
writel (ohci->hc_control, &ohci->regs->control); writel (ohci->hc_control, &ohci->regs->control);
ohci->hcd.state = USB_STATE_RUNNING;
/* Choose the interrupts we care about now, others later on demand */ /* Choose the interrupts we care about now, others later on demand */
mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH; mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH;
...@@ -586,9 +577,11 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) ...@@ -586,9 +577,11 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
} }
if (ints & OHCI_INTR_WDH) { if (ints & OHCI_INTR_WDH) {
writel (OHCI_INTR_WDH, &regs->intrdisable); if (HCD_IS_RUNNING(hcd->state))
writel (OHCI_INTR_WDH, &regs->intrdisable);
dl_done_list (ohci, dl_reverse_done_list (ohci), ptregs); dl_done_list (ohci, dl_reverse_done_list (ohci), ptregs);
writel (OHCI_INTR_WDH, &regs->intrenable); if (HCD_IS_RUNNING(hcd->state))
writel (OHCI_INTR_WDH, &regs->intrenable);
} }
/* could track INTR_SO to reduce available PCI/... bandwidth */ /* could track INTR_SO to reduce available PCI/... bandwidth */
...@@ -600,14 +593,17 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) ...@@ -600,14 +593,17 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
if (ohci->ed_rm_list) if (ohci->ed_rm_list)
finish_unlinks (ohci, le16_to_cpu (ohci->hcca->frame_no), finish_unlinks (ohci, le16_to_cpu (ohci->hcca->frame_no),
ptregs); ptregs);
if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list) if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
&& HCD_IS_RUNNING(ohci->hcd.state))
writel (OHCI_INTR_SF, &regs->intrdisable); writel (OHCI_INTR_SF, &regs->intrdisable);
spin_unlock (&ohci->lock); spin_unlock (&ohci->lock);
writel (ints, &regs->intrstatus); if (HCD_IS_RUNNING(ohci->hcd.state)) {
writel (OHCI_INTR_MIE, &regs->intrenable); writel (ints, &regs->intrstatus);
// flush those pci writes writel (OHCI_INTR_MIE, &regs->intrenable);
(void) readl (&ohci->regs->control); // flush those pci writes
(void) readl (&ohci->regs->control);
}
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -616,13 +612,12 @@ static void ohci_stop (struct usb_hcd *hcd) ...@@ -616,13 +612,12 @@ static void ohci_stop (struct usb_hcd *hcd)
{ {
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci_dbg (ohci, "stop %s controller%s\n", ohci_dbg (ohci, "stop %s controller (state 0x%02x)\n",
hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS), hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
ohci->disabled ? " (disabled)" : "" ohci->hcd.state);
);
ohci_dump (ohci, 1); ohci_dump (ohci, 1);
if (!ohci->disabled) if (HCD_IS_RUNNING(ohci->hcd.state))
hc_reset (ohci); hc_reset (ohci);
remove_debug_files (ohci); remove_debug_files (ohci);
...@@ -649,8 +644,7 @@ static int hc_restart (struct ohci_hcd *ohci) ...@@ -649,8 +644,7 @@ static int hc_restart (struct ohci_hcd *ohci)
int temp; int temp;
int i; int i;
ohci->disabled = 1; disable (ohci);
ohci->sleeping = 0;
if (hcd_to_bus (&ohci->hcd)->root_hub) if (hcd_to_bus (&ohci->hcd)->root_hub)
usb_disconnect (&hcd_to_bus (&ohci->hcd)->root_hub); usb_disconnect (&hcd_to_bus (&ohci->hcd)->root_hub);
......
...@@ -73,7 +73,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) ...@@ -73,7 +73,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
ports = roothub_a (ohci) & RH_A_NDP; ports = roothub_a (ohci) & RH_A_NDP;
if (ports > MAX_ROOT_PORTS) { if (ports > MAX_ROOT_PORTS) {
if (ohci->disabled) if (!HCD_IS_RUNNING(ohci->hcd.state))
return -ESHUTDOWN; return -ESHUTDOWN;
ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n", ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n",
ports, readl (&ohci->regs->roothub.a) & RH_A_NDP); ports, readl (&ohci->regs->roothub.a) & RH_A_NDP);
......
...@@ -117,7 +117,6 @@ ohci_pci_start (struct usb_hcd *hcd) ...@@ -117,7 +117,6 @@ ohci_pci_start (struct usb_hcd *hcd)
static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state) static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
{ {
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
unsigned long flags;
u16 cmd; u16 cmd;
u32 tmp; u32 tmp;
...@@ -129,16 +128,15 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state) ...@@ -129,16 +128,15 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
/* act as if usb suspend can always be used */ /* act as if usb suspend can always be used */
ohci_dbg (ohci, "suspend to %d\n", state); ohci_dbg (ohci, "suspend to %d\n", state);
ohci->sleeping = 1;
/* First stop processing */ /* First stop processing */
spin_lock_irqsave (&ohci->lock, flags); spin_lock_irq (&ohci->lock);
ohci->hc_control &= ohci->hc_control &=
~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE); ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);
writel (ohci->hc_control, &ohci->regs->control); writel (ohci->hc_control, &ohci->regs->control);
writel (OHCI_INTR_SF, &ohci->regs->intrstatus); writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
(void) readl (&ohci->regs->intrstatus); (void) readl (&ohci->regs->intrstatus);
spin_unlock_irqrestore (&ohci->lock, flags); spin_unlock_irq (&ohci->lock);
/* Wait a frame or two */ /* Wait a frame or two */
mdelay (1); mdelay (1);
...@@ -156,10 +154,14 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state) ...@@ -156,10 +154,14 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
&ohci->regs->intrenable); &ohci->regs->intrenable);
/* Suspend chip and let things settle down a bit */ /* Suspend chip and let things settle down a bit */
spin_lock_irq (&ohci->lock);
ohci->hc_control = OHCI_USB_SUSPEND; ohci->hc_control = OHCI_USB_SUSPEND;
writel (ohci->hc_control, &ohci->regs->control); writel (ohci->hc_control, &ohci->regs->control);
(void) readl (&ohci->regs->control); (void) readl (&ohci->regs->control);
mdelay (500); /* No schedule here ! */ spin_unlock_irq (&ohci->lock);
set_current_state (TASK_UNINTERRUPTIBLE);
schedule_timeout (HZ/2);
tmp = readl (&ohci->regs->control) | OHCI_CTRL_HCFS; tmp = readl (&ohci->regs->control) | OHCI_CTRL_HCFS;
switch (tmp) { switch (tmp) {
...@@ -199,7 +201,6 @@ static int ohci_pci_resume (struct usb_hcd *hcd) ...@@ -199,7 +201,6 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int temp; int temp;
int retval = 0; int retval = 0;
unsigned long flags;
#ifdef CONFIG_PMAC_PBOOK #ifdef CONFIG_PMAC_PBOOK
{ {
...@@ -226,6 +227,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd) ...@@ -226,6 +227,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
switch (temp) { switch (temp) {
case OHCI_USB_RESET: // lost power case OHCI_USB_RESET: // lost power
restart:
ohci_info (ohci, "USB restart\n"); ohci_info (ohci, "USB restart\n");
retval = hc_restart (ohci); retval = hc_restart (ohci);
break; break;
...@@ -235,31 +237,28 @@ static int ohci_pci_resume (struct usb_hcd *hcd) ...@@ -235,31 +237,28 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
ohci_info (ohci, "USB continue from %s wakeup\n", ohci_info (ohci, "USB continue from %s wakeup\n",
(temp == OHCI_USB_SUSPEND) (temp == OHCI_USB_SUSPEND)
? "host" : "remote"); ? "host" : "remote");
/* we "should" only need RESUME if we're SUSPENDed ... */
ohci->hc_control = OHCI_USB_RESUME; ohci->hc_control = OHCI_USB_RESUME;
writel (ohci->hc_control, &ohci->regs->control); writel (ohci->hc_control, &ohci->regs->control);
(void) readl (&ohci->regs->control); (void) readl (&ohci->regs->control);
mdelay (20); /* no schedule here ! */ /* Some controllers (lucent) need extra-long delays */
/* Some controllers (lucent) need a longer delay here */ mdelay (35); /* no schedule here ! */
mdelay (15);
temp = readl (&ohci->regs->control); temp = readl (&ohci->regs->control);
temp = ohci->hc_control & OHCI_CTRL_HCFS; temp = ohci->hc_control & OHCI_CTRL_HCFS;
if (temp != OHCI_USB_RESUME) { if (temp != OHCI_USB_RESUME) {
ohci_err (ohci, "controller won't resume\n"); ohci_err (ohci, "controller won't resume\n");
ohci->disabled = 1; /* maybe we can reset */
retval = -EIO; goto restart;
break;
} }
/* Some chips likes being resumed first */ /* Then re-enable operations */
writel (OHCI_USB_OPER, &ohci->regs->control); writel (OHCI_USB_OPER, &ohci->regs->control);
(void) readl (&ohci->regs->control); (void) readl (&ohci->regs->control);
mdelay (3); mdelay (3);
/* Then re-enable operations */ spin_lock_irq (&ohci->lock);
spin_lock_irqsave (&ohci->lock, flags);
ohci->disabled = 0;
ohci->sleeping = 0;
ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
if (!ohci->ed_rm_list) { if (!ohci->ed_rm_list) {
if (ohci->ed_controltail) if (ohci->ed_controltail)
...@@ -274,25 +273,22 @@ static int ohci_pci_resume (struct usb_hcd *hcd) ...@@ -274,25 +273,22 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
writel (OHCI_INTR_SF, &ohci->regs->intrstatus); writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
writel (OHCI_INTR_SF, &ohci->regs->intrenable); writel (OHCI_INTR_SF, &ohci->regs->intrenable);
/* Check for a pending done list */
writel (OHCI_INTR_WDH, &ohci->regs->intrdisable); writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);
(void) readl (&ohci->regs->intrdisable); (void) readl (&ohci->regs->intrdisable);
spin_unlock_irqrestore (&ohci->lock, flags); spin_unlock_irq (&ohci->lock);
#ifdef CONFIG_PMAC_PBOOK #ifdef CONFIG_PMAC_PBOOK
if (_machine == _MACH_Pmac) if (_machine == _MACH_Pmac)
enable_irq (hcd->pdev->irq); enable_irq (hcd->pdev->irq);
#endif #endif
/* Check for a pending done list */
if (ohci->hcca->done_head) if (ohci->hcca->done_head)
dl_done_list (ohci, dl_reverse_done_list (ohci), NULL); dl_done_list (ohci, dl_reverse_done_list (ohci), NULL);
writel (OHCI_INTR_WDH, &ohci->regs->intrenable); writel (OHCI_INTR_WDH, &ohci->regs->intrenable);
/* assume there are TDs on the bulk and control lists */ /* assume there are TDs on the bulk and control lists */
writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus); writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus);
// ohci_dump_status (ohci);
ohci_dbg (ohci, "sleeping = %d, disabled = %d\n",
ohci->sleeping, ohci->disabled);
break; break;
default: default:
......
...@@ -449,7 +449,7 @@ static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed) ...@@ -449,7 +449,7 @@ static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed)
ohci->ed_rm_list = ed; ohci->ed_rm_list = ed;
/* enable SOF interrupt */ /* enable SOF interrupt */
if (!ohci->sleeping) { if (HCD_IS_RUNNING (ohci->hcd.state)) {
writel (OHCI_INTR_SF, &ohci->regs->intrstatus); writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
writel (OHCI_INTR_SF, &ohci->regs->intrenable); writel (OHCI_INTR_SF, &ohci->regs->intrenable);
// flush those pci writes // flush those pci writes
...@@ -794,7 +794,16 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) ...@@ -794,7 +794,16 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
* looks odd ... that doesn't include protocol stalls * looks odd ... that doesn't include protocol stalls
* (or maybe some other things) * (or maybe some other things)
*/ */
if (cc != TD_CC_STALL || !usb_pipecontrol (urb->pipe)) switch (cc) {
case TD_DATAUNDERRUN:
if ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)
break;
/* fallthrough */
case TD_CC_STALL:
if (usb_pipecontrol (urb->pipe))
break;
/* fallthrough */
default:
ohci_dbg (ohci, ohci_dbg (ohci,
"urb %p path %s ep%d%s %08x cc %d --> status %d\n", "urb %p path %s ep%d%s %08x cc %d --> status %d\n",
urb, urb->dev->devpath, urb, urb->dev->devpath,
...@@ -802,6 +811,7 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) ...@@ -802,6 +811,7 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
usb_pipein (urb->pipe) ? "in" : "out", usb_pipein (urb->pipe) ? "in" : "out",
le32_to_cpu (td->hwINFO), le32_to_cpu (td->hwINFO),
cc, cc_to_error [cc]); cc, cc_to_error [cc]);
}
return rev; return rev;
} }
...@@ -871,7 +881,8 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs) ...@@ -871,7 +881,8 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs)
/* only take off EDs that the HC isn't using, accounting for /* only take off EDs that the HC isn't using, accounting for
* frame counter wraps. * frame counter wraps.
*/ */
if (tick_before (tick, ed->tick) && !ohci->disabled) { if (tick_before (tick, ed->tick)
&& HCD_IS_RUNNING(ohci->hcd.state)) {
last = &ed->ed_next; last = &ed->ed_next;
continue; continue;
} }
...@@ -901,7 +912,7 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs) ...@@ -901,7 +912,7 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs)
urb = td->urb; urb = td->urb;
urb_priv = td->urb->hcpriv; urb_priv = td->urb->hcpriv;
if (urb_priv->state != URB_DEL) { if (urb->status == -EINPROGRESS) {
prev = &td->hwNextTD; prev = &td->hwNextTD;
continue; continue;
} }
...@@ -938,7 +949,7 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs) ...@@ -938,7 +949,7 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs)
/* but if there's work queued, reschedule */ /* but if there's work queued, reschedule */
if (!list_empty (&ed->td_list)) { if (!list_empty (&ed->td_list)) {
if (!ohci->disabled && !ohci->sleeping) if (HCD_IS_RUNNING(ohci->hcd.state))
ed_schedule (ohci, ed); ed_schedule (ohci, ed);
} }
...@@ -947,7 +958,7 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs) ...@@ -947,7 +958,7 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs)
} }
/* maybe reenable control and bulk lists */ /* maybe reenable control and bulk lists */
if (!ohci->disabled && !ohci->ed_rm_list) { if (HCD_IS_RUNNING(ohci->hcd.state) && !ohci->ed_rm_list) {
u32 command = 0, control = 0; u32 command = 0, control = 0;
if (ohci->ed_controltail) { if (ohci->ed_controltail) {
......
...@@ -314,13 +314,10 @@ typedef struct urb_priv { ...@@ -314,13 +314,10 @@ typedef struct urb_priv {
struct ed *ed; struct ed *ed;
__u16 length; // # tds in this request __u16 length; // # tds in this request
__u16 td_cnt; // tds already serviced __u16 td_cnt; // tds already serviced
int state;
struct td *td [0]; // all TDs in this request struct td *td [0]; // all TDs in this request
} urb_priv_t; } urb_priv_t;
#define URB_DEL 1
#define TD_HASH_SIZE 64 /* power'o'two */ #define TD_HASH_SIZE 64 /* power'o'two */
// sizeof (struct td) ~= 64 == 2^6 ... // sizeof (struct td) ~= 64 == 2^6 ...
#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 6)) % TD_HASH_SIZE) #define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 6)) % TD_HASH_SIZE)
...@@ -365,8 +362,6 @@ struct ohci_hcd { ...@@ -365,8 +362,6 @@ struct ohci_hcd {
/* /*
* driver state * driver state
*/ */
int disabled; /* e.g. got a UE, we're hung */
int sleeping;
int load [NUM_INTS]; int load [NUM_INTS];
u32 hc_control; /* copy of hc control reg */ u32 hc_control; /* copy of hc control reg */
......
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