diff options
author | Michael Ellerman <michael@ellerman.id.au> | 2005-05-13 03:44:10 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-06-28 00:52:45 -0400 |
commit | 2311b1f2bbd36fa5f366a7448c718b2556e0f02c (patch) | |
tree | 10e836c5c34893f8098464a5ae15aba351a7bb2a | |
parent | a0d399a808916d22c1c222c6b5ca4e8edd6d91a9 (diff) |
[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>
-rw-r--r-- | arch/ppc/kernel/pci.c | 21 | ||||
-rw-r--r-- | arch/ppc64/kernel/pci.c | 22 | ||||
-rw-r--r-- | drivers/pci/pci-sysfs.c | 26 | ||||
-rw-r--r-- | drivers/pci/proc.c | 14 | ||||
-rw-r--r-- | include/asm-ppc/pci.h | 6 | ||||
-rw-r--r-- | include/asm-ppc64/pci.h | 7 | ||||
-rw-r--r-- | include/linux/pci.h | 14 |
7 files changed, 97 insertions, 13 deletions
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 6d7b92d72458..70cfb6ffd877 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c | |||
@@ -1495,7 +1495,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, | |||
1495 | *offset += hose->pci_mem_offset; | 1495 | *offset += hose->pci_mem_offset; |
1496 | res_bit = IORESOURCE_MEM; | 1496 | res_bit = IORESOURCE_MEM; |
1497 | } else { | 1497 | } else { |
1498 | io_offset = (unsigned long)hose->io_base_virt; | 1498 | io_offset = hose->io_base_virt - ___IO_BASE; |
1499 | *offset += io_offset; | 1499 | *offset += io_offset; |
1500 | res_bit = IORESOURCE_IO; | 1500 | res_bit = IORESOURCE_IO; |
1501 | } | 1501 | } |
@@ -1522,7 +1522,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, | |||
1522 | 1522 | ||
1523 | /* found it! construct the final physical address */ | 1523 | /* found it! construct the final physical address */ |
1524 | if (mmap_state == pci_mmap_io) | 1524 | if (mmap_state == pci_mmap_io) |
1525 | *offset += hose->io_base_phys - _IO_BASE; | 1525 | *offset += hose->io_base_phys - io_offset; |
1526 | return rp; | 1526 | return rp; |
1527 | } | 1527 | } |
1528 | 1528 | ||
@@ -1739,6 +1739,23 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) | |||
1739 | return result; | 1739 | return result; |
1740 | } | 1740 | } |
1741 | 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 | |||
1742 | void __init | 1759 | void __init |
1743 | pci_init_resource(struct resource *res, unsigned long start, unsigned long end, | 1760 | pci_init_resource(struct resource *res, unsigned long start, unsigned long end, |
1744 | int flags, char *name) | 1761 | int flags, char *name) |
diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index 580676f87d23..ae6f579d3fa0 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c | |||
@@ -351,7 +351,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, | |||
351 | *offset += hose->pci_mem_offset; | 351 | *offset += hose->pci_mem_offset; |
352 | res_bit = IORESOURCE_MEM; | 352 | res_bit = IORESOURCE_MEM; |
353 | } else { | 353 | } else { |
354 | io_offset = (unsigned long)hose->io_base_virt; | 354 | io_offset = (unsigned long)hose->io_base_virt - pci_io_base; |
355 | *offset += io_offset; | 355 | *offset += io_offset; |
356 | res_bit = IORESOURCE_IO; | 356 | res_bit = IORESOURCE_IO; |
357 | } | 357 | } |
@@ -378,7 +378,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, | |||
378 | 378 | ||
379 | /* found it! construct the final physical address */ | 379 | /* found it! construct the final physical address */ |
380 | if (mmap_state == pci_mmap_io) | 380 | if (mmap_state == pci_mmap_io) |
381 | *offset += hose->io_base_phys - io_offset; | 381 | *offset += hose->io_base_phys - io_offset; |
382 | return rp; | 382 | return rp; |
383 | } | 383 | } |
384 | 384 | ||
@@ -944,4 +944,22 @@ int pci_read_irq_line(struct pci_dev *pci_dev) | |||
944 | } | 944 | } |
945 | EXPORT_SYMBOL(pci_read_irq_line); | 945 | EXPORT_SYMBOL(pci_read_irq_line); |
946 | 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 | |||
947 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | 965 | #endif /* CONFIG_PPC_MULTIPLATFORM */ |
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index a15f94072a6f..cc9d65388e62 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -60,15 +60,18 @@ resource_show(struct device * dev, struct device_attribute *attr, char * buf) | |||
60 | char * str = buf; | 60 | char * str = buf; |
61 | int i; | 61 | int i; |
62 | int max = 7; | 62 | int max = 7; |
63 | u64 start, end; | ||
63 | 64 | ||
64 | if (pci_dev->subordinate) | 65 | if (pci_dev->subordinate) |
65 | max = DEVICE_COUNT_RESOURCE; | 66 | max = DEVICE_COUNT_RESOURCE; |
66 | 67 | ||
67 | for (i = 0; i < max; i++) { | 68 | for (i = 0; i < max; i++) { |
68 | str += sprintf(str,"0x%016lx 0x%016lx 0x%016lx\n", | 69 | struct resource *res = &pci_dev->resource[i]; |
69 | pci_resource_start(pci_dev,i), | 70 | pci_resource_to_user(pci_dev, i, res, &start, &end); |
70 | pci_resource_end(pci_dev,i), | 71 | str += sprintf(str,"0x%016llx 0x%016llx 0x%016llx\n", |
71 | pci_resource_flags(pci_dev,i)); | 72 | (unsigned long long)start, |
73 | (unsigned long long)end, | ||
74 | (unsigned long long)res->flags); | ||
72 | } | 75 | } |
73 | return (str - buf); | 76 | return (str - buf); |
74 | } | 77 | } |
@@ -313,8 +316,21 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, | |||
313 | struct device, kobj)); | 316 | struct device, kobj)); |
314 | struct resource *res = (struct resource *)attr->private; | 317 | struct resource *res = (struct resource *)attr->private; |
315 | enum pci_mmap_state mmap_type; | 318 | enum pci_mmap_state mmap_type; |
319 | u64 start, end; | ||
320 | int i; | ||
316 | 321 | ||
317 | vma->vm_pgoff += res->start >> PAGE_SHIFT; | 322 | for (i = 0; i < PCI_ROM_RESOURCE; i++) |
323 | if (res == &pdev->resource[i]) | ||
324 | break; | ||
325 | if (i >= PCI_ROM_RESOURCE) | ||
326 | return -ENODEV; | ||
327 | |||
328 | /* pci_mmap_page_range() expects the same kind of entry as coming | ||
329 | * from /proc/bus/pci/ which is a "user visible" value. If this is | ||
330 | * different from the resource itself, arch will do necessary fixup. | ||
331 | */ | ||
332 | pci_resource_to_user(pdev, i, res, &start, &end); | ||
333 | vma->vm_pgoff += start >> PAGE_SHIFT; | ||
318 | mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; | 334 | mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; |
319 | 335 | ||
320 | return pci_mmap_page_range(pdev, vma, mmap_type, 0); | 336 | return pci_mmap_page_range(pdev, vma, mmap_type, 0); |
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index e68bbfb1e7c3..7988fc8df3fd 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c | |||
@@ -355,14 +355,20 @@ static int show_device(struct seq_file *m, void *v) | |||
355 | dev->device, | 355 | dev->device, |
356 | dev->irq); | 356 | dev->irq); |
357 | /* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */ | 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 | seq_printf(m, LONG_FORMAT, | 361 | seq_printf(m, LONG_FORMAT, |
360 | dev->resource[i].start | | 362 | ((unsigned long)start) | |
361 | (dev->resource[i].flags & PCI_REGION_FLAG_MASK)); | 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 | seq_printf(m, LONG_FORMAT, | 368 | seq_printf(m, LONG_FORMAT, |
364 | dev->resource[i].start < dev->resource[i].end ? | 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 | seq_putc(m, '\t'); | 372 | seq_putc(m, '\t'); |
367 | if (drv) | 373 | if (drv) |
368 | seq_printf(m, "%s", drv->name); | 374 | seq_printf(m, "%s", drv->name); |
diff --git a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h index ce5ae6d048f5..002e7b305777 100644 --- a/include/asm-ppc/pci.h +++ b/include/asm-ppc/pci.h | |||
@@ -103,6 +103,12 @@ extern pgprot_t pci_phys_mem_access_prot(struct file *file, | |||
103 | unsigned long size, | 103 | unsigned long size, |
104 | pgprot_t prot); | 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 | #endif /* __KERNEL__ */ | 112 | #endif /* __KERNEL__ */ |
107 | 113 | ||
108 | #endif /* __PPC_PCI_H */ | 114 | #endif /* __PPC_PCI_H */ |
diff --git a/include/asm-ppc64/pci.h b/include/asm-ppc64/pci.h index 6cd593f660a0..411bf5dee394 100644 --- a/include/asm-ppc64/pci.h +++ b/include/asm-ppc64/pci.h | |||
@@ -136,6 +136,13 @@ extern pgprot_t pci_phys_mem_access_prot(struct file *file, | |||
136 | unsigned long size, | 136 | unsigned long size, |
137 | pgprot_t prot); | 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 | #endif /* __KERNEL__ */ | 147 | #endif /* __KERNEL__ */ |
141 | 148 | ||
diff --git a/include/linux/pci.h b/include/linux/pci.h index 0e9844929fe3..cfa1455848f4 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -1020,6 +1020,20 @@ static inline char *pci_name(struct pci_dev *pdev) | |||
1020 | #define pci_pretty_name(dev) "" | 1020 | #define pci_pretty_name(dev) "" |
1021 | #endif | 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 | * The world is not perfect and supplies us with broken PCI devices. | 1038 | * 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 | 1039 | * For at least a part of these bugs we need a work-around, so both |