arch/xtensa/mm/cache.c

Source file repositories/reference/linux-study-clean/arch/xtensa/mm/cache.c

File Facts

System
Linux kernel
Corpus path
arch/xtensa/mm/cache.c
Extension
.c
Size
8862 bytes
Lines
336
Domain
Architecture Layer
Bucket
arch/xtensa
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

if (!PageHighMem(page)) {
			kvaddr = (unsigned long)page_to_virt(page);

			__invalidate_dcache_page(kvaddr);
		} else {
			kvaddr = TLBTEMP_BASE_1 +
				(page_to_phys(page) & DCACHE_ALIAS_MASK);

			preempt_disable();
			__invalidate_dcache_page_alias(kvaddr,
						       page_to_phys(page));
			preempt_enable();
		}
	}
}

static inline void *coherent_kvaddr(struct page *page, unsigned long base,
				    unsigned long vaddr, unsigned long *paddr)
{
	*paddr = page_to_phys(page);
	return (void *)(base + (vaddr & DCACHE_ALIAS_MASK));
}

void clear_user_highpage(struct page *page, unsigned long vaddr)
{
	struct folio *folio = page_folio(page);
	unsigned long paddr;
	void *kvaddr = coherent_kvaddr(page, TLBTEMP_BASE_1, vaddr, &paddr);

	preempt_disable();
	kmap_invalidate_coherent(page, vaddr);
	set_bit(PG_arch_1, folio_flags(folio, 0));
	clear_page_alias(kvaddr, paddr);
	preempt_enable();
}
EXPORT_SYMBOL(clear_user_highpage);

void copy_user_highpage(struct page *dst, struct page *src,
			unsigned long vaddr, struct vm_area_struct *vma)
{
	struct folio *folio = page_folio(dst);
	unsigned long dst_paddr, src_paddr;
	void *dst_vaddr = coherent_kvaddr(dst, TLBTEMP_BASE_1, vaddr,
					  &dst_paddr);
	void *src_vaddr = coherent_kvaddr(src, TLBTEMP_BASE_2, vaddr,
					  &src_paddr);

	preempt_disable();
	kmap_invalidate_coherent(dst, vaddr);
	set_bit(PG_arch_1, folio_flags(folio, 0));
	copy_page_alias(dst_vaddr, src_vaddr, dst_paddr, src_paddr);
	preempt_enable();
}
EXPORT_SYMBOL(copy_user_highpage);

/*
 * Any time the kernel writes to a user page cache page, or it is about to
 * read from a page cache page this routine is called.
 *
 */

void flush_dcache_folio(struct folio *folio)
{
	struct address_space *mapping = folio_flush_mapping(folio);

	/*
	 * If we have a mapping but the page is not mapped to user-space
	 * yet, we simply mark this page dirty and defer flushing the 
	 * caches until update_mmu().
	 */

	if (mapping && !mapping_mapped(mapping)) {
		if (!test_bit(PG_arch_1, &folio->flags.f))
			set_bit(PG_arch_1, &folio->flags.f);
		return;

	} else {
		unsigned long phys = folio_pfn(folio) * PAGE_SIZE;
		unsigned long temp = folio_pos(folio);
		unsigned int i, nr = folio_nr_pages(folio);
		unsigned long alias = !(DCACHE_ALIAS_EQ(temp, phys));
		unsigned long virt;

		/* 
		 * Flush the page in kernel space and user space.
		 * Note that we can omit that step if aliasing is not
		 * an issue, but we do have to synchronize I$ and D$
		 * if we have a mapping.
		 */

Annotation

Implementation Notes