aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/pci_32.c
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/powerpc/kernel/pci_32.c
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/powerpc/kernel/pci_32.c')
-rw-r--r--arch/powerpc/kernel/pci_32.c45
1 files changed, 32 insertions, 13 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;