aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2006-12-08 01:14:33 -0500
committerPaul Mackerras <paulus@samba.org>2006-12-08 01:21:06 -0500
commit396a1a5832ae28ce2c4150f98827873cbef554f5 (patch)
tree26d72bdf3765184f64e6231e7962152272584401 /arch/ppc
parentf09b5ce0184da6a83bac7fafda4e624629272b37 (diff)
[POWERPC] Fix mmap of PCI resource with hack for X
The powerpc version of pci_resource_to_user() and associated hooks used by /proc/bus/pci and /sys/bus/pci mmap have been broken for some time on machines that don't have a 1:1 mapping of devices (basically on non-PowerMacs) and have PCI devices above 32 bits. This attempts to fix it as well as possible. The rule is supposed to be that pci_resource_to_user() always converts the resources back into a BAR values since that's what the /proc interface was supposed to deal with. However, for X to work on platforms where PCI MMIO is not mapped 1:1, it became a habit of platforms like powerpc to pass "fixed up" values there since X expects to be able to use values from /proc/bus/pci/devices as offsets to mmap of /dev/mem... So we keep that contraption here, causing also /sys/*/resource to expose fully absolute MMIO addresses instead of BAR values, which is ugly, but should still work as long as those are only used to calculate alignment within a page. X is still broken when built 32 bits on machines where PCI MMIO can be above 32-bit space unfortunately. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/ppc')
-rw-r--r--arch/ppc/kernel/pci.c41
1 files changed, 32 insertions, 9 deletions
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 63808e01cb0b..5e723c4c2571 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -879,7 +879,7 @@ pci_resource_to_bus(struct pci_dev *pdev, struct resource *res)
879 879
880 880
881static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, 881static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
882 unsigned long *offset, 882 resource_size_t *offset,
883 enum pci_mmap_state mmap_state) 883 enum pci_mmap_state mmap_state)
884{ 884{
885 struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); 885 struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
@@ -891,7 +891,9 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
891 891
892 /* If memory, add on the PCI bridge address offset */ 892 /* If memory, add on the PCI bridge address offset */
893 if (mmap_state == pci_mmap_mem) { 893 if (mmap_state == pci_mmap_mem) {
894#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
894 *offset += hose->pci_mem_offset; 895 *offset += hose->pci_mem_offset;
896#endif
895 res_bit = IORESOURCE_MEM; 897 res_bit = IORESOURCE_MEM;
896 } else { 898 } else {
897 io_offset = hose->io_base_virt - ___IO_BASE; 899 io_offset = hose->io_base_virt - ___IO_BASE;
@@ -1030,7 +1032,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
1030 enum pci_mmap_state mmap_state, 1032 enum pci_mmap_state mmap_state,
1031 int write_combine) 1033 int write_combine)
1032{ 1034{
1033 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 1035 resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
1034 struct resource *rp; 1036 struct resource *rp;
1035 int ret; 1037 int ret;
1036 1038
@@ -1132,21 +1134,42 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
1132 resource_size_t *start, resource_size_t *end) 1134 resource_size_t *start, resource_size_t *end)
1133{ 1135{
1134 struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); 1136 struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
1135 unsigned long offset = 0; 1137 resource_size_t offset = 0;
1136 1138
1137 if (hose == NULL) 1139 if (hose == NULL)
1138 return; 1140 return;
1139 1141
1140 if (rsrc->flags & IORESOURCE_IO) 1142 if (rsrc->flags & IORESOURCE_IO)
1141 offset = ___IO_BASE - hose->io_base_virt + hose->io_base_phys; 1143 offset = (unsigned long)hose->io_base_virt - _IO_BASE;
1144
1145 /* We pass a fully fixed up address to userland for MMIO instead of
1146 * a BAR value because X is lame and expects to be able to use that
1147 * to pass to /dev/mem !
1148 *
1149 * That means that we'll have potentially 64 bits values where some
1150 * userland apps only expect 32 (like X itself since it thinks only
1151 * Sparc has 64 bits MMIO) but if we don't do that, we break it on
1152 * 32 bits CHRPs :-(
1153 *
1154 * Hopefully, the sysfs insterface is immune to that gunk. Once X
1155 * has been fixed (and the fix spread enough), we can re-enable the
1156 * 2 lines below and pass down a BAR value to userland. In that case
1157 * we'll also have to re-enable the matching code in
1158 * __pci_mmap_make_offset().
1159 *
1160 * BenH.
1161 */
1162#if 0
1163 else if (rsrc->flags & IORESOURCE_MEM)
1164 offset = hose->pci_mem_offset;
1165#endif
1142 1166
1143 *start = rsrc->start + offset; 1167 *start = rsrc->start - offset;
1144 *end = rsrc->end + offset; 1168 *end = rsrc->end - offset;
1145} 1169}
1146 1170
1147void __init 1171void __init pci_init_resource(struct resource *res, resource_size_t start,
1148pci_init_resource(struct resource *res, unsigned long start, unsigned long end, 1172 resource_size_t end, int flags, char *name)
1149 int flags, char *name)
1150{ 1173{
1151 res->start = start; 1174 res->start = start;
1152 res->end = end; 1175 res->end = end;