162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/mm.h>
362306a36Sopenharmony_ci#include <linux/hugetlb.h>
462306a36Sopenharmony_ci#include <linux/security.h>
562306a36Sopenharmony_ci#include <asm/cacheflush.h>
662306a36Sopenharmony_ci#include <asm/machdep.h>
762306a36Sopenharmony_ci#include <asm/mman.h>
862306a36Sopenharmony_ci#include <asm/tlb.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_civoid radix__flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
1162306a36Sopenharmony_ci{
1262306a36Sopenharmony_ci	int psize;
1362306a36Sopenharmony_ci	struct hstate *hstate = hstate_file(vma->vm_file);
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci	psize = hstate_get_psize(hstate);
1662306a36Sopenharmony_ci	radix__flush_tlb_page_psize(vma->vm_mm, vmaddr, psize);
1762306a36Sopenharmony_ci}
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_civoid radix__local_flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	int psize;
2262306a36Sopenharmony_ci	struct hstate *hstate = hstate_file(vma->vm_file);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	psize = hstate_get_psize(hstate);
2562306a36Sopenharmony_ci	radix__local_flush_tlb_page_psize(vma->vm_mm, vmaddr, psize);
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_civoid radix__flush_hugetlb_tlb_range(struct vm_area_struct *vma, unsigned long start,
2962306a36Sopenharmony_ci				   unsigned long end)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	int psize;
3262306a36Sopenharmony_ci	struct hstate *hstate = hstate_file(vma->vm_file);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	psize = hstate_get_psize(hstate);
3562306a36Sopenharmony_ci	/*
3662306a36Sopenharmony_ci	 * Flush PWC even if we get PUD_SIZE hugetlb invalidate to keep this simpler.
3762306a36Sopenharmony_ci	 */
3862306a36Sopenharmony_ci	if (end - start >= PUD_SIZE)
3962306a36Sopenharmony_ci		radix__flush_tlb_pwc_range_psize(vma->vm_mm, start, end, psize);
4062306a36Sopenharmony_ci	else
4162306a36Sopenharmony_ci		radix__flush_tlb_range_psize(vma->vm_mm, start, end, psize);
4262306a36Sopenharmony_ci	mmu_notifier_arch_invalidate_secondary_tlbs(vma->vm_mm, start, end);
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_civoid radix__huge_ptep_modify_prot_commit(struct vm_area_struct *vma,
4662306a36Sopenharmony_ci					 unsigned long addr, pte_t *ptep,
4762306a36Sopenharmony_ci					 pte_t old_pte, pte_t pte)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct mm_struct *mm = vma->vm_mm;
5062306a36Sopenharmony_ci	unsigned long psize = huge_page_size(hstate_vma(vma));
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	/*
5362306a36Sopenharmony_ci	 * POWER9 NMMU must flush the TLB after clearing the PTE before
5462306a36Sopenharmony_ci	 * installing a PTE with more relaxed access permissions, see
5562306a36Sopenharmony_ci	 * radix__ptep_set_access_flags.
5662306a36Sopenharmony_ci	 */
5762306a36Sopenharmony_ci	if (!cpu_has_feature(CPU_FTR_ARCH_31) &&
5862306a36Sopenharmony_ci	    is_pte_rw_upgrade(pte_val(old_pte), pte_val(pte)) &&
5962306a36Sopenharmony_ci	    atomic_read(&mm->context.copros) > 0)
6062306a36Sopenharmony_ci		radix__flush_hugetlb_page(vma, addr);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	set_huge_pte_at(vma->vm_mm, addr, ptep, pte, psize);
6362306a36Sopenharmony_ci}
64