Skip to content

Commit 13f876b

Browse files
committed
highmem: High implementation details and document API
Move the gory details of kmap & al into a private header and only document the interfaces which are usable by drivers. Signed-off-by: Thomas Gleixner <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Christoph Hellwig <[email protected]> Cc: Andrew Morton <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 9bf6f7b commit 13f876b

File tree

3 files changed

+274
-177
lines changed

3 files changed

+274
-177
lines changed

include/linux/highmem-internal.h

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _LINUX_HIGHMEM_INTERNAL_H
3+
#define _LINUX_HIGHMEM_INTERNAL_H
4+
5+
/*
6+
* Outside of CONFIG_HIGHMEM to support X86 32bit iomap_atomic() cruft.
7+
*/
8+
#ifdef CONFIG_KMAP_LOCAL
9+
void *__kmap_local_pfn_prot(unsigned long pfn, pgprot_t prot);
10+
void *__kmap_local_page_prot(struct page *page, pgprot_t prot);
11+
void kunmap_local_indexed(void *vaddr);
12+
#endif
13+
14+
#ifdef CONFIG_HIGHMEM
15+
#include <asm/highmem.h>
16+
17+
#ifndef ARCH_HAS_KMAP_FLUSH_TLB
18+
static inline void kmap_flush_tlb(unsigned long addr) { }
19+
#endif
20+
21+
#ifndef kmap_prot
22+
#define kmap_prot PAGE_KERNEL
23+
#endif
24+
25+
void *kmap_high(struct page *page);
26+
void kunmap_high(struct page *page);
27+
void __kmap_flush_unused(void);
28+
struct page *__kmap_to_page(void *addr);
29+
30+
static inline void *kmap(struct page *page)
31+
{
32+
void *addr;
33+
34+
might_sleep();
35+
if (!PageHighMem(page))
36+
addr = page_address(page);
37+
else
38+
addr = kmap_high(page);
39+
kmap_flush_tlb((unsigned long)addr);
40+
return addr;
41+
}
42+
43+
static inline void kunmap(struct page *page)
44+
{
45+
might_sleep();
46+
if (!PageHighMem(page))
47+
return;
48+
kunmap_high(page);
49+
}
50+
51+
static inline struct page *kmap_to_page(void *addr)
52+
{
53+
return __kmap_to_page(addr);
54+
}
55+
56+
static inline void kmap_flush_unused(void)
57+
{
58+
__kmap_flush_unused();
59+
}
60+
61+
static inline void *kmap_atomic_prot(struct page *page, pgprot_t prot)
62+
{
63+
preempt_disable();
64+
pagefault_disable();
65+
return __kmap_local_page_prot(page, prot);
66+
}
67+
68+
static inline void *kmap_atomic(struct page *page)
69+
{
70+
return kmap_atomic_prot(page, kmap_prot);
71+
}
72+
73+
static inline void *kmap_atomic_pfn(unsigned long pfn)
74+
{
75+
preempt_disable();
76+
pagefault_disable();
77+
return __kmap_local_pfn_prot(pfn, kmap_prot);
78+
}
79+
80+
static inline void __kunmap_atomic(void *addr)
81+
{
82+
kunmap_local_indexed(addr);
83+
pagefault_enable();
84+
preempt_enable();
85+
}
86+
87+
unsigned int __nr_free_highpages(void);
88+
extern atomic_long_t _totalhigh_pages;
89+
90+
static inline unsigned int nr_free_highpages(void)
91+
{
92+
return __nr_free_highpages();
93+
}
94+
95+
static inline unsigned long totalhigh_pages(void)
96+
{
97+
return (unsigned long)atomic_long_read(&_totalhigh_pages);
98+
}
99+
100+
static inline void totalhigh_pages_inc(void)
101+
{
102+
atomic_long_inc(&_totalhigh_pages);
103+
}
104+
105+
static inline void totalhigh_pages_add(long count)
106+
{
107+
atomic_long_add(count, &_totalhigh_pages);
108+
}
109+
110+
#else /* CONFIG_HIGHMEM */
111+
112+
static inline struct page *kmap_to_page(void *addr)
113+
{
114+
return virt_to_page(addr);
115+
}
116+
117+
static inline void *kmap(struct page *page)
118+
{
119+
might_sleep();
120+
return page_address(page);
121+
}
122+
123+
static inline void kunmap_high(struct page *page) { }
124+
static inline void kmap_flush_unused(void) { }
125+
126+
static inline void kunmap(struct page *page)
127+
{
128+
#ifdef ARCH_HAS_FLUSH_ON_KUNMAP
129+
kunmap_flush_on_unmap(page_address(page));
130+
#endif
131+
}
132+
133+
static inline void *kmap_atomic(struct page *page)
134+
{
135+
preempt_disable();
136+
pagefault_disable();
137+
return page_address(page);
138+
}
139+
140+
static inline void *kmap_atomic_prot(struct page *page, pgprot_t prot)
141+
{
142+
return kmap_atomic(page);
143+
}
144+
145+
static inline void *kmap_atomic_pfn(unsigned long pfn)
146+
{
147+
return kmap_atomic(pfn_to_page(pfn));
148+
}
149+
150+
static inline void __kunmap_atomic(void *addr)
151+
{
152+
#ifdef ARCH_HAS_FLUSH_ON_KUNMAP
153+
kunmap_flush_on_unmap(addr);
154+
#endif
155+
pagefault_enable();
156+
preempt_enable();
157+
}
158+
159+
static inline unsigned int nr_free_highpages(void) { return 0; }
160+
static inline unsigned long totalhigh_pages(void) { return 0UL; }
161+
162+
#endif /* CONFIG_HIGHMEM */
163+
164+
/*
165+
* Prevent people trying to call kunmap_atomic() as if it were kunmap()
166+
* kunmap_atomic() should get the return value of kmap_atomic, not the page.
167+
*/
168+
#define kunmap_atomic(__addr) \
169+
do { \
170+
BUILD_BUG_ON(__same_type((__addr), struct page *)); \
171+
__kunmap_atomic(__addr); \
172+
} while (0)
173+
174+
#endif

0 commit comments

Comments
 (0)