diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2012-07-11 11:21:48 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-07-16 19:50:14 -0400 |
commit | c0c53dbc32ea05a1e1dd9dba4772327da9a11750 (patch) | |
tree | c292857a1d2c6e1c4b16bb08649df71fd92178e2 /drivers/usb/host/ehci-hcd.c | |
parent | 2f5bb665ba7a14c5842fa2e1cde2be039843a2a2 (diff) |
USB: EHCI: add new root-hub state: STOPPING
This patch (as1571) adds a new state for ehci-hcd's root hubs:
EHCI_RH_STOPPING. This value is used at times when the root hub is
being stopped and we don't know whether or not the hardware has
finished all its DMA yet.
Although the purpose may not be apparent, this distinction will come
in useful later on. Future patches will avoid actions that depend on
the root hub being operational (like turning on the async or periodic
schedules) when they see the state is EHCI_RH_STOPPING.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host/ehci-hcd.c')
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 13 |
1 files changed, 6 insertions, 7 deletions
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) | |||
357 | { | 357 | { |
358 | u32 temp; | 358 | u32 temp; |
359 | 359 | ||
360 | #ifdef DEBUG | ||
361 | if (ehci->rh_state != EHCI_RH_RUNNING) | 360 | if (ehci->rh_state != EHCI_RH_RUNNING) |
362 | BUG (); | 361 | return; |
363 | #endif | ||
364 | 362 | ||
365 | /* wait for any schedule enables/disables to take effect */ | 363 | /* wait for any schedule enables/disables to take effect */ |
366 | temp = (ehci->command << 10) & (STS_ASS | STS_PSS); | 364 | temp = (ehci->command << 10) & (STS_ASS | STS_PSS); |
@@ -494,6 +492,7 @@ static void ehci_shutdown(struct usb_hcd *hcd) | |||
494 | del_timer_sync(&ehci->iaa_watchdog); | 492 | del_timer_sync(&ehci->iaa_watchdog); |
495 | 493 | ||
496 | spin_lock_irq(&ehci->lock); | 494 | spin_lock_irq(&ehci->lock); |
495 | ehci->rh_state = EHCI_RH_STOPPING; | ||
497 | ehci_silence_controller(ehci); | 496 | ehci_silence_controller(ehci); |
498 | spin_unlock_irq(&ehci->lock); | 497 | spin_unlock_irq(&ehci->lock); |
499 | } | 498 | } |
@@ -562,8 +561,7 @@ static void ehci_stop (struct usb_hcd *hcd) | |||
562 | del_timer_sync(&ehci->iaa_watchdog); | 561 | del_timer_sync(&ehci->iaa_watchdog); |
563 | 562 | ||
564 | spin_lock_irq(&ehci->lock); | 563 | spin_lock_irq(&ehci->lock); |
565 | if (ehci->rh_state == EHCI_RH_RUNNING) | 564 | ehci_quiesce(ehci); |
566 | ehci_quiesce (ehci); | ||
567 | 565 | ||
568 | ehci_silence_controller(ehci); | 566 | ehci_silence_controller(ehci); |
569 | ehci_reset (ehci); | 567 | ehci_reset (ehci); |
@@ -951,6 +949,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) | |||
951 | /* PCI errors [4.15.2.4] */ | 949 | /* PCI errors [4.15.2.4] */ |
952 | if (unlikely ((status & STS_FATAL) != 0)) { | 950 | if (unlikely ((status & STS_FATAL) != 0)) { |
953 | ehci_err(ehci, "fatal error\n"); | 951 | ehci_err(ehci, "fatal error\n"); |
952 | ehci->rh_state = EHCI_RH_STOPPING; | ||
954 | dbg_cmd(ehci, "fatal", cmd); | 953 | dbg_cmd(ehci, "fatal", cmd); |
955 | dbg_status(ehci, "fatal", status); | 954 | dbg_status(ehci, "fatal", status); |
956 | ehci_halt(ehci); | 955 | ehci_halt(ehci); |
@@ -1026,7 +1025,7 @@ static int ehci_urb_enqueue ( | |||
1026 | static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) | 1025 | static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) |
1027 | { | 1026 | { |
1028 | /* failfast */ | 1027 | /* failfast */ |
1029 | if (ehci->rh_state != EHCI_RH_RUNNING && ehci->async_unlink) | 1028 | if (ehci->rh_state < EHCI_RH_RUNNING && ehci->async_unlink) |
1030 | end_unlink_async(ehci); | 1029 | end_unlink_async(ehci); |
1031 | 1030 | ||
1032 | /* If the QH isn't linked then there's nothing we can do | 1031 | /* If the QH isn't linked then there's nothing we can do |
@@ -1148,7 +1147,7 @@ rescan: | |||
1148 | goto idle_timeout; | 1147 | goto idle_timeout; |
1149 | } | 1148 | } |
1150 | 1149 | ||
1151 | if (ehci->rh_state != EHCI_RH_RUNNING) | 1150 | if (ehci->rh_state < EHCI_RH_RUNNING) |
1152 | qh->qh_state = QH_STATE_IDLE; | 1151 | qh->qh_state = QH_STATE_IDLE; |
1153 | switch (qh->qh_state) { | 1152 | switch (qh->qh_state) { |
1154 | case QH_STATE_LINKED: | 1153 | case QH_STATE_LINKED: |