aboutsummaryrefslogtreecommitdiffstats
path: root/arch
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
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')
-rw-r--r--arch/powerpc/kernel/pci_32.c45
-rw-r--r--arch/powerpc/kernel/pci_64.c42
-rw-r--r--arch/ppc/kernel/pci.c41
3 files changed, 95 insertions, 33 deletions
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index 2f54cd81dea5..ab5887bff02a 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -1544,7 +1544,7 @@ pci_resource_to_bus(struct pci_dev *pdev, struct resource *res)
1544 1544
1545 1545
1546static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, 1546static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
1547 unsigned long *offset, 1547 resource_size_t *offset,
1548 enum pci_mmap_state mmap_state) 1548 enum pci_mmap_state mmap_state)
1549{ 1549{
1550 struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); 1550 struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
@@ -1556,7 +1556,9 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
1556 1556
1557 /* If memory, add on the PCI bridge address offset */ 1557 /* If memory, add on the PCI bridge address offset */
1558 if (mmap_state == pci_mmap_mem) { 1558 if (mmap_state == pci_mmap_mem) {
1559#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
1559 *offset += hose->pci_mem_offset; 1560 *offset += hose->pci_mem_offset;
1561#endif
1560 res_bit = IORESOURCE_MEM; 1562 res_bit = IORESOURCE_MEM;
1561 } else { 1563 } else {
1562 io_offset = hose->io_base_virt - (void __iomem *)_IO_BASE; 1564 io_offset = hose->io_base_virt - (void __iomem *)_IO_BASE;
@@ -1624,9 +1626,6 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
1624 else 1626 else
1625 prot |= _PAGE_GUARDED; 1627 prot |= _PAGE_GUARDED;
1626 1628
1627 printk("PCI map for %s:%llx, prot: %lx\n", pci_name(dev),
1628 (unsigned long long)rp->start, prot);
1629
1630 return __pgprot(prot); 1629 return __pgprot(prot);
1631} 1630}
1632 1631
@@ -1695,7 +1694,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
1695 enum pci_mmap_state mmap_state, 1694 enum pci_mmap_state mmap_state,
1696 int write_combine) 1695 int write_combine)
1697{ 1696{
1698 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 1697 resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
1699 struct resource *rp; 1698 struct resource *rp;
1700 int ret; 1699 int ret;
1701 1700
@@ -1808,22 +1807,42 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
1808 resource_size_t *start, resource_size_t *end) 1807 resource_size_t *start, resource_size_t *end)
1809{ 1808{
1810 struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); 1809 struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
1811 unsigned long offset = 0; 1810 resource_size_t offset = 0;
1812 1811
1813 if (hose == NULL) 1812 if (hose == NULL)
1814 return; 1813 return;
1815 1814
1816 if (rsrc->flags & IORESOURCE_IO) 1815 if (rsrc->flags & IORESOURCE_IO)
1817 offset = (void __iomem *)_IO_BASE - hose->io_base_virt 1816 offset = (unsigned long)hose->io_base_virt - _IO_BASE;
1818 + hose->io_base_phys; 1817
1818 /* We pass a fully fixed up address to userland for MMIO instead of
1819 * a BAR value because X is lame and expects to be able to use that
1820 * to pass to /dev/mem !
1821 *
1822 * That means that we'll have potentially 64 bits values where some
1823 * userland apps only expect 32 (like X itself since it thinks only
1824 * Sparc has 64 bits MMIO) but if we don't do that, we break it on
1825 * 32 bits CHRPs :-(
1826 *
1827 * Hopefully, the sysfs insterface is immune to that gunk. Once X
1828 * has been fixed (and the fix spread enough), we can re-enable the
1829 * 2 lines below and pass down a BAR value to userland. In that case
1830 * we'll also have to re-enable the matching code in
1831 * __pci_mmap_make_offset().
1832 *
1833 * BenH.
1834 */
1835#if 0
1836 else if (rsrc->flags & IORESOURCE_MEM)
1837 offset = hose->pci_mem_offset;
1838#endif
1819 1839
1820 *start = rsrc->start + offset; 1840 *start = rsrc->start - offset;
1821 *end = rsrc->end + offset; 1841 *end = rsrc->end - offset;
1822} 1842}
1823 1843
1824void __init 1844void __init pci_init_resource(struct resource *res, resource_size_t start,
1825pci_init_resource(struct resource *res, unsigned long start, unsigned long end, 1845 resource_size_t end, int flags, char *name)
1826 int flags, char *name)
1827{ 1846{
1828 res->start = start; 1847 res->start = start;
1829 res->end = end; 1848 res->end = end;
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 6fa9a0a5c8db..a6b7692c7269 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -682,7 +682,7 @@ int pci_proc_domain(struct pci_bus *bus)
682 * Returns negative error code on failure, zero on success. 682 * Returns negative error code on failure, zero on success.
683 */ 683 */
684static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, 684static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
685 unsigned long *offset, 685 resource_size_t *offset,
686 enum pci_mmap_state mmap_state) 686 enum pci_mmap_state mmap_state)
687{ 687{
688 struct pci_controller *hose = pci_bus_to_host(dev->bus); 688 struct pci_controller *hose = pci_bus_to_host(dev->bus);
@@ -694,7 +694,9 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
694 694
695 /* If memory, add on the PCI bridge address offset */ 695 /* If memory, add on the PCI bridge address offset */
696 if (mmap_state == pci_mmap_mem) { 696 if (mmap_state == pci_mmap_mem) {
697#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
697 *offset += hose->pci_mem_offset; 698 *offset += hose->pci_mem_offset;
699#endif
698 res_bit = IORESOURCE_MEM; 700 res_bit = IORESOURCE_MEM;
699 } else { 701 } else {
700 io_offset = (unsigned long)hose->io_base_virt - pci_io_base; 702 io_offset = (unsigned long)hose->io_base_virt - pci_io_base;
@@ -762,9 +764,6 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
762 else 764 else
763 prot |= _PAGE_GUARDED; 765 prot |= _PAGE_GUARDED;
764 766
765 printk(KERN_DEBUG "PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
766 prot);
767
768 return __pgprot(prot); 767 return __pgprot(prot);
769} 768}
770 769
@@ -832,7 +831,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
832int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, 831int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
833 enum pci_mmap_state mmap_state, int write_combine) 832 enum pci_mmap_state mmap_state, int write_combine)
834{ 833{
835 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 834 resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
836 struct resource *rp; 835 struct resource *rp;
837 int ret; 836 int ret;
838 837
@@ -1333,20 +1332,41 @@ EXPORT_SYMBOL(pci_read_irq_line);
1333 1332
1334void pci_resource_to_user(const struct pci_dev *dev, int bar, 1333void pci_resource_to_user(const struct pci_dev *dev, int bar,
1335 const struct resource *rsrc, 1334 const struct resource *rsrc,
1336 u64 *start, u64 *end) 1335 resource_size_t *start, resource_size_t *end)
1337{ 1336{
1338 struct pci_controller *hose = pci_bus_to_host(dev->bus); 1337 struct pci_controller *hose = pci_bus_to_host(dev->bus);
1339 unsigned long offset = 0; 1338 resource_size_t offset = 0;
1340 1339
1341 if (hose == NULL) 1340 if (hose == NULL)
1342 return; 1341 return;
1343 1342
1344 if (rsrc->flags & IORESOURCE_IO) 1343 if (rsrc->flags & IORESOURCE_IO)
1345 offset = pci_io_base - (unsigned long)hose->io_base_virt + 1344 offset = (unsigned long)hose->io_base_virt - pci_io_base;
1346 hose->io_base_phys; 1345
1346 /* We pass a fully fixed up address to userland for MMIO instead of
1347 * a BAR value because X is lame and expects to be able to use that
1348 * to pass to /dev/mem !
1349 *
1350 * That means that we'll have potentially 64 bits values where some
1351 * userland apps only expect 32 (like X itself since it thinks only
1352 * Sparc has 64 bits MMIO) but if we don't do that, we break it on
1353 * 32 bits CHRPs :-(
1354 *
1355 * Hopefully, the sysfs insterface is immune to that gunk. Once X
1356 * has been fixed (and the fix spread enough), we can re-enable the
1357 * 2 lines below and pass down a BAR value to userland. In that case
1358 * we'll also have to re-enable the matching code in
1359 * __pci_mmap_make_offset().
1360 *
1361 * BenH.
1362 */
1363#if 0
1364 else if (rsrc->flags & IORESOURCE_MEM)
1365 offset = hose->pci_mem_offset;
1366#endif
1347 1367
1348 *start = rsrc->start + offset; 1368 *start = rsrc->start - offset;
1349 *end = rsrc->end + offset; 1369 *end = rsrc->end - offset;
1350} 1370}
1351 1371
1352struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node) 1372struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
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;