diff options
| author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-05-06 13:40:40 +1000 | 
|---|---|---|
| committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-05-06 13:40:40 +1000 | 
| commit | 3fd47f063b17692e843128e2abda3e697df42198 (patch) | |
| tree | d90a5bdd247b0cc5af7cf78cd18cf6e27a884f00 /arch/powerpc/kernel/pci-common.c | |
| parent | 342d6666f7276723e418b91c885b0c03f02eeaaf (diff) | |
| download | olio-linux-3.10-3fd47f063b17692e843128e2abda3e697df42198.tar.xz olio-linux-3.10-3fd47f063b17692e843128e2abda3e697df42198.zip  | |
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: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/pci-common.c')
| -rw-r--r-- | arch/powerpc/kernel/pci-common.c | 97 | 
1 files changed, 28 insertions, 69 deletions
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index cf00588b002..f5c5c90799a 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -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, ®ion, 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 */ -		} -		if (res->flags) { -			pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\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); +			continue;  		} -	} +		offset = hose->mem_offset[i]; -	pr_debug("PCI: PHB MEM offset     = %016llx\n", -		 (unsigned long long)hose->pci_mem_offset); + +		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, +			 (unsigned long long)offset); + +		pci_add_resource_offset(resources, res, offset); +	}  }  /*  |