[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 *offset += hose->pci_mem_offset; 1496 res_bit = IORESOURCE_MEM; 1497 } else { 1498 - io_offset = (unsigned long)hose->io_base_virt; 1499 *offset += io_offset; 1500 res_bit = IORESOURCE_IO; 1501 } ··· 1522 1523 /* found it! construct the final physical address */ 1524 if (mmap_state == pci_mmap_io) 1525 - *offset += hose->io_base_phys - _IO_BASE; 1526 return rp; 1527 } 1528 ··· 1737 } 1738 1739 return result; 1740 } 1741 1742 void __init
··· 1495 *offset += hose->pci_mem_offset; 1496 res_bit = IORESOURCE_MEM; 1497 } else { 1498 + io_offset = hose->io_base_virt - ___IO_BASE; 1499 *offset += io_offset; 1500 res_bit = IORESOURCE_IO; 1501 } ··· 1522 1523 /* found it! construct the final physical address */ 1524 if (mmap_state == pci_mmap_io) 1525 + *offset += hose->io_base_phys - io_offset; 1526 return rp; 1527 } 1528 ··· 1737 } 1738 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; 1757 } 1758 1759 void __init
+20 -2
arch/ppc64/kernel/pci.c
··· 351 *offset += hose->pci_mem_offset; 352 res_bit = IORESOURCE_MEM; 353 } else { 354 - io_offset = (unsigned long)hose->io_base_virt; 355 *offset += io_offset; 356 res_bit = IORESOURCE_IO; 357 } ··· 378 379 /* found it! construct the final physical address */ 380 if (mmap_state == pci_mmap_io) 381 - *offset += hose->io_base_phys - io_offset; 382 return rp; 383 } 384 ··· 943 return 0; 944 } 945 EXPORT_SYMBOL(pci_read_irq_line); 946 947 #endif /* CONFIG_PPC_MULTIPLATFORM */
··· 351 *offset += hose->pci_mem_offset; 352 res_bit = IORESOURCE_MEM; 353 } else { 354 + io_offset = (unsigned long)hose->io_base_virt - pci_io_base; 355 *offset += io_offset; 356 res_bit = IORESOURCE_IO; 357 } ··· 378 379 /* found it! construct the final physical address */ 380 if (mmap_state == pci_mmap_io) 381 + *offset += hose->io_base_phys - io_offset; 382 return rp; 383 } 384 ··· 943 return 0; 944 } 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 + } 964 965 #endif /* CONFIG_PPC_MULTIPLATFORM */
+21 -5
drivers/pci/pci-sysfs.c
··· 60 char * str = buf; 61 int i; 62 int max = 7; 63 64 if (pci_dev->subordinate) 65 max = DEVICE_COUNT_RESOURCE; 66 67 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)); 72 } 73 return (str - buf); 74 } ··· 316 struct device, kobj)); 317 struct resource *res = (struct resource *)attr->private; 318 enum pci_mmap_state mmap_type; 319 320 - vma->vm_pgoff += res->start >> PAGE_SHIFT; 321 mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; 322 323 return pci_mmap_page_range(pdev, vma, mmap_type, 0);
··· 60 char * str = buf; 61 int i; 62 int max = 7; 63 + u64 start, end; 64 65 if (pci_dev->subordinate) 66 max = DEVICE_COUNT_RESOURCE; 67 68 for (i = 0; i < max; 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); 75 } 76 return (str - buf); 77 } ··· 313 struct device, kobj)); 314 struct resource *res = (struct resource *)attr->private; 315 enum pci_mmap_state mmap_type; 316 + u64 start, end; 317 + int i; 318 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; 331 mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; 332 333 return pci_mmap_page_range(pdev, vma, mmap_type, 0);
+10 -4
drivers/pci/proc.c
··· 355 dev->device, 356 dev->irq); 357 /* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */ 358 - for(i=0; i<7; i++) 359 seq_printf(m, LONG_FORMAT, 360 - dev->resource[i].start | 361 (dev->resource[i].flags & PCI_REGION_FLAG_MASK)); 362 - for(i=0; i<7; i++) 363 seq_printf(m, LONG_FORMAT, 364 dev->resource[i].start < dev->resource[i].end ? 365 - dev->resource[i].end - dev->resource[i].start + 1 : 0); 366 seq_putc(m, '\t'); 367 if (drv) 368 seq_printf(m, "%s", drv->name);
··· 355 dev->device, 356 dev->irq); 357 /* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */ 358 + for (i=0; i<7; i++) { 359 + u64 start, end; 360 + pci_resource_to_user(dev, i, &dev->resource[i], &start, &end); 361 seq_printf(m, LONG_FORMAT, 362 + ((unsigned long)start) | 363 (dev->resource[i].flags & PCI_REGION_FLAG_MASK)); 364 + } 365 + for (i=0; i<7; i++) { 366 + u64 start, end; 367 + pci_resource_to_user(dev, i, &dev->resource[i], &start, &end); 368 seq_printf(m, LONG_FORMAT, 369 dev->resource[i].start < dev->resource[i].end ? 370 + (unsigned long)(end - start) + 1 : 0); 371 + } 372 seq_putc(m, '\t'); 373 if (drv) 374 seq_printf(m, "%s", drv->name);
+6
include/asm-ppc/pci.h
··· 103 unsigned long size, 104 pgprot_t prot); 105 106 #endif /* __KERNEL__ */ 107 108 #endif /* __PPC_PCI_H */
··· 103 unsigned long size, 104 pgprot_t prot); 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 + 112 #endif /* __KERNEL__ */ 113 114 #endif /* __PPC_PCI_H */
+7
include/asm-ppc64/pci.h
··· 136 unsigned long size, 137 pgprot_t prot); 138 139 140 #endif /* __KERNEL__ */ 141
··· 136 unsigned long size, 137 pgprot_t prot); 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 + 146 147 #endif /* __KERNEL__ */ 148
+14
include/linux/pci.h
··· 1020 #define pci_pretty_name(dev) "" 1021 #endif 1022 1023 /* 1024 * The world is not perfect and supplies us with broken PCI devices. 1025 * For at least a part of these bugs we need a work-around, so both
··· 1020 #define pci_pretty_name(dev) "" 1021 #endif 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 + 1037 /* 1038 * The world is not perfect and supplies us with broken PCI devices. 1039 * For at least a part of these bugs we need a work-around, so both