summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCatalin Marinas <catalin.marinas@arm.com>2011-11-07 16:16:55 +0000
committerNicolas Pitre <nicolas.pitre@linaro.org>2011-11-10 17:32:55 -0500
commit0eded4d23f4f6a5863834a7e0e983a30f2ecc5d4 (patch)
treea0ab025b7da0895744a3872368e8503d5bd421e7
parenteced83e4cee69d44d7f5b9ff09da0660a00406ab (diff)
ARM: LPAE: Add identity mapping support for the 3-level page table format
With LPAE, the pgd is a separate page table with entries pointing to the pmd. The identity_mapping_add() function needs to ensure that the pgd is populated before populating the pmd level. The do..while blocks now loop over the pmd in order to have the same implementation for the two page table formats. The pmd_addr_end() definition has been removed and the generic one used instead. The pmd clean-up is done in the pgd_free() function. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
-rw-r--r--arch/arm/mm/idmap.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
index 2be9139a4ef..24e06555bee 100644
--- a/arch/arm/mm/idmap.c
+++ b/arch/arm/mm/idmap.c
@@ -1,9 +1,36 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <asm/cputype.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
+#ifdef CONFIG_ARM_LPAE
+static void idmap_add_pmd(pud_t *pud, unsigned long addr, unsigned long end,
+ unsigned long prot)
+{
+ pmd_t *pmd;
+ unsigned long next;
+
+ if (pud_none_or_clear_bad(pud) || (pud_val(*pud) & L_PGD_SWAPPER)) {
+ pmd = pmd_alloc_one(NULL, addr);
+ if (!pmd) {
+ pr_warning("Failed to allocate identity pmd.\n");
+ return;
+ }
+ pud_populate(NULL, pud, pmd);
+ pmd += pmd_index(addr);
+ } else
+ pmd = pmd_offset(pud, addr);
+
+ do {
+ next = pmd_addr_end(addr, end);
+ *pmd = __pmd((addr & PMD_MASK) | prot);
+ flush_pmd_entry(pmd);
+ } while (pmd++, addr = next, addr != end);
+}
+#else /* !CONFIG_ARM_LPAE */
static void idmap_add_pmd(pud_t *pud, unsigned long addr, unsigned long end,
unsigned long prot)
{
@@ -15,6 +42,7 @@ static void idmap_add_pmd(pud_t *pud, unsigned long addr, unsigned long end,
pmd[1] = __pmd(addr);
flush_pmd_entry(pmd);
}
+#endif /* CONFIG_ARM_LPAE */
static void idmap_add_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
unsigned long prot)
@@ -32,7 +60,7 @@ void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end)
{
unsigned long prot, next;
- prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE;
+ prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF;
if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale())
prot |= PMD_BIT4;
@@ -46,7 +74,11 @@ void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end)
#ifdef CONFIG_SMP
static void idmap_del_pmd(pud_t *pud, unsigned long addr, unsigned long end)
{
- pmd_t *pmd = pmd_offset(pud, addr);
+ pmd_t *pmd;
+
+ if (pud_none_or_clear_bad(pud))
+ return;
+ pmd = pmd_offset(pud, addr);
pmd_clear(pmd);
}