diff options
Diffstat (limited to 'drivers/pnp/quirks.c')
-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 | ||