ioremap_pud_range() and ioremap_pmd_range() are changed to create
huge I/O mappings when their capability is enabled, and a request
meets required conditions -- both virtual & physical addresses
are aligned by their huge page size, and a requested range fufills
their huge page size.  When pud_set_huge() or pmd_set_huge() returns
zero, i.e. no-operation is performed, the code simply falls back to
the next level.

The changes are only enabled when CONFIG_HAVE_ARCH_HUGE_VMAP is
defined on the architecture.

Signed-off-by: Toshi Kani <toshi.k...@hp.com>
---
 include/asm-generic/pgtable.h |   15 +++++++++++++++
 lib/ioremap.c                 |   16 ++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index 4d46085..bf6e86c 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -6,6 +6,7 @@
 
 #include <linux/mm_types.h>
 #include <linux/bug.h>
+#include <linux/errno.h>
 
 /*
  * On almost all architectures and configurations, 0 can be used as the
@@ -697,4 +698,18 @@ static inline int pmd_protnone(pmd_t pmd)
 #define io_remap_pfn_range remap_pfn_range
 #endif
 
+#ifdef CONFIG_HAVE_ARCH_HUGE_VMAP
+int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot);
+int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot);
+#else  /* !CONFIG_HAVE_ARCH_HUGE_VMAP */
+static inline int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot)
+{
+       return 0;
+}
+static inline int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot)
+{
+       return 0;
+}
+#endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
+
 #endif /* _ASM_GENERIC_PGTABLE_H */
diff --git a/lib/ioremap.c b/lib/ioremap.c
index 0ce18aa..3055ada 100644
--- a/lib/ioremap.c
+++ b/lib/ioremap.c
@@ -81,6 +81,14 @@ static inline int ioremap_pmd_range(pud_t *pud, unsigned 
long addr,
                return -ENOMEM;
        do {
                next = pmd_addr_end(addr, end);
+
+               if (ioremap_pmd_enabled() &&
+                   ((next - addr) == PMD_SIZE) &&
+                   IS_ALIGNED(phys_addr + addr, PMD_SIZE)) {
+                       if (pmd_set_huge(pmd, phys_addr + addr, prot))
+                               continue;
+               }
+
                if (ioremap_pte_range(pmd, addr, next, phys_addr + addr, prot))
                        return -ENOMEM;
        } while (pmd++, addr = next, addr != end);
@@ -99,6 +107,14 @@ static inline int ioremap_pud_range(pgd_t *pgd, unsigned 
long addr,
                return -ENOMEM;
        do {
                next = pud_addr_end(addr, end);
+
+               if (ioremap_pud_enabled() &&
+                   ((next - addr) == PUD_SIZE) &&
+                   IS_ALIGNED(phys_addr + addr, PUD_SIZE)) {
+                       if (pud_set_huge(pud, phys_addr + addr, prot))
+                               continue;
+               }
+
                if (ioremap_pmd_range(pud, addr, next, phys_addr + addr, prot))
                        return -ENOMEM;
        } while (pud++, addr = next, addr != end);
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to