diff mbox

[RFC,2/3] drivers: of: of_pci_get_host_bridge_resources() range parsing update

Message ID 1420644571-18928-3-git-send-email-lorenzo.pieralisi@arm.com (mailing list archive)
State New, archived
Delegated to: Bjorn Helgaas
Headers show

Commit Message

Lorenzo Pieralisi Jan. 7, 2015, 3:29 p.m. UTC
Some host controllers require local bus physical addresses to
programme inbound/outbound requests from the bus hierarchy to be routed
properly through the PCI bus beyond the host controller. Owing
to bus address size conversion, the bus local addresses may be different
from the addresses as seen from the CPU (which are translated by DT core
code), so the PCI range parsing function:

of_pci_get_host_bridge_resources()

should be augmented in order to store the range parser along
with the parsed resource so that the CPU untranslated address can
be retrieved by the driver from the corresponding PCI range if needed.

Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Liviu Dudau <liviu.dudau@arm.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Rob Herring <robh+dt@kernel.org>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
---
 drivers/of/of_pci.c        | 38 +++++++++++++++++++++++++++++---------
 include/linux/of_address.h |  5 +++++
 2 files changed, 34 insertions(+), 9 deletions(-)
diff mbox

Patch

diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index 6fbfe99..f0e576f 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -144,6 +144,7 @@  int of_pci_get_host_bridge_resources(struct device_node *dev,
 	struct resource *bus_range;
 	struct of_pci_range range;
 	struct of_pci_range_parser parser;
+	struct of_pci_resource *of_pci_res;
 	char range_type[4];
 	int err;
 	struct pci_host_bridge_window *window;
@@ -151,12 +152,14 @@  int of_pci_get_host_bridge_resources(struct device_node *dev,
 	if (io_base)
 		*io_base = (resource_size_t)OF_BAD_ADDR;
 
-	bus_range = kzalloc(sizeof(*bus_range), GFP_KERNEL);
-	if (!bus_range)
+	of_pci_res = kzalloc(sizeof(*of_pci_res), GFP_KERNEL);
+	if (!of_pci_res)
 		return -ENOMEM;
 
 	pr_info("PCI host bridge %s ranges:\n", dev->full_name);
 
+	bus_range = &of_pci_res->res;
+
 	err = of_pci_parse_bus_range(dev, bus_range);
 	if (err) {
 		bus_range->start = busno;
@@ -195,17 +198,29 @@  int of_pci_get_host_bridge_resources(struct device_node *dev,
 		if (range.cpu_addr == OF_BAD_ADDR || range.size == 0)
 			continue;
 
-		res = kzalloc(sizeof(struct resource), GFP_KERNEL);
-		if (!res) {
+		of_pci_res = kzalloc(sizeof(*of_pci_res), GFP_KERNEL);
+		if (!of_pci_res) {
 			err = -ENOMEM;
 			goto parse_failed;
 		}
+		res = &of_pci_res->res;
 
 		err = of_pci_range_to_resource(&range, dev, res);
 		if (err)
 			goto conversion_failed;
 
-		if (resource_type(res) == IORESOURCE_IO) {
+		/* Stash the range parser */
+		of_pci_res->parser = parser;
+		/*
+		 * for_each_of_pci_range increments the range pointer
+		 * in the parser, so that it is ready to parse the
+		 * following range while looping; rewind the range pointer
+		 * to its current value to pass it to the drivers with its
+		 * initial value.
+		 */
+		of_pci_res->parser.range -= parser.np;
+
+		if  (resource_type(res) == IORESOURCE_IO) {
 			if (!io_base) {
 				pr_err("I/O range found for %s. Please provide an io_base pointer to save CPU base address\n",
 					dev->full_name);
@@ -224,12 +239,17 @@  int of_pci_get_host_bridge_resources(struct device_node *dev,
 	return 0;
 
 conversion_failed:
-	kfree(res);
+	kfree(of_pci_res);
 parse_failed:
-	list_for_each_entry(window, resources, list)
-		kfree(window->res);
+	list_for_each_entry(window, resources, list) {
+		of_pci_res = container_of(window->res, struct of_pci_resource,
+					  res);
+		kfree(of_pci_res);
+	}
 	pci_free_resource_list(resources);
-	kfree(bus_range);
+	of_pci_res = container_of(bus_range, struct of_pci_resource,
+				  res);
+	kfree(of_pci_res);
 	return err;
 }
 EXPORT_SYMBOL_GPL(of_pci_get_host_bridge_resources);
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index d88e81b..e4005be 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -20,6 +20,11 @@  struct of_pci_range {
 	u32 flags;
 };
 
+struct of_pci_resource {
+	struct resource res;
+	struct of_pci_range_parser parser;
+};
+
 #define for_each_of_pci_range(parser, range) \
 	for (; of_pci_range_parser_one(parser, range);)