arch/mips/mm/c-r4k.c

Source file repositories/reference/linux-study-clean/arch/mips/mm/c-r4k.c

File Facts

System
Linux kernel
Corpus path
arch/mips/mm/c-r4k.c
Extension
.c
Size
48236 bytes
Lines
1827
Domain
Architecture Layer
Bucket
arch/mips
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration 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_cache_page_args {
	struct vm_area_struct *vma;
	unsigned long addr;
	unsigned long pfn;
};

static inline void local_r4k_flush_cache_page(void *args)
{
	struct flush_cache_page_args *fcp_args = args;
	struct vm_area_struct *vma = fcp_args->vma;
	unsigned long addr = fcp_args->addr;
	struct page *page = pfn_to_page(fcp_args->pfn);
	int exec = vma->vm_flags & VM_EXEC;
	struct mm_struct *mm = vma->vm_mm;
	int map_coherent = 0;
	pmd_t *pmdp;
	pte_t *ptep;
	void *vaddr;

	/*
	 * If owns no valid ASID yet, cannot possibly have gotten
	 * this page into the cache.
	 */
	if (!has_valid_asid(mm, R4K_HIT))
		return;

	addr &= PAGE_MASK;
	pmdp = pmd_off(mm, addr);
	ptep = pte_offset_kernel(pmdp, addr);

	/*
	 * If the page isn't marked valid, the page cannot possibly be
	 * in the cache.
	 */
	if (!(pte_present(*ptep)))
		return;

	if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID))
		vaddr = NULL;
	else {
		struct folio *folio = page_folio(page);
		/*
		 * Use kmap_coherent or kmap_atomic to do flushes for
		 * another ASID than the current one.
		 */
		map_coherent = (cpu_has_dc_aliases &&
				folio_mapped(folio) &&
				!folio_test_dcache_dirty(folio));
		if (map_coherent)
			vaddr = kmap_coherent(page, addr);
		else
			vaddr = kmap_atomic(page);
		addr = (unsigned long)vaddr;
	}

	if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) {
		vaddr ? r4k_blast_dcache_page(addr) :
			r4k_blast_dcache_user_page(addr);
		if (exec && !cpu_icache_snoops_remote_store)
			r4k_blast_scache_page(addr);
	}
	if (exec) {
		if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) {
			drop_mmu_context(mm);
		} else
			vaddr ? r4k_blast_icache_page(addr) :
				r4k_blast_icache_user_page(addr);
	}

	if (vaddr) {
		if (map_coherent)
			kunmap_coherent();
		else
			kunmap_atomic(vaddr);
	}
}

static void r4k_flush_cache_page(struct vm_area_struct *vma,
	unsigned long addr, unsigned long pfn)
{
	struct flush_cache_page_args args;

	args.vma = vma;
	args.addr = addr;
	args.pfn = pfn;

	r4k_on_each_cpu(R4K_HIT, local_r4k_flush_cache_page, &args);
}

static inline void local_r4k_flush_data_cache_page(void * addr)

Annotation

Implementation Notes