diff options
author | Liviu Dudau <Liviu.Dudau@arm.com> | 2014-09-29 10:29:25 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2014-09-30 19:08:40 -0400 |
commit | 0b0b0893d49b34201a6c4416b1a707b580b91e3d (patch) | |
tree | 6705257f35735ce6bc8c85a760d49227905d6b13 | |
parent | 83bbde1cc0ec9d156b9271e29ffe0dc89c687feb (diff) |
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>
-rw-r--r-- | arch/arm/mach-integrator/pci_v3.c | 23 | ||||
-rw-r--r-- | drivers/of/address.c | 44 | ||||
-rw-r--r-- | drivers/pci/host/pci-tegra.c | 10 | ||||
-rw-r--r-- | drivers/pci/host/pcie-rcar.c | 21 | ||||
-rw-r--r-- | include/linux/of_address.h | 12 |
5 files changed, 80 insertions, 30 deletions
diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c index 05e1f73a1e8d..c186a17c2cff 100644 --- a/arch/arm/mach-integrator/pci_v3.c +++ b/arch/arm/mach-integrator/pci_v3.c | |||
@@ -660,6 +660,7 @@ static void __init pci_v3_preinit(void) | |||
660 | { | 660 | { |
661 | unsigned long flags; | 661 | unsigned long flags; |
662 | unsigned int temp; | 662 | unsigned int temp; |
663 | phys_addr_t io_address = pci_pio_to_address(io_mem.start); | ||
663 | 664 | ||
664 | pcibios_min_mem = 0x00100000; | 665 | pcibios_min_mem = 0x00100000; |
665 | 666 | ||
@@ -701,7 +702,7 @@ static void __init pci_v3_preinit(void) | |||
701 | /* | 702 | /* |
702 | * Setup window 2 - PCI IO | 703 | * Setup window 2 - PCI IO |
703 | */ | 704 | */ |
704 | v3_writel(V3_LB_BASE2, v3_addr_to_lb_base2(io_mem.start) | | 705 | v3_writel(V3_LB_BASE2, v3_addr_to_lb_base2(io_address) | |
705 | V3_LB_BASE_ENABLE); | 706 | V3_LB_BASE_ENABLE); |
706 | v3_writew(V3_LB_MAP2, v3_addr_to_lb_map2(0)); | 707 | v3_writew(V3_LB_MAP2, v3_addr_to_lb_map2(0)); |
707 | 708 | ||
@@ -742,6 +743,7 @@ static void __init pci_v3_preinit(void) | |||
742 | static void __init pci_v3_postinit(void) | 743 | static void __init pci_v3_postinit(void) |
743 | { | 744 | { |
744 | unsigned int pci_cmd; | 745 | unsigned int pci_cmd; |
746 | phys_addr_t io_address = pci_pio_to_address(io_mem.start); | ||
745 | 747 | ||
746 | pci_cmd = PCI_COMMAND_MEMORY | | 748 | pci_cmd = PCI_COMMAND_MEMORY | |
747 | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; | 749 | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; |
@@ -758,7 +760,7 @@ static void __init pci_v3_postinit(void) | |||
758 | "interrupt: %d\n", ret); | 760 | "interrupt: %d\n", ret); |
759 | #endif | 761 | #endif |
760 | 762 | ||
761 | register_isa_ports(non_mem.start, io_mem.start, 0); | 763 | register_isa_ports(non_mem.start, io_address, 0); |
762 | } | 764 | } |
763 | 765 | ||
764 | /* | 766 | /* |
@@ -867,33 +869,32 @@ static int __init pci_v3_probe(struct platform_device *pdev) | |||
867 | 869 | ||
868 | for_each_of_pci_range(&parser, &range) { | 870 | for_each_of_pci_range(&parser, &range) { |
869 | if (!range.flags) { | 871 | if (!range.flags) { |
870 | of_pci_range_to_resource(&range, np, &conf_mem); | 872 | ret = of_pci_range_to_resource(&range, np, &conf_mem); |
871 | conf_mem.name = "PCIv3 config"; | 873 | conf_mem.name = "PCIv3 config"; |
872 | } | 874 | } |
873 | if (range.flags & IORESOURCE_IO) { | 875 | if (range.flags & IORESOURCE_IO) { |
874 | of_pci_range_to_resource(&range, np, &io_mem); | 876 | ret = of_pci_range_to_resource(&range, np, &io_mem); |
875 | io_mem.name = "PCIv3 I/O"; | 877 | io_mem.name = "PCIv3 I/O"; |
876 | } | 878 | } |
877 | if ((range.flags & IORESOURCE_MEM) && | 879 | if ((range.flags & IORESOURCE_MEM) && |
878 | !(range.flags & IORESOURCE_PREFETCH)) { | 880 | !(range.flags & IORESOURCE_PREFETCH)) { |
879 | non_mem_pci = range.pci_addr; | 881 | non_mem_pci = range.pci_addr; |
880 | non_mem_pci_sz = range.size; | 882 | non_mem_pci_sz = range.size; |
881 | of_pci_range_to_resource(&range, np, &non_mem); | 883 | ret = of_pci_range_to_resource(&range, np, &non_mem); |
882 | non_mem.name = "PCIv3 non-prefetched mem"; | 884 | non_mem.name = "PCIv3 non-prefetched mem"; |
883 | } | 885 | } |
884 | if ((range.flags & IORESOURCE_MEM) && | 886 | if ((range.flags & IORESOURCE_MEM) && |
885 | (range.flags & IORESOURCE_PREFETCH)) { | 887 | (range.flags & IORESOURCE_PREFETCH)) { |
886 | pre_mem_pci = range.pci_addr; | 888 | pre_mem_pci = range.pci_addr; |
887 | pre_mem_pci_sz = range.size; | 889 | pre_mem_pci_sz = range.size; |
888 | of_pci_range_to_resource(&range, np, &pre_mem); | 890 | ret = of_pci_range_to_resource(&range, np, &pre_mem); |
889 | pre_mem.name = "PCIv3 prefetched mem"; | 891 | pre_mem.name = "PCIv3 prefetched mem"; |
890 | } | 892 | } |
891 | } | ||
892 | 893 | ||
893 | if (!conf_mem.start || !io_mem.start || | 894 | if (ret < 0) { |
894 | !non_mem.start || !pre_mem.start) { | 895 | dev_err(&pdev->dev, "missing ranges in device node\n"); |
895 | dev_err(&pdev->dev, "missing ranges in device node\n"); | 896 | return ret; |
896 | return -EINVAL; | 897 | } |
897 | } | 898 | } |
898 | 899 | ||
899 | pci_v3.map_irq = of_irq_parse_and_map_pci; | 900 | pci_v3.map_irq = of_irq_parse_and_map_pci; |
diff --git a/drivers/of/address.c b/drivers/of/address.c index 327a57410797..afdb78299f61 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c | |||
@@ -295,14 +295,50 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser, | |||
295 | } | 295 | } |
296 | EXPORT_SYMBOL_GPL(of_pci_range_parser_one); | 296 | EXPORT_SYMBOL_GPL(of_pci_range_parser_one); |
297 | 297 | ||
298 | void of_pci_range_to_resource(struct of_pci_range *range, | 298 | /* |
299 | struct device_node *np, struct resource *res) | 299 | * of_pci_range_to_resource - Create a resource from an of_pci_range |
300 | * @range: the PCI range that describes the resource | ||
301 | * @np: device node where the range belongs to | ||
302 | * @res: pointer to a valid resource that will be updated to | ||
303 | * reflect the values contained in the range. | ||
304 | * | ||
305 | * Returns EINVAL if the range cannot be converted to resource. | ||
306 | * | ||
307 | * Note that if the range is an IO range, the resource will be converted | ||
308 | * using pci_address_to_pio() which can fail if it is called too early or | ||
309 | * if the range cannot be matched to any host bridge IO space (our case here). | ||
310 | * To guard against that we try to register the IO range first. | ||
311 | * If that fails we know that pci_address_to_pio() will do too. | ||
312 | */ | ||
313 | int of_pci_range_to_resource(struct of_pci_range *range, | ||
314 | struct device_node *np, struct resource *res) | ||
300 | { | 315 | { |
316 | int err; | ||
301 | res->flags = range->flags; | 317 | res->flags = range->flags; |
302 | res->start = range->cpu_addr; | ||
303 | res->end = range->cpu_addr + range->size - 1; | ||
304 | res->parent = res->child = res->sibling = NULL; | 318 | res->parent = res->child = res->sibling = NULL; |
305 | res->name = np->full_name; | 319 | res->name = np->full_name; |
320 | |||
321 | if (res->flags & IORESOURCE_IO) { | ||
322 | unsigned long port; | ||
323 | err = pci_register_io_range(range->cpu_addr, range->size); | ||
324 | if (err) | ||
325 | goto invalid_range; | ||
326 | port = pci_address_to_pio(range->cpu_addr); | ||
327 | if (port == (unsigned long)-1) { | ||
328 | err = -EINVAL; | ||
329 | goto invalid_range; | ||
330 | } | ||
331 | res->start = port; | ||
332 | } else { | ||
333 | res->start = range->cpu_addr; | ||
334 | } | ||
335 | res->end = res->start + range->size - 1; | ||
336 | return 0; | ||
337 | |||
338 | invalid_range: | ||
339 | res->start = (resource_size_t)OF_BAD_ADDR; | ||
340 | res->end = (resource_size_t)OF_BAD_ADDR; | ||
341 | return err; | ||
306 | } | 342 | } |
307 | #endif /* CONFIG_PCI */ | 343 | #endif /* CONFIG_PCI */ |
308 | 344 | ||
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 0fb0fdb223d5..946935db62b6 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c | |||
@@ -626,13 +626,14 @@ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable); | |||
626 | static int tegra_pcie_setup(int nr, struct pci_sys_data *sys) | 626 | static int tegra_pcie_setup(int nr, struct pci_sys_data *sys) |
627 | { | 627 | { |
628 | struct tegra_pcie *pcie = sys_to_pcie(sys); | 628 | struct tegra_pcie *pcie = sys_to_pcie(sys); |
629 | phys_addr_t io_start = pci_pio_to_address(pcie->io.start); | ||
629 | 630 | ||
630 | pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset); | 631 | pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset); |
631 | pci_add_resource_offset(&sys->resources, &pcie->prefetch, | 632 | pci_add_resource_offset(&sys->resources, &pcie->prefetch, |
632 | sys->mem_offset); | 633 | sys->mem_offset); |
633 | pci_add_resource(&sys->resources, &pcie->busn); | 634 | pci_add_resource(&sys->resources, &pcie->busn); |
634 | 635 | ||
635 | pci_ioremap_io(nr * SZ_64K, pcie->io.start); | 636 | pci_ioremap_io(nr * SZ_64K, io_start); |
636 | 637 | ||
637 | return 1; | 638 | return 1; |
638 | } | 639 | } |
@@ -737,6 +738,7 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg) | |||
737 | static void tegra_pcie_setup_translations(struct tegra_pcie *pcie) | 738 | static void tegra_pcie_setup_translations(struct tegra_pcie *pcie) |
738 | { | 739 | { |
739 | u32 fpci_bar, size, axi_address; | 740 | u32 fpci_bar, size, axi_address; |
741 | phys_addr_t io_start = pci_pio_to_address(pcie->io.start); | ||
740 | 742 | ||
741 | /* Bar 0: type 1 extended configuration space */ | 743 | /* Bar 0: type 1 extended configuration space */ |
742 | fpci_bar = 0xfe100000; | 744 | fpci_bar = 0xfe100000; |
@@ -749,7 +751,7 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie) | |||
749 | /* Bar 1: downstream IO bar */ | 751 | /* Bar 1: downstream IO bar */ |
750 | fpci_bar = 0xfdfc0000; | 752 | fpci_bar = 0xfdfc0000; |
751 | size = resource_size(&pcie->io); | 753 | size = resource_size(&pcie->io); |
752 | axi_address = pcie->io.start; | 754 | axi_address = io_start; |
753 | afi_writel(pcie, axi_address, AFI_AXI_BAR1_START); | 755 | afi_writel(pcie, axi_address, AFI_AXI_BAR1_START); |
754 | afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ); | 756 | afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ); |
755 | afi_writel(pcie, fpci_bar, AFI_FPCI_BAR1); | 757 | afi_writel(pcie, fpci_bar, AFI_FPCI_BAR1); |
@@ -1520,7 +1522,9 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) | |||
1520 | } | 1522 | } |
1521 | 1523 | ||
1522 | for_each_of_pci_range(&parser, &range) { | 1524 | for_each_of_pci_range(&parser, &range) { |
1523 | of_pci_range_to_resource(&range, np, &res); | 1525 | err = of_pci_range_to_resource(&range, np, &res); |
1526 | if (err < 0) | ||
1527 | return err; | ||
1524 | 1528 | ||
1525 | switch (res.flags & IORESOURCE_TYPE_BITS) { | 1529 | switch (res.flags & IORESOURCE_TYPE_BITS) { |
1526 | case IORESOURCE_IO: | 1530 | case IORESOURCE_IO: |
diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c index 4884ee5e07d4..61158e03ab5f 100644 --- a/drivers/pci/host/pcie-rcar.c +++ b/drivers/pci/host/pcie-rcar.c | |||
@@ -323,6 +323,7 @@ static void rcar_pcie_setup_window(int win, struct rcar_pcie *pcie) | |||
323 | 323 | ||
324 | /* Setup PCIe address space mappings for each resource */ | 324 | /* Setup PCIe address space mappings for each resource */ |
325 | resource_size_t size; | 325 | resource_size_t size; |
326 | resource_size_t res_start; | ||
326 | u32 mask; | 327 | u32 mask; |
327 | 328 | ||
328 | rcar_pci_write_reg(pcie, 0x00000000, PCIEPTCTLR(win)); | 329 | rcar_pci_write_reg(pcie, 0x00000000, PCIEPTCTLR(win)); |
@@ -335,8 +336,13 @@ static void rcar_pcie_setup_window(int win, struct rcar_pcie *pcie) | |||
335 | mask = (roundup_pow_of_two(size) / SZ_128) - 1; | 336 | mask = (roundup_pow_of_two(size) / SZ_128) - 1; |
336 | rcar_pci_write_reg(pcie, mask << 7, PCIEPAMR(win)); | 337 | rcar_pci_write_reg(pcie, mask << 7, PCIEPAMR(win)); |
337 | 338 | ||
338 | rcar_pci_write_reg(pcie, upper_32_bits(res->start), PCIEPARH(win)); | 339 | if (res->flags & IORESOURCE_IO) |
339 | rcar_pci_write_reg(pcie, lower_32_bits(res->start), PCIEPARL(win)); | 340 | res_start = pci_pio_to_address(res->start); |
341 | else | ||
342 | res_start = res->start; | ||
343 | |||
344 | rcar_pci_write_reg(pcie, upper_32_bits(res_start), PCIEPARH(win)); | ||
345 | rcar_pci_write_reg(pcie, lower_32_bits(res_start), PCIEPARL(win)); | ||
340 | 346 | ||
341 | /* First resource is for IO */ | 347 | /* First resource is for IO */ |
342 | mask = PAR_ENABLE; | 348 | mask = PAR_ENABLE; |
@@ -363,9 +369,10 @@ static int rcar_pcie_setup(int nr, struct pci_sys_data *sys) | |||
363 | 369 | ||
364 | rcar_pcie_setup_window(i, pcie); | 370 | rcar_pcie_setup_window(i, pcie); |
365 | 371 | ||
366 | if (res->flags & IORESOURCE_IO) | 372 | if (res->flags & IORESOURCE_IO) { |
367 | pci_ioremap_io(nr * SZ_64K, res->start); | 373 | phys_addr_t io_start = pci_pio_to_address(res->start); |
368 | else | 374 | pci_ioremap_io(nr * SZ_64K, io_start); |
375 | } else | ||
369 | pci_add_resource(&sys->resources, res); | 376 | pci_add_resource(&sys->resources, res); |
370 | } | 377 | } |
371 | pci_add_resource(&sys->resources, &pcie->busn); | 378 | pci_add_resource(&sys->resources, &pcie->busn); |
@@ -935,8 +942,10 @@ static int rcar_pcie_probe(struct platform_device *pdev) | |||
935 | } | 942 | } |
936 | 943 | ||
937 | for_each_of_pci_range(&parser, &range) { | 944 | for_each_of_pci_range(&parser, &range) { |
938 | of_pci_range_to_resource(&range, pdev->dev.of_node, | 945 | err = of_pci_range_to_resource(&range, pdev->dev.of_node, |
939 | &pcie->res[win++]); | 946 | &pcie->res[win++]); |
947 | if (err < 0) | ||
948 | return err; | ||
940 | 949 | ||
941 | if (win > RCAR_PCI_MAX_RESOURCES) | 950 | if (win > RCAR_PCI_MAX_RESOURCES) |
942 | break; | 951 | break; |
diff --git a/include/linux/of_address.h b/include/linux/of_address.h index a38e1c846c23..8cb14eb393d6 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h | |||
@@ -134,9 +134,9 @@ extern const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, | |||
134 | u64 *size, unsigned int *flags); | 134 | u64 *size, unsigned int *flags); |
135 | extern int of_pci_address_to_resource(struct device_node *dev, int bar, | 135 | extern int of_pci_address_to_resource(struct device_node *dev, int bar, |
136 | struct resource *r); | 136 | struct resource *r); |
137 | extern void of_pci_range_to_resource(struct of_pci_range *range, | 137 | extern int of_pci_range_to_resource(struct of_pci_range *range, |
138 | struct device_node *np, | 138 | struct device_node *np, |
139 | struct resource *res); | 139 | struct resource *res); |
140 | #else /* CONFIG_OF_ADDRESS && CONFIG_PCI */ | 140 | #else /* CONFIG_OF_ADDRESS && CONFIG_PCI */ |
141 | static inline int of_pci_address_to_resource(struct device_node *dev, int bar, | 141 | static inline int of_pci_address_to_resource(struct device_node *dev, int bar, |
142 | struct resource *r) | 142 | struct resource *r) |
@@ -149,9 +149,9 @@ static inline const __be32 *of_get_pci_address(struct device_node *dev, | |||
149 | { | 149 | { |
150 | return NULL; | 150 | return NULL; |
151 | } | 151 | } |
152 | static inline void of_pci_range_to_resource(struct of_pci_range *range, | 152 | static inline int of_pci_range_to_resource(struct of_pci_range *range, |
153 | struct device_node *np, | 153 | struct device_node *np, |
154 | struct resource *res) | 154 | struct resource *res) |
155 | { | 155 | { |
156 | return -ENOSYS; | 156 | return -ENOSYS; |
157 | } | 157 | } |