aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64
diff options
context:
space:
mode:
authorSteve Capper <steve.capper@linaro.org>2014-05-06 09:02:27 -0400
committerCatalin Marinas <catalin.marinas@arm.com>2014-05-09 11:10:58 -0400
commit206a2a73a62d37c8b8f6ddd3180c202b2e7298ab (patch)
tree0d62a75a3e29667792ee37e3c5aed14d1bc03303 /arch/arm64
parentba6bf8c85cb0d263ca9a98ef6a76ab651a97c60b (diff)
arm64: mm: Create gigabyte kernel logical mappings where possible
We have the capability to map 1GB level 1 blocks when using a 4K granule. This patch adjusts the create_mapping logic s.t. when mapping physical memory on boot, we attempt to use a 1GB block if both the VA and PA start and end are 1GB aligned. This both reduces the levels of lookup required to resolve a kernel logical address, as well as reduces TLB pressure on cores that support 1GB TLB entries. Signed-off-by: Steve Capper <steve.capper@linaro.org> Tested-by: Jungseok Lee <jays.lee@samsung.com> [catalin.marinas@arm.com: s/prot_sect_kernel/PROT_SECT_NORMAL_EXEC/] Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'arch/arm64')
-rw-r--r--arch/arm64/include/asm/pgtable-hwdef.h2
-rw-r--r--arch/arm64/include/asm/pgtable.h7
-rw-r--r--arch/arm64/mm/mmu.c28
3 files changed, 36 insertions, 1 deletions
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
index 5fc8a66c3924..955e8c5f0afb 100644
--- a/arch/arm64/include/asm/pgtable-hwdef.h
+++ b/arch/arm64/include/asm/pgtable-hwdef.h
@@ -29,6 +29,8 @@
29 */ 29 */
30 30
31#define PUD_TABLE_BIT (_AT(pgdval_t, 1) << 1) 31#define PUD_TABLE_BIT (_AT(pgdval_t, 1) << 1)
32#define PUD_TYPE_MASK (_AT(pgdval_t, 3) << 0)
33#define PUD_TYPE_SECT (_AT(pgdval_t, 1) << 0)
32 34
33/* 35/*
34 * Level 2 descriptor (PMD). 36 * Level 2 descriptor (PMD).
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 752348dbb4f3..3de4ef8bfd82 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -259,6 +259,7 @@ static inline pmd_t pte_pmd(pte_t pte)
259#define mk_pmd(page,prot) pfn_pmd(page_to_pfn(page),prot) 259#define mk_pmd(page,prot) pfn_pmd(page_to_pfn(page),prot)
260 260
261#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK)) 261#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK))
262#define pud_pfn(pud) (((pud_val(pud) & PUD_MASK) & PHYS_MASK) >> PAGE_SHIFT)
262 263
263#define set_pmd_at(mm, addr, pmdp, pmd) set_pmd(pmdp, pmd) 264#define set_pmd_at(mm, addr, pmdp, pmd) set_pmd(pmdp, pmd)
264 265
@@ -292,6 +293,12 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
292#define pmd_sect(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) == \ 293#define pmd_sect(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) == \
293 PMD_TYPE_SECT) 294 PMD_TYPE_SECT)
294 295
296#ifdef ARM64_64K_PAGES
297#define pud_sect(pud) (0)
298#else
299#define pud_sect(pud) ((pud_val(pud) & PUD_TYPE_MASK) == \
300 PUD_TYPE_SECT)
301#endif
295 302
296static inline void set_pmd(pmd_t *pmdp, pmd_t pmd) 303static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
297{ 304{
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 2c0e1dda8163..3a729de96f15 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -195,7 +195,30 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
195 195
196 do { 196 do {
197 next = pud_addr_end(addr, end); 197 next = pud_addr_end(addr, end);
198 alloc_init_pmd(pud, addr, next, phys); 198
199 /*
200 * For 4K granule only, attempt to put down a 1GB block
201 */
202 if ((PAGE_SHIFT == 12) &&
203 ((addr | next | phys) & ~PUD_MASK) == 0) {
204 pud_t old_pud = *pud;
205 set_pud(pud, __pud(phys | PROT_SECT_NORMAL_EXEC));
206
207 /*
208 * If we have an old value for a pud, it will
209 * be pointing to a pmd table that we no longer
210 * need (from swapper_pg_dir).
211 *
212 * Look up the old pmd table and free it.
213 */
214 if (!pud_none(old_pud)) {
215 phys_addr_t table = __pa(pmd_offset(&old_pud, 0));
216 memblock_free(table, PAGE_SIZE);
217 flush_tlb_all();
218 }
219 } else {
220 alloc_init_pmd(pud, addr, next, phys);
221 }
199 phys += next - addr; 222 phys += next - addr;
200 } while (pud++, addr = next, addr != end); 223 } while (pud++, addr = next, addr != end);
201} 224}
@@ -338,6 +361,9 @@ int kern_addr_valid(unsigned long addr)
338 if (pud_none(*pud)) 361 if (pud_none(*pud))
339 return 0; 362 return 0;
340 363
364 if (pud_sect(*pud))
365 return pfn_valid(pud_pfn(*pud));
366
341 pmd = pmd_offset(pud, addr); 367 pmd = pmd_offset(pud, addr);
342 if (pmd_none(*pmd)) 368 if (pmd_none(*pmd))
343 return 0; 369 return 0;