USB: ehci shutdown refactored
This patch refactors some shutdown code so it can be shared between ehci_stop() and ehci_shutdown(). This also fixes a couple potential bugs: - ehci_shutdown() was not locking ehci->lock before halting the HC. - ehci_shutdown() didn't disable the watchdog and IAA timers. - ehci_stop() was resetting the host controller when it may have been running, which the EHCI spec says "may result in undefined behavior". ehci_stop() was calling port_power() to turn off the ports, which waited 20ms after applying the port change. The msleep was for the case where the HC might take 20ms to turn the ports on; since we're shutting them off, we can avoid the msleep and just use ehci_turn_off_ports(). ehci_stop() doesn't need to clear the intr_enable register or revert ownership of the companion controllers to the BIOS, because the host controller reset should have done that. There might be a buggy host controller that doesn't follow the reset rules, but for now we assume it's redundant code and remove it. [ A subsequent patch will cancel the timers later ... this version carries forward existing bugs where timers could get re-armed after they're canceled. ] Signed-off-by: Sarah Sharp <sarah.a.sharp@intel.com> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Родитель
3cf2723432
Коммит
21da84a893
|
@ -331,17 +331,13 @@ static void ehci_turn_off_all_ports(struct ehci_hcd *ehci)
|
|||
&ehci->regs->port_status[port]);
|
||||
}
|
||||
|
||||
/* ehci_shutdown kick in for silicon on any bus (not just pci, etc).
|
||||
* This forcibly disables dma and IRQs, helping kexec and other cases
|
||||
* where the next system software may expect clean state.
|
||||
/*
|
||||
* Halt HC, turn off all ports, and let the BIOS use the companion controllers.
|
||||
* Should be called with ehci->lock held.
|
||||
*/
|
||||
static void
|
||||
ehci_shutdown (struct usb_hcd *hcd)
|
||||
static void ehci_silence_controller(struct ehci_hcd *ehci)
|
||||
{
|
||||
struct ehci_hcd *ehci;
|
||||
|
||||
ehci = hcd_to_ehci (hcd);
|
||||
(void) ehci_halt (ehci);
|
||||
ehci_halt(ehci);
|
||||
ehci_turn_off_all_ports(ehci);
|
||||
|
||||
/* make BIOS/etc use companion controller during reboot */
|
||||
|
@ -351,6 +347,22 @@ ehci_shutdown (struct usb_hcd *hcd)
|
|||
ehci_readl(ehci, &ehci->regs->configured_flag);
|
||||
}
|
||||
|
||||
/* ehci_shutdown kick in for silicon on any bus (not just pci, etc).
|
||||
* This forcibly disables dma and IRQs, helping kexec and other cases
|
||||
* where the next system software may expect clean state.
|
||||
*/
|
||||
static void ehci_shutdown(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
del_timer_sync(&ehci->watchdog);
|
||||
del_timer_sync(&ehci->iaa_watchdog);
|
||||
|
||||
spin_lock_irq(&ehci->lock);
|
||||
ehci_silence_controller(ehci);
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
}
|
||||
|
||||
static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
|
||||
{
|
||||
unsigned port;
|
||||
|
@ -401,15 +413,15 @@ static void ehci_work (struct ehci_hcd *ehci)
|
|||
timer_action (ehci, TIMER_IO_WATCHDOG);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when the ehci_hcd module is removed.
|
||||
*/
|
||||
static void ehci_stop (struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
|
||||
|
||||
ehci_dbg (ehci, "stop\n");
|
||||
|
||||
/* Turn off port power on all root hub ports. */
|
||||
ehci_port_power (ehci, 0);
|
||||
|
||||
/* no more interrupts ... */
|
||||
del_timer_sync (&ehci->watchdog);
|
||||
del_timer_sync(&ehci->iaa_watchdog);
|
||||
|
@ -418,13 +430,10 @@ static void ehci_stop (struct usb_hcd *hcd)
|
|||
if (HC_IS_RUNNING (hcd->state))
|
||||
ehci_quiesce (ehci);
|
||||
|
||||
ehci_silence_controller(ehci);
|
||||
ehci_reset (ehci);
|
||||
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
|
||||
/* let companion controllers work when we aren't */
|
||||
ehci_writel(ehci, 0, &ehci->regs->configured_flag);
|
||||
|
||||
remove_companion_file(ehci);
|
||||
remove_debug_files (ehci);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче