From f4df0e334a9fc731689e8ba4f42a0d72a7491348 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 23 Apr 2005 12:49:16 -0700 Subject: [PATCH] USB: add reboot notifier to ohci Adds a reboot notifier to OHCI, mostly to benefit kexec; plus minor #include tweaks. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 28 ++++++++++++++++++++++++---- drivers/usb/host/ohci-mem.c | 1 + drivers/usb/host/ohci.h | 1 + 3 files changed, 26 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 1e27f10c1592..32120042ab65 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -95,12 +95,11 @@ #include #include #include -#include /* for in_interrupt () */ #include #include -#include "../core/hcd.h" #include -#include /* needed by ohci-mem.c when no PCI */ +#include +#include #include #include @@ -108,8 +107,9 @@ #include #include +#include "../core/hcd.h" -#define DRIVER_VERSION "2004 Nov 08" +#define DRIVER_VERSION "2005 April 22" #define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell" #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver" @@ -141,6 +141,7 @@ static const char hcd_name [] = "ohci_hcd"; static void ohci_dump (struct ohci_hcd *ohci, int verbose); static int ohci_init (struct ohci_hcd *ohci); static void ohci_stop (struct usb_hcd *hcd); +static int ohci_reboot (struct notifier_block *, unsigned long , void *); #include "ohci-hub.c" #include "ohci-dbg.c" @@ -420,6 +421,23 @@ static void ohci_usb_reset (struct ohci_hcd *ohci) ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); } +/* reboot notifier forcibly disables IRQs and DMA, helping kexec and + * other cases where the next software may expect clean state from the + * "firmware". this is bus-neutral, unlike shutdown() methods. + */ +static int +ohci_reboot (struct notifier_block *block, unsigned long code, void *null) +{ + struct ohci_hcd *ohci; + + ohci = container_of (block, struct ohci_hcd, reboot_notifier); + ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); + ohci_usb_reset (ohci); + /* flush the writes */ + (void) ohci_readl (ohci, &ohci->regs->control); + return 0; +} + /*-------------------------------------------------------------------------* * HC functions *-------------------------------------------------------------------------*/ @@ -684,6 +702,7 @@ retry: if (ohci->power_budget) hub_set_power_budget(udev, ohci->power_budget); + register_reboot_notifier (&ohci->reboot_notifier); create_debug_files (ohci); return 0; } @@ -781,6 +800,7 @@ static void ohci_stop (struct usb_hcd *hcd) ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); remove_debug_files (ohci); + unregister_reboot_notifier (&ohci->reboot_notifier); ohci_mem_cleanup (ohci); if (ohci->hcca) { dma_free_coherent (hcd->self.controller, diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index e55682b4919d..23735a36af00 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -29,6 +29,7 @@ static void ohci_hcd_init (struct ohci_hcd *ohci) spin_lock_init (&ohci->lock); INIT_LIST_HEAD (&ohci->pending); INIT_WORK (&ohci->rh_resume, ohci_rh_resume, ohci_to_hcd(ohci)); + ohci->reboot_notifier.notifier_call = ohci_reboot; } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 22e1ac138ac0..3dbc7c0eed43 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -390,6 +390,7 @@ struct ohci_hcd { u32 fminterval; /* saved register */ struct work_struct rh_resume; + struct notifier_block reboot_notifier; unsigned long flags; /* for HC bugs */ #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ -- cgit v1.2.2