diff options
| -rw-r--r-- | drivers/pnp/quirks.c | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index e903b8c2b1fa..37993206ae5d 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c | |||
| @@ -108,6 +108,77 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev) | |||
| 108 | "pnp: SB audio device quirk - increasing port range\n"); | 108 | "pnp: SB audio device quirk - increasing port range\n"); |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | |||
| 112 | #include <linux/pci.h> | ||
| 113 | |||
| 114 | static void quirk_system_pci_resources(struct pnp_dev *dev) | ||
| 115 | { | ||
| 116 | struct pci_dev *pdev = NULL; | ||
| 117 | resource_size_t pnp_start, pnp_end, pci_start, pci_end; | ||
| 118 | int i, j; | ||
| 119 | |||
| 120 | /* | ||
| 121 | * Some BIOSes have PNP motherboard devices with resources that | ||
| 122 | * partially overlap PCI BARs. The PNP system driver claims these | ||
| 123 | * motherboard resources, which prevents the normal PCI driver from | ||
| 124 | * requesting them later. | ||
| 125 | * | ||
| 126 | * This patch disables the PNP resources that conflict with PCI BARs | ||
| 127 | * so they won't be claimed by the PNP system driver. | ||
| 128 | */ | ||
| 129 | for_each_pci_dev(pdev) { | ||
| 130 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { | ||
| 131 | if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM) || | ||
| 132 | pci_resource_len(pdev, i) == 0) | ||
| 133 | continue; | ||
| 134 | |||
| 135 | pci_start = pci_resource_start(pdev, i); | ||
| 136 | pci_end = pci_resource_end(pdev, i); | ||
| 137 | for (j = 0; j < PNP_MAX_MEM; j++) { | ||
| 138 | if (!pnp_mem_valid(dev, j) || | ||
| 139 | pnp_mem_len(dev, j) == 0) | ||
| 140 | continue; | ||
| 141 | |||
| 142 | pnp_start = pnp_mem_start(dev, j); | ||
| 143 | pnp_end = pnp_mem_end(dev, j); | ||
| 144 | |||
| 145 | /* | ||
| 146 | * If the PNP region doesn't overlap the PCI | ||
| 147 | * region at all, there's no problem. | ||
| 148 | */ | ||
| 149 | if (pnp_end < pci_start || pnp_start > pci_end) | ||
| 150 | continue; | ||
| 151 | |||
| 152 | /* | ||
| 153 | * If the PNP region completely encloses (or is | ||
| 154 | * at least as large as) the PCI region, that's | ||
| 155 | * also OK. For example, this happens when the | ||
| 156 | * PNP device describes a bridge with PCI | ||
| 157 | * behind it. | ||
| 158 | */ | ||
| 159 | if (pnp_start <= pci_start && | ||
| 160 | pnp_end >= pci_end) | ||
| 161 | continue; | ||
| 162 | |||
| 163 | /* | ||
| 164 | * Otherwise, the PNP region overlaps *part* of | ||
| 165 | * the PCI region, and that might prevent a PCI | ||
| 166 | * driver from requesting its resources. | ||
| 167 | */ | ||
| 168 | dev_warn(&dev->dev, "mem resource " | ||
| 169 | "(0x%llx-0x%llx) overlaps %s BAR %d " | ||
| 170 | "(0x%llx-0x%llx), disabling\n", | ||
| 171 | (unsigned long long) pnp_start, | ||
| 172 | (unsigned long long) pnp_end, | ||
| 173 | pci_name(pdev), i, | ||
| 174 | (unsigned long long) pci_start, | ||
| 175 | (unsigned long long) pci_end); | ||
| 176 | pnp_mem_flags(dev, j) = 0; | ||
| 177 | } | ||
| 178 | } | ||
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 111 | /* | 182 | /* |
| 112 | * PnP Quirks | 183 | * PnP Quirks |
| 113 | * Cards or devices that need some tweaking due to incomplete resource info | 184 | * Cards or devices that need some tweaking due to incomplete resource info |
| @@ -128,6 +199,8 @@ static struct pnp_fixup pnp_fixups[] = { | |||
| 128 | {"CTL0043", quirk_sb16audio_resources}, | 199 | {"CTL0043", quirk_sb16audio_resources}, |
| 129 | {"CTL0044", quirk_sb16audio_resources}, | 200 | {"CTL0044", quirk_sb16audio_resources}, |
| 130 | {"CTL0045", quirk_sb16audio_resources}, | 201 | {"CTL0045", quirk_sb16audio_resources}, |
| 202 | {"PNP0c01", quirk_system_pci_resources}, | ||
| 203 | {"PNP0c02", quirk_system_pci_resources}, | ||
| 131 | {""} | 204 | {""} |
| 132 | }; | 205 | }; |
| 133 | 206 | ||
