18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * High memory handling common code and variables. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * (C) 1999 Andrea Arcangeli, SuSE GmbH, andrea@suse.de 68c2ecf20Sopenharmony_ci * Gerhard Wichert, Siemens AG, Gerhard.Wichert@pdb.siemens.de 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Redesigned the x86 32-bit VM architecture to deal with 108c2ecf20Sopenharmony_ci * 64-bit physical space. With current x86 CPUs this 118c2ecf20Sopenharmony_ci * means up to 64 Gigabytes physical RAM. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Rewrote high memory support to move the page cache into 148c2ecf20Sopenharmony_ci * high memory. Implemented permanent (schedulable) kmaps 158c2ecf20Sopenharmony_ci * based on Linus' idea. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com> 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <linux/mm.h> 218c2ecf20Sopenharmony_ci#include <linux/export.h> 228c2ecf20Sopenharmony_ci#include <linux/swap.h> 238c2ecf20Sopenharmony_ci#include <linux/bio.h> 248c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 258c2ecf20Sopenharmony_ci#include <linux/mempool.h> 268c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 278c2ecf20Sopenharmony_ci#include <linux/init.h> 288c2ecf20Sopenharmony_ci#include <linux/hash.h> 298c2ecf20Sopenharmony_ci#include <linux/highmem.h> 308c2ecf20Sopenharmony_ci#include <linux/kgdb.h> 318c2ecf20Sopenharmony_ci#include <asm/tlbflush.h> 328c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#if defined(CONFIG_HIGHMEM) || defined(CONFIG_X86_32) 358c2ecf20Sopenharmony_ciDEFINE_PER_CPU(int, __kmap_atomic_idx); 368c2ecf20Sopenharmony_ci#endif 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * Virtual_count is not a pure "count". 408c2ecf20Sopenharmony_ci * 0 means that it is not mapped, and has not been mapped 418c2ecf20Sopenharmony_ci * since a TLB flush - it is usable. 428c2ecf20Sopenharmony_ci * 1 means that there are no users, but it has been mapped 438c2ecf20Sopenharmony_ci * since the last TLB flush - so we can't use it. 448c2ecf20Sopenharmony_ci * n means that there are (n-1) current users of it. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_ci#ifdef CONFIG_HIGHMEM 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* 498c2ecf20Sopenharmony_ci * Architecture with aliasing data cache may define the following family of 508c2ecf20Sopenharmony_ci * helper functions in its asm/highmem.h to control cache color of virtual 518c2ecf20Sopenharmony_ci * addresses where physical memory pages are mapped by kmap. 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_ci#ifndef get_pkmap_color 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* 568c2ecf20Sopenharmony_ci * Determine color of virtual address where the page should be mapped. 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_cistatic inline unsigned int get_pkmap_color(struct page *page) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci return 0; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci#define get_pkmap_color get_pkmap_color 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* 658c2ecf20Sopenharmony_ci * Get next index for mapping inside PKMAP region for page with given color. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_cistatic inline unsigned int get_next_pkmap_nr(unsigned int color) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci static unsigned int last_pkmap_nr; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci last_pkmap_nr = (last_pkmap_nr + 1) & LAST_PKMAP_MASK; 728c2ecf20Sopenharmony_ci return last_pkmap_nr; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* 768c2ecf20Sopenharmony_ci * Determine if page index inside PKMAP region (pkmap_nr) of given color 778c2ecf20Sopenharmony_ci * has wrapped around PKMAP region end. When this happens an attempt to 788c2ecf20Sopenharmony_ci * flush all unused PKMAP slots is made. 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_cistatic inline int no_more_pkmaps(unsigned int pkmap_nr, unsigned int color) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci return pkmap_nr == 0; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* 868c2ecf20Sopenharmony_ci * Get the number of PKMAP entries of the given color. If no free slot is 878c2ecf20Sopenharmony_ci * found after checking that many entries, kmap will sleep waiting for 888c2ecf20Sopenharmony_ci * someone to call kunmap and free PKMAP slot. 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_cistatic inline int get_pkmap_entries_count(unsigned int color) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci return LAST_PKMAP; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/* 968c2ecf20Sopenharmony_ci * Get head of a wait queue for PKMAP entries of the given color. 978c2ecf20Sopenharmony_ci * Wait queues for different mapping colors should be independent to avoid 988c2ecf20Sopenharmony_ci * unnecessary wakeups caused by freeing of slots of other colors. 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_cistatic inline wait_queue_head_t *get_pkmap_wait_queue_head(unsigned int color) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci static DECLARE_WAIT_QUEUE_HEAD(pkmap_map_wait); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci return &pkmap_map_wait; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci#endif 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ciatomic_long_t _totalhigh_pages __read_mostly; 1098c2ecf20Sopenharmony_ciEXPORT_SYMBOL(_totalhigh_pages); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ciEXPORT_PER_CPU_SYMBOL(__kmap_atomic_idx); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ciunsigned int nr_free_highpages (void) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct zone *zone; 1168c2ecf20Sopenharmony_ci unsigned int pages = 0; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci for_each_populated_zone(zone) { 1198c2ecf20Sopenharmony_ci if (is_highmem(zone)) 1208c2ecf20Sopenharmony_ci pages += zone_page_state(zone, NR_FREE_PAGES); 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return pages; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int pkmap_count[LAST_PKMAP]; 1278c2ecf20Sopenharmony_cistatic __cacheline_aligned_in_smp DEFINE_SPINLOCK(kmap_lock); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cipte_t * pkmap_page_table; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/* 1328c2ecf20Sopenharmony_ci * Most architectures have no use for kmap_high_get(), so let's abstract 1338c2ecf20Sopenharmony_ci * the disabling of IRQ out of the locking in that case to save on a 1348c2ecf20Sopenharmony_ci * potential useless overhead. 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ci#ifdef ARCH_NEEDS_KMAP_HIGH_GET 1378c2ecf20Sopenharmony_ci#define lock_kmap() spin_lock_irq(&kmap_lock) 1388c2ecf20Sopenharmony_ci#define unlock_kmap() spin_unlock_irq(&kmap_lock) 1398c2ecf20Sopenharmony_ci#define lock_kmap_any(flags) spin_lock_irqsave(&kmap_lock, flags) 1408c2ecf20Sopenharmony_ci#define unlock_kmap_any(flags) spin_unlock_irqrestore(&kmap_lock, flags) 1418c2ecf20Sopenharmony_ci#else 1428c2ecf20Sopenharmony_ci#define lock_kmap() spin_lock(&kmap_lock) 1438c2ecf20Sopenharmony_ci#define unlock_kmap() spin_unlock(&kmap_lock) 1448c2ecf20Sopenharmony_ci#define lock_kmap_any(flags) \ 1458c2ecf20Sopenharmony_ci do { spin_lock(&kmap_lock); (void)(flags); } while (0) 1468c2ecf20Sopenharmony_ci#define unlock_kmap_any(flags) \ 1478c2ecf20Sopenharmony_ci do { spin_unlock(&kmap_lock); (void)(flags); } while (0) 1488c2ecf20Sopenharmony_ci#endif 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistruct page *kmap_to_page(void *vaddr) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci unsigned long addr = (unsigned long)vaddr; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (addr >= PKMAP_ADDR(0) && addr < PKMAP_ADDR(LAST_PKMAP)) { 1558c2ecf20Sopenharmony_ci int i = PKMAP_NR(addr); 1568c2ecf20Sopenharmony_ci return pte_page(pkmap_page_table[i]); 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return virt_to_page(addr); 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(kmap_to_page); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic void flush_all_zero_pkmaps(void) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci int i; 1668c2ecf20Sopenharmony_ci int need_flush = 0; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci flush_cache_kmaps(); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci for (i = 0; i < LAST_PKMAP; i++) { 1718c2ecf20Sopenharmony_ci struct page *page; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* 1748c2ecf20Sopenharmony_ci * zero means we don't have anything to do, 1758c2ecf20Sopenharmony_ci * >1 means that it is still in use. Only 1768c2ecf20Sopenharmony_ci * a count of 1 means that it is free but 1778c2ecf20Sopenharmony_ci * needs to be unmapped 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ci if (pkmap_count[i] != 1) 1808c2ecf20Sopenharmony_ci continue; 1818c2ecf20Sopenharmony_ci pkmap_count[i] = 0; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci /* sanity check */ 1848c2ecf20Sopenharmony_ci BUG_ON(pte_none(pkmap_page_table[i])); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* 1878c2ecf20Sopenharmony_ci * Don't need an atomic fetch-and-clear op here; 1888c2ecf20Sopenharmony_ci * no-one has the page mapped, and cannot get at 1898c2ecf20Sopenharmony_ci * its virtual address (and hence PTE) without first 1908c2ecf20Sopenharmony_ci * getting the kmap_lock (which is held here). 1918c2ecf20Sopenharmony_ci * So no dangers, even with speculative execution. 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_ci page = pte_page(pkmap_page_table[i]); 1948c2ecf20Sopenharmony_ci pte_clear(&init_mm, PKMAP_ADDR(i), &pkmap_page_table[i]); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci set_page_address(page, NULL); 1978c2ecf20Sopenharmony_ci need_flush = 1; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci if (need_flush) 2008c2ecf20Sopenharmony_ci flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP)); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci/** 2048c2ecf20Sopenharmony_ci * kmap_flush_unused - flush all unused kmap mappings in order to remove stray mappings 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_civoid kmap_flush_unused(void) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci lock_kmap(); 2098c2ecf20Sopenharmony_ci flush_all_zero_pkmaps(); 2108c2ecf20Sopenharmony_ci unlock_kmap(); 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic inline unsigned long map_new_virtual(struct page *page) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci unsigned long vaddr; 2168c2ecf20Sopenharmony_ci int count; 2178c2ecf20Sopenharmony_ci unsigned int last_pkmap_nr; 2188c2ecf20Sopenharmony_ci unsigned int color = get_pkmap_color(page); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistart: 2218c2ecf20Sopenharmony_ci count = get_pkmap_entries_count(color); 2228c2ecf20Sopenharmony_ci /* Find an empty entry */ 2238c2ecf20Sopenharmony_ci for (;;) { 2248c2ecf20Sopenharmony_ci last_pkmap_nr = get_next_pkmap_nr(color); 2258c2ecf20Sopenharmony_ci if (no_more_pkmaps(last_pkmap_nr, color)) { 2268c2ecf20Sopenharmony_ci flush_all_zero_pkmaps(); 2278c2ecf20Sopenharmony_ci count = get_pkmap_entries_count(color); 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci if (!pkmap_count[last_pkmap_nr]) 2308c2ecf20Sopenharmony_ci break; /* Found a usable entry */ 2318c2ecf20Sopenharmony_ci if (--count) 2328c2ecf20Sopenharmony_ci continue; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* 2358c2ecf20Sopenharmony_ci * Sleep for somebody else to unmap their entries 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_ci { 2388c2ecf20Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 2398c2ecf20Sopenharmony_ci wait_queue_head_t *pkmap_map_wait = 2408c2ecf20Sopenharmony_ci get_pkmap_wait_queue_head(color); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci __set_current_state(TASK_UNINTERRUPTIBLE); 2438c2ecf20Sopenharmony_ci add_wait_queue(pkmap_map_wait, &wait); 2448c2ecf20Sopenharmony_ci unlock_kmap(); 2458c2ecf20Sopenharmony_ci schedule(); 2468c2ecf20Sopenharmony_ci remove_wait_queue(pkmap_map_wait, &wait); 2478c2ecf20Sopenharmony_ci lock_kmap(); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* Somebody else might have mapped it while we slept */ 2508c2ecf20Sopenharmony_ci if (page_address(page)) 2518c2ecf20Sopenharmony_ci return (unsigned long)page_address(page); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* Re-start */ 2548c2ecf20Sopenharmony_ci goto start; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci vaddr = PKMAP_ADDR(last_pkmap_nr); 2588c2ecf20Sopenharmony_ci set_pte_at(&init_mm, vaddr, 2598c2ecf20Sopenharmony_ci &(pkmap_page_table[last_pkmap_nr]), mk_pte(page, kmap_prot)); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci pkmap_count[last_pkmap_nr] = 1; 2628c2ecf20Sopenharmony_ci set_page_address(page, (void *)vaddr); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci return vaddr; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/** 2688c2ecf20Sopenharmony_ci * kmap_high - map a highmem page into memory 2698c2ecf20Sopenharmony_ci * @page: &struct page to map 2708c2ecf20Sopenharmony_ci * 2718c2ecf20Sopenharmony_ci * Returns the page's virtual memory address. 2728c2ecf20Sopenharmony_ci * 2738c2ecf20Sopenharmony_ci * We cannot call this from interrupts, as it may block. 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_civoid *kmap_high(struct page *page) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci unsigned long vaddr; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* 2808c2ecf20Sopenharmony_ci * For highmem pages, we can't trust "virtual" until 2818c2ecf20Sopenharmony_ci * after we have the lock. 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_ci lock_kmap(); 2848c2ecf20Sopenharmony_ci vaddr = (unsigned long)page_address(page); 2858c2ecf20Sopenharmony_ci if (!vaddr) 2868c2ecf20Sopenharmony_ci vaddr = map_new_virtual(page); 2878c2ecf20Sopenharmony_ci pkmap_count[PKMAP_NR(vaddr)]++; 2888c2ecf20Sopenharmony_ci BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 2); 2898c2ecf20Sopenharmony_ci unlock_kmap(); 2908c2ecf20Sopenharmony_ci return (void*) vaddr; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ciEXPORT_SYMBOL(kmap_high); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci#ifdef ARCH_NEEDS_KMAP_HIGH_GET 2968c2ecf20Sopenharmony_ci/** 2978c2ecf20Sopenharmony_ci * kmap_high_get - pin a highmem page into memory 2988c2ecf20Sopenharmony_ci * @page: &struct page to pin 2998c2ecf20Sopenharmony_ci * 3008c2ecf20Sopenharmony_ci * Returns the page's current virtual memory address, or NULL if no mapping 3018c2ecf20Sopenharmony_ci * exists. If and only if a non null address is returned then a 3028c2ecf20Sopenharmony_ci * matching call to kunmap_high() is necessary. 3038c2ecf20Sopenharmony_ci * 3048c2ecf20Sopenharmony_ci * This can be called from any context. 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_civoid *kmap_high_get(struct page *page) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci unsigned long vaddr, flags; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci lock_kmap_any(flags); 3118c2ecf20Sopenharmony_ci vaddr = (unsigned long)page_address(page); 3128c2ecf20Sopenharmony_ci if (vaddr) { 3138c2ecf20Sopenharmony_ci BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 1); 3148c2ecf20Sopenharmony_ci pkmap_count[PKMAP_NR(vaddr)]++; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci unlock_kmap_any(flags); 3178c2ecf20Sopenharmony_ci return (void*) vaddr; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci#endif 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci/** 3228c2ecf20Sopenharmony_ci * kunmap_high - unmap a highmem page into memory 3238c2ecf20Sopenharmony_ci * @page: &struct page to unmap 3248c2ecf20Sopenharmony_ci * 3258c2ecf20Sopenharmony_ci * If ARCH_NEEDS_KMAP_HIGH_GET is not defined then this may be called 3268c2ecf20Sopenharmony_ci * only from user context. 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_civoid kunmap_high(struct page *page) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci unsigned long vaddr; 3318c2ecf20Sopenharmony_ci unsigned long nr; 3328c2ecf20Sopenharmony_ci unsigned long flags; 3338c2ecf20Sopenharmony_ci int need_wakeup; 3348c2ecf20Sopenharmony_ci unsigned int color = get_pkmap_color(page); 3358c2ecf20Sopenharmony_ci wait_queue_head_t *pkmap_map_wait; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci lock_kmap_any(flags); 3388c2ecf20Sopenharmony_ci vaddr = (unsigned long)page_address(page); 3398c2ecf20Sopenharmony_ci BUG_ON(!vaddr); 3408c2ecf20Sopenharmony_ci nr = PKMAP_NR(vaddr); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* 3438c2ecf20Sopenharmony_ci * A count must never go down to zero 3448c2ecf20Sopenharmony_ci * without a TLB flush! 3458c2ecf20Sopenharmony_ci */ 3468c2ecf20Sopenharmony_ci need_wakeup = 0; 3478c2ecf20Sopenharmony_ci switch (--pkmap_count[nr]) { 3488c2ecf20Sopenharmony_ci case 0: 3498c2ecf20Sopenharmony_ci BUG(); 3508c2ecf20Sopenharmony_ci case 1: 3518c2ecf20Sopenharmony_ci /* 3528c2ecf20Sopenharmony_ci * Avoid an unnecessary wake_up() function call. 3538c2ecf20Sopenharmony_ci * The common case is pkmap_count[] == 1, but 3548c2ecf20Sopenharmony_ci * no waiters. 3558c2ecf20Sopenharmony_ci * The tasks queued in the wait-queue are guarded 3568c2ecf20Sopenharmony_ci * by both the lock in the wait-queue-head and by 3578c2ecf20Sopenharmony_ci * the kmap_lock. As the kmap_lock is held here, 3588c2ecf20Sopenharmony_ci * no need for the wait-queue-head's lock. Simply 3598c2ecf20Sopenharmony_ci * test if the queue is empty. 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_ci pkmap_map_wait = get_pkmap_wait_queue_head(color); 3628c2ecf20Sopenharmony_ci need_wakeup = waitqueue_active(pkmap_map_wait); 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci unlock_kmap_any(flags); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* do wake-up, if needed, race-free outside of the spin lock */ 3678c2ecf20Sopenharmony_ci if (need_wakeup) 3688c2ecf20Sopenharmony_ci wake_up(pkmap_map_wait); 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(kunmap_high); 3728c2ecf20Sopenharmony_ci#endif /* CONFIG_HIGHMEM */ 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci#if defined(HASHED_PAGE_VIRTUAL) 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci#define PA_HASH_ORDER 7 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci/* 3798c2ecf20Sopenharmony_ci * Describes one page->virtual association 3808c2ecf20Sopenharmony_ci */ 3818c2ecf20Sopenharmony_cistruct page_address_map { 3828c2ecf20Sopenharmony_ci struct page *page; 3838c2ecf20Sopenharmony_ci void *virtual; 3848c2ecf20Sopenharmony_ci struct list_head list; 3858c2ecf20Sopenharmony_ci}; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic struct page_address_map page_address_maps[LAST_PKMAP]; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci/* 3908c2ecf20Sopenharmony_ci * Hash table bucket 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_cistatic struct page_address_slot { 3938c2ecf20Sopenharmony_ci struct list_head lh; /* List of page_address_maps */ 3948c2ecf20Sopenharmony_ci spinlock_t lock; /* Protect this bucket's list */ 3958c2ecf20Sopenharmony_ci} ____cacheline_aligned_in_smp page_address_htable[1<<PA_HASH_ORDER]; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic struct page_address_slot *page_slot(const struct page *page) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci return &page_address_htable[hash_ptr(page, PA_HASH_ORDER)]; 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci/** 4038c2ecf20Sopenharmony_ci * page_address - get the mapped virtual address of a page 4048c2ecf20Sopenharmony_ci * @page: &struct page to get the virtual address of 4058c2ecf20Sopenharmony_ci * 4068c2ecf20Sopenharmony_ci * Returns the page's virtual address. 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_civoid *page_address(const struct page *page) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci unsigned long flags; 4118c2ecf20Sopenharmony_ci void *ret; 4128c2ecf20Sopenharmony_ci struct page_address_slot *pas; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (!PageHighMem(page)) 4158c2ecf20Sopenharmony_ci return lowmem_page_address(page); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci pas = page_slot(page); 4188c2ecf20Sopenharmony_ci ret = NULL; 4198c2ecf20Sopenharmony_ci spin_lock_irqsave(&pas->lock, flags); 4208c2ecf20Sopenharmony_ci if (!list_empty(&pas->lh)) { 4218c2ecf20Sopenharmony_ci struct page_address_map *pam; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci list_for_each_entry(pam, &pas->lh, list) { 4248c2ecf20Sopenharmony_ci if (pam->page == page) { 4258c2ecf20Sopenharmony_ci ret = pam->virtual; 4268c2ecf20Sopenharmony_ci goto done; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_cidone: 4318c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pas->lock, flags); 4328c2ecf20Sopenharmony_ci return ret; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(page_address); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci/** 4388c2ecf20Sopenharmony_ci * set_page_address - set a page's virtual address 4398c2ecf20Sopenharmony_ci * @page: &struct page to set 4408c2ecf20Sopenharmony_ci * @virtual: virtual address to use 4418c2ecf20Sopenharmony_ci */ 4428c2ecf20Sopenharmony_civoid set_page_address(struct page *page, void *virtual) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci unsigned long flags; 4458c2ecf20Sopenharmony_ci struct page_address_slot *pas; 4468c2ecf20Sopenharmony_ci struct page_address_map *pam; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci BUG_ON(!PageHighMem(page)); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci pas = page_slot(page); 4518c2ecf20Sopenharmony_ci if (virtual) { /* Add */ 4528c2ecf20Sopenharmony_ci pam = &page_address_maps[PKMAP_NR((unsigned long)virtual)]; 4538c2ecf20Sopenharmony_ci pam->page = page; 4548c2ecf20Sopenharmony_ci pam->virtual = virtual; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci spin_lock_irqsave(&pas->lock, flags); 4578c2ecf20Sopenharmony_ci list_add_tail(&pam->list, &pas->lh); 4588c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pas->lock, flags); 4598c2ecf20Sopenharmony_ci } else { /* Remove */ 4608c2ecf20Sopenharmony_ci spin_lock_irqsave(&pas->lock, flags); 4618c2ecf20Sopenharmony_ci list_for_each_entry(pam, &pas->lh, list) { 4628c2ecf20Sopenharmony_ci if (pam->page == page) { 4638c2ecf20Sopenharmony_ci list_del(&pam->list); 4648c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pas->lock, flags); 4658c2ecf20Sopenharmony_ci goto done; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pas->lock, flags); 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_cidone: 4718c2ecf20Sopenharmony_ci return; 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_civoid __init page_address_init(void) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci int i; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(page_address_htable); i++) { 4798c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&page_address_htable[i].lh); 4808c2ecf20Sopenharmony_ci spin_lock_init(&page_address_htable[i].lock); 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci} 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci#endif /* defined(HASHED_PAGE_VIRTUAL) */ 485