diff options
Diffstat (limited to 'arch/sparc/kernel/pci.c')
| -rw-r--r-- | arch/sparc/kernel/pci.c | 67 | 
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, ®ion);  	}  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;  }  |