Skip to content

Commit d2f8671

Browse files
bibo-maochenhuacai
authored andcommitted
LoongArch: Set initial pte entry with PAGE_GLOBAL for kernel space
There are two pages in one TLB entry on LoongArch system. For kernel space, it requires both two pte entries (buddies) with PAGE_GLOBAL bit set, otherwise HW treats it as non-global tlb, there will be potential problems if tlb entry for kernel space is not global. Such as fail to flush kernel tlb with the function local_flush_tlb_kernel_range() which supposed only flush tlb with global bit. Kernel address space areas include percpu, vmalloc, vmemmap, fixmap and kasan areas. For these areas both two consecutive page table entries should be enabled with PAGE_GLOBAL bit. So with function set_pte() and pte_clear(), pte buddy entry is checked and set besides its own pte entry. However it is not atomic operation to set both two pte entries, there is problem with test_vmalloc test case. So function kernel_pte_init() is added to init a pte table when it is created for kernel address space, and the default initial pte value is PAGE_GLOBAL rather than zero at beginning. Then only its own pte entry need update with function set_pte() and pte_clear(), nothing to do with the pte buddy entry. Signed-off-by: Bibo Mao <[email protected]> Signed-off-by: Huacai Chen <[email protected]>
1 parent 134475a commit d2f8671

File tree

7 files changed

+54
-30
lines changed

7 files changed

+54
-30
lines changed

arch/loongarch/include/asm/pgalloc.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#define __HAVE_ARCH_PMD_ALLOC_ONE
1212
#define __HAVE_ARCH_PUD_ALLOC_ONE
13+
#define __HAVE_ARCH_PTE_ALLOC_ONE_KERNEL
1314
#include <asm-generic/pgalloc.h>
1415

1516
static inline void pmd_populate_kernel(struct mm_struct *mm,
@@ -44,6 +45,16 @@ extern void pagetable_init(void);
4445

4546
extern pgd_t *pgd_alloc(struct mm_struct *mm);
4647

48+
static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm)
49+
{
50+
pte_t *pte = __pte_alloc_one_kernel(mm);
51+
52+
if (pte)
53+
kernel_pte_init(pte);
54+
55+
return pte;
56+
}
57+
4758
#define __pte_free_tlb(tlb, pte, address) \
4859
do { \
4960
pagetable_pte_dtor(page_ptdesc(pte)); \

arch/loongarch/include/asm/pgtable.h

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ extern void set_pmd_at(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp, pm
269269
extern void pgd_init(void *addr);
270270
extern void pud_init(void *addr);
271271
extern void pmd_init(void *addr);
272+
extern void kernel_pte_init(void *addr);
272273

273274
/*
274275
* Encode/decode swap entries and swap PTEs. Swap PTEs are all PTEs that
@@ -325,39 +326,17 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
325326
{
326327
WRITE_ONCE(*ptep, pteval);
327328

328-
if (pte_val(pteval) & _PAGE_GLOBAL) {
329-
pte_t *buddy = ptep_buddy(ptep);
330-
/*
331-
* Make sure the buddy is global too (if it's !none,
332-
* it better already be global)
333-
*/
334-
if (pte_none(ptep_get(buddy))) {
335329
#ifdef CONFIG_SMP
336-
/*
337-
* For SMP, multiple CPUs can race, so we need
338-
* to do this atomically.
339-
*/
340-
__asm__ __volatile__(
341-
__AMOR "$zero, %[global], %[buddy] \n"
342-
: [buddy] "+ZB" (buddy->pte)
343-
: [global] "r" (_PAGE_GLOBAL)
344-
: "memory");
345-
346-
DBAR(0b11000); /* o_wrw = 0b11000 */
347-
#else /* !CONFIG_SMP */
348-
WRITE_ONCE(*buddy, __pte(pte_val(ptep_get(buddy)) | _PAGE_GLOBAL));
349-
#endif /* CONFIG_SMP */
350-
}
351-
}
330+
if (pte_val(pteval) & _PAGE_GLOBAL)
331+
DBAR(0b11000); /* o_wrw = 0b11000 */
332+
#endif
352333
}
353334

354335
static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
355336
{
356-
/* Preserve global status for the pair */
357-
if (pte_val(ptep_get(ptep_buddy(ptep))) & _PAGE_GLOBAL)
358-
set_pte(ptep, __pte(_PAGE_GLOBAL));
359-
else
360-
set_pte(ptep, __pte(0));
337+
pte_t pte = ptep_get(ptep);
338+
pte_val(pte) &= _PAGE_GLOBAL;
339+
set_pte(ptep, pte);
361340
}
362341

363342
#define PGD_T_LOG2 (__builtin_ffs(sizeof(pgd_t)) - 1)

arch/loongarch/mm/init.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,9 @@ pte_t * __init populate_kernel_pte(unsigned long addr)
201201
pte = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
202202
if (!pte)
203203
panic("%s: Failed to allocate memory\n", __func__);
204+
204205
pmd_populate_kernel(&init_mm, pmd, pte);
206+
kernel_pte_init(pte);
205207
}
206208

207209
return pte_offset_kernel(pmd, addr);

arch/loongarch/mm/pgtable.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,26 @@ void pud_init(void *addr)
116116
EXPORT_SYMBOL_GPL(pud_init);
117117
#endif
118118

119+
void kernel_pte_init(void *addr)
120+
{
121+
unsigned long *p, *end;
122+
123+
p = (unsigned long *)addr;
124+
end = p + PTRS_PER_PTE;
125+
126+
do {
127+
p[0] = _PAGE_GLOBAL;
128+
p[1] = _PAGE_GLOBAL;
129+
p[2] = _PAGE_GLOBAL;
130+
p[3] = _PAGE_GLOBAL;
131+
p[4] = _PAGE_GLOBAL;
132+
p += 8;
133+
p[-3] = _PAGE_GLOBAL;
134+
p[-2] = _PAGE_GLOBAL;
135+
p[-1] = _PAGE_GLOBAL;
136+
} while (p != end);
137+
}
138+
119139
pmd_t mk_pmd(struct page *page, pgprot_t prot)
120140
{
121141
pmd_t pmd;

include/linux/mm.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3818,8 +3818,9 @@ void *sparse_buffer_alloc(unsigned long size);
38183818
struct page * __populate_section_memmap(unsigned long pfn,
38193819
unsigned long nr_pages, int nid, struct vmem_altmap *altmap,
38203820
struct dev_pagemap *pgmap);
3821-
void pmd_init(void *addr);
38223821
void pud_init(void *addr);
3822+
void pmd_init(void *addr);
3823+
void kernel_pte_init(void *addr);
38233824
pgd_t *vmemmap_pgd_populate(unsigned long addr, int node);
38243825
p4d_t *vmemmap_p4d_populate(pgd_t *pgd, unsigned long addr, int node);
38253826
pud_t *vmemmap_pud_populate(p4d_t *p4d, unsigned long addr, int node);

mm/kasan/init.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ static void __ref zero_pte_populate(pmd_t *pmd, unsigned long addr,
106106
}
107107
}
108108

109+
void __weak __meminit kernel_pte_init(void *addr)
110+
{
111+
}
112+
109113
static int __ref zero_pmd_populate(pud_t *pud, unsigned long addr,
110114
unsigned long end)
111115
{
@@ -126,8 +130,10 @@ static int __ref zero_pmd_populate(pud_t *pud, unsigned long addr,
126130

127131
if (slab_is_available())
128132
p = pte_alloc_one_kernel(&init_mm);
129-
else
133+
else {
130134
p = early_alloc(PAGE_SIZE, NUMA_NO_NODE);
135+
kernel_pte_init(p);
136+
}
131137
if (!p)
132138
return -ENOMEM;
133139

mm/sparse-vmemmap.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,13 +184,18 @@ static void * __meminit vmemmap_alloc_block_zero(unsigned long size, int node)
184184
return p;
185185
}
186186

187+
void __weak __meminit kernel_pte_init(void *addr)
188+
{
189+
}
190+
187191
pmd_t * __meminit vmemmap_pmd_populate(pud_t *pud, unsigned long addr, int node)
188192
{
189193
pmd_t *pmd = pmd_offset(pud, addr);
190194
if (pmd_none(*pmd)) {
191195
void *p = vmemmap_alloc_block_zero(PAGE_SIZE, node);
192196
if (!p)
193197
return NULL;
198+
kernel_pte_init(p);
194199
pmd_populate_kernel(&init_mm, pmd, p);
195200
}
196201
return pmd;

0 commit comments

Comments
 (0)