18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/compiler.h>
38c2ecf20Sopenharmony_ci#include <linux/init.h>
48c2ecf20Sopenharmony_ci#include <linux/export.h>
58c2ecf20Sopenharmony_ci#include <linux/highmem.h>
68c2ecf20Sopenharmony_ci#include <linux/sched.h>
78c2ecf20Sopenharmony_ci#include <linux/smp.h>
88c2ecf20Sopenharmony_ci#include <asm/fixmap.h>
98c2ecf20Sopenharmony_ci#include <asm/tlbflush.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cistatic pte_t *kmap_pte;
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ciunsigned long highstart_pfn, highend_pfn;
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_civoid kmap_flush_tlb(unsigned long addr)
168c2ecf20Sopenharmony_ci{
178c2ecf20Sopenharmony_ci	flush_tlb_one(addr);
188c2ecf20Sopenharmony_ci}
198c2ecf20Sopenharmony_ciEXPORT_SYMBOL(kmap_flush_tlb);
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_civoid *kmap_atomic_high_prot(struct page *page, pgprot_t prot)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	unsigned long vaddr;
248c2ecf20Sopenharmony_ci	int idx, type;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	type = kmap_atomic_idx_push();
278c2ecf20Sopenharmony_ci	idx = type + KM_TYPE_NR*smp_processor_id();
288c2ecf20Sopenharmony_ci	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
298c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_HIGHMEM
308c2ecf20Sopenharmony_ci	BUG_ON(!pte_none(*(kmap_pte - idx)));
318c2ecf20Sopenharmony_ci#endif
328c2ecf20Sopenharmony_ci	set_pte(kmap_pte-idx, mk_pte(page, prot));
338c2ecf20Sopenharmony_ci	local_flush_tlb_one((unsigned long)vaddr);
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	return (void*) vaddr;
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(kmap_atomic_high_prot);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_civoid kunmap_atomic_high(void *kvaddr)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
428c2ecf20Sopenharmony_ci	int type __maybe_unused;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	if (vaddr < FIXADDR_START)
458c2ecf20Sopenharmony_ci		return;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	type = kmap_atomic_idx();
488c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_HIGHMEM
498c2ecf20Sopenharmony_ci	{
508c2ecf20Sopenharmony_ci		int idx = type + KM_TYPE_NR * smp_processor_id();
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci		BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci		/*
558c2ecf20Sopenharmony_ci		 * force other mappings to Oops if they'll try to access
568c2ecf20Sopenharmony_ci		 * this pte without first remap it
578c2ecf20Sopenharmony_ci		 */
588c2ecf20Sopenharmony_ci		pte_clear(&init_mm, vaddr, kmap_pte-idx);
598c2ecf20Sopenharmony_ci		local_flush_tlb_one(vaddr);
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci#endif
628c2ecf20Sopenharmony_ci	kmap_atomic_idx_pop();
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ciEXPORT_SYMBOL(kunmap_atomic_high);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci/*
678c2ecf20Sopenharmony_ci * This is the same as kmap_atomic() but can map memory that doesn't
688c2ecf20Sopenharmony_ci * have a struct page associated with it.
698c2ecf20Sopenharmony_ci */
708c2ecf20Sopenharmony_civoid *kmap_atomic_pfn(unsigned long pfn)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	unsigned long vaddr;
738c2ecf20Sopenharmony_ci	int idx, type;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	preempt_disable();
768c2ecf20Sopenharmony_ci	pagefault_disable();
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	type = kmap_atomic_idx_push();
798c2ecf20Sopenharmony_ci	idx = type + KM_TYPE_NR*smp_processor_id();
808c2ecf20Sopenharmony_ci	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
818c2ecf20Sopenharmony_ci	set_pte(kmap_pte-idx, pfn_pte(pfn, PAGE_KERNEL));
828c2ecf20Sopenharmony_ci	flush_tlb_one(vaddr);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	return (void*) vaddr;
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_civoid __init kmap_init(void)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	unsigned long kmap_vstart;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	/* cache the first kmap pte */
928c2ecf20Sopenharmony_ci	kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
938c2ecf20Sopenharmony_ci	kmap_pte = virt_to_kpte(kmap_vstart);
948c2ecf20Sopenharmony_ci}
95