aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/of
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-10-09 15:03:49 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-09 15:03:49 -0400
commit80213c03c4151d900cf293ef0fc51f8d88495e14 (patch)
treeaf2422fa255aed96c23cef894e0adbf817f30c45 /drivers/of
parentea584595fc85e65796335033dfca25ed655cd0ed (diff)
parentf92d9ee3ab39841d1f29f2d1aa96ff7c74b36ee1 (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.c154
-rw-r--r--drivers/of/of_pci.c142
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}
294EXPORT_SYMBOL_GPL(of_pci_range_parser_one); 296EXPORT_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 */
313int 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
338invalid_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}
602EXPORT_SYMBOL(of_get_address); 649EXPORT_SYMBOL(of_get_address);
603 650
651#ifdef PCI_IOBASE
652struct io_range {
653 struct list_head list;
654 phys_addr_t start;
655 resource_size_t size;
656};
657
658static LIST_HEAD(io_range_list);
659static 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 */
666int __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
708end_register:
709 spin_unlock(&io_range_lock);
710#endif
711
712 return err;
713}
714
715phys_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
604unsigned long __weak pci_address_to_pio(phys_addr_t address) 740unsigned 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
612static int __of_address_to_resource(struct device_node *dev, 766static 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
6static inline int __of_pci_pci_compare(struct device_node *node, 8static 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}
90EXPORT_SYMBOL_GPL(of_pci_parse_bus_range); 92EXPORT_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 */
103int 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}
117EXPORT_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 */
139int 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
225conversion_failed:
226 kfree(res);
227parse_failed:
228 pci_free_resource_list(resources);
229 return err;
230}
231EXPORT_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
94static LIST_HEAD(of_pci_msi_chip_list); 236static LIST_HEAD(of_pci_msi_chip_list);