forked from mirrors/linux
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
1 changed files with 22 additions and 10 deletions
|
|
@ -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
|
/* 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
|
* 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.
|
* 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)
|
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,
|
void set_ptes(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
|
||||||
pte_t pte, unsigned int nr)
|
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
|
/* Note: mm->context.id might not yet have been assigned as
|
||||||
* this context might not have been activated yet when this
|
* 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);
|
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 (;;) {
|
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);
|
__set_pte_at(mm, addr, ptep, pte, 0);
|
||||||
if (--nr == 0)
|
if (--nr == 0)
|
||||||
break;
|
break;
|
||||||
ptep++;
|
ptep++;
|
||||||
pte = __pte(pte_val(pte) + (1UL << PTE_RPN_SHIFT));
|
|
||||||
addr += PAGE_SIZE;
|
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)
|
void unmap_kernel_page(unsigned long va)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue