Branch data Line data Source code
1 : : /*
2 : : * arch/arm/mm/highmem.c -- ARM highmem support
3 : : *
4 : : * Author: Nicolas Pitre
5 : : * Created: september 8, 2008
6 : : * Copyright: Marvell Semiconductors Inc.
7 : : *
8 : : * This program is free software; you can redistribute it and/or modify
9 : : * it under the terms of the GNU General Public License version 2 as
10 : : * published by the Free Software Foundation.
11 : : */
12 : :
13 : : #include <linux/module.h>
14 : : #include <linux/highmem.h>
15 : : #include <linux/interrupt.h>
16 : : #include <asm/fixmap.h>
17 : : #include <asm/cacheflush.h>
18 : : #include <asm/tlbflush.h>
19 : : #include "mm.h"
20 : :
21 : 0 : void *kmap(struct page *page)
22 : : {
23 : : might_sleep();
24 [ + + ]: 2049429 : if (!PageHighMem(page))
25 : 731201 : return page_address(page);
26 : 1318228 : return kmap_high(page);
27 : : }
28 : : EXPORT_SYMBOL(kmap);
29 : :
30 : 0 : void kunmap(struct page *page)
31 : : {
32 [ - + ]: 2049428 : BUG_ON(in_interrupt());
33 [ + + ]: 2049428 : if (!PageHighMem(page))
34 : 1 : return;
35 : 1318229 : kunmap_high(page);
36 : : }
37 : : EXPORT_SYMBOL(kunmap);
38 : :
39 : 0 : void *kmap_atomic(struct page *page)
40 : : {
41 : : unsigned int idx;
42 : : unsigned long vaddr;
43 : : void *kmap;
44 : : int type;
45 : :
46 : : pagefault_disable();
47 [ + + ]: 220554872 : if (!PageHighMem(page))
48 : 76441568 : return page_address(page);
49 : :
50 : : #ifdef CONFIG_DEBUG_HIGHMEM
51 : : /*
52 : : * There is no cache coherency issue when non VIVT, so force the
53 : : * dedicated kmap usage for better debugging purposes in that case.
54 : : */
55 : : if (!cache_is_vivt())
56 : : kmap = NULL;
57 : : else
58 : : #endif
59 : 144113304 : kmap = kmap_high_get(page);
60 [ + + ]: 144212996 : if (kmap)
61 : : return kmap;
62 : :
63 : : type = kmap_atomic_idx_push();
64 : :
65 : 141519098 : idx = type + KM_TYPE_NR * smp_processor_id();
66 : 141519098 : vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
67 : : #ifdef CONFIG_DEBUG_HIGHMEM
68 : : /*
69 : : * With debugging enabled, kunmap_atomic forces that entry to 0.
70 : : * Make sure it was indeed properly unmapped.
71 : : */
72 : : BUG_ON(!pte_none(get_top_pte(vaddr)));
73 : : #endif
74 : : /*
75 : : * When debugging is off, kunmap_atomic leaves the previous mapping
76 : : * in place, so the contained TLB flush ensures the TLB is updated
77 : : * with the new mapping.
78 : : */
79 : 141519098 : set_top_pte(vaddr, mk_pte(page, kmap_prot));
80 : :
81 : 141518940 : return (void *)vaddr;
82 : : }
83 : : EXPORT_SYMBOL(kmap_atomic);
84 : :
85 : 0 : void __kunmap_atomic(void *kvaddr)
86 : : {
87 : 220560739 : unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
88 : : int idx, type;
89 : :
90 [ + + ]: 220560739 : if (kvaddr >= (void *)FIXADDR_START) {
91 : : type = kmap_atomic_idx();
92 : : idx = type + KM_TYPE_NR * smp_processor_id();
93 : :
94 : : if (cache_is_vivt())
95 : : __cpuc_flush_dcache_area((void *)vaddr, PAGE_SIZE);
96 : : #ifdef CONFIG_DEBUG_HIGHMEM
97 : : BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
98 : : set_top_pte(vaddr, __pte(0));
99 : : #else
100 : : (void) idx; /* to kill a warning */
101 : : #endif
102 : : kmap_atomic_idx_pop();
103 [ + + ]: 79132129 : } else if (vaddr >= PKMAP_ADDR(0) && vaddr < PKMAP_ADDR(LAST_PKMAP)) {
104 : : /* this address was obtained through kmap_high_get() */
105 : 2694301 : kunmap_high(pte_page(pkmap_page_table[PKMAP_NR(vaddr)]));
106 : : }
107 : : pagefault_enable();
108 : 220533900 : }
109 : : EXPORT_SYMBOL(__kunmap_atomic);
110 : :
111 : 0 : void *kmap_atomic_pfn(unsigned long pfn)
112 : : {
113 : : unsigned long vaddr;
114 : : int idx, type;
115 : :
116 : : pagefault_disable();
117 : :
118 : : type = kmap_atomic_idx_push();
119 : 0 : idx = type + KM_TYPE_NR * smp_processor_id();
120 : 0 : vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
121 : : #ifdef CONFIG_DEBUG_HIGHMEM
122 : : BUG_ON(!pte_none(get_top_pte(vaddr)));
123 : : #endif
124 : 0 : set_top_pte(vaddr, pfn_pte(pfn, kmap_prot));
125 : :
126 : 0 : return (void *)vaddr;
127 : : }
128 : :
129 : 0 : struct page *kmap_atomic_to_page(const void *ptr)
130 : : {
131 : 0 : unsigned long vaddr = (unsigned long)ptr;
132 : :
133 [ # # ]: 0 : if (vaddr < FIXADDR_START)
134 : 0 : return virt_to_page(ptr);
135 : :
136 : 0 : return pte_page(get_top_pte(vaddr));
137 : : }
|