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
	
	 Aneesh Kumar K.V
						Aneesh Kumar K.V