diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 76120957d60a..f0c00de035ef 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -706,6 +706,8 @@ static const char *rh_state_string(struct ehci_hcd *ehci) return "suspended"; case EHCI_RH_RUNNING: return "running"; + case EHCI_RH_STOPPING: + return "stopping"; } return "?"; } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 8b75e4279a47..bc94822f4c5d 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -357,10 +357,8 @@ static void ehci_quiesce (struct ehci_hcd *ehci) { 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); @@ -494,6 +492,7 @@ static void ehci_shutdown(struct usb_hcd *hcd) 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); } @@ -562,8 +561,7 @@ static void ehci_stop (struct usb_hcd *hcd) 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); @@ -951,6 +949,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* 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); @@ -1026,7 +1025,7 @@ static int ehci_urb_enqueue ( 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 @@ -1148,7 +1147,7 @@ rescan: 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: diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 77d3324b4b28..fb1b99e74937 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -227,8 +227,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) } /* 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 diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 5193612c96ea..285d5a0f3f70 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -433,7 +433,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) /* 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 */ @@ -441,7 +441,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) 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 @@ -1241,7 +1241,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) 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 */ @@ -1263,7 +1263,7 @@ static void scan_async (struct ehci_hcd *ehci) 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) { diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 027df3de2dc9..3429b8a33c58 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -2299,7 +2299,7 @@ scan_periodic (struct ehci_hcd *ehci) * 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 { @@ -2334,7 +2334,7 @@ restart: 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 */ @@ -2459,7 +2459,7 @@ restart: * 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; } @@ -2475,7 +2475,7 @@ restart: 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; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 475f23e10bbf..9e8e82ecce58 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -62,10 +62,15 @@ struct ehci_stats { #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 */