|
@@ -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);
|
|
|
|