Patchwork [v2,6/7] sparc/PCI: convert devtree and arch-probed bus addresses to resource

login
register
mail settings
Submitter Bjorn Helgaas
Date March 16, 2012, 11:48 p.m.
Message ID <20120316234824.6649.79503.stgit@bhelgaas.mtv.corp.google.com>
Download mbox | patch
Permalink /patch/147288/
State Not Applicable
Delegated to: David Miller
Headers show

Comments

Bjorn Helgaas - March 16, 2012, 11:48 p.m.
Normal PCI enumeration via PCI config space uses __pci_read_base(), where
the PCI core applies any bus-to-resource offset.  But sparc sometimes
reads PCI config space itself, and sometimes it gets addresses from the
device tree.

In ac1edcc579b6, I converted sparc to use the PCI core bus-to-resource
conversion, but I missed these sparc-specific paths.  I don't have a way
to test it, but I think sparc is broken between that commit and this one.

This patch replaces the sparc-specific pci_resource_adjust() with the
generic pcibios_bus_to_resource() in the following paths:

    pci_cfg_fake_ranges()       (addresses read from PCI config)
    apb_fake_ranges()           (addresses computed based on PCI config)
    of_scan_pci_bridge()        (addresses from OF "ranges" property)

N.B.: Resources of non-P2P bridge devices are set in pci_parse_of_addrs()
and, as far as I can see, never converted to CPU addresses.  I do not
understand why these would be treated differently than bridge windows.

CC: "David S. Miller" <davem@davemloft.net>
CC: sparclinux@vger.kernel.org
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
---
 arch/sparc/kernel/pci.c |   60 ++++++++++++++++++++---------------------------
 1 files changed, 25 insertions(+), 35 deletions(-)


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

Patch

diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 253e8ac..fdaf218 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -375,13 +375,6 @@  static void __devinit apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p)
 	*last_p = last;
 }
 
-static void pci_resource_adjust(struct resource *res,
-				struct resource *root)
-{
-	res->start += root->start;
-	res->end += root->start;
-}
-
 /* For PCI bus devices which lack a 'ranges' property we interrogate
  * the config space values to set the resources, just like the generic
  * Linux PCI probing code does.
@@ -390,7 +383,8 @@  static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev,
 					  struct pci_bus *bus,
 					  struct pci_pbm_info *pbm)
 {
-	struct resource *res;
+	struct pci_bus_region region;
+	struct resource *res, res2;
 	u8 io_base_lo, io_limit_lo;
 	u16 mem_base_lo, mem_limit_lo;
 	unsigned long base, limit;
@@ -412,11 +406,14 @@  static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev,
 	res = bus->resource[0];
 	if (base <= limit) {
 		res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
+		res2.flags = res->flags;
+		region.start = base;
+		region.end = limit + 0xfff;
+		pcibios_bus_to_resource(dev, &res2, &region);
 		if (!res->start)
-			res->start = base;
+			res->start = res2.start;
 		if (!res->end)
-			res->end = limit + 0xfff;
-		pci_resource_adjust(res, &pbm->io_space);
+			res->end = res2.end;
 	}
 
 	pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
@@ -428,9 +425,9 @@  static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev,
 	if (base <= limit) {
 		res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) |
 			      IORESOURCE_MEM);
-		res->start = base;
-		res->end = limit + 0xfffff;
-		pci_resource_adjust(res, &pbm->mem_space);
+		region.start = base;
+		region.end = limit + 0xfffff;
+		pcibios_bus_to_resource(dev, res, &region);
 	}
 
 	pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
@@ -459,9 +456,9 @@  static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev,
 	if (base <= limit) {
 		res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) |
 			      IORESOURCE_MEM | IORESOURCE_PREFETCH);
-		res->start = base;
-		res->end = limit + 0xfffff;
-		pci_resource_adjust(res, &pbm->mem_space);
+		region.start = base;
+		region.end = limit + 0xfffff;
+		pcibios_bus_to_resource(dev, res, &region);
 	}
 }
 
@@ -472,6 +469,7 @@  static void __devinit apb_fake_ranges(struct pci_dev *dev,
 				      struct pci_bus *bus,
 				      struct pci_pbm_info *pbm)
 {
+	struct pci_bus_region region;
 	struct resource *res;
 	u32 first, last;
 	u8 map;
@@ -479,18 +477,18 @@  static void __devinit apb_fake_ranges(struct pci_dev *dev,
 	pci_read_config_byte(dev, APB_IO_ADDRESS_MAP, &map);
 	apb_calc_first_last(map, &first, &last);
 	res = bus->resource[0];
-	res->start = (first << 21);
-	res->end = (last << 21) + ((1 << 21) - 1);
 	res->flags = IORESOURCE_IO;
-	pci_resource_adjust(res, &pbm->io_space);
+	region.start = (first << 21);
+	region.end = (last << 21) + ((1 << 21) - 1);
+	pcibios_bus_to_resource(dev, res, &region);
 
 	pci_read_config_byte(dev, APB_MEM_ADDRESS_MAP, &map);
 	apb_calc_first_last(map, &first, &last);
 	res = bus->resource[1];
-	res->start = (first << 21);
-	res->end = (last << 21) + ((1 << 21) - 1);
 	res->flags = IORESOURCE_MEM;
-	pci_resource_adjust(res, &pbm->mem_space);
+	region.start = (first << 21);
+	region.end = (last << 21) + ((1 << 21) - 1);
+	pcibios_bus_to_resource(dev, res, &region);
 }
 
 static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm,
@@ -506,6 +504,7 @@  static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
 	struct pci_bus *bus;
 	const u32 *busrange, *ranges;
 	int len, i, simba;
+	struct pci_bus_region region;
 	struct resource *res;
 	unsigned int flags;
 	u64 size;
@@ -556,8 +555,6 @@  static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
 	}
 	i = 1;
 	for (; len >= 32; len -= 32, ranges += 8) {
-		struct resource *root;
-
 		flags = pci_parse_of_flags(ranges[0]);
 		size = GET_64BIT(ranges, 6);
 		if (flags == 0 || size == 0)
@@ -569,7 +566,6 @@  static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
 				       " for bridge %s\n", node->full_name);
 				continue;
 			}
-			root = &pbm->io_space;
 		} else {
 			if (i >= PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES) {
 				printk(KERN_ERR "PCI: too many memory ranges"
@@ -578,18 +574,12 @@  static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
 			}
 			res = bus->resource[i];
 			++i;
-			root = &pbm->mem_space;
 		}
 
-		res->start = GET_64BIT(ranges, 1);
-		res->end = res->start + size - 1;
 		res->flags = flags;
-
-		/* Another way to implement this would be to add an of_device
-		 * layer routine that can calculate a resource for a given
-		 * range property value in a PCI device.
-		 */
-		pci_resource_adjust(res, root);
+		region.start = GET_64BIT(ranges, 1);
+		region.end = region.start + size - 1;
+		pcibios_bus_to_resource(dev, res, &region);
 	}
 after_ranges:
 	sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),