Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a031589b authored by Bjorn Helgaas's avatar Bjorn Helgaas Committed by Jesse Barnes
Browse files

sparc/PCI: convert devtree and arch-probed bus addresses to resource



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 ac1edcc5, 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: default avatarBjorn Helgaas <bhelgaas@google.com>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
parent c0f20946
Loading
Loading
Loading
Loading
+25 −35
Original line number Diff line number Diff line
@@ -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),