of/pci: Fix the conversion of IO ranges into IO resources
The ranges property for a host bridge controller in DT describes the mapping between the PCI bus address and the CPU physical address. The resources framework however expects that the IO resources start at a pseudo "port" address 0 (zero) and have a maximum size of IO_SPACE_LIMIT. The conversion from PCI ranges to resources failed to take that into account, returning a CPU physical address instead of a port number. Also fix all the drivers that depend on the old behaviour by fetching the CPU physical address based on the port number where it is being needed. Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> CC: Grant Likely <grant.likely@linaro.org> CC: Rob Herring <robh+dt@kernel.org> CC: Arnd Bergmann <arnd@arndb.de> CC: Thierry Reding <thierry.reding@gmail.com> CC: Simon Horman <horms@verge.net.au> CC: Catalin Marinas <catalin.marinas@arm.com>
This commit is contained in:
committed by
Bjorn Helgaas
parent
83bbde1cc0
commit
0b0b0893d4
+40
-4
@@ -295,14 +295,50 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_pci_range_parser_one);
|
||||
|
||||
void of_pci_range_to_resource(struct of_pci_range *range,
|
||||
struct device_node *np, struct resource *res)
|
||||
/*
|
||||
* of_pci_range_to_resource - Create a resource from an of_pci_range
|
||||
* @range: the PCI range that describes the resource
|
||||
* @np: device node where the range belongs to
|
||||
* @res: pointer to a valid resource that will be updated to
|
||||
* reflect the values contained in the range.
|
||||
*
|
||||
* Returns EINVAL if the range cannot be converted to resource.
|
||||
*
|
||||
* Note that if the range is an IO range, the resource will be converted
|
||||
* using pci_address_to_pio() which can fail if it is called too early or
|
||||
* if the range cannot be matched to any host bridge IO space (our case here).
|
||||
* To guard against that we try to register the IO range first.
|
||||
* If that fails we know that pci_address_to_pio() will do too.
|
||||
*/
|
||||
int of_pci_range_to_resource(struct of_pci_range *range,
|
||||
struct device_node *np, struct resource *res)
|
||||
{
|
||||
int err;
|
||||
res->flags = range->flags;
|
||||
res->start = range->cpu_addr;
|
||||
res->end = range->cpu_addr + range->size - 1;
|
||||
res->parent = res->child = res->sibling = NULL;
|
||||
res->name = np->full_name;
|
||||
|
||||
if (res->flags & IORESOURCE_IO) {
|
||||
unsigned long port;
|
||||
err = pci_register_io_range(range->cpu_addr, range->size);
|
||||
if (err)
|
||||
goto invalid_range;
|
||||
port = pci_address_to_pio(range->cpu_addr);
|
||||
if (port == (unsigned long)-1) {
|
||||
err = -EINVAL;
|
||||
goto invalid_range;
|
||||
}
|
||||
res->start = port;
|
||||
} else {
|
||||
res->start = range->cpu_addr;
|
||||
}
|
||||
res->end = res->start + range->size - 1;
|
||||
return 0;
|
||||
|
||||
invalid_range:
|
||||
res->start = (resource_size_t)OF_BAD_ADDR;
|
||||
res->end = (resource_size_t)OF_BAD_ADDR;
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user