forked from luck/tmp_suning_uos_patched
USB host: Fix lockdep warning in AMD PLL quirk
Booting latest kernel on my test machine produces a lockdep warning from the usb_amd_find_chipset_info() function: WARNING: at /data/lemmy/linux.trees.git/kernel/lockdep.c:2465 lockdep_trace_alloc+0x95/0xc2() Hardware name: Snook Modules linked in: Pid: 959, comm: work_for_cpu Not tainted 2.6.39-rc2+ #22 Call Trace: [<ffffffff8103c0d4>] warn_slowpath_common+0x80/0x98 [<ffffffff812387e6>] ? T.492+0x24/0x26 [<ffffffff8103c101>] warn_slowpath_null+0x15/0x17 [<ffffffff81068667>] lockdep_trace_alloc+0x95/0xc2 [<ffffffff810ed9ac>] slab_pre_alloc_hook+0x18/0x3b [<ffffffff810ef227>] kmem_cache_alloc_trace+0x25/0xba [<ffffffff812387e6>] T.492+0x24/0x26 [<ffffffff81238816>] pci_get_subsys+0x2e/0x73 [<ffffffff8123886c>] pci_get_device+0x11/0x13 [<ffffffff814082a9>] usb_amd_find_chipset_info+0x3f/0x18a ... It turns out that this function calls pci_get_device under a spin_lock with irqs disabled, but the pci_get_device function is only allowed in preemptible context. This patch fixes the warning by making all data-structure modifications on temporal storage and commiting this back into the visible structure at the end. While at it, this patch also moves the pci_dev_put calls out of the spinlocks because this function might sleep too. Signed-off-by: Joerg Roedel <joerg.roedel@amd.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
16a2f970f3
commit
9ab7927bb8
@ -84,65 +84,92 @@ int usb_amd_find_chipset_info(void)
|
||||
{
|
||||
u8 rev = 0;
|
||||
unsigned long flags;
|
||||
struct amd_chipset_info info;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&amd_lock, flags);
|
||||
|
||||
amd_chipset.probe_count++;
|
||||
/* probe only once */
|
||||
if (amd_chipset.probe_count > 1) {
|
||||
if (amd_chipset.probe_count > 0) {
|
||||
amd_chipset.probe_count++;
|
||||
spin_unlock_irqrestore(&amd_lock, flags);
|
||||
return amd_chipset.probe_result;
|
||||
}
|
||||
memset(&info, 0, sizeof(info));
|
||||
spin_unlock_irqrestore(&amd_lock, flags);
|
||||
|
||||
amd_chipset.smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL);
|
||||
if (amd_chipset.smbus_dev) {
|
||||
rev = amd_chipset.smbus_dev->revision;
|
||||
info.smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL);
|
||||
if (info.smbus_dev) {
|
||||
rev = info.smbus_dev->revision;
|
||||
if (rev >= 0x40)
|
||||
amd_chipset.sb_type = 1;
|
||||
info.sb_type = 1;
|
||||
else if (rev >= 0x30 && rev <= 0x3b)
|
||||
amd_chipset.sb_type = 3;
|
||||
info.sb_type = 3;
|
||||
} else {
|
||||
amd_chipset.smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
|
||||
0x780b, NULL);
|
||||
if (!amd_chipset.smbus_dev) {
|
||||
spin_unlock_irqrestore(&amd_lock, flags);
|
||||
return 0;
|
||||
info.smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
|
||||
0x780b, NULL);
|
||||
if (!info.smbus_dev) {
|
||||
ret = 0;
|
||||
goto commit;
|
||||
}
|
||||
rev = amd_chipset.smbus_dev->revision;
|
||||
|
||||
rev = info.smbus_dev->revision;
|
||||
if (rev >= 0x11 && rev <= 0x18)
|
||||
amd_chipset.sb_type = 2;
|
||||
info.sb_type = 2;
|
||||
}
|
||||
|
||||
if (amd_chipset.sb_type == 0) {
|
||||
if (amd_chipset.smbus_dev) {
|
||||
pci_dev_put(amd_chipset.smbus_dev);
|
||||
amd_chipset.smbus_dev = NULL;
|
||||
if (info.sb_type == 0) {
|
||||
if (info.smbus_dev) {
|
||||
pci_dev_put(info.smbus_dev);
|
||||
info.smbus_dev = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&amd_lock, flags);
|
||||
return 0;
|
||||
ret = 0;
|
||||
goto commit;
|
||||
}
|
||||
|
||||
amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x9601, NULL);
|
||||
if (amd_chipset.nb_dev) {
|
||||
amd_chipset.nb_type = 1;
|
||||
info.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x9601, NULL);
|
||||
if (info.nb_dev) {
|
||||
info.nb_type = 1;
|
||||
} else {
|
||||
amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
|
||||
0x1510, NULL);
|
||||
if (amd_chipset.nb_dev) {
|
||||
amd_chipset.nb_type = 2;
|
||||
} else {
|
||||
amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
|
||||
0x9600, NULL);
|
||||
if (amd_chipset.nb_dev)
|
||||
amd_chipset.nb_type = 3;
|
||||
info.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL);
|
||||
if (info.nb_dev) {
|
||||
info.nb_type = 2;
|
||||
} else {
|
||||
info.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
|
||||
0x9600, NULL);
|
||||
if (info.nb_dev)
|
||||
info.nb_type = 3;
|
||||
}
|
||||
}
|
||||
|
||||
amd_chipset.probe_result = 1;
|
||||
ret = info.probe_result = 1;
|
||||
printk(KERN_DEBUG "QUIRK: Enable AMD PLL fix\n");
|
||||
|
||||
spin_unlock_irqrestore(&amd_lock, flags);
|
||||
return amd_chipset.probe_result;
|
||||
commit:
|
||||
|
||||
spin_lock_irqsave(&amd_lock, flags);
|
||||
if (amd_chipset.probe_count > 0) {
|
||||
/* race - someone else was faster - drop devices */
|
||||
|
||||
/* Mark that we where here */
|
||||
amd_chipset.probe_count++;
|
||||
ret = amd_chipset.probe_result;
|
||||
|
||||
spin_unlock_irqrestore(&amd_lock, flags);
|
||||
|
||||
if (info.nb_dev)
|
||||
pci_dev_put(info.nb_dev);
|
||||
if (info.smbus_dev)
|
||||
pci_dev_put(info.smbus_dev);
|
||||
|
||||
} else {
|
||||
/* no race - commit the result */
|
||||
info.probe_count++;
|
||||
amd_chipset = info;
|
||||
spin_unlock_irqrestore(&amd_lock, flags);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_amd_find_chipset_info);
|
||||
|
||||
@ -284,6 +311,7 @@ EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_enable);
|
||||
|
||||
void usb_amd_dev_put(void)
|
||||
{
|
||||
struct pci_dev *nb, *smbus;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&amd_lock, flags);
|
||||
@ -294,20 +322,23 @@ void usb_amd_dev_put(void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (amd_chipset.nb_dev) {
|
||||
pci_dev_put(amd_chipset.nb_dev);
|
||||
amd_chipset.nb_dev = NULL;
|
||||
}
|
||||
if (amd_chipset.smbus_dev) {
|
||||
pci_dev_put(amd_chipset.smbus_dev);
|
||||
amd_chipset.smbus_dev = NULL;
|
||||
}
|
||||
/* save them to pci_dev_put outside of spinlock */
|
||||
nb = amd_chipset.nb_dev;
|
||||
smbus = amd_chipset.smbus_dev;
|
||||
|
||||
amd_chipset.nb_dev = NULL;
|
||||
amd_chipset.smbus_dev = NULL;
|
||||
amd_chipset.nb_type = 0;
|
||||
amd_chipset.sb_type = 0;
|
||||
amd_chipset.isoc_reqs = 0;
|
||||
amd_chipset.probe_result = 0;
|
||||
|
||||
spin_unlock_irqrestore(&amd_lock, flags);
|
||||
|
||||
if (nb)
|
||||
pci_dev_put(nb);
|
||||
if (smbus)
|
||||
pci_dev_put(smbus);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_amd_dev_put);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user