1 /* << 2 * High memory support for Xtensa architecture << 3 * << 4 * This file is subject to the terms and condi << 5 * Public License. See the file "COPYING" in << 6 * this archive for more details. << 7 * << 8 * Copyright (C) 2014 Cadence Design Systems I << 9 */ << 10 << 11 #include <linux/export.h> << 12 #include <linux/highmem.h> 1 #include <linux/highmem.h> 13 #include <asm/tlbflush.h> << 14 2 15 #if DCACHE_WAY_SIZE > PAGE_SIZE !! 3 void *kmap(struct page *page) 16 unsigned int last_pkmap_nr_arr[DCACHE_N_COLORS !! 4 { 17 wait_queue_head_t pkmap_map_wait_arr[DCACHE_N_ !! 5 might_sleep(); >> 6 if (page < highmem_start_page) >> 7 return page_address(page); >> 8 return kmap_high(page); >> 9 } >> 10 >> 11 void kunmap(struct page *page) >> 12 { >> 13 if (in_interrupt()) >> 14 BUG(); >> 15 if (page < highmem_start_page) >> 16 return; >> 17 kunmap_high(page); >> 18 } 18 19 19 static void __init kmap_waitqueues_init(void) !! 20 /* >> 21 * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because >> 22 * no global lock is needed and because the kmap code must perform a global TLB >> 23 * invalidation when the kmap pool wraps. >> 24 * >> 25 * However when holding an atomic kmap is is not legal to sleep, so atomic >> 26 * kmaps are appropriate for short, tight code paths only. >> 27 */ >> 28 void *kmap_atomic(struct page *page, enum km_type type) 20 { 29 { 21 unsigned int i; !! 30 enum fixed_addresses idx; >> 31 unsigned long vaddr; >> 32 >> 33 inc_preempt_count(); >> 34 if (page < highmem_start_page) >> 35 return page_address(page); >> 36 >> 37 idx = type + KM_TYPE_NR*smp_processor_id(); >> 38 vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); >> 39 #ifdef CONFIG_DEBUG_HIGHMEM >> 40 if (!pte_none(*(kmap_pte-idx))) >> 41 BUG(); >> 42 #endif >> 43 set_pte(kmap_pte-idx, mk_pte(page, kmap_prot)); >> 44 __flush_tlb_one(vaddr); 22 45 23 for (i = 0; i < ARRAY_SIZE(pkmap_map_w !! 46 return (void*) vaddr; 24 init_waitqueue_head(pkmap_map_ << 25 } 47 } 26 48 27 static inline enum fixed_addresses kmap_idx(in !! 49 void kunmap_atomic(void *kvaddr, enum km_type type) 28 { 50 { 29 int idx = (type + KM_MAX_IDX * smp_pro !! 51 #ifdef CONFIG_DEBUG_HIGHMEM >> 52 unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; >> 53 enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id(); >> 54 >> 55 if (vaddr < FIXADDR_START) { // FIXME >> 56 dec_preempt_count(); >> 57 return; >> 58 } >> 59 >> 60 if (vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx)) >> 61 BUG(); 30 62 31 /* 63 /* 32 * The fixmap operates top down, so th !! 64 * force other mappings to Oops if they'll try to access 33 * reverse as well. !! 65 * this pte without first remap it 34 */ 66 */ 35 return idx + DCACHE_N_COLORS - 1 - col !! 67 pte_clear(kmap_pte-idx); 36 } !! 68 __flush_tlb_one(vaddr); >> 69 #endif 37 70 38 enum fixed_addresses kmap_local_map_idx(int ty !! 71 dec_preempt_count(); 39 { << 40 return kmap_idx(type, DCACHE_ALIAS(pfn << 41 } 72 } 42 73 43 enum fixed_addresses kmap_local_unmap_idx(int !! 74 struct page *kmap_atomic_to_page(void *ptr) 44 { 75 { 45 return kmap_idx(type, DCACHE_ALIAS(add !! 76 unsigned long idx, vaddr = (unsigned long)ptr; 46 } !! 77 pte_t *pte; 47 78 48 #else !! 79 if (vaddr < FIXADDR_START) 49 static inline void kmap_waitqueues_init(void) !! 80 return virt_to_page(ptr); 50 #endif << 51 81 52 void __init kmap_init(void) !! 82 idx = virt_to_fix(vaddr); 53 { !! 83 pte = kmap_pte - (idx - FIX_KMAP_BEGIN); 54 /* Check if this memory layout is brok !! 84 return pte_page(*pte); 55 * page table. << 56 */ << 57 BUILD_BUG_ON(PKMAP_BASE < TLBTEMP_BASE << 58 kmap_waitqueues_init(); << 59 } 85 } >> 86 60 87
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.