aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/asm-generic/memory_model.h77
-rw-r--r--include/asm-sparc64/page.h2
-rw-r--r--include/linux/mmzone.h11
-rw-r--r--mm/page_alloc.c42
4 files changed, 121 insertions, 11 deletions
diff --git a/include/asm-generic/memory_model.h b/include/asm-generic/memory_model.h
new file mode 100644
index 000000000000..a7bb4978e808
--- /dev/null
+++ b/include/asm-generic/memory_model.h
@@ -0,0 +1,77 @@
1#ifndef __ASM_MEMORY_MODEL_H
2#define __ASM_MEMORY_MODEL_H
3
4#ifdef __KERNEL__
5#ifndef __ASSEMBLY__
6
7#if defined(CONFIG_FLATMEM)
8
9#ifndef ARCH_PFN_OFFSET
10#define ARCH_PFN_OFFSET (0UL)
11#endif
12
13#elif defined(CONFIG_DISCONTIGMEM)
14
15#ifndef arch_pfn_to_nid
16#define arch_pfn_to_nid(pfn) pfn_to_nid(pfn)
17#endif
18
19#ifndef arch_local_page_offset
20#define arch_local_page_offset(pfn, nid) \
21 ((pfn) - NODE_DATA(nid)->node_start_pfn)
22#endif
23
24#endif /* CONFIG_DISCONTIGMEM */
25
26#ifdef CONFIG_OUT_OF_LINE_PFN_TO_PAGE
27struct page;
28/* this is useful when inlined pfn_to_page is too big */
29extern struct page *pfn_to_page(unsigned long pfn);
30extern unsigned long page_to_pfn(struct page *page);
31#else
32/*
33 * supports 3 memory models.
34 */
35#if defined(CONFIG_FLATMEM)
36
37#define pfn_to_page(pfn) (mem_map + ((pfn) - ARCH_PFN_OFFSET))
38#define page_to_pfn(page) ((unsigned long)((page) - mem_map) + \
39 ARCH_PFN_OFFSET)
40#elif defined(CONFIG_DISCONTIGMEM)
41
42#define pfn_to_page(pfn) \
43({ unsigned long __pfn = (pfn); \
44 unsigned long __nid = arch_pfn_to_nid(pfn); \
45 NODE_DATA(__nid)->node_mem_map + arch_local_page_offset(__pfn, __nid);\
46})
47
48#define page_to_pfn(pg) \
49({ struct page *__pg = (pg); \
50 struct zone *__zone = page_zone(__pg); \
51 (unsigned long)(__pg - __zone->zone_mem_map) + \
52 __zone->zone_start_pfn; \
53})
54
55#elif defined(CONFIG_SPARSEMEM)
56/*
57 * Note: section's mem_map is encorded to reflect its start_pfn.
58 * section[i].section_mem_map == mem_map's address - start_pfn;
59 */
60#define page_to_pfn(pg) \
61({ struct page *__pg = (pg); \
62 int __sec = page_to_section(__pg); \
63 __pg - __section_mem_map_addr(__nr_to_section(__sec)); \
64})
65
66#define pfn_to_page(pfn) \
67({ unsigned long __pfn = (pfn); \
68 struct mem_section *__sec = __pfn_to_section(__pfn); \
69 __section_mem_map_addr(__sec) + __pfn; \
70})
71#endif /* CONFIG_FLATMEM/DISCONTIGMEM/SPARSEMEM */
72#endif /* CONFIG_OUT_OF_LINE_PFN_TO_PAGE */
73
74#endif /* __ASSEMBLY__ */
75#endif /* __KERNEL__ */
76
77#endif
diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h
index 66fe4ac59fd6..aabb21906724 100644
--- a/include/asm-sparc64/page.h
+++ b/include/asm-sparc64/page.h
@@ -111,6 +111,8 @@ typedef unsigned long pgprot_t;
111 (_AC(0x0000000070000000,UL)) : \ 111 (_AC(0x0000000070000000,UL)) : \
112 (_AC(0xfffff80000000000,UL) + (1UL << 32UL))) 112 (_AC(0xfffff80000000000,UL) + (1UL << 32UL)))
113 113
114#include <asm-generic/memory_model.h>
115
114#endif /* !(__ASSEMBLY__) */ 116#endif /* !(__ASSEMBLY__) */
115 117
116/* to align the pointer to the (next) page boundary */ 118/* to align the pointer to the (next) page boundary */
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index ebfc238cc243..0c1c0c0cce65 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -602,17 +602,6 @@ static inline struct mem_section *__pfn_to_section(unsigned long pfn)
602 return __nr_to_section(pfn_to_section_nr(pfn)); 602 return __nr_to_section(pfn_to_section_nr(pfn));
603} 603}
604 604
605#define pfn_to_page(pfn) \
606({ \
607 unsigned long __pfn = (pfn); \
608 __section_mem_map_addr(__pfn_to_section(__pfn)) + __pfn; \
609})
610#define page_to_pfn(page) \
611({ \
612 page - __section_mem_map_addr(__nr_to_section( \
613 page_to_section(page))); \
614})
615
616static inline int pfn_valid(unsigned long pfn) 605static inline int pfn_valid(unsigned long pfn)
617{ 606{
618 if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS) 607 if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 338a02bb004d..349b328763b7 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -2745,3 +2745,45 @@ void *__init alloc_large_system_hash(const char *tablename,
2745 2745
2746 return table; 2746 return table;
2747} 2747}
2748
2749#ifdef CONFIG_OUT_OF_LINE_PFN_TO_PAGE
2750/*
2751 * pfn <-> page translation. out-of-line version.
2752 * (see asm-generic/memory_model.h)
2753 */
2754#if defined(CONFIG_FLATMEM)
2755struct page *pfn_to_page(unsigned long pfn)
2756{
2757 return mem_map + (pfn - ARCH_PFN_OFFSET);
2758}
2759unsigned long page_to_pfn(struct page *page)
2760{
2761 return (page - mem_map) + ARCH_PFN_OFFSET;
2762}
2763#elif defined(CONFIG_DISCONTIGMEM)
2764struct page *pfn_to_page(unsigned long pfn)
2765{
2766 int nid = arch_pfn_to_nid(pfn);
2767 return NODE_DATA(nid)->node_mem_map + arch_local_page_offset(pfn,nid);
2768}
2769unsigned long page_to_pfn(struct page *page)
2770{
2771 struct zone *zone = page_zone(page);
2772 return (page - zone->zone_mem_map) + zone->zone_start_pfn;
2773
2774}
2775#elif defined(CONFIG_SPARSEMEM)
2776struct page *pfn_to_page(unsigned long pfn)
2777{
2778 return __section_mem_map_addr(__pfn_to_section(pfn)) + pfn;
2779}
2780
2781unsigned long page_to_pfn(struct page *page)
2782{
2783 long section_id = page_to_section(page);
2784 return page - __section_mem_map_addr(__nr_to_section(section_id));
2785}
2786#endif /* CONFIG_FLATMEM/DISCONTIGMME/SPARSEMEM */
2787EXPORT_SYMBOL(pfn_to_page);
2788EXPORT_SYMBOL(page_to_pfn);
2789#endif /* CONFIG_OUT_OF_LINE_PFN_TO_PAGE */