mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Joe Wang <joe_wang@aspeedtech.com>
To: Alan Stern <stern@rowland.harvard.edu>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: <linux-aspeed@lists.ozlabs.org>, <linux-usb@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>,
	Joe Wang <joe_wang@aspeedtech.com>
Subject: [PATCH v2] usb: ehci: Quiesce controller before halting it on shutdown
Date: Thu, 22 Oct 2026 09:21:11 +0800	[thread overview]
Message-ID: <20261022-upstream_ehci_aspeed_shutdown-v2-1-62712169bc07@aspeedtech.com> (raw)

ehci_shutdown() runs from the .shutdown callback during reboot,
poweroff and kexec, for example when LinuxBoot firmware boots the
final OS. The HCD is not removed in that path, so ehci_stop() is not
called and the controller may still be running. ehci_shutdown() then
halts it without first turning off the schedules, leaving a DMA master
running while the system shuts down.

On ASPEED EHCI controllers, clearing USBCMD.RS while both the periodic
and asynchronous schedules are enabled may also leave the controller
unable to halt. If an asynchronous transaction runs past the end of
the micro-frame after RS is cleared, the controller walks the periodic
schedule with a cleared internal buffer, reads from address 0x0 and
never sets USBSTS.HCHalted.

If the controller was running, call ehci_quiesce() before halting it,
as ehci_stop() and ehci_bus_suspend() already do. Do this after
rh_state is set to EHCI_RH_STOPPING, so that URB submissions and
hrtimer events cannot re-enable the schedules, and let ehci_quiesce()
accept that state: like EHCI_RH_RUNNING, it means the controller may
still be doing DMA. The controller-death path in ehci_irq() also sets
EHCI_RH_STOPPING, but it has already cleared CMD_RUN, CMD_ASE and
CMD_PSE, so a quiesce there cannot re-enable anything.

Signed-off-by: Joe Wang <joe_wang@aspeedtech.com>
---
This issue was observed on a customer host platform using the AST2700
PCIe EHCI (ehci-pci), and the root cause was confirmed by the ASPEED
hardware team in RTL simulation. The stop sequence used here (clear
PSE/ASE, wait for PSS/ASS to clear, then clear RS) is their
recommended workaround and was confirmed to resolve the issue on that
platform.

When the controller is running, the added delay at shutdown is bounded
by the two existing 16-uframe handshakes in ehci_quiesce().

Tested on AST2700 (ehci-platform): reboot with a hub and USB mass
storage under load, ehci_shutdown() on already halted controllers,
and unbind/bind (ehci_stop()); no regressions.
---
Changes in v2:
- Apply to all EHCI controllers, not only ASPEED (Alan)
- Quiesce only if the controller was running (Alan)
- Link to v1: https://lore.kernel.org/r/20261016-upstream_ehci_aspeed_shutdown-v1-1-8440c13b5652@aspeedtech.com
---
 drivers/usb/host/ehci-hcd.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 3c46bb18c7f3..d9d816eedc66 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -274,7 +274,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
 {
 	u32	temp;
 
-	if (ehci->rh_state != EHCI_RH_RUNNING)
+	if (ehci->rh_state < EHCI_RH_RUNNING)
 		return;
 
 	/* wait for any schedule enables/disables to take effect */
@@ -356,6 +356,7 @@ static void ehci_silence_controller(struct ehci_hcd *ehci)
 static void ehci_shutdown(struct usb_hcd *hcd)
 {
 	struct ehci_hcd	*ehci = hcd_to_ehci(hcd);
+	bool		was_running;
 
 	/**
 	 * Protect the system from crashing at system shutdown in cases where
@@ -367,11 +368,19 @@ static void ehci_shutdown(struct usb_hcd *hcd)
 		return;
 
 	spin_lock_irq(&ehci->lock);
+	was_running = ehci->rh_state == EHCI_RH_RUNNING;
 	ehci->shutdown = true;
 	ehci->rh_state = EHCI_RH_STOPPING;
 	ehci->enabled_hrtimer_events = 0;
 	spin_unlock_irq(&ehci->lock);
 
+	/*
+	 * Turn off the schedules before halting. rh_state is STOPPING now,
+	 * so they cannot be re-enabled.
+	 */
+	if (was_running)
+		ehci_quiesce(ehci);
+
 	ehci_silence_controller(ehci);
 
 	hrtimer_cancel(&ehci->hrtimer);

---
base-commit: 2f2f7eeef8b0a1a9b9ca998231419873ccae8d4e
change-id: 20261016-upstream_ehci_aspeed_shutdown-9ccffedb2a1c

Best regards,
-- 
Joe Wang <joe_wang@aspeedtech.com>


             reply	other threads:[~2026-10-22  1:21 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-22  1:21 Joe Wang [this message]
2026-10-22  1:47 ` Alan Stern

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261022-upstream_ehci_aspeed_shutdown-v2-1-62712169bc07@aspeedtech.com \
    --to=joe_wang@aspeedtech.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-aspeed@lists.ozlabs.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=stern@rowland.harvard.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®