PCI: Add pci_remap_iospace() to map bus I/O resources
authorLiviu Dudau <Liviu.Dudau@arm.com>
Mon, 29 Sep 2014 14:29:30 +0000 (15:29 +0100)
committerBjorn Helgaas <bhelgaas@google.com>
Tue, 30 Sep 2014 23:08:57 +0000 (17:08 -0600)
Add pci_remap_iospace() to map bus I/O resources into the CPU virtual
address space.  Architectures with special needs may provide their own
version, but most should be able to use this one.

This function is useful for PCI host bridge drivers that need to map the
PCI I/O resources into virtual memory space.

[bhelgaas: phys_addr description, drop temporary "err" variable]
Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
CC: Arnd Bergmann <arnd@arndb.de>
drivers/pci/pci.c
include/asm-generic/pgtable.h
include/linux/pci.h

index d36f35ff6c5d9e824646ea8dc55b0598f30138fe..6e994fc077f45c5bdc9499279dd4cf2cd3042091 100644 (file)
@@ -2704,6 +2704,37 @@ int pci_request_regions_exclusive(struct pci_dev *pdev, const char *res_name)
 }
 EXPORT_SYMBOL(pci_request_regions_exclusive);
 
+/**
+ *     pci_remap_iospace - Remap the memory mapped I/O space
+ *     @res: Resource describing the I/O space
+ *     @phys_addr: physical address of range to be mapped
+ *
+ *     Remap the memory mapped I/O space described by the @res
+ *     and the CPU physical address @phys_addr into virtual address space.
+ *     Only architectures that have memory mapped IO functions defined
+ *     (and the PCI_IOBASE value defined) should call this function.
+ */
+int __weak pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr)
+{
+#if defined(PCI_IOBASE) && defined(CONFIG_MMU)
+       unsigned long vaddr = (unsigned long)PCI_IOBASE + res->start;
+
+       if (!(res->flags & IORESOURCE_IO))
+               return -EINVAL;
+
+       if (res->end > IO_SPACE_LIMIT)
+               return -EINVAL;
+
+       return ioremap_page_range(vaddr, vaddr + resource_size(res), phys_addr,
+                                 pgprot_device(PAGE_KERNEL));
+#else
+       /* this architecture does not have memory mapped I/O space,
+          so this function should never be called */
+       WARN_ONCE(1, "This architecture does not support memory mapped I/O\n");
+       return -ENODEV;
+#endif
+}
+
 static void __pci_set_master(struct pci_dev *dev, bool enable)
 {
        u16 old_cmd, cmd;
index 53b2acc38213298ff75d8c32a3f1dbfa196562a9..977e545a64c33ab0c0d965b881b7870b2fa31889 100644 (file)
@@ -249,6 +249,10 @@ static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b)
 #define pgprot_writecombine pgprot_noncached
 #endif
 
+#ifndef pgprot_device
+#define pgprot_device pgprot_noncached
+#endif
+
 /*
  * When walking page tables, get the address of the next boundary,
  * or the end address of the range if that comes earlier.  Although no
index 150da2d644e76476e4f57d417975b90ed00fff26..b4995fdfffb140fbe16705f22ac83d90972e5ed8 100644 (file)
@@ -1100,6 +1100,9 @@ int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
                                                  resource_size_t),
                        void *alignf_data);
 
+
+int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr);
+
 static inline dma_addr_t pci_bus_address(struct pci_dev *pdev, int bar)
 {
        struct pci_bus_region region;