Definitions of pfn_to_page/page_to_pfn are defined in each arch's include files.
But most of them just do the same thing.
This patch consolidates all definitions to generic one.
Changelog: v1->v2
- linux/memory_model.h is added. this defines pfn<->page translation.
- new config options (set by arch) CONFIG_DONT_INLINE_PFN_TO_PAGE
and CONFIG_ARCH_HAS_PFN_TO_PAGE are added.
- SPARSEMEM's page_to_pfn is moved to linux/memory_model.h
-- Kame.
This patch adds generci pfn_to_page/page_to_pfn definition.
Now, each arch has its own page_to_pfn/pfn_to_page. But most of them
do the same arithmatic. And I think this arithmatic is defined by memory model,
not by architecture.
3 types of arithmatic is defined in linux/memory_model.h.
New configs are added.
CONFIG_ARCH_HASH_PFN_TO_PAGE ..... for arch which uses *unusual* memory model.
(see m68k..)
CONFIG_DONT_INLINE_PFN_TO_PAGE ... for achh which doesn't want to make these
funcs inlined. (for sparc64, x86_64, maybe
making good result for some other archs.)
Helper macro ARCH_PFN_OFFSET, arch_pfn_to_nid, arch_local_pfn_offset()
are also added.
Signed-Off-BY: KAMEZAWA Hiroyuki <[email protected]>
Index: test-layout-free-zone/include/linux/memory_model.h
===================================================================
--- /dev/null
+++ test-layout-free-zone/include/linux/memory_model.h
@@ -0,0 +1,88 @@
+#ifndef __LINUX_MEMORY_MODEL_H
+#define __LINUX_MEMORY_MODEL_H
+/*
+ * pfn <-> page struct arithmatic for each memory model.
+ *
+ * 3 memory models are supported.
+ *
+ * FLATMEM -- pfn = (page - mem_map) + offset
+ * page struct is contigous to max_pfn.
+ * DISCONTIGMEM -- pfn = (page - node->node_mem_map) + node->node_start_pfn.
+ * page struct is contigous within each node.
+ * SPARSEMEM -- pfn = pfn_to_section(page_to_section(page)) + offset in section.
+ * page struct is contigous in each section.
+ */
+
+#ifndef CONFIG_ARCH_HAS_PFN_TO_PAGE
+/*
+ * some arch defines helper macro if necessary.
+ */
+/* used by FLATMEM */
+#ifndef ARCH_PFN_OFFSET
+#define ARCH_PFN_OFFSET (0UL)
+#endif
+
+/* used by DISCONTIGMEM */
+#ifndef arch_pfn_to_nid
+#define arch_pfn_to_nid(pfn) pfn_to_nid((pfn))
+#endif
+
+#ifndef arch_local_pfn_offset
+#define arch_local_pfn_offset(pfn, nid) ((pfn) - NODE_DATA((nid))->node_start_pfn)
+#endif
+
+#ifdef CONFIG_DONT_INLINE_PFN_TO_PAGE
+
+/* not-inlined version for some archs. funcs are defined in mm/page_alloc.c */
+extern unsigned long page_to_pfn(struct page *page);
+extern struct page *pfn_to_page(unsigned long pfn);
+
+#else
+
+#if defined(CONFIG_FLATMEM)
+
+static inline unsigned long page_to_pfn(struct page *page)
+{
+ return (unsigned long)(page - mem_map) + ARCH_PFN_OFFSET;
+}
+
+static inline struct page *pfn_to_page(unsigned long pfn)
+{
+ return mem_map + (pfn - ARCH_PFN_OFFSET);
+}
+
+#elif defined(CONFIG_DISCONTIGMEM)
+
+static inline unsigned long page_to_pfn(struct page *page)
+{
+ struct zone *z = page_zone(page)
+ return (unsigned long)(page - z->zone_mem_map) + z->zone_start_pfn;
+}
+
+static inline struct page *pfn_to_page(unsigned long pfn)
+{
+ int nid = arch_pfn_to_nid(pfn);
+ struct pglist_data *pgdat = NODE_DATA(nid);
+ return pgdat->node_mem_map + arch_local_pfn_offset(pfn, nid);
+}
+
+#elif defined(CONFIG_SPARSEMEM)
+
+static inline unsigned long page_to_pfn(struct page *page)
+{
+ long section_id = page_to_section(page);
+ return page - __section_mem_map_addr(__nr_to_section(section_id));
+}
+
+static inline struct page * pfn_to_page(unsigned long pfn)
+{
+ return __section_mem_map_addr(__pfn_to_section(pfn)) + pfn;
+}
+
+#endif /* CONFIG_FLATMEM/DISCONTIGMEM/SPARSEMEM */
+
+#endif /* CONFIG_DONT_INLINE_PFN_TO_PAGE */
+
+#endif /* CONFIG_ARCH_HAS_PFN_TO_PAGE */
+
+#endif /* __LINUX_MEMORY_MODEL_H */
Index: test-layout-free-zone/include/linux/mmzone.h
===================================================================
--- test-layout-free-zone.orig/include/linux/mmzone.h
+++ test-layout-free-zone/include/linux/mmzone.h
@@ -602,16 +602,6 @@ static inline struct mem_section *__pfn_
return __nr_to_section(pfn_to_section_nr(pfn));
}
-#define pfn_to_page(pfn) \
-({ \
- unsigned long __pfn = (pfn); \
- __section_mem_map_addr(__pfn_to_section(__pfn)) + __pfn; \
-})
-#define page_to_pfn(page) \
-({ \
- page - __section_mem_map_addr(__nr_to_section( \
- page_to_section(page))); \
-})
static inline int pfn_valid(unsigned long pfn)
{
Index: test-layout-free-zone/mm/page_alloc.c
===================================================================
--- test-layout-free-zone.orig/mm/page_alloc.c
+++ test-layout-free-zone/mm/page_alloc.c
@@ -85,6 +85,55 @@ int min_free_kbytes = 1024;
unsigned long __initdata nr_kernel_pages;
unsigned long __initdata nr_all_pages;
+/*
+ * page <-> pfn translation, not-inlined ver. (see linux/memory_model.h)
+ */
+#ifdef CONFIG_DONT_INLINE_PFN_TO_PAGE
+#if defined(CONFIG_FLATMEM)
+
+unsigned long page_to_pfn(struct page *page)
+{
+ return (unsigned long)(page - mem_map) + ARCH_PFN_OFFSET;
+}
+
+static inline struct page *pfn_to_page(unsigned long pfn)
+{
+ return mem_map + (pfn - ARCH_PFN_OFFSET);
+}
+
+#elif defined (CONFIG_DISCONTIGMEM)
+
+unsigned long page_to_pfn(struct page *page)
+{
+ struct zone *z = page_zone(page)
+ return (unsigned long)(page - z->zone_mem_map) + z->zone_start_pfn;
+}
+
+struct page *pfn_to_page(unsigned long pfn)
+{
+ int nid = arch_pfn_to_nid(pfn);
+ struct pglist_data *pgdat = NODE_DATA(nid);
+ return pgdat->node_mem_map + arch_local_pfn_offset(pfn, nid);
+}
+
+#elif defined (CONFIG_SPARSEMEM)
+
+static inline unsigned long page_to_pfn(struct page *page)
+{
+ long section_id = page_to_section(page);
+ return page - __section_mem_map_addr(__nr_to_section(section_id));
+}
+
+static inline struct page * pfn_to_page(unsigned long pfn)
+{
+ return __section_mem_map_addr(__pfn_to_section(pfn)) + pfn;
+}
+#endif
+
+EXPORT_SYMBOL(pfn_to_page);
+EXPORT_SYMBOL(page_to_pfn);
+#endif
+
#ifdef CONFIG_DEBUG_VM
static int page_outside_zone_boundaries(struct zone *zone, struct page *page)
{
Index: test-layout-free-zone/include/linux/mm.h
===================================================================
--- test-layout-free-zone.orig/include/linux/mm.h
+++ test-layout-free-zone/include/linux/mm.h
@@ -512,6 +512,9 @@ static inline void set_page_links(struct
extern struct page *mem_map;
#endif
+/* include pfn <-> page struct arithmatic for each memory model */
+#include <linux/memory_model.h>
+
static __always_inline void *lowmem_page_address(struct page *page)
{
return __va(page_to_pfn(page) << PAGE_SHIFT);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]