diff options
author | Yin Kangkai <kangkai.yin@intel.com> | 2011-01-27 23:04:35 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-02-03 19:57:43 -0500 |
commit | 148fc55fd0449683a1d15bf219ad8d8b6fa17545 (patch) | |
tree | afeb8c44c4993f6f5acd6228a1efbb8ff654874d | |
parent | 4e8ed7e4991a24860c0504c403f015a8201c2ffa (diff) |
USB: EHCI: fix scheduling while atomic during suspend
There is a msleep with spin lock held during ehci pci suspend, which will
cause kernel BUG: scheduling while atomic. Fix that.
[ 184.139620] BUG: scheduling while atomic: kworker/u:11/416/0x00000002
[ 184.139632] 4 locks held by kworker/u:11/416:
[ 184.139640] #0: (events_unbound){+.+.+.}, at: [<c104ddd4>] process_one_work+0x1b3/0x4cb
[ 184.139669] #1: ((&entry->work)){+.+.+.}, at: [<c104ddd4>] process_one_work+0x1b3/0x4cb
[ 184.139686] #2: (&__lockdep_no_validate__){+.+.+.}, at: [<c127cde3>] __device_suspend+0x2c/0x154
[ 184.139706] #3: (&(&ehci->lock)->rlock){-.-...}, at: [<c132f3d8>] ehci_pci_suspend+0x35/0x7b
[ 184.139725] Modules linked in: serio_raw pegasus joydev mrst_gfx(C) battery
[ 184.139748] irq event stamp: 52
[ 184.139753] hardirqs last enabled at (51): [<c14fdaac>] mutex_lock_nested+0x258/0x293
[ 184.139766] hardirqs last disabled at (52): [<c14fe7b4>] _raw_spin_lock_irqsave+0xf/0x3e
[ 184.139777] softirqs last enabled at (0): [<c10371c1>] copy_process+0x3d2/0x109d
[ 184.139789] softirqs last disabled at (0): [< (null)>] (null)
[ 184.139802] Pid: 416, comm: kworker/u:11 Tainted: G C 2.6.37-6.3-adaptation-oaktrail #37
[ 184.139809] Call Trace:
[ 184.139820] [<c102eeff>] __schedule_bug+0x5e/0x65
[ 184.139829] [<c14fbca5>] schedule+0xac/0xc4c
[ 184.139840] [<c11d4845>] ? string+0x37/0x8b
[ 184.139853] [<c1044f21>] ? lock_timer_base+0x1f/0x3e
[ 184.139863] [<c14fe7da>] ? _raw_spin_lock_irqsave+0x35/0x3e
[ 184.139876] [<c1061590>] ? trace_hardirqs_off+0xb/0xd
[ 184.139885] [<c14fccdc>] schedule_timeout+0x283/0x2d9
[ 184.139896] [<c104516f>] ? process_timeout+0x0/0xa
[ 184.139906] [<c14fcd47>] schedule_timeout_uninterruptible+0x15/0x17
[ 184.139916] [<c104566a>] msleep+0x10/0x16
[ 184.139926] [<c132f316>] ehci_adjust_port_wakeup_flags+0x69/0xf6
[ 184.139937] [<c132f3eb>] ehci_pci_suspend+0x48/0x7b
[ 184.139946] [<c1326587>] suspend_common+0x52/0xbb
[ 184.139956] [<c1326625>] hcd_pci_suspend+0x26/0x28
[ 184.139967] [<c11e7182>] pci_pm_suspend+0x5f/0xd0
[ 184.139976] [<c127ca3a>] pm_op+0x5d/0xf0
[ 184.139986] [<c127ceac>] __device_suspend+0xf5/0x154
[ 184.139996] [<c127d2c8>] async_suspend+0x16/0x3a
[ 184.140006] [<c1058f54>] async_run_entry_fn+0x89/0x111
[ 184.140016] [<c104deb6>] process_one_work+0x295/0x4cb
[ 184.140026] [<c1058ecb>] ? async_run_entry_fn+0x0/0x111
[ 184.140036] [<c104e3d0>] worker_thread+0x17f/0x298
[ 184.140045] [<c104e251>] ? worker_thread+0x0/0x298
[ 184.140055] [<c105277f>] kthread+0x64/0x69
[ 184.140064] [<c105271b>] ? kthread+0x0/0x69
[ 184.140075] [<c1002efa>] kernel_thread_helper+0x6/0x1a
Signed-off-by: Yin Kangkai <kangkai.yin@intel.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
CC: David Brownell <dbrownell@users.sourceforge.net>
CC: stable@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/host/ehci-au1xxx.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 7 | ||||
-rw-r--r-- | drivers/usb/host/ehci-pci.c | 2 |
3 files changed, 9 insertions, 2 deletions
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index 2baf8a849086..a869e3c103d3 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c | |||
@@ -227,8 +227,8 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev) | |||
227 | * mark HW unaccessible. The PM and USB cores make sure that | 227 | * mark HW unaccessible. The PM and USB cores make sure that |
228 | * the root hub is either suspended or stopped. | 228 | * the root hub is either suspended or stopped. |
229 | */ | 229 | */ |
230 | spin_lock_irqsave(&ehci->lock, flags); | ||
231 | ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev)); | 230 | ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev)); |
231 | spin_lock_irqsave(&ehci->lock, flags); | ||
232 | ehci_writel(ehci, 0, &ehci->regs->intr_enable); | 232 | ehci_writel(ehci, 0, &ehci->regs->intr_enable); |
233 | (void)ehci_readl(ehci, &ehci->regs->intr_enable); | 233 | (void)ehci_readl(ehci, &ehci->regs->intr_enable); |
234 | 234 | ||
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 796ea0c8900f..8a515f0d5988 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
@@ -111,6 +111,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, | |||
111 | { | 111 | { |
112 | int port; | 112 | int port; |
113 | u32 temp; | 113 | u32 temp; |
114 | unsigned long flags; | ||
114 | 115 | ||
115 | /* If remote wakeup is enabled for the root hub but disabled | 116 | /* If remote wakeup is enabled for the root hub but disabled |
116 | * for the controller, we must adjust all the port wakeup flags | 117 | * for the controller, we must adjust all the port wakeup flags |
@@ -120,6 +121,8 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, | |||
120 | if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup) | 121 | if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup) |
121 | return; | 122 | return; |
122 | 123 | ||
124 | spin_lock_irqsave(&ehci->lock, flags); | ||
125 | |||
123 | /* clear phy low-power mode before changing wakeup flags */ | 126 | /* clear phy low-power mode before changing wakeup flags */ |
124 | if (ehci->has_hostpc) { | 127 | if (ehci->has_hostpc) { |
125 | port = HCS_N_PORTS(ehci->hcs_params); | 128 | port = HCS_N_PORTS(ehci->hcs_params); |
@@ -131,7 +134,9 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, | |||
131 | temp = ehci_readl(ehci, hostpc_reg); | 134 | temp = ehci_readl(ehci, hostpc_reg); |
132 | ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg); | 135 | ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg); |
133 | } | 136 | } |
137 | spin_unlock_irqrestore(&ehci->lock, flags); | ||
134 | msleep(5); | 138 | msleep(5); |
139 | spin_lock_irqsave(&ehci->lock, flags); | ||
135 | } | 140 | } |
136 | 141 | ||
137 | port = HCS_N_PORTS(ehci->hcs_params); | 142 | port = HCS_N_PORTS(ehci->hcs_params); |
@@ -170,6 +175,8 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, | |||
170 | /* Does the root hub have a port wakeup pending? */ | 175 | /* Does the root hub have a port wakeup pending? */ |
171 | if (!suspending && (ehci_readl(ehci, &ehci->regs->status) & STS_PCD)) | 176 | if (!suspending && (ehci_readl(ehci, &ehci->regs->status) & STS_PCD)) |
172 | usb_hcd_resume_root_hub(ehci_to_hcd(ehci)); | 177 | usb_hcd_resume_root_hub(ehci_to_hcd(ehci)); |
178 | |||
179 | spin_unlock_irqrestore(&ehci->lock, flags); | ||
173 | } | 180 | } |
174 | 181 | ||
175 | static int ehci_bus_suspend (struct usb_hcd *hcd) | 182 | static int ehci_bus_suspend (struct usb_hcd *hcd) |
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index bed07d4aab06..07bb982e59f6 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c | |||
@@ -367,8 +367,8 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) | |||
367 | * mark HW unaccessible. The PM and USB cores make sure that | 367 | * mark HW unaccessible. The PM and USB cores make sure that |
368 | * the root hub is either suspended or stopped. | 368 | * the root hub is either suspended or stopped. |
369 | */ | 369 | */ |
370 | spin_lock_irqsave (&ehci->lock, flags); | ||
371 | ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup); | 370 | ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup); |
371 | spin_lock_irqsave (&ehci->lock, flags); | ||
372 | ehci_writel(ehci, 0, &ehci->regs->intr_enable); | 372 | ehci_writel(ehci, 0, &ehci->regs->intr_enable); |
373 | (void)ehci_readl(ehci, &ehci->regs->intr_enable); | 373 | (void)ehci_readl(ehci, &ehci->regs->intr_enable); |
374 | 374 | ||