xref: /kernel/linux/linux-5.10/arch/xtensa/mm/highmem.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * High memory support for Xtensa architecture
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General
58c2ecf20Sopenharmony_ci * Public License.  See the file "COPYING" in the main directory of
68c2ecf20Sopenharmony_ci * this archive for more details.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright (C) 2014 Cadence Design Systems Inc.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/export.h>
128c2ecf20Sopenharmony_ci#include <linux/highmem.h>
138c2ecf20Sopenharmony_ci#include <asm/tlbflush.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistatic pte_t *kmap_pte;
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#if DCACHE_WAY_SIZE > PAGE_SIZE
188c2ecf20Sopenharmony_ciunsigned int last_pkmap_nr_arr[DCACHE_N_COLORS];
198c2ecf20Sopenharmony_ciwait_queue_head_t pkmap_map_wait_arr[DCACHE_N_COLORS];
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic void __init kmap_waitqueues_init(void)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	unsigned int i;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pkmap_map_wait_arr); ++i)
268c2ecf20Sopenharmony_ci		init_waitqueue_head(pkmap_map_wait_arr + i);
278c2ecf20Sopenharmony_ci}
288c2ecf20Sopenharmony_ci#else
298c2ecf20Sopenharmony_cistatic inline void kmap_waitqueues_init(void)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_ci#endif
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic inline enum fixed_addresses kmap_idx(int type, unsigned long color)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	return (type + KM_TYPE_NR * smp_processor_id()) * DCACHE_N_COLORS +
378c2ecf20Sopenharmony_ci		color;
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_civoid *kmap_atomic_high_prot(struct page *page, pgprot_t prot)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	enum fixed_addresses idx;
438c2ecf20Sopenharmony_ci	unsigned long vaddr;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	idx = kmap_idx(kmap_atomic_idx_push(),
468c2ecf20Sopenharmony_ci		       DCACHE_ALIAS(page_to_phys(page)));
478c2ecf20Sopenharmony_ci	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
488c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_HIGHMEM
498c2ecf20Sopenharmony_ci	BUG_ON(!pte_none(*(kmap_pte + idx)));
508c2ecf20Sopenharmony_ci#endif
518c2ecf20Sopenharmony_ci	set_pte(kmap_pte + idx, mk_pte(page, prot));
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	return (void *)vaddr;
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ciEXPORT_SYMBOL(kmap_atomic_high_prot);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_civoid kunmap_atomic_high(void *kvaddr)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	if (kvaddr >= (void *)FIXADDR_START &&
608c2ecf20Sopenharmony_ci	    kvaddr < (void *)FIXADDR_TOP) {
618c2ecf20Sopenharmony_ci		int idx = kmap_idx(kmap_atomic_idx(),
628c2ecf20Sopenharmony_ci				   DCACHE_ALIAS((unsigned long)kvaddr));
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci		/*
658c2ecf20Sopenharmony_ci		 * Force other mappings to Oops if they'll try to access this
668c2ecf20Sopenharmony_ci		 * pte without first remap it.  Keeping stale mappings around
678c2ecf20Sopenharmony_ci		 * is a bad idea also, in case the page changes cacheability
688c2ecf20Sopenharmony_ci		 * attributes or becomes a protected page in a hypervisor.
698c2ecf20Sopenharmony_ci		 */
708c2ecf20Sopenharmony_ci		pte_clear(&init_mm, kvaddr, kmap_pte + idx);
718c2ecf20Sopenharmony_ci		local_flush_tlb_kernel_range((unsigned long)kvaddr,
728c2ecf20Sopenharmony_ci					     (unsigned long)kvaddr + PAGE_SIZE);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci		kmap_atomic_idx_pop();
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(kunmap_atomic_high);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_civoid __init kmap_init(void)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	unsigned long kmap_vstart;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	/* Check if this memory layout is broken because PKMAP overlaps
848c2ecf20Sopenharmony_ci	 * page table.
858c2ecf20Sopenharmony_ci	 */
868c2ecf20Sopenharmony_ci	BUILD_BUG_ON(PKMAP_BASE < TLBTEMP_BASE_1 + TLBTEMP_SIZE);
878c2ecf20Sopenharmony_ci	/* cache the first kmap pte */
888c2ecf20Sopenharmony_ci	kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
898c2ecf20Sopenharmony_ci	kmap_pte = virt_to_kpte(kmap_vstart);
908c2ecf20Sopenharmony_ci	kmap_waitqueues_init();
918c2ecf20Sopenharmony_ci}
92