arch/riscv/mm/tlbflush.c

Source file repositories/reference/linux-study-clean/arch/riscv/mm/tlbflush.c

File Facts

System
Linux kernel
Corpus path
arch/riscv/mm/tlbflush.c
Extension
.c
Size
6117 bytes
Lines
243
Domain
Architecture Layer
Bucket
arch/riscv
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct flush_tlb_range_data {
	unsigned long asid;
	unsigned long start;
	unsigned long size;
	unsigned long stride;
};

static void __ipi_flush_tlb_range_asid(void *info)
{
	struct flush_tlb_range_data *d = info;

	local_flush_tlb_range_asid(d->start, d->size, d->stride, d->asid);
}

static inline unsigned long get_mm_asid(struct mm_struct *mm)
{
	return mm ? cntx2asid(atomic_long_read(&mm->context.id)) : FLUSH_TLB_NO_ASID;
}

static void __flush_tlb_range(struct mm_struct *mm,
			      const struct cpumask *cmask,
			      unsigned long start, unsigned long size,
			      unsigned long stride)
{
	unsigned long asid = get_mm_asid(mm);
	unsigned int cpu;

	if (cpumask_empty(cmask))
		return;

	cpu = get_cpu();

	/* Check if the TLB flush needs to be sent to other CPUs. */
	if (cpumask_any_but(cmask, cpu) >= nr_cpu_ids) {
		local_flush_tlb_range_asid(start, size, stride, asid);
	} else if (riscv_use_sbi_for_rfence()) {
		sbi_remote_sfence_vma_asid(cmask, start, size, asid);
	} else {
		struct flush_tlb_range_data ftd;

		ftd.asid = asid;
		ftd.start = start;
		ftd.size = size;
		ftd.stride = stride;
		on_each_cpu_mask(cmask, __ipi_flush_tlb_range_asid, &ftd, 1);
	}

	put_cpu();

	if (mm)
		mmu_notifier_arch_invalidate_secondary_tlbs(mm, start, start + size);
}

void flush_tlb_mm(struct mm_struct *mm)
{
	__flush_tlb_range(mm, mm_cpumask(mm), 0, FLUSH_TLB_MAX_SIZE, PAGE_SIZE);
}

void flush_tlb_mm_range(struct mm_struct *mm,
			unsigned long start, unsigned long end,
			unsigned int page_size)
{
	__flush_tlb_range(mm, mm_cpumask(mm), start, end - start, page_size);
}

void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
{
	__flush_tlb_range(vma->vm_mm, mm_cpumask(vma->vm_mm),
			  addr, PAGE_SIZE, PAGE_SIZE);
}

void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
		     unsigned long end)
{
	unsigned long stride_size;

	if (!is_vm_hugetlb_page(vma)) {
		stride_size = PAGE_SIZE;
	} else {
		stride_size = huge_page_size(hstate_vma(vma));

		/*
		 * As stated in the privileged specification, every PTE in a
		 * NAPOT region must be invalidated, so reset the stride in that
		 * case.
		 */
		if (has_svnapot()) {
			if (stride_size >= PGDIR_SIZE)
				stride_size = PGDIR_SIZE;
			else if (stride_size >= P4D_SIZE)

Annotation

Implementation Notes