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

Commit 3fd47f06 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt
Browse files

powerpc/pci: Support per-aperture memory offset



The PCI core supports an offset per aperture nowadays but our arch
code still has a single offset per host bridge representing the
difference betwen CPU memory addresses and PCI MMIO addresses.

This is a problem as new machines and hypervisor versions are
coming out where the 64-bit windows will have a different offset
(basically mapped 1:1) from the 32-bit windows.

This fixes it by using separate offsets. In the long run, we probably
want to get rid of that intermediary struct pci_controller and have
those directly stored into the pci_host_bridge as they are parsed
but this will be a more invasive change.

Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 342d6666
Loading
Loading
Loading
Loading
+1 −5
Original line number Diff line number Diff line
@@ -39,11 +39,6 @@ struct pci_controller {
	resource_size_t io_base_phys;
	resource_size_t pci_io_size;

	/* Some machines (PReP) have a non 1:1 mapping of
	 * the PCI memory space in the CPU bus space
	 */
	resource_size_t pci_mem_offset;

	/* Some machines have a special region to forward the ISA
	 * "memory" cycles such as VGA memory regions. Left to 0
	 * if unsupported
@@ -86,6 +81,7 @@ struct pci_controller {
	 */
	struct resource	io_resource;
	struct resource mem_resources[3];
	resource_size_t mem_offset[3];
	int global_number;		/* PCI domain number */

	resource_size_t dma_window_base_cur;
+28 −69
Original line number Diff line number Diff line
@@ -786,22 +786,8 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
				hose->isa_mem_size = size;
			}

			/* We get the PCI/Mem offset from the first range or
			 * the, current one if the offset came from an ISA
			 * hole. If they don't match, bugger.
			 */
			if (memno == 0 ||
			    (isa_hole >= 0 && pci_addr != 0 &&
			     hose->pci_mem_offset == isa_mb))
				hose->pci_mem_offset = cpu_addr - pci_addr;
			else if (pci_addr != 0 &&
				 hose->pci_mem_offset != cpu_addr - pci_addr) {
				printk(KERN_INFO
				       " \\--> Skipped (offset mismatch) !\n");
				continue;
			}

			/* Build resource */
			hose->mem_offset[memno] = cpu_addr - pci_addr;
			res = &hose->mem_resources[memno++];
			res->flags = IORESOURCE_MEM;
			if (pci_space & 0x40000000)
@@ -817,20 +803,6 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
			res->child = NULL;
		}
	}

	/* If there's an ISA hole and the pci_mem_offset is -not- matching
	 * the ISA hole offset, then we need to remove the ISA hole from
	 * the resource list for that brige
	 */
	if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
		unsigned int next = isa_hole + 1;
		printk(KERN_INFO " Removing ISA hole at 0x%016llx\n", isa_mb);
		if (next < memno)
			memmove(&hose->mem_resources[isa_hole],
				&hose->mem_resources[next],
				sizeof(struct resource) * (memno - next));
		hose->mem_resources[--memno].flags = 0;
	}
}

/* Decide whether to display the domain number in /proc */
@@ -916,6 +888,7 @@ static int pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
	struct pci_controller *hose = pci_bus_to_host(bus);
	struct pci_dev *dev = bus->self;
	resource_size_t offset;
	struct pci_bus_region region;
	u16 command;
	int i;

@@ -925,10 +898,10 @@ static int pcibios_uninitialized_bridge_resource(struct pci_bus *bus,

	/* Job is a bit different between memory and IO */
	if (res->flags & IORESOURCE_MEM) {
		/* If the BAR is non-0 (res != pci_mem_offset) then it's probably been
		 * initialized by somebody
		 */
		if (res->start != hose->pci_mem_offset)
		pcibios_resource_to_bus(dev, &region, res);

		/* If the BAR is non-0 then it's probably been initialized */
		if (region.start != 0)
			return 0;

		/* The BAR is 0, let's check if memory decoding is enabled on
@@ -940,11 +913,11 @@ static int pcibios_uninitialized_bridge_resource(struct pci_bus *bus,

		/* Memory decoding is enabled and the BAR is 0. If any of the bridge
		 * resources covers that starting address (0 then it's good enough for
		 * us for memory
		 * us for memory space)
		 */
		for (i = 0; i < 3; i++) {
			if ((hose->mem_resources[i].flags & IORESOURCE_MEM) &&
			    hose->mem_resources[i].start == hose->pci_mem_offset)
			    hose->mem_resources[i].start == hose->mem_offset[i])
				return 0;
		}

@@ -1381,10 +1354,9 @@ static void __init pcibios_reserve_legacy_regions(struct pci_bus *bus)

 no_io:
	/* Check for memory */
	offset = hose->pci_mem_offset;
	pr_debug("hose mem offset: %016llx\n", (unsigned long long)offset);
	for (i = 0; i < 3; i++) {
		pres = &hose->mem_resources[i];
		offset = hose->mem_offset[i];
		if (!(pres->flags & IORESOURCE_MEM))
			continue;
		pr_debug("hose mem res: %pR\n", pres);
@@ -1524,6 +1496,7 @@ static void pcibios_setup_phb_resources(struct pci_controller *hose,
					struct list_head *resources)
{
	struct resource *res;
	resource_size_t offset;
	int i;

	/* Hookup PHB IO resource */
@@ -1533,51 +1506,37 @@ static void pcibios_setup_phb_resources(struct pci_controller *hose,
		printk(KERN_WARNING "PCI: I/O resource not set for host"
		       " bridge %s (domain %d)\n",
		       hose->dn->full_name, hose->global_number);
#ifdef CONFIG_PPC32
		/* Workaround for lack of IO resource only on 32-bit */
		res->start = (unsigned long)hose->io_base_virt - isa_io_base;
		res->end = res->start + IO_SPACE_LIMIT;
		res->flags = IORESOURCE_IO;
#endif /* CONFIG_PPC32 */
	}
	if (res->flags) {
		pr_debug("PCI: PHB IO resource    = %016llx-%016llx [%lx]\n",
	} else {
		offset = pcibios_io_space_offset(hose);

		pr_debug("PCI: PHB IO resource    = %08llx-%08llx [%lx] off 0x%08llx\n",
			 (unsigned long long)res->start,
			 (unsigned long long)res->end,
			 (unsigned long)res->flags);
		pci_add_resource_offset(resources, res, pcibios_io_space_offset(hose));

		pr_debug("PCI: PHB IO  offset     = %08lx\n",
			 (unsigned long)hose->io_base_virt - _IO_BASE);
			 (unsigned long)res->flags,
			 (unsigned long long)offset);
		pci_add_resource_offset(resources, res, offset);
	}

	/* Hookup PHB Memory resources */
	for (i = 0; i < 3; ++i) {
		res = &hose->mem_resources[i];
		if (!res->flags) {
			if (i > 0)
				continue;
			printk(KERN_ERR "PCI: Memory resource 0 not set for "
			       "host bridge %s (domain %d)\n",
			       hose->dn->full_name, hose->global_number);
#ifdef CONFIG_PPC32
			/* Workaround for lack of MEM resource only on 32-bit */
			res->start = hose->pci_mem_offset;
			res->end = (resource_size_t)-1LL;
			res->flags = IORESOURCE_MEM;
#endif /* CONFIG_PPC32 */
			continue;
		}
		if (res->flags) {
			pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n", i,
		offset = hose->mem_offset[i];


		pr_debug("PCI: PHB MEM resource %d = %08llx-%08llx [%lx] off 0x%08llx\n", i,
			 (unsigned long long)res->start,
			 (unsigned long long)res->end,
				 (unsigned long)res->flags);
			pci_add_resource_offset(resources, res, hose->pci_mem_offset);
		}
	}
			 (unsigned long)res->flags,
			 (unsigned long long)offset);

	pr_debug("PCI: PHB MEM offset     = %016llx\n",
		 (unsigned long long)hose->pci_mem_offset);
		pci_add_resource_offset(resources, res, offset);
	}
}

/*
+1 −1
Original line number Diff line number Diff line
@@ -295,7 +295,7 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
	case IOBASE_BRIDGE_NUMBER:
		return (long)hose->first_busno;
	case IOBASE_MEMORY:
		return (long)hose->pci_mem_offset;
		return (long)hose->mem_offset[0];
	case IOBASE_IO:
		return (long)hose->io_base_phys;
	case IOBASE_ISA_IO:
+1 −1
Original line number Diff line number Diff line
@@ -246,7 +246,7 @@ long sys_pciconfig_iobase(long which, unsigned long in_bus,
	case IOBASE_BRIDGE_NUMBER:
		return (long)hose->first_busno;
	case IOBASE_MEMORY:
		return (long)hose->pci_mem_offset;
		return (long)hose->mem_offset[0];
	case IOBASE_IO:
		return (long)hose->io_base_phys;
	case IOBASE_ISA_IO:
+0 −11
Original line number Diff line number Diff line
@@ -81,17 +81,6 @@
#define	MPC10X_MAPB_PCI_MEM_OFFSET	(MPC10X_MAPB_ISA_MEM_BASE -	\
					 MPC10X_MAPB_PCI_MEM_START)

/* Set hose members to values appropriate for the mem map used */
#define	MPC10X_SETUP_HOSE(hose, map) {					\
	(hose)->pci_mem_offset = MPC10X_MAP##map##_PCI_MEM_OFFSET;	\
	(hose)->io_space.start = MPC10X_MAP##map##_PCI_IO_START;	\
	(hose)->io_space.end = MPC10X_MAP##map##_PCI_IO_END;		\
	(hose)->mem_space.start = MPC10X_MAP##map##_PCI_MEM_START;	\
	(hose)->mem_space.end = MPC10X_MAP##map##_PCI_MEM_END;		\
	(hose)->io_base_virt = (void *)MPC10X_MAP##map##_ISA_IO_BASE;	\
}


/* Miscellaneous Configuration register offsets */
#define	MPC10X_CFG_PIR_REG		0x09
#define	MPC10X_CFG_PIR_HOST_BRIDGE	0x00
Loading