18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/mm.h>
38c2ecf20Sopenharmony_ci#include <linux/hugetlb.h>
48c2ecf20Sopenharmony_ci#include <linux/security.h>
58c2ecf20Sopenharmony_ci#include <asm/cacheflush.h>
68c2ecf20Sopenharmony_ci#include <asm/machdep.h>
78c2ecf20Sopenharmony_ci#include <asm/mman.h>
88c2ecf20Sopenharmony_ci#include <asm/tlb.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_civoid radix__flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
118c2ecf20Sopenharmony_ci{
128c2ecf20Sopenharmony_ci	int psize;
138c2ecf20Sopenharmony_ci	struct hstate *hstate = hstate_file(vma->vm_file);
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci	psize = hstate_get_psize(hstate);
168c2ecf20Sopenharmony_ci	radix__flush_tlb_page_psize(vma->vm_mm, vmaddr, psize);
178c2ecf20Sopenharmony_ci}
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_civoid radix__local_flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	int psize;
228c2ecf20Sopenharmony_ci	struct hstate *hstate = hstate_file(vma->vm_file);
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	psize = hstate_get_psize(hstate);
258c2ecf20Sopenharmony_ci	radix__local_flush_tlb_page_psize(vma->vm_mm, vmaddr, psize);
268c2ecf20Sopenharmony_ci}
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_civoid radix__flush_hugetlb_tlb_range(struct vm_area_struct *vma, unsigned long start,
298c2ecf20Sopenharmony_ci				   unsigned long end)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	int psize;
328c2ecf20Sopenharmony_ci	struct hstate *hstate = hstate_file(vma->vm_file);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	psize = hstate_get_psize(hstate);
358c2ecf20Sopenharmony_ci	radix__flush_tlb_range_psize(vma->vm_mm, start, end, psize);
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/*
398c2ecf20Sopenharmony_ci * A vairant of hugetlb_get_unmapped_area doing topdown search
408c2ecf20Sopenharmony_ci * FIXME!! should we do as x86 does or non hugetlb area does ?
418c2ecf20Sopenharmony_ci * ie, use topdown or not based on mmap_is_legacy check ?
428c2ecf20Sopenharmony_ci */
438c2ecf20Sopenharmony_ciunsigned long
448c2ecf20Sopenharmony_ciradix__hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
458c2ecf20Sopenharmony_ci				unsigned long len, unsigned long pgoff,
468c2ecf20Sopenharmony_ci				unsigned long flags)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	struct mm_struct *mm = current->mm;
498c2ecf20Sopenharmony_ci	struct vm_area_struct *vma;
508c2ecf20Sopenharmony_ci	struct hstate *h = hstate_file(file);
518c2ecf20Sopenharmony_ci	int fixed = (flags & MAP_FIXED);
528c2ecf20Sopenharmony_ci	unsigned long high_limit;
538c2ecf20Sopenharmony_ci	struct vm_unmapped_area_info info;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	high_limit = DEFAULT_MAP_WINDOW;
568c2ecf20Sopenharmony_ci	if (addr >= high_limit || (fixed && (addr + len > high_limit)))
578c2ecf20Sopenharmony_ci		high_limit = TASK_SIZE;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	if (len & ~huge_page_mask(h))
608c2ecf20Sopenharmony_ci		return -EINVAL;
618c2ecf20Sopenharmony_ci	if (len > high_limit)
628c2ecf20Sopenharmony_ci		return -ENOMEM;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	if (fixed) {
658c2ecf20Sopenharmony_ci		if (addr > high_limit - len)
668c2ecf20Sopenharmony_ci			return -ENOMEM;
678c2ecf20Sopenharmony_ci		if (prepare_hugepage_range(file, addr, len))
688c2ecf20Sopenharmony_ci			return -EINVAL;
698c2ecf20Sopenharmony_ci		return addr;
708c2ecf20Sopenharmony_ci	}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	if (addr) {
738c2ecf20Sopenharmony_ci		addr = ALIGN(addr, huge_page_size(h));
748c2ecf20Sopenharmony_ci		vma = find_vma(mm, addr);
758c2ecf20Sopenharmony_ci		if (high_limit - len >= addr && addr >= mmap_min_addr &&
768c2ecf20Sopenharmony_ci		    (!vma || addr + len <= vm_start_gap(vma)))
778c2ecf20Sopenharmony_ci			return addr;
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci	/*
808c2ecf20Sopenharmony_ci	 * We are always doing an topdown search here. Slice code
818c2ecf20Sopenharmony_ci	 * does that too.
828c2ecf20Sopenharmony_ci	 */
838c2ecf20Sopenharmony_ci	info.flags = VM_UNMAPPED_AREA_TOPDOWN;
848c2ecf20Sopenharmony_ci	info.length = len;
858c2ecf20Sopenharmony_ci	info.low_limit = max(PAGE_SIZE, mmap_min_addr);
868c2ecf20Sopenharmony_ci	info.high_limit = mm->mmap_base + (high_limit - DEFAULT_MAP_WINDOW);
878c2ecf20Sopenharmony_ci	info.align_mask = PAGE_MASK & ~huge_page_mask(h);
888c2ecf20Sopenharmony_ci	info.align_offset = 0;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	return vm_unmapped_area(&info);
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_civoid radix__huge_ptep_modify_prot_commit(struct vm_area_struct *vma,
948c2ecf20Sopenharmony_ci					 unsigned long addr, pte_t *ptep,
958c2ecf20Sopenharmony_ci					 pte_t old_pte, pte_t pte)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	struct mm_struct *mm = vma->vm_mm;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	/*
1008c2ecf20Sopenharmony_ci	 * To avoid NMMU hang while relaxing access we need to flush the tlb before
1018c2ecf20Sopenharmony_ci	 * we set the new value.
1028c2ecf20Sopenharmony_ci	 */
1038c2ecf20Sopenharmony_ci	if (is_pte_rw_upgrade(pte_val(old_pte), pte_val(pte)) &&
1048c2ecf20Sopenharmony_ci	    (atomic_read(&mm->context.copros) > 0))
1058c2ecf20Sopenharmony_ci		radix__flush_hugetlb_page(vma, addr);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
1088c2ecf20Sopenharmony_ci}
109