Skip to content

Commit 23b13bc

Browse files
committed
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 <[email protected]>
1 parent c96ec95 commit 23b13bc

File tree

1 file changed

+12
-6
lines changed

1 file changed

+12
-6
lines changed

drivers/pci/probe.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
171171
struct resource *res, unsigned int pos)
172172
{
173173
u32 l, sz, mask;
174+
u64 l64, sz64, mask64;
174175
u16 orig_cmd;
175176
struct pci_bus_region region, inverted_region;
176177
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,
226227
}
227228

228229
if (res->flags & IORESOURCE_MEM_64) {
229-
u64 l64 = l;
230-
u64 sz64 = sz;
231-
u64 mask64 = mask | (u64)~0 << 32;
230+
l64 = l;
231+
sz64 = sz;
232+
mask64 = mask | (u64)~0 << 32;
232233

233234
pci_read_config_dword(dev, pos + 4, &l);
234235
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,
243244
if (!sz64)
244245
goto fail;
245246

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;
247252
bar_too_big = true;
248-
goto fail;
253+
goto out;
249254
}
250255

251256
if ((sizeof(resource_size_t) < 8) && l) {
@@ -303,7 +308,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
303308
pci_write_config_word(dev, PCI_COMMAND, orig_cmd);
304309

305310
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);
307313
if (res->flags && !bar_disabled)
308314
dev_printk(KERN_DEBUG, &dev->dev, "reg 0x%x: %pR\n", pos, res);
309315

0 commit comments

Comments
 (0)