X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=drivers%2Fpnp%2Fquirks.c;h=d049a2279feac460d0dda5e4a21f2471c1b059b0;hb=b66e1f11ebc429569a3784aaf64123633d9e3ed1;hp=4065139753b6c4b6e9e1becf06df11234bde8b5f;hpb=70ec75c5b8e0bda7a16fb387f91e08545f379a0e;p=~andy%2Flinux diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index 4065139753b..d049a2279fe 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include "base.h" @@ -50,8 +49,11 @@ static void quirk_awe32_resources(struct pnp_dev *dev) port2->max += 0x400; port3->min += 0x800; port3->max += 0x800; + dev_info(&dev->dev, + "AWE32 quirk - added ioports 0x%lx and 0x%lx\n", + (unsigned long)port2->min, + (unsigned long)port3->min); } - printk(KERN_INFO "pnp: AWE32 quirk - adding two ports\n"); } static void quirk_cmi8330_resources(struct pnp_dev *dev) @@ -74,7 +76,8 @@ static void quirk_cmi8330_resources(struct pnp_dev *dev) IORESOURCE_DMA_8BIT) dma->map = 0x000A; } - printk(KERN_INFO "pnp: CMI8330 quirk - fixing interrupts and dma\n"); + dev_info(&dev->dev, "CMI8330 quirk - forced possible IRQs to 5, 7, 10 " + "and DMA channels to 1, 3\n"); } static void quirk_sb16audio_resources(struct pnp_dev *dev) @@ -105,46 +108,79 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev) changed = 1; } if (changed) - printk(KERN_INFO - "pnp: SB audio device quirk - increasing port range\n"); + dev_info(&dev->dev, "SB audio device quirk - increased port range\n"); } -static void quirk_supermicro_h8dce_system(struct pnp_dev *dev) + +#include + +static void quirk_system_pci_resources(struct pnp_dev *dev) { - int i; - static struct dmi_system_id supermicro_h8dce[] = { - { - .ident = "Supermicro H8DCE", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"), - DMI_MATCH(DMI_PRODUCT_NAME, "H8DCE"), - }, - }, - { } - }; - - if (!dmi_check_system(supermicro_h8dce)) - return; + struct pci_dev *pdev = NULL; + struct resource *res; + resource_size_t pnp_start, pnp_end, pci_start, pci_end; + int i, j; /* - * On the Supermicro H8DCE, there's a system device with resources - * that overlap BAR 6 of the built-in SATA PCI adapter. If the PNP - * system device claims them, the sata_nv driver won't be able to. - * More details at: - * https://bugzilla.redhat.com/show_bug.cgi?id=280641 - * https://bugzilla.redhat.com/show_bug.cgi?id=313491 - * http://lkml.org/lkml/2008/1/9/449 - * http://thread.gmane.org/gmane.linux.acpi.devel/27312 + * Some BIOSes have PNP motherboard devices with resources that + * partially overlap PCI BARs. The PNP system driver claims these + * motherboard resources, which prevents the normal PCI driver from + * requesting them later. + * + * This patch disables the PNP resources that conflict with PCI BARs + * so they won't be claimed by the PNP system driver. */ - for (i = 0; i < PNP_MAX_MEM; i++) { - if (pnp_mem_valid(dev, i) && pnp_mem_len(dev, i) && - (pnp_mem_start(dev, i) & 0xdfef0000) == 0xdfef0000) { - dev_warn(&dev->dev, "disabling 0x%llx-0x%llx to prevent" - " conflict with sata_nv PCI device\n", - (unsigned long long) pnp_mem_start(dev, i), - (unsigned long long) (pnp_mem_start(dev, i) + - pnp_mem_len(dev, i) - 1)); - pnp_mem_flags(dev, i) = 0; + for_each_pci_dev(pdev) { + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM) || + pci_resource_len(pdev, i) == 0) + continue; + + pci_start = pci_resource_start(pdev, i); + pci_end = pci_resource_end(pdev, i); + for (j = 0; + (res = pnp_get_resource(dev, IORESOURCE_MEM, j)); + j++) { + if (res->flags & IORESOURCE_UNSET || + (res->start == 0 && res->end == 0)) + continue; + + pnp_start = res->start; + pnp_end = res->end; + + /* + * If the PNP region doesn't overlap the PCI + * region at all, there's no problem. + */ + if (pnp_end < pci_start || pnp_start > pci_end) + continue; + + /* + * If the PNP region completely encloses (or is + * at least as large as) the PCI region, that's + * also OK. For example, this happens when the + * PNP device describes a bridge with PCI + * behind it. + */ + if (pnp_start <= pci_start && + pnp_end >= pci_end) + continue; + + /* + * Otherwise, the PNP region overlaps *part* of + * the PCI region, and that might prevent a PCI + * driver from requesting its resources. + */ + dev_warn(&dev->dev, "mem resource " + "(0x%llx-0x%llx) overlaps %s BAR %d " + "(0x%llx-0x%llx), disabling\n", + (unsigned long long) pnp_start, + (unsigned long long) pnp_end, + pci_name(pdev), i, + (unsigned long long) pci_start, + (unsigned long long) pci_end); + res->flags = 0; + } } } } @@ -169,8 +205,8 @@ static struct pnp_fixup pnp_fixups[] = { {"CTL0043", quirk_sb16audio_resources}, {"CTL0044", quirk_sb16audio_resources}, {"CTL0045", quirk_sb16audio_resources}, - {"PNP0c01", quirk_supermicro_h8dce_system}, - {"PNP0c02", quirk_supermicro_h8dce_system}, + {"PNP0c01", quirk_system_pci_resources}, + {"PNP0c02", quirk_system_pci_resources}, {""} }; @@ -184,8 +220,8 @@ void pnp_fixup_device(struct pnp_dev *dev) quirk = pnp_fixups[i].quirk_function; #ifdef DEBUG - dev_dbg(&dev->dev, "calling quirk 0x%p", quirk); - print_fn_descriptor_symbol(": %s()\n", + dev_dbg(&dev->dev, "calling "); + print_fn_descriptor_symbol("%s()\n", (unsigned long) *quirk); #endif (*quirk)(dev);