18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * highmem.c: virtual kernel memory mappings for high memory
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * PowerPC version, stolen from the i386 version.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Used in CONFIG_HIGHMEM systems for memory pages which
88c2ecf20Sopenharmony_ci * are not addressable by direct kernel virtual addresses.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Copyright (C) 1999 Gerhard Wichert, Siemens AG
118c2ecf20Sopenharmony_ci *		      Gerhard.Wichert@pdb.siemens.de
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * Redesigned the x86 32-bit VM architecture to deal with
158c2ecf20Sopenharmony_ci * up to 16 Terrabyte physical memory. With current x86 CPUs
168c2ecf20Sopenharmony_ci * we now support up to 64 Gigabytes physical RAM.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * Reworked for PowerPC by various contributors. Moved from
218c2ecf20Sopenharmony_ci * highmem.h by Benjamin Herrenschmidt (c) 2009 IBM Corp.
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include <linux/export.h>
258c2ecf20Sopenharmony_ci#include <linux/highmem.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/*
288c2ecf20Sopenharmony_ci * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap
298c2ecf20Sopenharmony_ci * gives a more generic (and caching) interface. But kmap_atomic can
308c2ecf20Sopenharmony_ci * be used in IRQ contexts, so in some (very limited) cases we need
318c2ecf20Sopenharmony_ci * it.
328c2ecf20Sopenharmony_ci */
338c2ecf20Sopenharmony_ci#include <asm/tlbflush.h>
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_civoid *kmap_atomic_high_prot(struct page *page, pgprot_t prot)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	unsigned long vaddr;
398c2ecf20Sopenharmony_ci	int idx, type;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	type = kmap_atomic_idx_push();
428c2ecf20Sopenharmony_ci	idx = type + KM_TYPE_NR*smp_processor_id();
438c2ecf20Sopenharmony_ci	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
448c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_HIGHMEM
458c2ecf20Sopenharmony_ci	BUG_ON(!pte_none(*(kmap_pte-idx)));
468c2ecf20Sopenharmony_ci#endif
478c2ecf20Sopenharmony_ci	set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot));
488c2ecf20Sopenharmony_ci	local_flush_tlb_page(NULL, vaddr);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	return (void *) vaddr;
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(kmap_atomic_high_prot);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_civoid kunmap_atomic_high(void *kvaddr)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
578c2ecf20Sopenharmony_ci	int type;
588c2ecf20Sopenharmony_ci	unsigned int idx;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if (vaddr < __fix_to_virt(FIX_KMAP_END))
618c2ecf20Sopenharmony_ci		return;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	type = kmap_atomic_idx();
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	idx = type + KM_TYPE_NR * smp_processor_id();
668c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_HIGHMEM
678c2ecf20Sopenharmony_ci	BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
688c2ecf20Sopenharmony_ci#endif
698c2ecf20Sopenharmony_ci	/*
708c2ecf20Sopenharmony_ci	 * force other mappings to Oops if they'll try to access
718c2ecf20Sopenharmony_ci	 * this pte without first remap it
728c2ecf20Sopenharmony_ci	 */
738c2ecf20Sopenharmony_ci	pte_clear(&init_mm, vaddr, kmap_pte-idx);
748c2ecf20Sopenharmony_ci	local_flush_tlb_page(NULL, vaddr);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	kmap_atomic_idx_pop();
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(kunmap_atomic_high);
79