diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-09 15:03:49 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-09 15:03:49 -0400 |
| commit | 80213c03c4151d900cf293ef0fc51f8d88495e14 (patch) | |
| tree | af2422fa255aed96c23cef894e0adbf817f30c45 /drivers/of | |
| parent | ea584595fc85e65796335033dfca25ed655cd0ed (diff) | |
| parent | f92d9ee3ab39841d1f29f2d1aa96ff7c74b36ee1 (diff) | |
Merge tag 'pci-v3.18-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI updates from Bjorn Helgaas:
"The interesting things here are:
- Turn on Config Request Retry Status Software Visibility. This
caused hangs last time, but we included a fix this time.
- Rework PCI device configuration to use _HPP/_HPX more aggressively
- Allow PCI devices to be put into D3cold during system suspend
- Add arm64 PCI support
- Add APM X-Gene host bridge driver
- Add TI Keystone host bridge driver
- Add Xilinx AXI host bridge driver
More detailed summary:
Enumeration
- Check Vendor ID only for Config Request Retry Status (Rajat Jain)
- Enable Config Request Retry Status when supported (Rajat Jain)
- Add generic domain handling (Catalin Marinas)
- Generate uppercase hex for modalias interface class (Ricardo Ribalda Delgado)
Resource management
- Add missing MEM_64 mask in pci_assign_unassigned_bridge_resources() (Yinghai Lu)
- Increase IBM ipr SAS Crocodile BARs to at least system page size (Douglas Lehr)
PCI device hotplug
- Prevent NULL dereference during pciehp probe (Andreas Noever)
- Move _HPP & _HPX handling into core (Bjorn Helgaas)
- Apply _HPP to PCIe devices as well as PCI (Bjorn Helgaas)
- Apply _HPP/_HPX to display devices (Bjorn Helgaas)
- Preserve SERR & PARITY settings when applying _HPP/_HPX (Bjorn Helgaas)
- Preserve MPS and MRRS settings when applying _HPP/_HPX (Bjorn Helgaas)
- Apply _HPP/_HPX to all devices, not just hot-added ones (Bjorn Helgaas)
- Fix wait time in pciehp timeout message (Yinghai Lu)
- Add more pciehp Slot Control debug output (Yinghai Lu)
- Stop disabling pciehp notifications during init (Yinghai Lu)
MSI
- Remove arch_msi_check_device() (Alexander Gordeev)
- Rename pci_msi_check_device() to pci_msi_supported() (Alexander Gordeev)
- Move D0 check into pci_msi_check_device() (Alexander Gordeev)
- Remove unused kobject from struct msi_desc (Yijing Wang)
- Remove "pos" from the struct msi_desc msi_attrib (Yijing Wang)
- Add "msi_bus" sysfs MSI/MSI-X control for endpoints (Yijing Wang)
- Use __get_cached_msi_msg() instead of get_cached_msi_msg() (Yijing Wang)
- Use __read_msi_msg() instead of read_msi_msg() (Yijing Wang)
- Use __write_msi_msg() instead of write_msi_msg() (Yijing Wang)
Power management
- Drop unused runtime PM support code for PCIe ports (Rafael J. Wysocki)
- Allow PCI devices to be put into D3cold during system suspend (Rafael J. Wysocki)
AER
- Add additional AER error strings (Gong Chen)
- Make <linux/aer.h> standalone includable (Thierry Reding)
Virtualization
- Add ACS quirk for Solarflare SFC9120 & SFC9140 (Alex Williamson)
- Add ACS quirk for Intel 10G NICs (Alex Williamson)
- Add ACS quirk for AMD A88X southbridge (Marti Raudsepp)
- Remove unused pci_find_upstream_pcie_bridge(), pci_get_dma_source() (Alex Williamson)
- Add device flag helpers (Ethan Zhao)
- Assume all Mellanox devices have broken INTx masking (Gavin Shan)
Generic host bridge driver
- Fix ioport_map() for !CONFIG_GENERIC_IOMAP (Liviu Dudau)
- Add pci_register_io_range() and pci_pio_to_address() (Liviu Dudau)
- Define PCI_IOBASE as the base of virtual PCI IO space (Liviu Dudau)
- Fix the conversion of IO ranges into IO resources (Liviu Dudau)
- Add pci_get_new_domain_nr() and of_get_pci_domain_nr() (Liviu Dudau)
- Add support for parsing PCI host bridge resources from DT (Liviu Dudau)
- Add pci_remap_iospace() to map bus I/O resources (Liviu Dudau)
- Add arm64 architectural support for PCI (Liviu Dudau)
APM X-Gene
- Add APM X-Gene PCIe driver (Tanmay Inamdar)
- Add arm64 DT APM X-Gene PCIe device tree nodes (Tanmay Inamdar)
Freescale i.MX6
- Probe in module_init(), not fs_initcall() (Lucas Stach)
- Delay enabling reference clock for SS until it stabilizes (Tim Harvey)
Marvell MVEBU
- Fix uninitialized variable in mvebu_get_tgt_attr() (Thomas Petazzoni)
NVIDIA Tegra
- Make sure the PCIe PLL is really reset (Eric Yuen)
- Add error path tegra_msi_teardown_irq() cleanup (Jisheng Zhang)
- Fix extended configuration space mapping (Peter Daifuku)
- Implement resource hierarchy (Thierry Reding)
- Clear CLKREQ# enable on port disable (Thierry Reding)
- Add Tegra124 support (Thierry Reding)
ST Microelectronics SPEAr13xx
- Pass config resource through reg property (Pratyush Anand)
Synopsys DesignWare
- Use NULL instead of false (Fabio Estevam)
- Parse bus-range property from devicetree (Lucas Stach)
- Use pci_create_root_bus() instead of pci_scan_root_bus() (Lucas Stach)
- Remove pci_assign_unassigned_resources() (Lucas Stach)
- Check private_data validity in single place (Lucas Stach)
- Setup and clear exactly one MSI at a time (Lucas Stach)
- Remove open-coded bitmap operations (Lucas Stach)
- Fix configuration base address when using 'reg' (Minghuan Lian)
- Fix IO resource end address calculation (Minghuan Lian)
- Rename get_msi_data() to get_msi_addr() (Minghuan Lian)
- Add get_msi_data() to pcie_host_ops (Minghuan Lian)
- Add support for v3.65 hardware (Murali Karicheri)
- Fold struct pcie_port_info into struct pcie_port (Pratyush Anand)
TI Keystone
- Add TI Keystone PCIe driver (Murali Karicheri)
- Limit MRSS for all downstream devices (Murali Karicheri)
- Assume controller is already in RC mode (Murali Karicheri)
- Set device ID based on SoC to support multiple ports (Murali Karicheri)
Xilinx AXI
- Add Xilinx AXI PCIe driver (Srikanth Thokala)
- Fix xilinx_pcie_assign_msi() return value test (Dan Carpenter)
Miscellaneous
- Clean up whitespace (Quentin Lambert)
- Remove assignments from "if" conditions (Quentin Lambert)
- Move PCI_VENDOR_ID_VMWARE to pci_ids.h (Francesco Ruggeri)
- x86: Mark DMI tables as initialization data (Mathias Krause)
- x86: Move __init annotation to the correct place (Mathias Krause)
- x86: Mark constants of pci_mmcfg_nvidia_mcp55() as __initconst (Mathias Krause)
- x86: Constify pci_mmcfg_probes[] array (Mathias Krause)
- x86: Mark PCI BIOS initialization code as such (Mathias Krause)
- Parenthesize PCI_DEVID and PCI_VPD_LRDT_ID parameters (Megan Kamiya)
- Remove unnecessary variable in pci_add_dynid() (Tobias Klauser)"
* tag 'pci-v3.18-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (109 commits)
arm64: dts: Add APM X-Gene PCIe device tree nodes
PCI: Add ACS quirk for AMD A88X southbridge devices
PCI: xgene: Add APM X-Gene PCIe driver
PCI: designware: Remove open-coded bitmap operations
PCI/MSI: Remove unnecessary temporary variable
PCI/MSI: Use __write_msi_msg() instead of write_msi_msg()
MSI/powerpc: Use __read_msi_msg() instead of read_msi_msg()
PCI/MSI: Use __get_cached_msi_msg() instead of get_cached_msi_msg()
PCI/MSI: Add "msi_bus" sysfs MSI/MSI-X control for endpoints
PCI/MSI: Remove "pos" from the struct msi_desc msi_attrib
PCI/MSI: Remove unused kobject from struct msi_desc
PCI/MSI: Rename pci_msi_check_device() to pci_msi_supported()
PCI/MSI: Move D0 check into pci_msi_check_device()
PCI/MSI: Remove arch_msi_check_device()
irqchip: armada-370-xp: Remove arch_msi_check_device()
PCI/MSI/PPC: Remove arch_msi_check_device()
arm64: Add architectural support for PCI
PCI: Add pci_remap_iospace() to map bus I/O resources
of/pci: Add support for parsing PCI host bridge resources from DT
of/pci: Add pci_get_new_domain_nr() and of_get_pci_domain_nr()
...
Conflicts:
arch/arm64/boot/dts/apm-storm.dtsi
Diffstat (limited to 'drivers/of')
| -rw-r--r-- | drivers/of/address.c | 154 | ||||
| -rw-r--r-- | drivers/of/of_pci.c | 142 |
2 files changed, 296 insertions, 0 deletions
diff --git a/drivers/of/address.c b/drivers/of/address.c index e3718250d66e..afdb78299f61 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c | |||
| @@ -5,6 +5,8 @@ | |||
| 5 | #include <linux/module.h> | 5 | #include <linux/module.h> |
| 6 | #include <linux/of_address.h> | 6 | #include <linux/of_address.h> |
| 7 | #include <linux/pci_regs.h> | 7 | #include <linux/pci_regs.h> |
| 8 | #include <linux/sizes.h> | ||
| 9 | #include <linux/slab.h> | ||
| 8 | #include <linux/string.h> | 10 | #include <linux/string.h> |
| 9 | 11 | ||
| 10 | /* Max address size we deal with */ | 12 | /* Max address size we deal with */ |
| @@ -293,6 +295,51 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser, | |||
| 293 | } | 295 | } |
| 294 | EXPORT_SYMBOL_GPL(of_pci_range_parser_one); | 296 | EXPORT_SYMBOL_GPL(of_pci_range_parser_one); |
| 295 | 297 | ||
| 298 | /* | ||
| 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) | ||
| 315 | { | ||
| 316 | int err; | ||
| 317 | res->flags = range->flags; | ||
| 318 | res->parent = res->child = res->sibling = NULL; | ||
| 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; | ||
| 342 | } | ||
| 296 | #endif /* CONFIG_PCI */ | 343 | #endif /* CONFIG_PCI */ |
| 297 | 344 | ||
| 298 | /* | 345 | /* |
| @@ -601,12 +648,119 @@ const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, | |||
| 601 | } | 648 | } |
| 602 | EXPORT_SYMBOL(of_get_address); | 649 | EXPORT_SYMBOL(of_get_address); |
| 603 | 650 | ||
| 651 | #ifdef PCI_IOBASE | ||
| 652 | struct io_range { | ||
| 653 | struct list_head list; | ||
| 654 | phys_addr_t start; | ||
| 655 | resource_size_t size; | ||
| 656 | }; | ||
| 657 | |||
| 658 | static LIST_HEAD(io_range_list); | ||
| 659 | static DEFINE_SPINLOCK(io_range_lock); | ||
| 660 | #endif | ||
| 661 | |||
| 662 | /* | ||
| 663 | * Record the PCI IO range (expressed as CPU physical address + size). | ||
| 664 | * Return a negative value if an error has occured, zero otherwise | ||
| 665 | */ | ||
| 666 | int __weak pci_register_io_range(phys_addr_t addr, resource_size_t size) | ||
| 667 | { | ||
| 668 | int err = 0; | ||
| 669 | |||
| 670 | #ifdef PCI_IOBASE | ||
| 671 | struct io_range *range; | ||
| 672 | resource_size_t allocated_size = 0; | ||
| 673 | |||
| 674 | /* check if the range hasn't been previously recorded */ | ||
| 675 | spin_lock(&io_range_lock); | ||
| 676 | list_for_each_entry(range, &io_range_list, list) { | ||
| 677 | if (addr >= range->start && addr + size <= range->start + size) { | ||
| 678 | /* range already registered, bail out */ | ||
| 679 | goto end_register; | ||
| 680 | } | ||
| 681 | allocated_size += range->size; | ||
| 682 | } | ||
| 683 | |||
| 684 | /* range not registed yet, check for available space */ | ||
| 685 | if (allocated_size + size - 1 > IO_SPACE_LIMIT) { | ||
| 686 | /* if it's too big check if 64K space can be reserved */ | ||
| 687 | if (allocated_size + SZ_64K - 1 > IO_SPACE_LIMIT) { | ||
| 688 | err = -E2BIG; | ||
| 689 | goto end_register; | ||
| 690 | } | ||
| 691 | |||
| 692 | size = SZ_64K; | ||
| 693 | pr_warn("Requested IO range too big, new size set to 64K\n"); | ||
| 694 | } | ||
| 695 | |||
| 696 | /* add the range to the list */ | ||
| 697 | range = kzalloc(sizeof(*range), GFP_KERNEL); | ||
| 698 | if (!range) { | ||
| 699 | err = -ENOMEM; | ||
| 700 | goto end_register; | ||
| 701 | } | ||
| 702 | |||
| 703 | range->start = addr; | ||
| 704 | range->size = size; | ||
| 705 | |||
| 706 | list_add_tail(&range->list, &io_range_list); | ||
| 707 | |||
| 708 | end_register: | ||
| 709 | spin_unlock(&io_range_lock); | ||
| 710 | #endif | ||
| 711 | |||
| 712 | return err; | ||
| 713 | } | ||
| 714 | |||
| 715 | phys_addr_t pci_pio_to_address(unsigned long pio) | ||
| 716 | { | ||
| 717 | phys_addr_t address = (phys_addr_t)OF_BAD_ADDR; | ||
| 718 | |||
| 719 | #ifdef PCI_IOBASE | ||
| 720 | struct io_range *range; | ||
| 721 | resource_size_t allocated_size = 0; | ||
| 722 | |||
| 723 | if (pio > IO_SPACE_LIMIT) | ||
| 724 | return address; | ||
| 725 | |||
| 726 | spin_lock(&io_range_lock); | ||
| 727 | list_for_each_entry(range, &io_range_list, list) { | ||
| 728 | if (pio >= allocated_size && pio < allocated_size + range->size) { | ||
| 729 | address = range->start + pio - allocated_size; | ||
| 730 | break; | ||
| 731 | } | ||
| 732 | allocated_size += range->size; | ||
| 733 | } | ||
| 734 | spin_unlock(&io_range_lock); | ||
| 735 | #endif | ||
| 736 | |||
| 737 | return address; | ||
| 738 | } | ||
| 739 | |||
| 604 | unsigned long __weak pci_address_to_pio(phys_addr_t address) | 740 | unsigned long __weak pci_address_to_pio(phys_addr_t address) |
| 605 | { | 741 | { |
| 742 | #ifdef PCI_IOBASE | ||
| 743 | struct io_range *res; | ||
| 744 | resource_size_t offset = 0; | ||
| 745 | unsigned long addr = -1; | ||
| 746 | |||
| 747 | spin_lock(&io_range_lock); | ||
| 748 | list_for_each_entry(res, &io_range_list, list) { | ||
| 749 | if (address >= res->start && address < res->start + res->size) { | ||
| 750 | addr = res->start - address + offset; | ||
| 751 | break; | ||
| 752 | } | ||
| 753 | offset += res->size; | ||
| 754 | } | ||
| 755 | spin_unlock(&io_range_lock); | ||
| 756 | |||
| 757 | return addr; | ||
| 758 | #else | ||
| 606 | if (address > IO_SPACE_LIMIT) | 759 | if (address > IO_SPACE_LIMIT) |
| 607 | return (unsigned long)-1; | 760 | return (unsigned long)-1; |
| 608 | 761 | ||
| 609 | return (unsigned long) address; | 762 | return (unsigned long) address; |
| 763 | #endif | ||
| 610 | } | 764 | } |
| 611 | 765 | ||
| 612 | static int __of_address_to_resource(struct device_node *dev, | 766 | static int __of_address_to_resource(struct device_node *dev, |
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index 848199633798..8882b467be95 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c | |||
| @@ -1,7 +1,9 @@ | |||
| 1 | #include <linux/kernel.h> | 1 | #include <linux/kernel.h> |
| 2 | #include <linux/export.h> | 2 | #include <linux/export.h> |
| 3 | #include <linux/of.h> | 3 | #include <linux/of.h> |
| 4 | #include <linux/of_address.h> | ||
| 4 | #include <linux/of_pci.h> | 5 | #include <linux/of_pci.h> |
| 6 | #include <linux/slab.h> | ||
| 5 | 7 | ||
| 6 | static inline int __of_pci_pci_compare(struct device_node *node, | 8 | static inline int __of_pci_pci_compare(struct device_node *node, |
| 7 | unsigned int data) | 9 | unsigned int data) |
| @@ -89,6 +91,146 @@ int of_pci_parse_bus_range(struct device_node *node, struct resource *res) | |||
| 89 | } | 91 | } |
| 90 | EXPORT_SYMBOL_GPL(of_pci_parse_bus_range); | 92 | EXPORT_SYMBOL_GPL(of_pci_parse_bus_range); |
| 91 | 93 | ||
| 94 | /** | ||
| 95 | * This function will try to obtain the host bridge domain number by | ||
| 96 | * finding a property called "linux,pci-domain" of the given device node. | ||
| 97 | * | ||
| 98 | * @node: device tree node with the domain information | ||
| 99 | * | ||
| 100 | * Returns the associated domain number from DT in the range [0-0xffff], or | ||
| 101 | * a negative value if the required property is not found. | ||
| 102 | */ | ||
| 103 | int of_get_pci_domain_nr(struct device_node *node) | ||
| 104 | { | ||
| 105 | const __be32 *value; | ||
| 106 | int len; | ||
| 107 | u16 domain; | ||
| 108 | |||
| 109 | value = of_get_property(node, "linux,pci-domain", &len); | ||
| 110 | if (!value || len < sizeof(*value)) | ||
| 111 | return -EINVAL; | ||
| 112 | |||
| 113 | domain = (u16)be32_to_cpup(value); | ||
| 114 | |||
| 115 | return domain; | ||
| 116 | } | ||
| 117 | EXPORT_SYMBOL_GPL(of_get_pci_domain_nr); | ||
| 118 | |||
| 119 | #if defined(CONFIG_OF_ADDRESS) | ||
| 120 | /** | ||
| 121 | * of_pci_get_host_bridge_resources - Parse PCI host bridge resources from DT | ||
| 122 | * @dev: device node of the host bridge having the range property | ||
| 123 | * @busno: bus number associated with the bridge root bus | ||
| 124 | * @bus_max: maximum number of buses for this bridge | ||
| 125 | * @resources: list where the range of resources will be added after DT parsing | ||
| 126 | * @io_base: pointer to a variable that will contain on return the physical | ||
| 127 | * address for the start of the I/O range. Can be NULL if the caller doesn't | ||
| 128 | * expect IO ranges to be present in the device tree. | ||
| 129 | * | ||
| 130 | * It is the caller's job to free the @resources list. | ||
| 131 | * | ||
| 132 | * This function will parse the "ranges" property of a PCI host bridge device | ||
| 133 | * node and setup the resource mapping based on its content. It is expected | ||
| 134 | * that the property conforms with the Power ePAPR document. | ||
| 135 | * | ||
| 136 | * It returns zero if the range parsing has been successful or a standard error | ||
| 137 | * value if it failed. | ||
| 138 | */ | ||
| 139 | int of_pci_get_host_bridge_resources(struct device_node *dev, | ||
| 140 | unsigned char busno, unsigned char bus_max, | ||
| 141 | struct list_head *resources, resource_size_t *io_base) | ||
| 142 | { | ||
| 143 | struct resource *res; | ||
| 144 | struct resource *bus_range; | ||
| 145 | struct of_pci_range range; | ||
| 146 | struct of_pci_range_parser parser; | ||
| 147 | char range_type[4]; | ||
| 148 | int err; | ||
| 149 | |||
| 150 | if (io_base) | ||
| 151 | *io_base = (resource_size_t)OF_BAD_ADDR; | ||
| 152 | |||
| 153 | bus_range = kzalloc(sizeof(*bus_range), GFP_KERNEL); | ||
| 154 | if (!bus_range) | ||
| 155 | return -ENOMEM; | ||
| 156 | |||
| 157 | pr_info("PCI host bridge %s ranges:\n", dev->full_name); | ||
| 158 | |||
| 159 | err = of_pci_parse_bus_range(dev, bus_range); | ||
| 160 | if (err) { | ||
| 161 | bus_range->start = busno; | ||
| 162 | bus_range->end = bus_max; | ||
| 163 | bus_range->flags = IORESOURCE_BUS; | ||
| 164 | pr_info(" No bus range found for %s, using %pR\n", | ||
| 165 | dev->full_name, bus_range); | ||
| 166 | } else { | ||
| 167 | if (bus_range->end > bus_range->start + bus_max) | ||
| 168 | bus_range->end = bus_range->start + bus_max; | ||
| 169 | } | ||
| 170 | pci_add_resource(resources, bus_range); | ||
| 171 | |||
| 172 | /* Check for ranges property */ | ||
| 173 | err = of_pci_range_parser_init(&parser, dev); | ||
| 174 | if (err) | ||
| 175 | goto parse_failed; | ||
| 176 | |||
| 177 | pr_debug("Parsing ranges property...\n"); | ||
| 178 | for_each_of_pci_range(&parser, &range) { | ||
| 179 | /* Read next ranges element */ | ||
| 180 | if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO) | ||
| 181 | snprintf(range_type, 4, " IO"); | ||
| 182 | else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM) | ||
| 183 | snprintf(range_type, 4, "MEM"); | ||
| 184 | else | ||
| 185 | snprintf(range_type, 4, "err"); | ||
| 186 | pr_info(" %s %#010llx..%#010llx -> %#010llx\n", range_type, | ||
| 187 | range.cpu_addr, range.cpu_addr + range.size - 1, | ||
| 188 | range.pci_addr); | ||
| 189 | |||
| 190 | /* | ||
| 191 | * If we failed translation or got a zero-sized region | ||
| 192 | * then skip this range | ||
| 193 | */ | ||
| 194 | if (range.cpu_addr == OF_BAD_ADDR || range.size == 0) | ||
| 195 | continue; | ||
| 196 | |||
| 197 | res = kzalloc(sizeof(struct resource), GFP_KERNEL); | ||
| 198 | if (!res) { | ||
| 199 | err = -ENOMEM; | ||
| 200 | goto parse_failed; | ||
| 201 | } | ||
| 202 | |||
| 203 | err = of_pci_range_to_resource(&range, dev, res); | ||
| 204 | if (err) | ||
| 205 | goto conversion_failed; | ||
| 206 | |||
| 207 | if (resource_type(res) == IORESOURCE_IO) { | ||
| 208 | if (!io_base) { | ||
| 209 | pr_err("I/O range found for %s. Please provide an io_base pointer to save CPU base address\n", | ||
| 210 | dev->full_name); | ||
| 211 | err = -EINVAL; | ||
| 212 | goto conversion_failed; | ||
| 213 | } | ||
| 214 | if (*io_base != (resource_size_t)OF_BAD_ADDR) | ||
| 215 | pr_warn("More than one I/O resource converted for %s. CPU base address for old range lost!\n", | ||
| 216 | dev->full_name); | ||
| 217 | *io_base = range.cpu_addr; | ||
| 218 | } | ||
| 219 | |||
| 220 | pci_add_resource_offset(resources, res, res->start - range.pci_addr); | ||
| 221 | } | ||
| 222 | |||
| 223 | return 0; | ||
| 224 | |||
| 225 | conversion_failed: | ||
| 226 | kfree(res); | ||
| 227 | parse_failed: | ||
| 228 | pci_free_resource_list(resources); | ||
| 229 | return err; | ||
| 230 | } | ||
| 231 | EXPORT_SYMBOL_GPL(of_pci_get_host_bridge_resources); | ||
| 232 | #endif /* CONFIG_OF_ADDRESS */ | ||
| 233 | |||
| 92 | #ifdef CONFIG_PCI_MSI | 234 | #ifdef CONFIG_PCI_MSI |
| 93 | 235 | ||
| 94 | static LIST_HEAD(of_pci_msi_chip_list); | 236 | static LIST_HEAD(of_pci_msi_chip_list); |
