From: Alexander Graf <agraf@suse.de>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 2/9] arm64: Make full va map code more dynamic
Date: Wed, 24 Feb 2016 11:55:39 +0100 [thread overview]
Message-ID: <56CD8C2B.9090102@suse.de> (raw)
In-Reply-To: <CAPnjgZ034s9EHtUt_F=VGhgbqVzeYKKjtUj4n0vGLqVGUiHcEw@mail.gmail.com>
On 23.02.16 14:17, Simon Glass wrote:
> Hi Alex,
>
> On 21 February 2016 at 18:57, Alexander Graf <agraf@suse.de> wrote:
>> The idea to generate our pages tables from an array of memory ranges
>> is very sound. However, instead of hard coding the code to create up
>> to 2 levels of 64k granule page tables, we really should just create
>> normal 4k page tables that allow us to set caching attributes on 2M
>> or 4k level later on.
>>
>> So this patch moves the full_va mapping code to 4k page size and
>> makes it fully flexible to dynamically create as many levels as
>> necessary for a map (including dynamic 1G/2M pages). It also adds
>> support to dynamically split a large map into smaller ones when
>> some code wants to set dcache attributes.
>>
>> With all this in place, there is very little reason to create your
>> own page tables in board specific files.
>>
>> Signed-off-by: Alexander Graf <agraf@suse.de>
>> ---
>> arch/arm/cpu/armv8/cache_v8.c | 346 +++++++++++++++++++++++++++++++------
>> arch/arm/include/asm/armv8/mmu.h | 68 ++++----
>> arch/arm/include/asm/global_data.h | 4 +-
>> arch/arm/include/asm/system.h | 3 +-
>> include/configs/thunderx_88xx.h | 14 +-
>> 5 files changed, 332 insertions(+), 103 deletions(-)
>>
>
> Should the change to the thunderx file go in a separate patch?
We're changing semantics for some defines from "this define acts in
L1/L2 page table entries" to "this define is for level/block type PTEs".
So it's tied to this patch :).
>
>> diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c
>> index 9229532..4369a83 100644
>> --- a/arch/arm/cpu/armv8/cache_v8.c
>> +++ b/arch/arm/cpu/armv8/cache_v8.c
>> @@ -2,6 +2,9 @@
>> * (C) Copyright 2013
>> * David Feng <fenghua@phytium.com.cn>
>> *
>> + * (C) Copyright 2016
>> + * Alexander Graf <agraf@suse.de>
>> + *
>> * SPDX-License-Identifier: GPL-2.0+
>> */
>>
>> @@ -9,35 +12,40 @@
>> #include <asm/system.h>
>> #include <asm/armv8/mmu.h>
>>
>> -DECLARE_GLOBAL_DATA_PTR;
>> -
>> -#ifndef CONFIG_SYS_DCACHE_OFF
>> +/* #define DEBUG_MMU */
>>
>> -#ifdef CONFIG_SYS_FULL_VA
>> -static void set_ptl1_entry(u64 index, u64 ptl2_entry)
>> -{
>> - u64 *pgd = (u64 *)gd->arch.tlb_addr;
>> - u64 value;
>> +#ifdef DEBUG_MMU
>> +#define DPRINTF(a, ...) printf("%s:%d: " a, __func__, __LINE__, __VA_ARGS__)
>> +#else
>> +#define DPRINTF(a, ...) do { } while(0)
>> +#endif
>
> Can you use the normal DEBUG and debug()?
Uh, I guess so, yeah.
>
>>
>> - value = ptl2_entry | PTL1_TYPE_TABLE;
>> - pgd[index] = value;
>> -}
>> +DECLARE_GLOBAL_DATA_PTR;
>>
>> -static void set_ptl2_block(u64 ptl1, u64 bfn, u64 address, u64 memory_attrs)
>> -{
>> - u64 *pmd = (u64 *)ptl1;
>> - u64 value;
>> +#ifndef CONFIG_SYS_DCACHE_OFF
>>
>> - value = address | PTL2_TYPE_BLOCK | PTL2_BLOCK_AF;
>> - value |= memory_attrs;
>> - pmd[bfn] = value;
>> -}
>> +/*
>> + * With 4k page granule, a virtual address is split into 4 lookup parts
>> + * spanning 9 bits each:
>> + *
>> + * _______________________________________________
>> + * | | | | | | |
>> + * | 0 | Lv0 | Lv1 | Lv2 | Lv3 | off |
>> + * |_______|_______|_______|_______|_______|_______|
>> + * 63-48 47-39 38-30 29-21 20-12 11-00
>> + *
>> + * mask page size
>> + *
>> + * Lv0: FF8000000000 --
>> + * Lv1: 7FC0000000 1G
>> + * Lv2: 3FE00000 2M
>> + * Lv3: 1FF000 4K
>> + * off: FFF
>> + */
>>
>> +#ifdef CONFIG_SYS_FULL_VA
>> static struct mm_region mem_map[] = CONFIG_SYS_MEM_MAP;
>
> I am not ken on the idea of using a big #define table on these boards.
> Is there not a device-tree binding for this that we can use? It is
> just a data table, We are moving to Kconfig and eventually want to
> drop the config files.
I'll move this into board files which then can do whatever they like
with it - take if from a #define in a header, populate it dynamically
from device tree, do something halfway in between, whatever fits your
needs best :).
Btw, if you want to use dt for it, you don't need to add any new
bindings at all. Simply take all of your device regs/ranges and memory
ranges and gobble them into the memory map.
>
>>
>> -#define PTL1_ENTRIES CONFIG_SYS_PTL1_ENTRIES
>> -#define PTL2_ENTRIES CONFIG_SYS_PTL2_ENTRIES
>> -
>> static u64 get_tcr(int el, u64 *pips, u64 *pva_bits)
>> {
>> u64 max_addr = 0;
>> @@ -79,8 +87,8 @@ static u64 get_tcr(int el, u64 *pips, u64 *pva_bits)
>> }
>>
>> /* PTWs cacheable, inner/outer WBWA and inner shareable */
>> - tcr |= TCR_TG0_64K | TCR_SHARED_INNER | TCR_ORGN_WBWA | TCR_IRGN_WBWA;
>> - tcr |= TCR_T0SZ(VA_BITS);
>> + tcr |= TCR_TG0_4K | TCR_SHARED_INNER | TCR_ORGN_WBWA | TCR_IRGN_WBWA;
>> + tcr |= TCR_T0SZ(va_bits);
>>
>> if (pips)
>> *pips = ips;
>> @@ -90,39 +98,196 @@ static u64 get_tcr(int el, u64 *pips, u64 *pva_bits)
>> return tcr;
>> }
>>
>> -static void setup_pgtables(void)
>> +#define MAX_PTE_ENTRIES 512
>> +
>> +static int pte_type(u64 *pte)
>> +{
>> + return *pte & PTE_TYPE_MASK;
>> +}
>> +
>> +/* Returns the LSB number for a PTE on level <level> */
>> +static int level2shift(int level)
>> {
>> - int l1_e, l2_e;
>> - unsigned long pmd = 0;
>> - unsigned long address;
>> -
>> - /* Setup the PMD pointers */
>> - for (l1_e = 0; l1_e < CONFIG_SYS_MEM_MAP_SIZE; l1_e++) {
>> - gd->arch.pmd_addr[l1_e] = gd->arch.tlb_addr +
>> - PTL1_ENTRIES * sizeof(u64);
>> - gd->arch.pmd_addr[l1_e] += PTL2_ENTRIES * sizeof(u64) * l1_e;
>> - gd->arch.pmd_addr[l1_e] = ALIGN(gd->arch.pmd_addr[l1_e],
>> - 0x10000UL);
>> + /* Page is 12 bits wide, every level translates 9 bits */
>> + return (12 + 9 * (3 - level));
>> +}
>> +
>> +static u64 *find_pte(u64 addr, int level)
>> +{
>> + int start_level = 0;
>> + u64 *pte;
>> + u64 idx;
>> + u64 va_bits;
>> + int i;
>> +
>> + DPRINTF("addr=%llx level=%d\n", addr, level);
>> +
>> + get_tcr(0, NULL, &va_bits);
>> + if (va_bits < 39)
>> + start_level = 1;
>> +
>> + if (level < start_level)
>> + return NULL;
>> +
>> + /* Walk through all page table levels to find our PTE */
>> + pte = (u64*)gd->arch.tlb_addr;
>> + for (i = start_level; i < 4; i++) {
>> + idx = (addr >> level2shift(i)) & 0x1FF;
>> + pte += idx;
>> + DPRINTF("idx=%llx PTE %p at level %d: %llx\n", idx, pte, i, *pte);
>> +
>> + /* Found it */
>> + if (i == level)
>> + return pte;
>> + /* PTE is no table (either invalid or block), can't traverse */
>> + if (pte_type(pte) != PTE_TYPE_TABLE)
>> + return NULL;
>> + /* Off to the next level */
>> + pte = (u64*)(*pte & 0x0000fffffffff000ULL);
>> }
>>
>> - /* Setup the page tables */
>> - for (l1_e = 0; l1_e < PTL1_ENTRIES; l1_e++) {
>> - if (mem_map[pmd].base ==
>> - (uintptr_t)l1_e << PTL2_BITS) {
>> - set_ptl1_entry(l1_e, gd->arch.pmd_addr[pmd]);
>> -
>> - for (l2_e = 0; l2_e < PTL2_ENTRIES; l2_e++) {
>> - address = mem_map[pmd].base
>> - + (uintptr_t)l2_e * BLOCK_SIZE;
>> - set_ptl2_block(gd->arch.pmd_addr[pmd], l2_e,
>> - address, mem_map[pmd].attrs);
>> - }
>> + /* Should never reach here */
>> + return NULL;
>> +}
>> +
>> +/* Creates a new full table (512 entries) and sets *pte to refer to it */
>> +static u64 *create_table(void)
>> +{
>> + u64 *new_table = (u64*)gd->arch.tlb_fillptr;
>> + u64 pt_len = MAX_PTE_ENTRIES * sizeof(u64);
>> +
>> + /* Allocate MAX_PTE_ENTRIES pte entries */
>> + gd->arch.tlb_fillptr += pt_len;
>> +
>> + if (gd->arch.tlb_fillptr - gd->arch.tlb_addr > gd->arch.tlb_size)
>> + panic("Insufficient RAM for page table: 0x%lx > 0x%lx",
>> + gd->arch.tlb_fillptr - gd->arch.tlb_addr,
>> + gd->arch.tlb_size);
>
> For each of these panic() calls can you please add a comment as to
> what the user should do? It needs to be very clear what action should
> be taken to resolve the problem.
Good idea. The only case where I can't think of a good text is at
if (pte_type(pte) != PTE_TYPE_TABLE)
panic("PTE %p (%llx) for addr=%llx should be a table",
pte, *pte, start);
because this really is more of an assert(). We should never reach it.
Thanks a bunch for the reviews,
Alex
next prev parent reply other threads:[~2016-02-24 10:55 UTC|newest]
Thread overview: 50+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-02-22 1:57 [U-Boot] [PATCH 0/9] arm64: Unify MMU code Alexander Graf
2016-02-22 1:57 ` [U-Boot] [PATCH 1/9] thunderx: Calculate TCR dynamically Alexander Graf
2016-02-22 1:57 ` [U-Boot] [PATCH 2/9] arm64: Make full va map code more dynamic Alexander Graf
2016-02-22 18:18 ` Stephen Warren
2016-02-22 18:37 ` Alexander Graf
2016-02-22 18:45 ` Stephen Warren
2016-02-24 10:21 ` Alexander Graf
2016-02-22 18:42 ` Stephen Warren
2016-02-23 13:17 ` Simon Glass
2016-02-23 17:21 ` Stephen Warren
2016-02-23 17:30 ` Simon Glass
2016-02-23 17:40 ` Stephen Warren
2016-02-23 20:00 ` Simon Glass
2016-02-23 20:33 ` Stephen Warren
2016-02-24 4:42 ` Simon Glass
2016-02-24 16:56 ` Stephen Warren
2016-02-24 10:55 ` Alexander Graf [this message]
2016-02-24 17:01 ` Stephen Warren
2016-02-24 17:04 ` Alexander Graf
2016-02-22 1:57 ` [U-Boot] [PATCH 3/9] zymqmp: Replace home grown mmu code with generic table approach Alexander Graf
2016-02-23 11:04 ` Michal Simek
2016-02-23 11:33 ` Alexander Graf
2016-02-23 13:07 ` Michal Simek
2016-02-26 0:49 ` Alexander Graf
2016-02-26 8:29 ` Michal Simek
2016-02-26 8:55 ` Alexander Graf
2017-02-16 15:26 ` brettstahlman
2016-02-22 1:57 ` [U-Boot] [PATCH 4/9] tegra: " Alexander Graf
2016-02-22 18:28 ` Stephen Warren
2016-02-23 10:37 ` Michal Simek
2016-02-23 17:29 ` Stephen Warren
2016-02-24 10:28 ` Alexander Graf
2016-02-22 1:57 ` [U-Boot] [PATCH 5/9] vexpress64: Add MMU tables Alexander Graf
2016-02-22 1:57 ` [U-Boot] [PATCH 6/9] dwmmc: Increase retry timeout Alexander Graf
2016-02-22 1:57 ` [U-Boot] [PATCH 7/9] hikey: Add MMU tables Alexander Graf
2016-02-22 1:57 ` [U-Boot] [PATCH 8/9] arm64: Remove non-full-va map code Alexander Graf
2016-02-22 1:57 ` [U-Boot] [PATCH 9/9] arm64: Only allow dcache disabled in SPL builds Alexander Graf
2016-02-22 17:37 ` [U-Boot] [PATCH 0/9] arm64: Unify MMU code york sun
2016-02-22 18:02 ` Alexander Graf
2016-02-22 18:12 ` york sun
2016-02-22 18:31 ` Alexander Graf
2016-02-22 18:39 ` york sun
2016-02-22 19:42 ` Alexander Graf
2016-02-22 19:52 ` york sun
2016-02-22 20:09 ` Alexander Graf
2016-02-22 20:15 ` york sun
2016-02-24 10:19 ` Alexander Graf
2016-02-24 16:57 ` Stephen Warren
2016-02-22 18:34 ` Stephen Warren
2016-02-24 10:33 ` Alexander Graf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=56CD8C2B.9090102@suse.de \
--to=agraf@suse.de \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.