summaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorAleksey Gorelov <dared1st@yahoo.com>2006-08-08 17:24:08 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2006-09-27 11:58:54 -0700
commit64a21d025d3a979a8715f2ec7acabca7b5406c8a (patch)
treee3cbcef560d848e177cddde6d093aa2411cddd53 /drivers/usb/host
parenta94da8971e836f32315f8832b0bf3e88bee9efae (diff)
downloadlinux-64a21d025d3a979a8715f2ec7acabca7b5406c8a.tar.bz2
USB: Properly unregister reboot notifier in case of failure in ehci hcd
If some problem occurs during ehci startup, for instance, request_irq fails, echi hcd driver tries it best to cleanup, but fails to unregister reboot notifier, which in turn leads to crash on reboot/poweroff. The following patch resolves this problem by not using reboot notifiers anymore, but instead making ehci/ohci driver get its own shutdown method. For PCI, it is done through pci glue, for everything else through platform driver glue. One downside: sa1111 does not use platform driver stuff, and does not have its own shutdown hook, so no 'shutdown' is called for it now. I'm not sure if it is really necessary on that platform, though. Signed-off-by: Aleks Gorelov <dared1st@yahoo.com> Cc: Alan Stern <stern@rowland.harvard.edu> Cc: David Brownell <david-b@pacbell.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/ehci-au1xxx.c2
-rw-r--r--drivers/usb/host/ehci-fsl.c2
-rw-r--r--drivers/usb/host/ehci-hcd.c16
-rw-r--r--drivers/usb/host/ehci-pci.c2
-rw-r--r--drivers/usb/host/ehci.h1
-rw-r--r--drivers/usb/host/ohci-at91.c2
-rw-r--r--drivers/usb/host/ohci-au1xxx.c2
-rw-r--r--drivers/usb/host/ohci-ep93xx.c2
-rw-r--r--drivers/usb/host/ohci-hcd.c12
-rw-r--r--drivers/usb/host/ohci-lh7a404.c2
-rw-r--r--drivers/usb/host/ohci-mem.c1
-rw-r--r--drivers/usb/host/ohci-omap.c2
-rw-r--r--drivers/usb/host/ohci-pci.c3
-rw-r--r--drivers/usb/host/ohci-ppc-soc.c2
-rw-r--r--drivers/usb/host/ohci-pxa27x.c2
-rw-r--r--drivers/usb/host/ohci-s3c2410.c2
-rw-r--r--drivers/usb/host/ohci.h2
17 files changed, 34 insertions, 23 deletions
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index 26ed757d22a6..5d1b12aad776 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -200,6 +200,7 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
.reset = ehci_init,
.start = ehci_run,
.stop = ehci_stop,
+ .shutdown = ehci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -268,6 +269,7 @@ MODULE_ALIAS("au1xxx-ehci");
static struct platform_driver ehci_hcd_au1xxx_driver = {
.probe = ehci_hcd_au1xxx_drv_probe,
.remove = ehci_hcd_au1xxx_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
/*.suspend = ehci_hcd_au1xxx_drv_suspend, */
/*.resume = ehci_hcd_au1xxx_drv_resume, */
.driver = {
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index d030516edfb9..1a915e982c1c 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -285,6 +285,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
.resume = ehci_bus_resume,
#endif
.stop = ehci_stop,
+ .shutdown = ehci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -329,6 +330,7 @@ MODULE_ALIAS("fsl-ehci");
static struct platform_driver ehci_fsl_driver = {
.probe = ehci_fsl_drv_probe,
.remove = ehci_fsl_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "fsl-ehci",
},
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index d63177a8eaea..1c54b303e5fc 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -292,21 +292,20 @@ static void ehci_watchdog (unsigned long param)
spin_unlock_irqrestore (&ehci->lock, flags);
}
-/* Reboot notifiers kick in for silicon on any bus (not just pci, etc).
+/* 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 int
-ehci_reboot (struct notifier_block *self, unsigned long code, void *null)
+static void
+ehci_shutdown (struct usb_hcd *hcd)
{
- struct ehci_hcd *ehci;
+ struct ehci_hcd *ehci;
- ehci = container_of (self, struct ehci_hcd, reboot_notifier);
+ ehci = hcd_to_ehci (hcd);
(void) ehci_halt (ehci);
/* make BIOS/etc use companion controller during reboot */
writel (0, &ehci->regs->configured_flag);
- return 0;
}
static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
@@ -381,7 +380,6 @@ static void ehci_stop (struct usb_hcd *hcd)
/* let companion controllers work when we aren't */
writel (0, &ehci->regs->configured_flag);
- unregister_reboot_notifier (&ehci->reboot_notifier);
remove_debug_files (ehci);
@@ -483,9 +481,6 @@ static int ehci_init(struct usb_hcd *hcd)
}
ehci->command = temp;
- ehci->reboot_notifier.notifier_call = ehci_reboot;
- register_reboot_notifier(&ehci->reboot_notifier);
-
return 0;
}
@@ -499,7 +494,6 @@ static int ehci_run (struct usb_hcd *hcd)
/* EHCI spec section 4.1 */
if ((retval = ehci_reset(ehci)) != 0) {
- unregister_reboot_notifier(&ehci->reboot_notifier);
ehci_mem_cleanup(ehci);
return retval;
}
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 6967ab71e282..e6a3bcddd55b 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -338,6 +338,7 @@ static const struct hc_driver ehci_pci_hc_driver = {
.resume = ehci_pci_resume,
#endif
.stop = ehci_stop,
+ .shutdown = ehci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -384,4 +385,5 @@ static struct pci_driver ehci_pci_driver = {
.suspend = usb_hcd_pci_suspend,
.resume = usb_hcd_pci_resume,
#endif
+ .shutdown = usb_hcd_pci_shutdown,
};
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 679c1cdcc915..1385ce2b3f0a 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -82,7 +82,6 @@ struct ehci_hcd { /* one per controller */
struct dma_pool *sitd_pool; /* sitd per split iso urb */
struct timer_list watchdog;
- struct notifier_block reboot_notifier;
unsigned long actions;
unsigned stamp;
unsigned long next_statechange;
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 33b75087bc0c..5a5bdf374d76 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -221,6 +221,7 @@ static const struct hc_driver ohci_at91_hc_driver = {
*/
.start = ohci_at91_start,
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -310,6 +311,7 @@ MODULE_ALIAS("at91_ohci");
static struct platform_driver ohci_hcd_at91_driver = {
.probe = ohci_hcd_at91_drv_probe,
.remove = ohci_hcd_at91_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
.suspend = ohci_hcd_at91_drv_suspend,
.resume = ohci_hcd_at91_drv_resume,
.driver = {
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index 44ed3a4c01ef..24e23c5783d8 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -269,6 +269,7 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
*/
.start = ohci_au1xxx_start,
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -335,6 +336,7 @@ static int ohci_hcd_au1xxx_drv_resume(struct platform_device *dev)
static struct platform_driver ohci_hcd_au1xxx_driver = {
.probe = ohci_hcd_au1xxx_drv_probe,
.remove = ohci_hcd_au1xxx_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
/*.suspend = ohci_hcd_au1xxx_drv_suspend, */
/*.resume = ohci_hcd_au1xxx_drv_resume, */
.driver = {
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index 1a1d320b7995..1bf5e7a4e735 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -128,6 +128,7 @@ static struct hc_driver ohci_ep93xx_hc_driver = {
.flags = HCD_USB11 | HCD_MEMORY,
.start = ohci_ep93xx_start,
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
.urb_enqueue = ohci_urb_enqueue,
.urb_dequeue = ohci_urb_dequeue,
.endpoint_disable = ohci_endpoint_disable,
@@ -203,6 +204,7 @@ static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev)
static struct platform_driver ohci_hcd_ep93xx_driver = {
.probe = ohci_hcd_ep93xx_drv_probe,
.remove = ohci_hcd_ep93xx_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_hcd_ep93xx_drv_suspend,
.resume = ohci_hcd_ep93xx_drv_resume,
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 7c3d8c60a60f..2c614af8f733 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -136,7 +136,6 @@ 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"
@@ -419,21 +418,20 @@ 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
+/* ohci_shutdown 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)
+static void
+ohci_shutdown (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci;
- ohci = container_of (block, struct ohci_hcd, reboot_notifier);
+ ohci = hcd_to_ohci (hcd);
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;
}
/*-------------------------------------------------------------------------*
@@ -504,7 +502,6 @@ static int ohci_init (struct ohci_hcd *ohci)
if ((ret = ohci_mem_init (ohci)) < 0)
ohci_stop (hcd);
else {
- register_reboot_notifier (&ohci->reboot_notifier);
create_debug_files (ohci);
}
@@ -800,7 +797,6 @@ 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-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
index f2c9161d6d6a..e121d97ed91c 100644
--- a/drivers/usb/host/ohci-lh7a404.c
+++ b/drivers/usb/host/ohci-lh7a404.c
@@ -174,6 +174,7 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
*/
.start = ohci_lh7a404_start,
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -241,6 +242,7 @@ static int ohci_hcd_lh7a404_drv_resume(struct platform_device *dev)
static struct platform_driver ohci_hcd_lh7a404_driver = {
.probe = ohci_hcd_lh7a404_drv_probe,
.remove = ohci_hcd_lh7a404_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
/*.suspend = ohci_hcd_lh7a404_drv_suspend, */
/*.resume = ohci_hcd_lh7a404_drv_resume, */
.driver = {
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index bfbe328a4788..d976614eebd3 100644
--- a/drivers/usb/host/ohci-mem.c
+++ b/drivers/usb/host/ohci-mem.c
@@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
ohci->next_statechange = jiffies;
spin_lock_init (&ohci->lock);
INIT_LIST_HEAD (&ohci->pending);
- ohci->reboot_notifier.notifier_call = ohci_reboot;
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 160cd4c58a03..9c02177de50a 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -447,6 +447,7 @@ static const struct hc_driver ohci_omap_hc_driver = {
.reset = ohci_omap_init,
.start = ohci_omap_start,
.stop = ohci_omap_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -532,6 +533,7 @@ static int ohci_omap_resume(struct platform_device *dev)
static struct platform_driver ohci_hcd_omap_driver = {
.probe = ohci_hcd_omap_drv_probe,
.remove = ohci_hcd_omap_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_omap_suspend,
.resume = ohci_omap_resume,
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index ef874443aa9f..3732db7d68eb 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -177,6 +177,7 @@ static const struct hc_driver ohci_pci_hc_driver = {
.reset = ohci_pci_reset,
.start = ohci_pci_start,
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
#ifdef CONFIG_PM
/* these suspend/resume entries are for upstream PCI glue ONLY */
@@ -232,6 +233,8 @@ static struct pci_driver ohci_pci_driver = {
.suspend = usb_hcd_pci_suspend,
.resume = usb_hcd_pci_resume,
#endif
+
+ .shutdown = usb_hcd_pci_shutdown,
};
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index 270aaaad8c6d..d9d1ae236bd5 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -148,6 +148,7 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = {
*/
.start = ohci_ppc_soc_start,
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -196,6 +197,7 @@ static int ohci_hcd_ppc_soc_drv_remove(struct platform_device *pdev)
static struct platform_driver ohci_hcd_ppc_soc_driver = {
.probe = ohci_hcd_ppc_soc_drv_probe,
.remove = ohci_hcd_ppc_soc_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
/*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/
/*.resume = ohci_hcd_ppc_soc_drv_resume,*/
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 2752d36c2a78..e176b04d7aeb 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -270,6 +270,7 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
*/
.start = ohci_pxa27x_start,
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -358,6 +359,7 @@ static int ohci_hcd_pxa27x_drv_resume(struct platform_device *pdev)
static struct platform_driver ohci_hcd_pxa27x_driver = {
.probe = ohci_hcd_pxa27x_drv_probe,
.remove = ohci_hcd_pxa27x_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_hcd_pxa27x_drv_suspend,
.resume = ohci_hcd_pxa27x_drv_resume,
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index cd37eddf7d42..59e436424d41 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -447,6 +447,7 @@ static const struct hc_driver ohci_s3c2410_hc_driver = {
*/
.start = ohci_s3c2410_start,
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -491,6 +492,7 @@ static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
static struct platform_driver ohci_hcd_s3c2410_driver = {
.probe = ohci_hcd_s3c2410_drv_probe,
.remove = ohci_hcd_s3c2410_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
/*.suspend = ohci_hcd_s3c2410_drv_suspend, */
/*.resume = ohci_hcd_s3c2410_drv_resume, */
.driver = {
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index caacf14371f5..650d1bf21c1d 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -389,8 +389,6 @@ struct ohci_hcd {
unsigned long next_statechange; /* suspend/resume */
u32 fminterval; /* saved register */
- struct notifier_block reboot_notifier;
-
unsigned long flags; /* for HC bugs */
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
#define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */