aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2007-05-07 01:16:23 -0400
committerPaul Mackerras <paulus@samba.org>2007-05-07 21:54:19 -0400
commit11fbb00c67e19737757e747ec7dd3ba8d584f5d1 (patch)
tree72490560f34432c23abb3afc9b380f39af2c5047 /arch
parent0bd15c4b503b971024a3962b6a6b34c1af0628bf (diff)
[POWERPC] Cope with PCI host bridge I/O window not starting at 0
Currently our code to set up the data structures for a PCI host bridge and create the mapping for its I/O window assumes that the window starts at I/O port 0 on the PCI side. If this is not true, we can end up with I/O port numbers in the resources for PCI devices which will cause an oops if a driver tries to access them via inb/outb etc., because there is no mapping for the corresponding addresses. Normally the I/O window starts at 0, but there are some situations on partitioned machines with a hypervisor where the window may not start at 0. This fixes the problem by allocating space for the range from 0 to the end of the I/O window. That is, hose->io_base_virt contains the virtual address for I/O port 0 on the PCI bus, and thus the assumption that hose->io_base_virt - pci_io_base is the offset between the "global" I/O port numbers (those in the PCI device resources) and the I/O port numbers on the PCI bus is maintained. For PCI host bridges that are present at boot, we only map the portion of that range that correspond to the bridge's I/O window. For bridges added after boot we ioremap the range from 0 to the end of the I/O window, for now; in fact hot-added bridges should be using reserve_phb_iospace() and __ioremap_explicit (so they get sensible global port numbers), but we don't have the infrastructure yet to do that (basically a free_phb_iospace() routine plus appropriate locking). Interestingly, this makes the two arms of the if statement in get_bus_io_range do almost exactly the same thing; that function could now be simplified in a further patch. Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/kernel/pci_64.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 60d7d4baa227..706b7f3da5ff 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -1006,8 +1006,9 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
1006 1006
1007 switch ((pci_space >> 24) & 0x3) { 1007 switch ((pci_space >> 24) & 0x3) {
1008 case 1: /* I/O space */ 1008 case 1: /* I/O space */
1009 hose->io_base_phys = cpu_phys_addr; 1009 hose->io_base_phys = cpu_phys_addr - pci_addr;
1010 hose->pci_io_size = size; 1010 /* handle from 0 to top of I/O window */
1011 hose->pci_io_size = pci_addr + size;
1011 1012
1012 res = &hose->io_resource; 1013 res = &hose->io_resource;
1013 res->flags = IORESOURCE_IO; 1014 res->flags = IORESOURCE_IO;
@@ -1117,8 +1118,8 @@ static int get_bus_io_range(struct pci_bus *bus, unsigned long *start_phys,
1117 } else { 1118 } else {
1118 /* Root Bus */ 1119 /* Root Bus */
1119 res = &hose->io_resource; 1120 res = &hose->io_resource;
1120 *start_phys = hose->io_base_phys; 1121 *start_phys = hose->io_base_phys + res->start;
1121 *start_virt = (unsigned long) hose->io_base_virt; 1122 *start_virt = (unsigned long) hose->io_base_virt + res->start;
1122 if (res->end > res->start) 1123 if (res->end > res->start)
1123 *size = res->end - res->start + 1; 1124 *size = res->end - res->start + 1;
1124 else { 1125 else {