Skip to content

Commit 5c63db5

Browse files
Ryan Robertswilldeacon
authored andcommitted
arm64: mm: Don't remap pgtables per-cont(pte|pmd) block
A large part of the kernel boot time is creating the kernel linear map page tables. When rodata=full, all memory is mapped by pte. And when there is lots of physical ram, there are lots of pte tables to populate. The primary cost associated with this is mapping and unmapping the pte table memory in the fixmap; at unmap time, the TLB entry must be invalidated and this is expensive. Previously, each pmd and pte table was fixmapped/fixunmapped for each cont(pte|pmd) block of mappings (16 entries with 4K granule). This means we ended up issuing 32 TLBIs per (pmd|pte) table during the population phase. Let's fix that, and fixmap/fixunmap each page once per population, for a saving of 31 TLBIs per (pmd|pte) table. This gives a significant boot speedup. Execution time of map_mem(), which creates the kernel linear map page tables, was measured on different machines with different RAM configs: | Apple M2 VM | Ampere Altra| Ampere Altra| Ampere Altra | VM, 16G | VM, 64G | VM, 256G | Metal, 512G ---------------|-------------|-------------|-------------|------------- | ms (%) | ms (%) | ms (%) | ms (%) ---------------|-------------|-------------|-------------|------------- before | 168 (0%) | 2198 (0%) | 8644 (0%) | 17447 (0%) after | 78 (-53%) | 435 (-80%) | 1723 (-80%) | 3779 (-78%) Signed-off-by: Ryan Roberts <[email protected]> Tested-by: Itaru Kitayama <[email protected]> Tested-by: Eric Chanudet <[email protected]> Reviewed-by: Mark Rutland <[email protected]> Reviewed-by: Ard Biesheuvel <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent fec50db commit 5c63db5

File tree

1 file changed

+14
-13
lines changed

1 file changed

+14
-13
lines changed

arch/arm64/mm/mmu.c

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,9 @@ bool pgattr_change_is_safe(u64 old, u64 new)
172172
return ((old ^ new) & ~mask) == 0;
173173
}
174174

175-
static void init_pte(pmd_t *pmdp, unsigned long addr, unsigned long end,
175+
static void init_pte(pte_t *ptep, unsigned long addr, unsigned long end,
176176
phys_addr_t phys, pgprot_t prot)
177177
{
178-
pte_t *ptep;
179-
180-
ptep = pte_set_fixmap_offset(pmdp, addr);
181178
do {
182179
pte_t old_pte = __ptep_get(ptep);
183180

@@ -192,8 +189,6 @@ static void init_pte(pmd_t *pmdp, unsigned long addr, unsigned long end,
192189

193190
phys += PAGE_SIZE;
194191
} while (ptep++, addr += PAGE_SIZE, addr != end);
195-
196-
pte_clear_fixmap();
197192
}
198193

199194
static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr,
@@ -204,6 +199,7 @@ static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr,
204199
{
205200
unsigned long next;
206201
pmd_t pmd = READ_ONCE(*pmdp);
202+
pte_t *ptep;
207203

208204
BUG_ON(pmd_sect(pmd));
209205
if (pmd_none(pmd)) {
@@ -219,6 +215,7 @@ static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr,
219215
}
220216
BUG_ON(pmd_bad(pmd));
221217

218+
ptep = pte_set_fixmap_offset(pmdp, addr);
222219
do {
223220
pgprot_t __prot = prot;
224221

@@ -229,20 +226,21 @@ static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr,
229226
(flags & NO_CONT_MAPPINGS) == 0)
230227
__prot = __pgprot(pgprot_val(prot) | PTE_CONT);
231228

232-
init_pte(pmdp, addr, next, phys, __prot);
229+
init_pte(ptep, addr, next, phys, __prot);
233230

231+
ptep += pte_index(next) - pte_index(addr);
234232
phys += next - addr;
235233
} while (addr = next, addr != end);
234+
235+
pte_clear_fixmap();
236236
}
237237

238-
static void init_pmd(pud_t *pudp, unsigned long addr, unsigned long end,
238+
static void init_pmd(pmd_t *pmdp, unsigned long addr, unsigned long end,
239239
phys_addr_t phys, pgprot_t prot,
240240
phys_addr_t (*pgtable_alloc)(int), int flags)
241241
{
242242
unsigned long next;
243-
pmd_t *pmdp;
244243

245-
pmdp = pmd_set_fixmap_offset(pudp, addr);
246244
do {
247245
pmd_t old_pmd = READ_ONCE(*pmdp);
248246

@@ -268,8 +266,6 @@ static void init_pmd(pud_t *pudp, unsigned long addr, unsigned long end,
268266
}
269267
phys += next - addr;
270268
} while (pmdp++, addr = next, addr != end);
271-
272-
pmd_clear_fixmap();
273269
}
274270

275271
static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr,
@@ -279,6 +275,7 @@ static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr,
279275
{
280276
unsigned long next;
281277
pud_t pud = READ_ONCE(*pudp);
278+
pmd_t *pmdp;
282279

283280
/*
284281
* Check for initial section mappings in the pgd/pud.
@@ -297,6 +294,7 @@ static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr,
297294
}
298295
BUG_ON(pud_bad(pud));
299296

297+
pmdp = pmd_set_fixmap_offset(pudp, addr);
300298
do {
301299
pgprot_t __prot = prot;
302300

@@ -307,10 +305,13 @@ static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr,
307305
(flags & NO_CONT_MAPPINGS) == 0)
308306
__prot = __pgprot(pgprot_val(prot) | PTE_CONT);
309307

310-
init_pmd(pudp, addr, next, phys, __prot, pgtable_alloc, flags);
308+
init_pmd(pmdp, addr, next, phys, __prot, pgtable_alloc, flags);
311309

310+
pmdp += pmd_index(next) - pmd_index(addr);
312311
phys += next - addr;
313312
} while (addr = next, addr != end);
313+
314+
pmd_clear_fixmap();
314315
}
315316

316317
static void alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end,

0 commit comments

Comments
 (0)