return "suspended";
case EHCI_RH_RUNNING:
return "running";
+ case EHCI_RH_STOPPING:
+ return "stopping";
}
return "?";
}
{
u32 temp;
-#ifdef DEBUG
if (ehci->rh_state != EHCI_RH_RUNNING)
- BUG ();
-#endif
+ return;
/* wait for any schedule enables/disables to take effect */
temp = (ehci->command << 10) & (STS_ASS | STS_PSS);
del_timer_sync(&ehci->iaa_watchdog);
spin_lock_irq(&ehci->lock);
+ ehci->rh_state = EHCI_RH_STOPPING;
ehci_silence_controller(ehci);
spin_unlock_irq(&ehci->lock);
}
del_timer_sync(&ehci->iaa_watchdog);
spin_lock_irq(&ehci->lock);
- if (ehci->rh_state == EHCI_RH_RUNNING)
- ehci_quiesce (ehci);
+ ehci_quiesce(ehci);
ehci_silence_controller(ehci);
ehci_reset (ehci);
/* PCI errors [4.15.2.4] */
if (unlikely ((status & STS_FATAL) != 0)) {
ehci_err(ehci, "fatal error\n");
+ ehci->rh_state = EHCI_RH_STOPPING;
dbg_cmd(ehci, "fatal", cmd);
dbg_status(ehci, "fatal", status);
ehci_halt(ehci);
static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
/* failfast */
- if (ehci->rh_state != EHCI_RH_RUNNING && ehci->async_unlink)
+ if (ehci->rh_state < EHCI_RH_RUNNING && ehci->async_unlink)
end_unlink_async(ehci);
/* If the QH isn't linked then there's nothing we can do
goto idle_timeout;
}
- if (ehci->rh_state != EHCI_RH_RUNNING)
+ if (ehci->rh_state < EHCI_RH_RUNNING)
qh->qh_state = QH_STATE_IDLE;
switch (qh->qh_state) {
case QH_STATE_LINKED:
}
/* stop schedules, clean any completed work */
- if (ehci->rh_state == EHCI_RH_RUNNING)
- ehci_quiesce (ehci);
+ ehci_quiesce(ehci);
ehci_work(ehci);
/* Unlike other USB host controller types, EHCI doesn't have
/* stop scanning when we reach qtds the hc is using */
} else if (likely (!stopped
- && ehci->rh_state == EHCI_RH_RUNNING)) {
+ && ehci->rh_state >= EHCI_RH_RUNNING)) {
break;
/* scan the whole queue for unlinks whenever it stops */
stopped = 1;
/* cancel everything if we halt, suspend, etc */
- if (ehci->rh_state != EHCI_RH_RUNNING)
+ if (ehci->rh_state < EHCI_RH_RUNNING)
last_status = -ESHUTDOWN;
/* this qtd is active; skip it unless a previous qtd
wmb ();
/* If the controller isn't running, we don't have to wait for it */
- if (unlikely(ehci->rh_state != EHCI_RH_RUNNING)) {
+ if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) {
/* if (unlikely (qh->unlink_next != 0))
* this will recurse, probably not much
*/
enum ehci_timer_action action = TIMER_IO_WATCHDOG;
timer_action_done (ehci, TIMER_ASYNC_SHRINK);
- stopped = (ehci->rh_state != EHCI_RH_RUNNING);
+ stopped = (ehci->rh_state < EHCI_RH_RUNNING);
ehci->qh_scan_next = ehci->async->qh_next.qh;
while (ehci->qh_scan_next) {
* Touches as few pages as possible: cache-friendly.
*/
now_uframe = ehci->next_uframe;
- if (ehci->rh_state == EHCI_RH_RUNNING) {
+ if (ehci->rh_state >= EHCI_RH_RUNNING) {
clock = ehci_read_frame_index(ehci);
clock_frame = (clock >> 3) & (ehci->periodic_size - 1);
} else {
union ehci_shadow temp;
int live;
- live = (ehci->rh_state == EHCI_RH_RUNNING);
+ live = (ehci->rh_state >= EHCI_RH_RUNNING);
switch (hc32_to_cpu(ehci, type)) {
case Q_TYPE_QH:
/* handle any completions */
* We can't advance our scan without collecting the ISO
* transfers that are still pending in this frame.
*/
- if (incomplete && ehci->rh_state == EHCI_RH_RUNNING) {
+ if (incomplete && ehci->rh_state >= EHCI_RH_RUNNING) {
ehci->next_uframe = now_uframe;
break;
}
if (now_uframe == clock) {
unsigned now;
- if (ehci->rh_state != EHCI_RH_RUNNING
+ if (ehci->rh_state < EHCI_RH_RUNNING
|| ehci->periodic_sched == 0)
break;
ehci->next_uframe = now_uframe;
#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */
+/*
+ * ehci_rh_state values of EHCI_RH_RUNNING or above mean that the
+ * controller may be doing DMA. Lower values mean there's no DMA.
+ */
enum ehci_rh_state {
EHCI_RH_HALTED,
EHCI_RH_SUSPENDED,
- EHCI_RH_RUNNING
+ EHCI_RH_RUNNING,
+ EHCI_RH_STOPPING
};
struct ehci_hcd { /* one per controller */