summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/cpu/armv8/cache_v8.c70
1 files changed, 38 insertions, 32 deletions
diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c
index b8867a79ce..8604035e14 100644
--- a/arch/arm/cpu/armv8/cache_v8.c
+++ b/arch/arm/cpu/armv8/cache_v8.c
@@ -167,6 +167,37 @@ static void set_pte_table(u64 *pte, u64 *table)
*pte = PTE_TYPE_TABLE | (ulong)table;
}
+/* Splits a block PTE into table with subpages spanning the old block */
+static void split_block(u64 *pte, int level)
+{
+ u64 old_pte = *pte;
+ u64 *new_table;
+ u64 i = 0;
+ /* level describes the parent level, we need the child ones */
+ int levelshift = level2shift(level + 1);
+
+ if (pte_type(pte) != PTE_TYPE_BLOCK)
+ panic("PTE %p (%llx) is not a block. Some driver code wants to "
+ "modify dcache settings for an range not covered in "
+ "mem_map.", pte, old_pte);
+
+ new_table = create_table();
+ debug("Splitting pte %p (%llx) into %p\n", pte, old_pte, new_table);
+
+ for (i = 0; i < MAX_PTE_ENTRIES; i++) {
+ new_table[i] = old_pte | (i << levelshift);
+
+ /* Level 3 block PTEs have the table type */
+ if ((level + 1) == 3)
+ new_table[i] |= PTE_TYPE_TABLE;
+
+ debug("Setting new_table[%lld] = %llx\n", i, new_table[i]);
+ }
+
+ /* Set the new table into effect */
+ set_pte_table(pte, new_table);
+}
+
/* Add one mm_region map entry to the page tables */
static void add_map(struct mm_region *map)
{
@@ -188,6 +219,8 @@ static void add_map(struct mm_region *map)
for (level = 1; level < 4; level++) {
pte = find_pte(addr, level);
+ if (!pte)
+ panic("pte not found\n");
blocksize = 1ULL << level2shift(level);
debug("Checking if pte fits for addr=%llx size=%llx "
"blocksize=%llx\n", addr, size, blocksize);
@@ -199,48 +232,21 @@ static void add_map(struct mm_region *map)
addr += blocksize;
size -= blocksize;
break;
- } else if ((pte_type(pte) == PTE_TYPE_FAULT)) {
+ } else if (pte_type(pte) == PTE_TYPE_FAULT) {
/* Page doesn't fit, create subpages */
debug("Creating subtable for addr 0x%llx "
"blksize=%llx\n", addr, blocksize);
new_table = create_table();
set_pte_table(pte, new_table);
+ } else if (pte_type(pte) == PTE_TYPE_BLOCK) {
+ debug("Split block into subtable for addr 0x%llx blksize=0x%llx\n",
+ addr, blocksize);
+ split_block(pte, level);
}
}
}
}
-/* Splits a block PTE into table with subpages spanning the old block */
-static void split_block(u64 *pte, int level)
-{
- u64 old_pte = *pte;
- u64 *new_table;
- u64 i = 0;
- /* level describes the parent level, we need the child ones */
- int levelshift = level2shift(level + 1);
-
- if (pte_type(pte) != PTE_TYPE_BLOCK)
- panic("PTE %p (%llx) is not a block. Some driver code wants to "
- "modify dcache settings for an range not covered in "
- "mem_map.", pte, old_pte);
-
- new_table = create_table();
- debug("Splitting pte %p (%llx) into %p\n", pte, old_pte, new_table);
-
- for (i = 0; i < MAX_PTE_ENTRIES; i++) {
- new_table[i] = old_pte | (i << levelshift);
-
- /* Level 3 block PTEs have the table type */
- if ((level + 1) == 3)
- new_table[i] |= PTE_TYPE_TABLE;
-
- debug("Setting new_table[%lld] = %llx\n", i, new_table[i]);
- }
-
- /* Set the new table into effect */
- set_pte_table(pte, new_table);
-}
-
enum pte_type {
PTE_INVAL,
PTE_BLOCK,