powerpc/mm: Avoid calling arch_enter/leave_lazy_mmu() in set_ptes
With commit9fee28baa6
("powerpc: implement the new page table range API") we added set_ptes to powerpc architecture. The implementation included calling arch_enter/leave_lazy_mmu() calls. The patch removes the usage of arch_enter/leave_lazy_mmu() because set_pte is not supposed to be used when updating a pte entry. Powerpc architecture uses this rule to skip the expensive tlb invalidate which is not needed when you are setting up the pte for the first time. See commit56eecdb912
("mm: Use ptep/pmdp_set_numa() for updating _PAGE_NUMA bit") for more details The patch also makes sure we are not using the interface to update a valid/present pte entry by adding VM_WARN_ON check all the ptes we are setting up. Furthermore, we add a comment to set_pte_filter to clarify it can only update folio-related flags and cannot filter pfn specific details in pte filtering. Removal of arch_enter/leave_lazy_mmu() also will avoid nesting of these functions that are not supported. For ex: remap_pte_range() -> arch_enter_lazy_mmu() -> set_ptes() -> arch_enter_lazy_mmu() -> arch_leave_lazy_mmu() -> arch_leave_lazy_mmu() Fixes:9fee28baa6
("powerpc: implement the new page table range API") Signed-off-by: "Aneesh Kumar K.V" <aneesh.kumar@linux.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://msgid.link/20231024143604.16749-1-aneesh.kumar@linux.ibm.com
This commit is contained in:
parent
daa9ada209
commit
47b8def935
@ -104,6 +104,8 @@ static pte_t set_pte_filter_hash(pte_t pte) { return pte; }
|
||||
/* Embedded type MMU with HW exec support. This is a bit more complicated
|
||||
* as we don't have two bits to spare for _PAGE_EXEC and _PAGE_HWEXEC so
|
||||
* instead we "filter out" the exec permission for non clean pages.
|
||||
*
|
||||
* This is also called once for the folio. So only work with folio->flags here.
|
||||
*/
|
||||
static inline pte_t set_pte_filter(pte_t pte)
|
||||
{
|
||||
@ -190,29 +192,39 @@ static pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma,
|
||||
void set_ptes(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
|
||||
pte_t pte, unsigned int nr)
|
||||
{
|
||||
/*
|
||||
* Make sure hardware valid bit is not set. We don't do
|
||||
* tlb flush for this update.
|
||||
*/
|
||||
VM_WARN_ON(pte_hw_valid(*ptep) && !pte_protnone(*ptep));
|
||||
|
||||
/* Note: mm->context.id might not yet have been assigned as
|
||||
* this context might not have been activated yet when this
|
||||
* is called.
|
||||
* is called. Filter the pte value and use the filtered value
|
||||
* to setup all the ptes in the range.
|
||||
*/
|
||||
pte = set_pte_filter(pte);
|
||||
|
||||
/* Perform the setting of the PTE */
|
||||
arch_enter_lazy_mmu_mode();
|
||||
/*
|
||||
* We don't need to call arch_enter/leave_lazy_mmu_mode()
|
||||
* because we expect set_ptes to be only be used on not present
|
||||
* and not hw_valid ptes. Hence there is no translation cache flush
|
||||
* involved that need to be batched.
|
||||
*/
|
||||
for (;;) {
|
||||
|
||||
/*
|
||||
* Make sure hardware valid bit is not set. We don't do
|
||||
* tlb flush for this update.
|
||||
*/
|
||||
VM_WARN_ON(pte_hw_valid(*ptep) && !pte_protnone(*ptep));
|
||||
|
||||
/* Perform the setting of the PTE */
|
||||
__set_pte_at(mm, addr, ptep, pte, 0);
|
||||
if (--nr == 0)
|
||||
break;
|
||||
ptep++;
|
||||
pte = __pte(pte_val(pte) + (1UL << PTE_RPN_SHIFT));
|
||||
addr += PAGE_SIZE;
|
||||
/*
|
||||
* increment the pfn.
|
||||
*/
|
||||
pte = pfn_pte(pte_pfn(pte) + 1, pte_pgprot((pte)));
|
||||
}
|
||||
arch_leave_lazy_mmu_mode();
|
||||
}
|
||||
|
||||
void unmap_kernel_page(unsigned long va)
|
||||
|
Loading…
Reference in New Issue
Block a user