Commit 59f13fee authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] EHCI suspend/resume updates

This patch much improves suspend/resume behavior of EHCI, as tested with
"echo suspend > /sys/power/state" and "echo disk > /sys/power/state".

 - Quiescing the controller has to handle a case where the software has
   finished shutting down periodic and async schedules, but the hardware
   hasn't yet finished its part.

 - When suspending the root hub, be more by-the-book so that resumes
   behave better.

 - When resuming after suspend-to-disk, or in general when no port is
   suspended, the driver re-uses the initialization logic.  That logic
   needed to understand that resources don't need re-allocation, and
   that a few things need to be reset to the default state.

 - More code paths needed to notice a suspended controller, and stop
   right away.

 - To shut down the controller, start with the root hub ports and
   work up from there.

Tested by writing "suspend" or "disk" to /sys/power/state; several
systems resumed OK, at least given the associated usbcore patches.
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 84050a84
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
* 2001-June Works with usb-storage and NEC EHCI on 2.4 * 2001-June Works with usb-storage and NEC EHCI on 2.4
*/ */
#define DRIVER_VERSION "2004-May-10" #define DRIVER_VERSION "26 Oct 2004"
#define DRIVER_AUTHOR "David Brownell" #define DRIVER_AUTHOR "David Brownell"
#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver" #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
...@@ -207,7 +207,7 @@ static int ehci_reset (struct ehci_hcd *ehci) ...@@ -207,7 +207,7 @@ static int ehci_reset (struct ehci_hcd *ehci)
} }
/* idle the controller (from running) */ /* idle the controller (from running) */
static void ehci_ready (struct ehci_hcd *ehci) static void ehci_quiesce (struct ehci_hcd *ehci)
{ {
u32 temp; u32 temp;
...@@ -217,11 +217,8 @@ static void ehci_ready (struct ehci_hcd *ehci) ...@@ -217,11 +217,8 @@ static void ehci_ready (struct ehci_hcd *ehci)
#endif #endif
/* wait for any schedule enables/disables to take effect */ /* wait for any schedule enables/disables to take effect */
temp = 0; temp = readl (&ehci->regs->command) << 10;
if (ehci->async->qh_next.qh) temp &= STS_ASS | STS_PSS;
temp = STS_ASS;
if (ehci->next_uframe != -1)
temp |= STS_PSS;
if (handshake (&ehci->regs->status, STS_ASS | STS_PSS, if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
temp, 16 * 125) != 0) { temp, 16 * 125) != 0) {
ehci->hcd.state = USB_STATE_HALT; ehci->hcd.state = USB_STATE_HALT;
...@@ -402,17 +399,22 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -402,17 +399,22 @@ static int ehci_start (struct usb_hcd *hcd)
int retval; int retval;
u32 hcc_params; u32 hcc_params;
u8 sbrn = 0; u8 sbrn = 0;
int first;
init_timer (&ehci->watchdog);
ehci->watchdog.function = ehci_watchdog; /* skip some things on restart paths */
ehci->watchdog.data = (unsigned long) ehci; first = (ehci->watchdog.data == 0);
if (first) {
init_timer (&ehci->watchdog);
ehci->watchdog.function = ehci_watchdog;
ehci->watchdog.data = (unsigned long) ehci;
}
/* /*
* hw default: 1K periodic list heads, one per frame. * hw default: 1K periodic list heads, one per frame.
* periodic_size can shrink by USBCMD update if hcc_params allows. * periodic_size can shrink by USBCMD update if hcc_params allows.
*/ */
ehci->periodic_size = DEFAULT_I_TDPS; ehci->periodic_size = DEFAULT_I_TDPS;
if ((retval = ehci_mem_init (ehci, GFP_KERNEL)) < 0) if (first && (retval = ehci_mem_init (ehci, GFP_KERNEL)) < 0)
return retval; return retval;
/* controllers may cache some of the periodic schedule ... */ /* controllers may cache some of the periodic schedule ... */
...@@ -423,6 +425,7 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -423,6 +425,7 @@ static int ehci_start (struct usb_hcd *hcd)
ehci->i_thresh = 2 + HCC_ISOC_THRES (hcc_params); ehci->i_thresh = 2 + HCC_ISOC_THRES (hcc_params);
ehci->reclaim = NULL; ehci->reclaim = NULL;
ehci->reclaim_ready = 0;
ehci->next_uframe = -1; ehci->next_uframe = -1;
/* controller state: unknown --> reset */ /* controller state: unknown --> reset */
...@@ -469,14 +472,16 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -469,14 +472,16 @@ static int ehci_start (struct usb_hcd *hcd)
* its dummy is used in hw_alt_next of many tds, to prevent the qh * its dummy is used in hw_alt_next of many tds, to prevent the qh
* from automatically advancing to the next td after short reads. * from automatically advancing to the next td after short reads.
*/ */
ehci->async->qh_next.qh = NULL; if (first) {
ehci->async->hw_next = QH_NEXT (ehci->async->qh_dma); ehci->async->qh_next.qh = NULL;
ehci->async->hw_info1 = cpu_to_le32 (QH_HEAD); ehci->async->hw_next = QH_NEXT (ehci->async->qh_dma);
ehci->async->hw_token = cpu_to_le32 (QTD_STS_HALT); ehci->async->hw_info1 = cpu_to_le32 (QH_HEAD);
ehci->async->hw_qtd_next = EHCI_LIST_END; ehci->async->hw_token = cpu_to_le32 (QTD_STS_HALT);
ehci->async->qh_state = QH_STATE_LINKED; ehci->async->hw_qtd_next = EHCI_LIST_END;
ehci->async->hw_alt_next = QTD_NEXT (ehci->async->dummy->qtd_dma); ehci->async->qh_state = QH_STATE_LINKED;
writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next); ehci->async->hw_alt_next = QTD_NEXT (ehci->async->dummy->qtd_dma);
writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
}
/* /*
* hcc_params controls whether ehci->regs->segment must (!!!) * hcc_params controls whether ehci->regs->segment must (!!!)
...@@ -527,12 +532,15 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -527,12 +532,15 @@ static int ehci_start (struct usb_hcd *hcd)
/* wire up the root hub */ /* wire up the root hub */
bus = hcd_to_bus (hcd); bus = hcd_to_bus (hcd);
udev = usb_alloc_dev (NULL, bus, 0); udev = first ? usb_alloc_dev (NULL, bus, 0) : bus->root_hub;
if (!udev) { if (!udev) {
done2: done2:
ehci_mem_cleanup (ehci); ehci_mem_cleanup (ehci);
return -ENOMEM; return -ENOMEM;
} }
udev->speed = USB_SPEED_HIGH;
udev->state = first ? USB_STATE_ATTACHED : USB_STATE_CONFIGURED;
udev->dev.power.power_state = PM_SUSPEND_ON;
/* /*
* Start, enabling full USB 2.0 functionality ... usb 1.1 devices * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
...@@ -540,8 +548,10 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -540,8 +548,10 @@ static int ehci_start (struct usb_hcd *hcd)
* involved with the root hub. (Except where one is integrated, * involved with the root hub. (Except where one is integrated,
* and there's no companion controller unless maybe for USB OTG.) * and there's no companion controller unless maybe for USB OTG.)
*/ */
ehci->reboot_notifier.notifier_call = ehci_reboot; if (first) {
register_reboot_notifier (&ehci->reboot_notifier); ehci->reboot_notifier.notifier_call = ehci_reboot;
register_reboot_notifier (&ehci->reboot_notifier);
}
ehci->hcd.state = USB_STATE_RUNNING; ehci->hcd.state = USB_STATE_RUNNING;
writel (FLAG_CF, &ehci->regs->configured_flag); writel (FLAG_CF, &ehci->regs->configured_flag);
...@@ -549,21 +559,23 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -549,21 +559,23 @@ static int ehci_start (struct usb_hcd *hcd)
temp = HC_VERSION(readl (&ehci->caps->hc_capbase)); temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
ehci_info (ehci, ehci_info (ehci,
"USB %x.%x enabled, EHCI %x.%02x, driver %s\n", "USB %x.%x %s, EHCI %x.%02x, driver %s\n",
((sbrn & 0xf0)>>4), (sbrn & 0x0f), ((sbrn & 0xf0)>>4), (sbrn & 0x0f),
first ? "initialized" : "restarted",
temp >> 8, temp & 0xff, DRIVER_VERSION); temp >> 8, temp & 0xff, DRIVER_VERSION);
/* /*
* From here on, khubd concurrently accesses the root * From here on, khubd concurrently accesses the root
* hub; drivers will be talking to enumerated devices. * hub; drivers will be talking to enumerated devices.
* (On restart paths, khubd already knows about the root
* hub and could find work as soon as we wrote FLAG_CF.)
* *
* Before this point the HC was idle/ready. After, khubd * Before this point the HC was idle/ready. After, khubd
* and device drivers may start it running. * and device drivers may start it running.
*/ */
udev->speed = USB_SPEED_HIGH; if (first && hcd_register_root (udev, hcd) != 0) {
if (hcd_register_root (udev, hcd) != 0) {
if (hcd->state == USB_STATE_RUNNING) if (hcd->state == USB_STATE_RUNNING)
ehci_ready (ehci); ehci_quiesce (ehci);
ehci_reset (ehci); ehci_reset (ehci);
usb_put_dev (udev); usb_put_dev (udev);
retval = -ENODEV; retval = -ENODEV;
...@@ -572,7 +584,8 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -572,7 +584,8 @@ static int ehci_start (struct usb_hcd *hcd)
writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */ writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
create_debug_files (ehci); if (first)
create_debug_files (ehci);
return 0; return 0;
} }
...@@ -586,24 +599,23 @@ static void ehci_stop (struct usb_hcd *hcd) ...@@ -586,24 +599,23 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci_dbg (ehci, "stop\n"); ehci_dbg (ehci, "stop\n");
/* no more interrupts ... */
if (hcd->state == USB_STATE_RUNNING)
ehci_ready (ehci);
if (in_interrupt ()) { /* must not happen!! */
ehci_err (ehci, "stopped in_interrupt!\n");
return;
}
del_timer_sync (&ehci->watchdog);
/* Turn off port power on all root hub ports. */ /* Turn off port power on all root hub ports. */
rh_ports = HCS_N_PORTS (ehci->hcs_params); rh_ports = HCS_N_PORTS (ehci->hcs_params);
for (port = 1; port <= rh_ports; port++) { for (port = 1; port <= rh_ports; port++)
ehci_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, (void) ehci_hub_control(hcd,
ClearPortFeature, USB_PORT_FEAT_POWER,
port, NULL, 0); port, NULL, 0);
}
/* no more interrupts ... */
del_timer_sync (&ehci->watchdog);
spin_lock_irq(&ehci->lock);
if (HCD_IS_RUNNING (ehci->hcd.state))
ehci_quiesce (ehci);
ehci_reset (ehci); ehci_reset (ehci);
writel (0, &ehci->regs->intr_enable); writel (0, &ehci->regs->intr_enable);
spin_unlock_irq(&ehci->lock);
/* let companion controllers work when we aren't */ /* let companion controllers work when we aren't */
writel (0, &ehci->regs->configured_flag); writel (0, &ehci->regs->configured_flag);
...@@ -641,7 +653,8 @@ static int ehci_get_frame (struct usb_hcd *hcd) ...@@ -641,7 +653,8 @@ static int ehci_get_frame (struct usb_hcd *hcd)
/* suspend/resume, section 4.3 */ /* suspend/resume, section 4.3 */
/* These routines rely on PCI to handle powerdown and wakeup, and /* These routines rely on the bus (pci, platform, etc)
* to handle powerdown and wakeup, and currently also on
* transceivers that don't need any software attention to set up * transceivers that don't need any software attention to set up
* the right sort of wakeup. * the right sort of wakeup.
*/ */
...@@ -650,6 +663,9 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state) ...@@ -650,6 +663,9 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state)
{ {
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
if (hcd->self.root_hub->dev.power.power_state)
return 0;
while (time_before (jiffies, ehci->next_statechange)) while (time_before (jiffies, ehci->next_statechange))
msleep (100); msleep (100);
...@@ -668,19 +684,51 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state) ...@@ -668,19 +684,51 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state)
static int ehci_resume (struct usb_hcd *hcd) static int ehci_resume (struct usb_hcd *hcd)
{ {
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
int retval; unsigned port;
struct usb_device *root = hcd->self.root_hub;
int retval = -EINVAL;
// maybe restore (PCI) FLADJ // maybe restore (PCI) FLADJ
while (time_before (jiffies, ehci->next_statechange)) while (time_before (jiffies, ehci->next_statechange))
msleep (100); msleep (100);
#ifdef CONFIG_USB_SUSPEND /* If any port is suspended, we know we can/must resume the HC. */
retval = usb_resume_device (hcd->self.root_hub); for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) {
#else u32 status;
/* FIXME lock root hub */ port--;
retval = ehci_hub_resume (hcd); status = readl (&ehci->regs->port_status [port]);
#endif if (status & PORT_SUSPEND) {
down (&hcd->self.root_hub->serialize);
retval = ehci_hub_resume (hcd);
up (&hcd->self.root_hub->serialize);
break;
}
if (!root->children [port])
continue;
dbg_port (ehci, __FUNCTION__, port + 1, status);
usb_set_device_state (root->children[port],
USB_STATE_NOTATTACHED);
}
/* Else reset, to cope with power loss or flush-to-storage
* style "resume" having activated BIOS during reboot.
*/
if (port == 0) {
(void) ehci_halt (ehci);
(void) ehci_reset (ehci);
(void) ehci_hc_reset (hcd);
/* emptying the schedule aborts any urbs */
spin_lock_irq (&ehci->lock);
if (ehci->reclaim)
ehci->reclaim_ready = 1;
ehci_work (ehci, NULL);
spin_unlock_irq (&ehci->lock);
/* restart; khubd will disconnect devices */
retval = ehci_start (hcd);
}
if (retval == 0) if (retval == 0)
hcd->self.controller->power.power_state = 0; hcd->self.controller->power.power_state = 0;
return retval; return retval;
...@@ -716,7 +764,8 @@ static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -716,7 +764,8 @@ static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
* misplace IRQs, and should let us run completely without IRQs. * misplace IRQs, and should let us run completely without IRQs.
* such lossage has been observed on both VT6202 and VT8235. * such lossage has been observed on both VT6202 and VT8235.
*/ */
if ((ehci->async->qh_next.ptr != 0) || (ehci->periodic_sched != 0)) if (HCD_IS_RUNNING (ehci->hcd.state) && (ehci->async->qh_next.ptr != 0
|| ehci->periodic_sched != 0))
timer_action (ehci, TIMER_IO_WATCHDOG); timer_action (ehci, TIMER_IO_WATCHDOG);
} }
......
...@@ -35,7 +35,6 @@ static int ehci_hub_suspend (struct usb_hcd *hcd) ...@@ -35,7 +35,6 @@ static int ehci_hub_suspend (struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
struct usb_device *root = hcd_to_bus (&ehci->hcd)->root_hub; struct usb_device *root = hcd_to_bus (&ehci->hcd)->root_hub;
int port; int port;
int status = 0;
if (root->dev.power.power_state != 0) if (root->dev.power.power_state != 0)
return 0; return 0;
...@@ -45,10 +44,23 @@ static int ehci_hub_suspend (struct usb_hcd *hcd) ...@@ -45,10 +44,23 @@ static int ehci_hub_suspend (struct usb_hcd *hcd)
port = HCS_N_PORTS (ehci->hcs_params); port = HCS_N_PORTS (ehci->hcs_params);
spin_lock_irq (&ehci->lock); spin_lock_irq (&ehci->lock);
/* for hcd->state HCD_STATE_SUSPENDED, also stop the non-USB side */
root->dev.power.power_state = 3;
root->state = USB_STATE_SUSPENDED;
/* stop schedules, clean any completed work */
if (HCD_IS_RUNNING(hcd->state))
ehci_quiesce (ehci);
ehci->command = readl (&ehci->regs->command);
if (ehci->reclaim)
ehci->reclaim_ready = 1;
ehci_work(ehci, NULL);
/* suspend any active/unsuspended ports, maybe allow wakeup */ /* suspend any active/unsuspended ports, maybe allow wakeup */
while (port--) { while (port--) {
u32 t1 = readl (&ehci->regs->port_status [port]); u32 __iomem *reg = &ehci->regs->port_status [port];
u32 t2 = t1; u32 t1 = readl (reg);
u32 t2 = t1;
if ((t1 & PORT_PE) && !(t1 & PORT_OWNER)) if ((t1 & PORT_PE) && !(t1 & PORT_OWNER))
t2 |= PORT_SUSPEND; t2 |= PORT_SUSPEND;
...@@ -60,24 +72,16 @@ static int ehci_hub_suspend (struct usb_hcd *hcd) ...@@ -60,24 +72,16 @@ static int ehci_hub_suspend (struct usb_hcd *hcd)
if (t1 != t2) { if (t1 != t2) {
ehci_vdbg (ehci, "port %d, %08x -> %08x\n", ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
port + 1, t1, t2); port + 1, t1, t2);
writel (t2, &ehci->regs->port_status [port]); writel (t2, reg);
} }
} }
/* stop schedules, then turn off HC and clean any completed work */ /* turn off now-idle HC */
if (hcd->state == USB_STATE_RUNNING) ehci_halt (ehci);
ehci_ready (ehci);
ehci->command = readl (&ehci->regs->command);
writel (ehci->command & ~CMD_RUN, &ehci->regs->command);
if (ehci->reclaim)
ehci->reclaim_ready = 1;
ehci_work(ehci, NULL);
(void) handshake (&ehci->regs->status, STS_HALT, STS_HALT, 2000);
root->dev.power.power_state = 3;
ehci->next_statechange = jiffies + msecs_to_jiffies(10); ehci->next_statechange = jiffies + msecs_to_jiffies(10);
spin_unlock_irq (&ehci->lock); spin_unlock_irq (&ehci->lock);
return status; return 0;
} }
...@@ -96,12 +100,16 @@ static int ehci_hub_resume (struct usb_hcd *hcd) ...@@ -96,12 +100,16 @@ static int ehci_hub_resume (struct usb_hcd *hcd)
/* re-init operational registers in case we lost power */ /* re-init operational registers in case we lost power */
if (readl (&ehci->regs->intr_enable) == 0) { if (readl (&ehci->regs->intr_enable) == 0) {
temp = 1;
writel (INTR_MASK, &ehci->regs->intr_enable); writel (INTR_MASK, &ehci->regs->intr_enable);
writel (0, &ehci->regs->segment); writel (0, &ehci->regs->segment);
writel (ehci->periodic_dma, &ehci->regs->frame_list); writel (ehci->periodic_dma, &ehci->regs->frame_list);
writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next); writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
/* FIXME will this work even (pci) vAUX was lost? */ /* FIXME will this work even if (pci) vAUX was lost? */
} } else
temp = 0;
ehci_dbg(ehci, "resume root hub%s\n",
temp ? " after power loss" : "");
/* restore CMD_RUN, framelist size, and irq threshold */ /* restore CMD_RUN, framelist size, and irq threshold */
writel (ehci->command, &ehci->regs->command); writel (ehci->command, &ehci->regs->command);
...@@ -135,8 +143,10 @@ static int ehci_hub_resume (struct usb_hcd *hcd) ...@@ -135,8 +143,10 @@ static int ehci_hub_resume (struct usb_hcd *hcd)
temp |= CMD_ASE; temp |= CMD_ASE;
if (ehci->periodic_sched) if (ehci->periodic_sched)
temp |= CMD_PSE; temp |= CMD_PSE;
if (temp) if (temp) {
writel (ehci->command | temp, &ehci->regs->command); ehci->command |= temp;
writel (ehci->command, &ehci->regs->command);
}
root->dev.power.power_state = 0; root->dev.power.power_state = 0;
ehci->next_statechange = jiffies + msecs_to_jiffies(5); ehci->next_statechange = jiffies + msecs_to_jiffies(5);
......
...@@ -307,6 +307,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs) ...@@ -307,6 +307,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
} else { } else {
stopped = 1; stopped = 1;
if (unlikely (!HCD_IS_RUNNING (ehci->hcd.state)))
urb->status = -ESHUTDOWN;
/* ignore active urbs unless some previous qtd /* ignore active urbs unless some previous qtd
* for the urb faulted (including short read) or * for the urb faulted (including short read) or
* its urb was canceled. we may patch qh or qtds. * its urb was canceled. we may patch qh or qtds.
......
...@@ -1836,7 +1836,9 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -1836,7 +1836,9 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs)
while (q.ptr != 0) { while (q.ptr != 0) {
unsigned uf; unsigned uf;
union ehci_shadow temp; union ehci_shadow temp;
int live;
live = HCD_IS_RUNNING (ehci->hcd.state);
switch (type) { switch (type) {
case Q_TYPE_QH: case Q_TYPE_QH:
/* handle any completions */ /* handle any completions */
...@@ -1861,7 +1863,7 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -1861,7 +1863,7 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs)
case Q_TYPE_ITD: case Q_TYPE_ITD:
/* skip itds for later in the frame */ /* skip itds for later in the frame */
rmb (); rmb ();
for (uf = uframes; uf < 8; uf++) { for (uf = live ? uframes : 8; uf < 8; uf++) {
if (0 == (q.itd->hw_transaction [uf] if (0 == (q.itd->hw_transaction [uf]
& ITD_ACTIVE)) & ITD_ACTIVE))
continue; continue;
...@@ -1885,7 +1887,8 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -1885,7 +1887,8 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs)
q = *q_p; q = *q_p;
break; break;
case Q_TYPE_SITD: case Q_TYPE_SITD:
if (q.sitd->hw_results & SITD_ACTIVE) { if ((q.sitd->hw_results & SITD_ACTIVE)
&& live) {
q_p = &q.sitd->sitd_next; q_p = &q.sitd->sitd_next;
hw_p = &q.sitd->hw_next; hw_p = &q.sitd->hw_next;
type = Q_NEXT_TYPE (q.sitd->hw_next); type = Q_NEXT_TYPE (q.sitd->hw_next);
......
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