aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/probe.c
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2014-04-14 17:25:54 -0400
committerBjorn Helgaas <bhelgaas@google.com>2014-05-23 12:47:19 -0400
commit23b13bc76f359e99140baf083dc44314f4eb1b87 (patch)
tree4ad84a406118d70534b6b199e78646b052e57df9 /drivers/pci/probe.c
parentc96ec95315b9242ec423b8348984c394d27a8135 (diff)
PCI: Fail safely if we can't handle BARs larger than 4GB
We can only handle BARs larger than 4GB if both dma_addr_t and resource_size_t are 64 bits wide. If dma_addr_t is 32 bits, we can't represent all the bus addresses, and if resource_size_t is 32 bits, we can't represent all the CPU addresses. Previously we cleared res->flags (at "fail:") for resources that were too large. That means we think the BAR doesn't exist at all, which in turn means that we could enable the device even though we can't keep track of where the BAR is and we can't make sure it doesn't overlap something else. This preserves the type flags (MEM/IO) so we can keep from enabling the device. Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci/probe.c')
-rw-r--r--drivers/pci/probe.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index ef09f5f2fe6c..c7f8b717c2e7 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -171,6 +171,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
171 struct resource *res, unsigned int pos) 171 struct resource *res, unsigned int pos)
172{ 172{
173 u32 l, sz, mask; 173 u32 l, sz, mask;
174 u64 l64, sz64, mask64;
174 u16 orig_cmd; 175 u16 orig_cmd;
175 struct pci_bus_region region, inverted_region; 176 struct pci_bus_region region, inverted_region;
176 bool bar_too_big = false, bar_disabled = false; 177 bool bar_too_big = false, bar_disabled = false;
@@ -226,9 +227,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
226 } 227 }
227 228
228 if (res->flags & IORESOURCE_MEM_64) { 229 if (res->flags & IORESOURCE_MEM_64) {
229 u64 l64 = l; 230 l64 = l;
230 u64 sz64 = sz; 231 sz64 = sz;
231 u64 mask64 = mask | (u64)~0 << 32; 232 mask64 = mask | (u64)~0 << 32;
232 233
233 pci_read_config_dword(dev, pos + 4, &l); 234 pci_read_config_dword(dev, pos + 4, &l);
234 pci_write_config_dword(dev, pos + 4, ~0); 235 pci_write_config_dword(dev, pos + 4, ~0);
@@ -243,9 +244,13 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
243 if (!sz64) 244 if (!sz64)
244 goto fail; 245 goto fail;
245 246
246 if ((sizeof(resource_size_t) < 8) && (sz64 > 0x100000000ULL)) { 247 if ((sizeof(dma_addr_t) < 8 || sizeof(resource_size_t) < 8) &&
248 sz64 > 0x100000000ULL) {
249 res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
250 res->start = 0;
251 res->end = 0;
247 bar_too_big = true; 252 bar_too_big = true;
248 goto fail; 253 goto out;
249 } 254 }
250 255
251 if ((sizeof(resource_size_t) < 8) && l) { 256 if ((sizeof(resource_size_t) < 8) && l) {
@@ -303,7 +308,8 @@ out:
303 pci_write_config_word(dev, PCI_COMMAND, orig_cmd); 308 pci_write_config_word(dev, PCI_COMMAND, orig_cmd);
304 309
305 if (bar_too_big) 310 if (bar_too_big)
306 dev_err(&dev->dev, "reg 0x%x: can't handle 64-bit BAR\n", pos); 311 dev_err(&dev->dev, "reg 0x%x: can't handle BAR larger than 4GB (size %#010llx)\n",
312 pos, (unsigned long long) sz64);
307 if (res->flags && !bar_disabled) 313 if (res->flags && !bar_disabled)
308 dev_printk(KERN_DEBUG, &dev->dev, "reg 0x%x: %pR\n", pos, res); 314 dev_printk(KERN_DEBUG, &dev->dev, "reg 0x%x: %pR\n", pos, res);
309 315