[PATCH RFC 16/18] riscv: make set_direct_map_*_noflush actually noflush

From: Mike Rapoport (Microsoft)

Date: Tue Jul 21 2026 - 13:15:02 EST


riscv versions of set_direct_memory_{default,invalid,valid}_noflush call
core CPA API (change_page_attr_set_clr()) that actually flush TLB after
the page table update.

This was also the case before the conversion of riscv to use generic CPA
core, riscv::__set_memory() always flushed TLBs, even when it was called
from _noflush API variants.

Switch the _noflush APIs to use __change_page_attr_set_clr() that does
not flush TLB unless there was an error or there was a split of higher
level page tables.

Signed-off-by: Mike Rapoport (Microsoft) <rppt@xxxxxxxxxx>
---
arch/riscv/mm/pageattr.c | 36 +++++++++++++++++++++++++-----------
1 file changed, 25 insertions(+), 11 deletions(-)

diff --git a/arch/riscv/mm/pageattr.c b/arch/riscv/mm/pageattr.c
index 677f42a6750d..66a20fc3d805 100644
--- a/arch/riscv/mm/pageattr.c
+++ b/arch/riscv/mm/pageattr.c
@@ -199,32 +199,46 @@ int set_memory_nx(unsigned long addr, int numpages)
int set_direct_map_invalid_noflush(struct page *page)
{
unsigned long start = (unsigned long)page_address(page);
-
- return change_page_attr_clear(&start, 1, __pgprot(_PAGE_PRESENT), 0);
+ struct cpa_data cpa = { .vaddr = &start,
+ .pgd = NULL,
+ .numpages = 1,
+ .mask_set = __pgprot(0),
+ .mask_clr = __pgprot(_PAGE_PRESENT),
+ .flags = CPA_NO_CHECK_ALIAS };
+
+ return __change_page_attr_set_clr(&cpa, 1);
}

int set_direct_map_default_noflush(struct page *page)
{
unsigned long start = (unsigned long)page_address(page);
-
- return change_page_attr_set_clr(&start, 1, PAGE_KERNEL,
- __pgprot(_PAGE_EXEC), 0, 0, NULL);
+ struct cpa_data cpa = { .vaddr = &start,
+ .pgd = NULL,
+ .numpages = 1,
+ .mask_set = PAGE_KERNEL,
+ .mask_clr = __pgprot(_PAGE_EXEC),
+ .flags = CPA_NO_CHECK_ALIAS };
+
+ return __change_page_attr_set_clr(&cpa, 1);
}

int set_direct_map_valid_noflush(struct page *page, unsigned nr, bool valid)
{
unsigned long start = (unsigned long)page_address(page);
- pgprot_t set, clear;
+ struct cpa_data cpa = { .vaddr = &start,
+ .pgd = NULL,
+ .numpages = nr,
+ .flags = CPA_NO_CHECK_ALIAS };

if (valid) {
- set = PAGE_KERNEL;
- clear = __pgprot(_PAGE_EXEC);
+ cpa.mask_set = PAGE_KERNEL;
+ cpa.mask_clr = __pgprot(_PAGE_EXEC);
} else {
- set = __pgprot(0);
- clear = __pgprot(_PAGE_PRESENT);
+ cpa.mask_set = __pgprot(0);
+ cpa.mask_clr = __pgprot(_PAGE_PRESENT);
}

- return change_page_attr_set_clr(&start, nr, set, clear, 0, 0, NULL);
+ return __change_page_attr_set_clr(&cpa, 1);
}

#ifdef CONFIG_DEBUG_PAGEALLOC

--
2.53.0