summaryrefslogtreecommitdiff
path: root/arch/sparc/kernel/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel/pci.c')
-rw-r--r--arch/sparc/kernel/pci.c67
1 files changed, 66 insertions, 1 deletions
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 539babf00bb2..b36365f49478 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -432,6 +432,11 @@ static void of_scan_pci_bridge(struct pci_pbm_info *pbm,
node->full_name);
return;
}
+
+ if (ofpci_verbose)
+ printk(" Bridge bus range [%u --> %u]\n",
+ busrange[0], busrange[1]);
+
ranges = of_get_property(node, "ranges", &len);
simba = 0;
if (ranges == NULL) {
@@ -451,6 +456,10 @@ static void of_scan_pci_bridge(struct pci_pbm_info *pbm,
pci_bus_insert_busn_res(bus, busrange[0], busrange[1]);
bus->bridge_ctl = 0;
+ if (ofpci_verbose)
+ printk(" Bridge ranges[%p] simba[%d]\n",
+ ranges, simba);
+
/* parse ranges property, or cook one up by hand for Simba */
/* PCI #address-cells == 3 and #size-cells == 2 always */
res = &dev->resource[PCI_BRIDGE_RESOURCES];
@@ -468,10 +477,29 @@ static void of_scan_pci_bridge(struct pci_pbm_info *pbm,
}
i = 1;
for (; len >= 32; len -= 32, ranges += 8) {
+ u64 start;
+
+ if (ofpci_verbose)
+ printk(" RAW Range[%08x:%08x:%08x:%08x:%08x:%08x:"
+ "%08x:%08x]\n",
+ ranges[0], ranges[1], ranges[2], ranges[3],
+ ranges[4], ranges[5], ranges[6], ranges[7]);
+
flags = pci_parse_of_flags(ranges[0]);
size = GET_64BIT(ranges, 6);
if (flags == 0 || size == 0)
continue;
+
+ /* On PCI-Express systems, PCI bridges that have no devices downstream
+ * have a bogus size value where the first 32-bit cell is 0xffffffff.
+ * This results in a bogus range where start + size overflows.
+ *
+ * Just skip these otherwise the kernel will complain when the resource
+ * tries to be claimed.
+ */
+ if (size >> 32 == 0xffffffff)
+ continue;
+
if (flags & IORESOURCE_IO) {
res = bus->resource[0];
if (res->flags) {
@@ -490,8 +518,13 @@ static void of_scan_pci_bridge(struct pci_pbm_info *pbm,
}
res->flags = flags;
- region.start = GET_64BIT(ranges, 1);
+ region.start = start = GET_64BIT(ranges, 1);
region.end = region.start + size - 1;
+
+ if (ofpci_verbose)
+ printk(" Using flags[%08x] start[%016llx] size[%016llx]\n",
+ flags, start, size);
+
pcibios_bus_to_resource(dev->bus, res, &region);
}
after_ranges:
@@ -584,6 +617,36 @@ static void pci_bus_register_of_sysfs(struct pci_bus *bus)
pci_bus_register_of_sysfs(child_bus);
}
+static void pci_claim_bus_resources(struct pci_bus *bus)
+{
+ struct pci_bus *child_bus;
+ struct pci_dev *dev;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ int i;
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ struct resource *r = &dev->resource[i];
+
+ if (r->parent || !r->start || !r->flags)
+ continue;
+
+ if (ofpci_verbose)
+ printk("PCI: Claiming %s: "
+ "Resource %d: %016llx..%016llx [%x]\n",
+ pci_name(dev), i,
+ (unsigned long long)r->start,
+ (unsigned long long)r->end,
+ (unsigned int)r->flags);
+
+ pci_claim_resource(dev, i);
+ }
+ }
+
+ list_for_each_entry(child_bus, &bus->children, node)
+ pci_claim_bus_resources(child_bus);
+}
+
struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
struct device *parent)
{
@@ -614,6 +677,8 @@ struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
pci_bus_add_devices(bus);
pci_bus_register_of_sysfs(bus);
+ pci_claim_bus_resources(bus);
+
return bus;
}