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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




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@xxxxxxxx>
Cc: Liviu Dudau <liviu.dudau@xxxxxxx>
Cc: Bjorn Helgaas <bhelgaas@xxxxxxxxxx>
Cc: Rob Herring <robh+dt@xxxxxxxxxx>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@xxxxxxx>
---
 drivers/of/of_pci.c        | 38 +++++++++++++++++++++++++++++---------
 include/linux/of_address.h |  5 +++++
 2 files changed, 34 insertions(+), 9 deletions(-)

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);)
 
-- 
2.2.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux