[PATCH] PCI: fix-pci-mmap-on-ppc-and-ppc64.patch

This is an updated version of Ben's fix-pci-mmap-on-ppc-and-ppc64.patch
which is in 2.6.12-rc4-mm1.

It fixes the patch to work on PPC iSeries, removes some debug printks
at Ben's request, and incorporates your
fix-pci-mmap-on-ppc-and-ppc64-fix.patch also.

Originally from Benjamin Herrenschmidt <benh@kernel.crashing.org>

This patch was discussed at length on linux-pci and so far, the last
iteration of it didn't raise any comment. It's effect is a nop on
architecture that don't define the new pci_resource_to_user() callback
anyway. It allows architecture like ppc who put weird things inside of
PCI resource structures to convert to some different value for user
visible ones. It also fixes mmap'ing of IO space on those archs.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by Michael Ellerman and committed by Greg Kroah-Hartman 2311b1f2 a0d399a8

+97 -13
+19 -2
arch/ppc/kernel/pci.c
··· 1495 1495 *offset += hose->pci_mem_offset; 1496 1496 res_bit = IORESOURCE_MEM; 1497 1497 } else { 1498 - io_offset = (unsigned long)hose->io_base_virt; 1498 + io_offset = hose->io_base_virt - ___IO_BASE; 1499 1499 *offset += io_offset; 1500 1500 res_bit = IORESOURCE_IO; 1501 1501 } ··· 1522 1522 1523 1523 /* found it! construct the final physical address */ 1524 1524 if (mmap_state == pci_mmap_io) 1525 - *offset += hose->io_base_phys - _IO_BASE; 1525 + *offset += hose->io_base_phys - io_offset; 1526 1526 return rp; 1527 1527 } 1528 1528 ··· 1737 1737 } 1738 1738 1739 1739 return result; 1740 + } 1741 + 1742 + void pci_resource_to_user(const struct pci_dev *dev, int bar, 1743 + const struct resource *rsrc, 1744 + u64 *start, u64 *end) 1745 + { 1746 + struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); 1747 + unsigned long offset = 0; 1748 + 1749 + if (hose == NULL) 1750 + return; 1751 + 1752 + if (rsrc->flags & IORESOURCE_IO) 1753 + offset = ___IO_BASE - hose->io_base_virt + hose->io_base_phys; 1754 + 1755 + *start = rsrc->start + offset; 1756 + *end = rsrc->end + offset; 1740 1757 } 1741 1758 1742 1759 void __init
+20 -2
arch/ppc64/kernel/pci.c
··· 351 351 *offset += hose->pci_mem_offset; 352 352 res_bit = IORESOURCE_MEM; 353 353 } else { 354 - io_offset = (unsigned long)hose->io_base_virt; 354 + io_offset = (unsigned long)hose->io_base_virt - pci_io_base; 355 355 *offset += io_offset; 356 356 res_bit = IORESOURCE_IO; 357 357 } ··· 378 378 379 379 /* found it! construct the final physical address */ 380 380 if (mmap_state == pci_mmap_io) 381 - *offset += hose->io_base_phys - io_offset; 381 + *offset += hose->io_base_phys - io_offset; 382 382 return rp; 383 383 } 384 384 ··· 943 943 return 0; 944 944 } 945 945 EXPORT_SYMBOL(pci_read_irq_line); 946 + 947 + void pci_resource_to_user(const struct pci_dev *dev, int bar, 948 + const struct resource *rsrc, 949 + u64 *start, u64 *end) 950 + { 951 + struct pci_controller *hose = pci_bus_to_host(dev->bus); 952 + unsigned long offset = 0; 953 + 954 + if (hose == NULL) 955 + return; 956 + 957 + if (rsrc->flags & IORESOURCE_IO) 958 + offset = pci_io_base - (unsigned long)hose->io_base_virt + 959 + hose->io_base_phys; 960 + 961 + *start = rsrc->start + offset; 962 + *end = rsrc->end + offset; 963 + } 946 964 947 965 #endif /* CONFIG_PPC_MULTIPLATFORM */
+21 -5
drivers/pci/pci-sysfs.c
··· 60 60 char * str = buf; 61 61 int i; 62 62 int max = 7; 63 + u64 start, end; 63 64 64 65 if (pci_dev->subordinate) 65 66 max = DEVICE_COUNT_RESOURCE; 66 67 67 68 for (i = 0; i < max; i++) { 68 - str += sprintf(str,"0x%016lx 0x%016lx 0x%016lx\n", 69 - pci_resource_start(pci_dev,i), 70 - pci_resource_end(pci_dev,i), 71 - pci_resource_flags(pci_dev,i)); 69 + struct resource *res = &pci_dev->resource[i]; 70 + pci_resource_to_user(pci_dev, i, res, &start, &end); 71 + str += sprintf(str,"0x%016llx 0x%016llx 0x%016llx\n", 72 + (unsigned long long)start, 73 + (unsigned long long)end, 74 + (unsigned long long)res->flags); 72 75 } 73 76 return (str - buf); 74 77 } ··· 316 313 struct device, kobj)); 317 314 struct resource *res = (struct resource *)attr->private; 318 315 enum pci_mmap_state mmap_type; 316 + u64 start, end; 317 + int i; 319 318 320 - vma->vm_pgoff += res->start >> PAGE_SHIFT; 319 + for (i = 0; i < PCI_ROM_RESOURCE; i++) 320 + if (res == &pdev->resource[i]) 321 + break; 322 + if (i >= PCI_ROM_RESOURCE) 323 + return -ENODEV; 324 + 325 + /* pci_mmap_page_range() expects the same kind of entry as coming 326 + * from /proc/bus/pci/ which is a "user visible" value. If this is 327 + * different from the resource itself, arch will do necessary fixup. 328 + */ 329 + pci_resource_to_user(pdev, i, res, &start, &end); 330 + vma->vm_pgoff += start >> PAGE_SHIFT; 321 331 mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; 322 332 323 333 return pci_mmap_page_range(pdev, vma, mmap_type, 0);
+10 -4
drivers/pci/proc.c
··· 355 355 dev->device, 356 356 dev->irq); 357 357 /* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */ 358 - for(i=0; i<7; i++) 358 + for (i=0; i<7; i++) { 359 + u64 start, end; 360 + pci_resource_to_user(dev, i, &dev->resource[i], &start, &end); 359 361 seq_printf(m, LONG_FORMAT, 360 - dev->resource[i].start | 362 + ((unsigned long)start) | 361 363 (dev->resource[i].flags & PCI_REGION_FLAG_MASK)); 362 - for(i=0; i<7; i++) 364 + } 365 + for (i=0; i<7; i++) { 366 + u64 start, end; 367 + pci_resource_to_user(dev, i, &dev->resource[i], &start, &end); 363 368 seq_printf(m, LONG_FORMAT, 364 369 dev->resource[i].start < dev->resource[i].end ? 365 - dev->resource[i].end - dev->resource[i].start + 1 : 0); 370 + (unsigned long)(end - start) + 1 : 0); 371 + } 366 372 seq_putc(m, '\t'); 367 373 if (drv) 368 374 seq_printf(m, "%s", drv->name);
+6
include/asm-ppc/pci.h
··· 103 103 unsigned long size, 104 104 pgprot_t prot); 105 105 106 + #define HAVE_ARCH_PCI_RESOURCE_TO_USER 107 + extern void pci_resource_to_user(const struct pci_dev *dev, int bar, 108 + const struct resource *rsrc, 109 + u64 *start, u64 *end); 110 + 111 + 106 112 #endif /* __KERNEL__ */ 107 113 108 114 #endif /* __PPC_PCI_H */
+7
include/asm-ppc64/pci.h
··· 136 136 unsigned long size, 137 137 pgprot_t prot); 138 138 139 + #ifdef CONFIG_PPC_MULTIPLATFORM 140 + #define HAVE_ARCH_PCI_RESOURCE_TO_USER 141 + extern void pci_resource_to_user(const struct pci_dev *dev, int bar, 142 + const struct resource *rsrc, 143 + u64 *start, u64 *end); 144 + #endif /* CONFIG_PPC_MULTIPLATFORM */ 145 + 139 146 140 147 #endif /* __KERNEL__ */ 141 148
+14
include/linux/pci.h
··· 1020 1020 #define pci_pretty_name(dev) "" 1021 1021 #endif 1022 1022 1023 + 1024 + /* Some archs don't want to expose struct resource to userland as-is 1025 + * in sysfs and /proc 1026 + */ 1027 + #ifndef HAVE_ARCH_PCI_RESOURCE_TO_USER 1028 + static inline void pci_resource_to_user(const struct pci_dev *dev, int bar, 1029 + const struct resource *rsrc, u64 *start, u64 *end) 1030 + { 1031 + *start = rsrc->start; 1032 + *end = rsrc->end; 1033 + } 1034 + #endif /* HAVE_ARCH_PCI_RESOURCE_TO_USER */ 1035 + 1036 + 1023 1037 /* 1024 1038 * The world is not perfect and supplies us with broken PCI devices. 1025 1039 * For at least a part of these bugs we need a work-around, so both