From e2dc9d598b4945be932e176ff19b9f804c7ab1a4 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Sat, 7 Feb 2015 21:20:35 +0200 Subject: [PATCH] ARM: implement ioremap_prot --- arch/arm/Kconfig | 1 + arch/arm/include/asm/io.h | 3 ++ arch/arm/include/asm/pgtable-2level-types.h | 2 ++ arch/arm/mm/ioremap.c | 37 +++++++++++++++++++++ 4 files changed, 43 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3ea62da77aa5..870794acb02f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -30,6 +30,7 @@ config ARM select HAVE_C_RECORDMCOUNT select HAVE_GENERIC_HARDIRQS select HAVE_SPARSE_IRQ + select HAVE_IOREMAP_PROT select GENERIC_IRQ_SHOW select CPU_PM if (SUSPEND || CPU_IDLE) help diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index 065d100fa63e..cb81b3b97c9c 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -83,6 +83,9 @@ extern void __iomem *__arm_ioremap(unsigned long, size_t, unsigned int); extern void __iomem *__arm_ioremap_exec(unsigned long, size_t, bool cached); extern void __iounmap(volatile void __iomem *addr); +extern void __iomem *ioremap_prot(resource_size_t, unsigned long size, + unsigned long prot_val); + /* * Bad read/write accesses... */ diff --git a/arch/arm/include/asm/pgtable-2level-types.h b/arch/arm/include/asm/pgtable-2level-types.h index 66cb5b0e89c5..93ce673183a0 100644 --- a/arch/arm/include/asm/pgtable-2level-types.h +++ b/arch/arm/include/asm/pgtable-2level-types.h @@ -64,4 +64,6 @@ typedef pteval_t pgprot_t; #endif /* STRICT_MM_TYPECHECKS */ +#define pte_pgprot(pte) __pgprot(pte_val(pte)) + #endif /* _ASM_PGTABLE_2LEVEL_TYPES_H */ diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 80632e8d7538..c6f20dc3218c 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -335,6 +335,43 @@ __arm_ioremap_exec(unsigned long phys_addr, size_t size, bool cached) __builtin_return_address(0)); } +void __iomem *ioremap_prot(resource_size_t phys_addr, unsigned long size, + unsigned long prot_val) +{ + const struct mem_type *type; + unsigned long addr; + struct vm_struct * area; + pteval_t prot_pte; + int err; + + size = PAGE_ALIGN(size); + + type = get_mem_type(MT_DEVICE); + if (!type) + return NULL; + + prot_pte = type->prot_pte & ~L_PTE_MT_MASK; + prot_pte |= prot_val & L_PTE_MT_MASK; + + area = get_vm_area_caller(size, VM_IOREMAP, + __builtin_return_address(0)); + if (!area) + return NULL; + addr = (unsigned long)area->addr; + + err = ioremap_page_range(addr, addr + size, phys_addr, + __pgprot(prot_pte)); + if (err) { + vunmap((void *)addr); + return NULL; + } + + flush_cache_vmap(addr, addr + size); + return (void __iomem *)addr; +} + +EXPORT_SYMBOL(ioremap_prot); + void __iounmap(volatile void __iomem *io_addr) { void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr); -- 2.39.2