diff options
author | Steve Capper <steve.capper@linaro.org> | 2014-05-06 09:02:27 -0400 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2014-05-09 11:10:58 -0400 |
commit | 206a2a73a62d37c8b8f6ddd3180c202b2e7298ab (patch) | |
tree | 0d62a75a3e29667792ee37e3c5aed14d1bc03303 /arch/arm64 | |
parent | ba6bf8c85cb0d263ca9a98ef6a76ab651a97c60b (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.h | 2 | ||||
-rw-r--r-- | arch/arm64/include/asm/pgtable.h | 7 | ||||
-rw-r--r-- | arch/arm64/mm/mmu.c | 28 |
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 | ||
296 | static inline void set_pmd(pmd_t *pmdp, pmd_t pmd) | 303 | static 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; |