diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2014-03-19 15:11:19 -0600 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2014-03-19 15:11:19 -0600 |
commit | 30723cbf6f7aec2ab4810bdc4bf12c5749a09e33 (patch) | |
tree | 840833435357419595fee44b2a06f9864f1458c9 /drivers/pci | |
parent | 91b4adc983d8e9975bc677c2b8395631edf7b92d (diff) | |
parent | f2e6027b816df3326d3f40d6ce55539a2f381529 (diff) | |
download | linux-30723cbf6f7aec2ab4810bdc4bf12c5749a09e33.tar.bz2 |
Merge branch 'pci/resource' into next
* pci/resource: (26 commits)
Revert "[PATCH] Insert GART region into resource map"
PCI: Log IDE resource quirk in dmesg
PCI: Change pci_bus_alloc_resource() type_mask to unsigned long
PCI: Check all IORESOURCE_TYPE_BITS in pci_bus_alloc_from_region()
resources: Set type in __request_region()
PCI: Don't check resource_size() in pci_bus_alloc_resource()
s390/PCI: Use generic pci_enable_resources()
tile PCI RC: Use default pcibios_enable_device()
sparc/PCI: Use default pcibios_enable_device() (Leon only)
sh/PCI: Use default pcibios_enable_device()
microblaze/PCI: Use default pcibios_enable_device()
alpha/PCI: Use default pcibios_enable_device()
PCI: Add "weak" generic pcibios_enable_device() implementation
PCI: Don't enable decoding if BAR hasn't been assigned an address
PCI: Mark 64-bit resource as IORESOURCE_UNSET if we only support 32-bit
PCI: Don't try to claim IORESOURCE_UNSET resources
PCI: Check IORESOURCE_UNSET before updating BAR
PCI: Don't clear IORESOURCE_UNSET when updating BAR
PCI: Mark resources as IORESOURCE_UNSET if we can't assign them
PCI: Remove pci_find_parent_resource() use for allocation
...
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/bus.c | 8 | ||||
-rw-r--r-- | drivers/pci/host-bridge.c | 8 | ||||
-rw-r--r-- | drivers/pci/pci.c | 46 | ||||
-rw-r--r-- | drivers/pci/probe.c | 17 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 5 | ||||
-rw-r--r-- | drivers/pci/rom.c | 2 | ||||
-rw-r--r-- | drivers/pci/setup-res.c | 37 |
7 files changed, 78 insertions, 45 deletions
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 00660cc502c5..fb8aed307c28 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -132,7 +132,7 @@ static void pci_clip_resource_to_region(struct pci_bus *bus, static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res, resource_size_t size, resource_size_t align, - resource_size_t min, unsigned int type_mask, + resource_size_t min, unsigned long type_mask, resource_size_t (*alignf)(void *, const struct resource *, resource_size_t, @@ -144,7 +144,7 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res, struct resource *r, avail; resource_size_t max; - type_mask |= IORESOURCE_IO | IORESOURCE_MEM; + type_mask |= IORESOURCE_TYPE_BITS; pci_bus_for_each_resource(bus, r, i) { if (!r) @@ -162,8 +162,6 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res, avail = *r; pci_clip_resource_to_region(bus, &avail, region); - if (!resource_size(&avail)) - continue; /* * "min" is typically PCIBIOS_MIN_IO or PCIBIOS_MIN_MEM to @@ -202,7 +200,7 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res, */ int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, resource_size_t size, resource_size_t align, - resource_size_t min, unsigned int type_mask, + resource_size_t min, unsigned long type_mask, resource_size_t (*alignf)(void *, const struct resource *, resource_size_t, diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c index 06ace6248c61..47aaf22d814e 100644 --- a/drivers/pci/host-bridge.c +++ b/drivers/pci/host-bridge.c @@ -32,11 +32,6 @@ void pci_set_host_bridge_release(struct pci_host_bridge *bridge, bridge->release_data = release_data; } -static bool resource_contains(struct resource *res1, struct resource *res2) -{ - return res1->start <= res2->start && res1->end >= res2->end; -} - void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region, struct resource *res) { @@ -45,9 +40,6 @@ void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region, resource_size_t offset = 0; list_for_each_entry(window, &bridge->windows, list) { - if (resource_type(res) != resource_type(window->res)) - continue; - if (resource_contains(window->res, res)) { offset = window->offset; break; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 505fbb670d6a..7325d43bf030 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -401,33 +401,40 @@ EXPORT_SYMBOL_GPL(pci_find_ht_capability); * @res: child resource record for which parent is sought * * For given resource region of given device, return the resource - * region of parent bus the given region is contained in or where - * it should be allocated from. + * region of parent bus the given region is contained in. */ struct resource * pci_find_parent_resource(const struct pci_dev *dev, struct resource *res) { const struct pci_bus *bus = dev->bus; + struct resource *r; int i; - struct resource *best = NULL, *r; pci_bus_for_each_resource(bus, r, i) { if (!r) continue; - if (res->start && !(res->start >= r->start && res->end <= r->end)) - continue; /* Not contained */ - if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM)) - continue; /* Wrong type */ - if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH)) - return r; /* Exact match */ - /* We can't insert a non-prefetch resource inside a prefetchable parent .. */ - if (r->flags & IORESOURCE_PREFETCH) - continue; - /* .. but we can put a prefetchable resource inside a non-prefetchable one */ - if (!best) - best = r; + if (res->start && resource_contains(r, res)) { + + /* + * If the window is prefetchable but the BAR is + * not, the allocator made a mistake. + */ + if (r->flags & IORESOURCE_PREFETCH && + !(res->flags & IORESOURCE_PREFETCH)) + return NULL; + + /* + * If we're below a transparent bridge, there may + * be both a positively-decoded aperture and a + * subtractively-decoded region that contain the BAR. + * We want the positively-decoded one, so this depends + * on pci_bus_for_each_resource() giving us those + * first. + */ + return r; + } } - return best; + return NULL; } /** @@ -1178,6 +1185,11 @@ int pci_load_and_free_saved_state(struct pci_dev *dev, } EXPORT_SYMBOL_GPL(pci_load_and_free_saved_state); +int __weak pcibios_enable_device(struct pci_dev *dev, int bars) +{ + return pci_enable_resources(dev, bars); +} + static int do_pci_enable_device(struct pci_dev *dev, int bars) { int err; @@ -4262,6 +4274,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev) "Rounding up size of resource #%d to %#llx.\n", i, (unsigned long long)size); } + r->flags |= IORESOURCE_UNSET; r->end = size - 1; r->start = 0; } @@ -4275,6 +4288,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev) r = &dev->resource[i]; if (!(r->flags & IORESOURCE_MEM)) continue; + r->flags |= IORESOURCE_UNSET; r->end = resource_size(r) - 1; r->start = 0; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 509494381a7a..ef09f5f2fe6c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -252,6 +252,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, /* Address above 32-bit boundary; disable the BAR */ pci_write_config_dword(dev, pos, 0); pci_write_config_dword(dev, pos + 4, 0); + res->flags |= IORESOURCE_UNSET; region.start = 0; region.end = sz64; bar_disabled = true; @@ -1107,10 +1108,10 @@ int pci_setup_device(struct pci_dev *dev) pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device); /* - * Do the ugly legacy mode stuff here rather than broken chip - * quirk code. Legacy mode ATA controllers have fixed - * addresses. These are not always echoed in BAR0-3, and - * BAR0-3 in a few cases contain junk! + * Do the ugly legacy mode stuff here rather than broken chip + * quirk code. Legacy mode ATA controllers have fixed + * addresses. These are not always echoed in BAR0-3, and + * BAR0-3 in a few cases contain junk! */ if (class == PCI_CLASS_STORAGE_IDE) { u8 progif; @@ -1121,11 +1122,15 @@ int pci_setup_device(struct pci_dev *dev) res = &dev->resource[0]; res->flags = LEGACY_IO_RESOURCE; pcibios_bus_to_resource(dev->bus, res, ®ion); + dev_info(&dev->dev, "legacy IDE quirk: reg 0x10: %pR\n", + res); region.start = 0x3F6; region.end = 0x3F6; res = &dev->resource[1]; res->flags = LEGACY_IO_RESOURCE; pcibios_bus_to_resource(dev->bus, res, ®ion); + dev_info(&dev->dev, "legacy IDE quirk: reg 0x14: %pR\n", + res); } if ((progif & 4) == 0) { region.start = 0x170; @@ -1133,11 +1138,15 @@ int pci_setup_device(struct pci_dev *dev) res = &dev->resource[2]; res->flags = LEGACY_IO_RESOURCE; pcibios_bus_to_resource(dev->bus, res, ®ion); + dev_info(&dev->dev, "legacy IDE quirk: reg 0x18: %pR\n", + res); region.start = 0x376; region.end = 0x376; res = &dev->resource[3]; res->flags = LEGACY_IO_RESOURCE; pcibios_bus_to_resource(dev->bus, res, ®ion); + dev_info(&dev->dev, "legacy IDE quirk: reg 0x1c: %pR\n", + res); } } break; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index ed2ed867c34c..e7292065a1b1 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -296,6 +296,7 @@ static void quirk_s3_64M(struct pci_dev *dev) struct resource *r = &dev->resource[0]; if ((r->start & 0x3ffffff) || r->end != r->start + 0x3ffffff) { + r->flags |= IORESOURCE_UNSET; r->start = 0; r->end = 0x3ffffff; } @@ -937,6 +938,8 @@ DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C static void quirk_dunord(struct pci_dev *dev) { struct resource *r = &dev->resource [1]; + + r->flags |= IORESOURCE_UNSET; r->start = 0; r->end = 0xffffff; } @@ -1740,6 +1743,7 @@ static void quirk_tc86c001_ide(struct pci_dev *dev) struct resource *r = &dev->resource[0]; if (r->start & 0x8) { + r->flags |= IORESOURCE_UNSET; r->start = 0; r->end = 0xf; } @@ -1769,6 +1773,7 @@ static void quirk_plx_pci9050(struct pci_dev *dev) dev_info(&dev->dev, "Re-allocating PLX PCI 9050 BAR %u to length 256 to avoid bit 7 bug\n", bar); + r->flags |= IORESOURCE_UNSET; r->start = 0; r->end = 0xff; } diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index 5d595724e5f4..c1839450d4d6 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -197,8 +197,10 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom) void pci_cleanup_rom(struct pci_dev *pdev) { struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; + if (res->flags & IORESOURCE_ROM_COPY) { kfree((void*)(unsigned long)res->start); + res->flags |= IORESOURCE_UNSET; res->flags &= ~IORESOURCE_ROM_COPY; res->start = 0; res->end = 0; diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 5c060b152ce6..7eed671d5586 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -44,6 +44,9 @@ void pci_update_resource(struct pci_dev *dev, int resno) if (!res->flags) return; + if (res->flags & IORESOURCE_UNSET) + return; + /* * Ignore non-moveable resources. This might be legacy resources for * which no functional BAR register exists or another important @@ -101,11 +104,6 @@ void pci_update_resource(struct pci_dev *dev, int resno) if (disable) pci_write_config_word(dev, PCI_COMMAND, cmd); - - res->flags &= ~IORESOURCE_UNSET; - dev_dbg(&dev->dev, "BAR %d: set to %pR (PCI address [%#llx-%#llx])\n", - resno, res, (unsigned long long)region.start, - (unsigned long long)region.end); } int pci_claim_resource(struct pci_dev *dev, int resource) @@ -113,18 +111,23 @@ int pci_claim_resource(struct pci_dev *dev, int resource) struct resource *res = &dev->resource[resource]; struct resource *root, *conflict; + if (res->flags & IORESOURCE_UNSET) { + dev_info(&dev->dev, "can't claim BAR %d %pR: no address assigned\n", + resource, res); + return -EINVAL; + } + root = pci_find_parent_resource(dev, res); if (!root) { - dev_info(&dev->dev, "no compatible bridge window for %pR\n", - res); + dev_info(&dev->dev, "can't claim BAR %d %pR: no compatible bridge window\n", + resource, res); return -EINVAL; } conflict = request_resource_conflict(root, res); if (conflict) { - dev_info(&dev->dev, - "address space collision: %pR conflicts with %s %pR\n", - res, conflict->name, conflict); + dev_info(&dev->dev, "can't claim BAR %d %pR: address conflict with %s %pR\n", + resource, res, conflict->name, conflict); return -EBUSY; } @@ -263,6 +266,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno) resource_size_t align, size; int ret; + res->flags |= IORESOURCE_UNSET; align = pci_resource_alignment(dev, res); if (!align) { dev_info(&dev->dev, "BAR %d: can't assign %pR " @@ -282,6 +286,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno) ret = pci_revert_fw_address(res, dev, resno, size); if (!ret) { + res->flags &= ~IORESOURCE_UNSET; res->flags &= ~IORESOURCE_STARTALIGN; dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res); if (resno < PCI_BRIDGE_RESOURCES) @@ -297,6 +302,7 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz resource_size_t new_size; int ret; + res->flags |= IORESOURCE_UNSET; if (!res->parent) { dev_info(&dev->dev, "BAR %d: can't reassign an unassigned resource %pR " "\n", resno, res); @@ -307,6 +313,7 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz new_size = resource_size(res) + addsize; ret = _pci_assign_resource(dev, resno, new_size, min_align); if (!ret) { + res->flags &= ~IORESOURCE_UNSET; res->flags &= ~IORESOURCE_STARTALIGN; dev_info(&dev->dev, "BAR %d: reassigned %pR\n", resno, res); if (resno < PCI_BRIDGE_RESOURCES) @@ -336,9 +343,15 @@ int pci_enable_resources(struct pci_dev *dev, int mask) (!(r->flags & IORESOURCE_ROM_ENABLE))) continue; + if (r->flags & IORESOURCE_UNSET) { + dev_err(&dev->dev, "can't enable device: BAR %d %pR not assigned\n", + i, r); + return -EINVAL; + } + if (!r->parent) { - dev_err(&dev->dev, "device not available " - "(can't reserve %pR)\n", r); + dev_err(&dev->dev, "can't enable device: BAR %d %pR not claimed\n", + i, r); return -EINVAL; } |