summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeeti Desai <neetid@codeaurora.org>2014-06-25 17:17:35 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:03:19 -0700
commit6992ec518124e02eda15bb568bee2a6e0e8c2b5c (patch)
treef3f3b4e3c7bedd4821ef0c42556461101f11b2ad
parent52c49cdc5e7202a1ed08d6add67684ba7932621e (diff)
arm64: Allow remapping lowmem as 4K pages
For certain debug features the lowmem needs to be mapped as pages instead of sections. Add config option to allow remapping of lowmem as 4K pages Change-Id: I50179311facd91b97ecde720da38ec7e47512e95 Signed-off-by: Neeti Desai <neetid@codeaurora.org>
-rw-r--r--arch/arm64/Kconfig.debug10
-rw-r--r--arch/arm64/mm/mmu.c72
2 files changed, 82 insertions, 0 deletions
diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug
index 04fb73b973f1..8c80724c8774 100644
--- a/arch/arm64/Kconfig.debug
+++ b/arch/arm64/Kconfig.debug
@@ -85,6 +85,16 @@ config DEBUG_ALIGN_RODATA
If in doubt, say N
+config FORCE_PAGES
+ bool "Force lowmem to be mapped with 4K pages"
+ help
+ There are some advanced debug features that can only be done when
+ memory is mapped with pages instead of sections. Enable this option
+ to always map lowmem pages with pages. This may have a performance
+ cost due to increased TLB pressure.
+
+ If unsure say N.
+
source "drivers/hwtracing/coresight/Kconfig"
endmenu
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index a652d959ffaa..5cf16a160e76 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -442,6 +442,77 @@ static void __init map_mem(void)
/* Limit no longer required. */
memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE);
}
+#ifdef CONFIG_FORCE_PAGES
+static noinline void split_and_set_pmd(pmd_t *pmd, unsigned long addr,
+ unsigned long end, unsigned long pfn)
+{
+ pte_t *pte, *start_pte;
+
+ start_pte = early_alloc(PTRS_PER_PTE * sizeof(pte_t));
+ pte = start_pte;
+
+ do {
+ set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
+ pfn++;
+ } while (pte++, addr += PAGE_SIZE, addr != end);
+
+ set_pmd(pmd, __pmd((__pa(start_pte)) | PMD_TYPE_TABLE));
+}
+
+static noinline void __init remap_pages(void)
+{
+ struct memblock_region *reg;
+
+ for_each_memblock(memory, reg) {
+ phys_addr_t phys_pgd = reg->base;
+ phys_addr_t phys_end = reg->base + reg->size;
+ unsigned long addr_pgd = (unsigned long)__va(phys_pgd);
+ unsigned long end = (unsigned long)__va(phys_end);
+ pmd_t *pmd = NULL;
+ pud_t *pud = NULL;
+ pgd_t *pgd = NULL;
+ unsigned long next_pud, next_pmd, next_pgd;
+ unsigned long addr_pmd, addr_pud;
+ phys_addr_t phys_pud, phys_pmd;
+
+ if (phys_pgd >= phys_end)
+ break;
+
+ pgd = pgd_offset(&init_mm, addr_pgd);
+ do {
+ next_pgd = pgd_addr_end(addr_pgd, end);
+ pud = pud_offset(pgd, addr_pgd);
+ addr_pud = addr_pgd;
+ phys_pud = phys_pgd;
+ do {
+ next_pud = pud_addr_end(addr_pud, next_pgd);
+ pmd = pmd_offset(pud, addr_pud);
+ addr_pmd = addr_pud;
+ phys_pmd = phys_pud;
+ do {
+ next_pmd = pmd_addr_end(addr_pmd,
+ next_pud);
+ if (pmd_none(*pmd) || pmd_bad(*pmd))
+ split_and_set_pmd(pmd, addr_pmd,
+ next_pmd, __phys_to_pfn(phys_pmd));
+ pmd++;
+ phys_pmd += next_pmd - addr_pmd;
+ } while (addr_pmd = next_pmd,
+ addr_pmd < next_pud);
+ phys_pud += next_pud - addr_pud;
+ } while (pud++, addr_pud = next_pud,
+ addr_pud < next_pgd);
+ phys_pgd += next_pgd - addr_pgd;
+ } while (pgd++, addr_pgd = next_pgd, addr_pgd < end);
+ }
+}
+
+#else
+static void __init remap_pages(void)
+{
+
+}
+#endif
static void __init fixup_executable(void)
{
@@ -494,6 +565,7 @@ void __init paging_init(void)
map_mem();
fixup_executable();
dma_contiguous_remap();
+ remap_pages();
/*
* Finally flush the caches and tlb to ensure that we're in a