linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Andy Whitcroft <apw@shadowen.org>
To: apw@shadowen.org, lhms-devel@lists.sourceforge.net, linux-mm@kvack.org
Subject: 150 nonlinear
Date: Mon, 18 Oct 2004 15:35:48 +0100	[thread overview]
Message-ID: <E1CJYc0-0000aK-A8@ladymac.shadowen.org> (raw)
In-Reply-To: <4173D219.3010706@shadowen.org>

CONFIG_NONLINEAR memory model.

Revision: $Rev$

Signed-off-by: Andy Whitcroft <apw@shadowen.org>

diffstat 150-nonlinear
---
 include/linux/mm.h     |  103 +++++++++++++++++++++++++++++++++---
 include/linux/mmzone.h |  140 +++++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/numa.h   |    2 
 init/main.c            |    1 
 mm/Makefile            |    2 
 mm/bootmem.c           |   15 ++++-
 mm/memory.c            |    2 
 mm/nonlinear.c         |  137 +++++++++++++++++++++++++++++++++++++++++++++++
 mm/page_alloc.c        |   87 +++++++++++++++++++++++++++++-
 9 files changed, 469 insertions(+), 20 deletions(-)

diff -upN reference/include/linux/mm.h current/include/linux/mm.h
--- reference/include/linux/mm.h
+++ current/include/linux/mm.h
@@ -379,24 +379,76 @@ static inline void put_page(struct page 
 
 #define FLAGS_SHIFT	(sizeof(page_flags_t)*8)
 
-/* 32bit: NODE:ZONE */
+/*
+ * CONFIG_NONLINEAR:
+ *   If there is room for SECTIONS, NODES AND ZONES then:
+ *     NODE:ZONE:SECTION
+ *   else:
+ *     SECTION:ZONE
+ *
+ * Otherwise:
+ *   NODE:ZONE
+ */
+#ifdef CONFIG_NONLINEAR
+
+#if FLAGS_TOTAL_SHIFT >= SECTIONS_SHIFT + NODES_SHIFT + ZONES_SHIFT
+
+/* NODE:ZONE:SECTION */
 #define PGFLAGS_NODES_SHIFT	(FLAGS_SHIFT - NODES_SHIFT)
 #define PGFLAGS_ZONES_SHIFT	(PGFLAGS_NODES_SHIFT - ZONES_SHIFT)
+#define PGFLAGS_SECTIONS_SHIFT	(PGFLAGS_ZONES_SHIFT - SECTIONS_SHIFT)
+
+#define FLAGS_USED_SHIFT	(NODES_SHIFT + ZONES_SHIFT + SECTIONS_SHIFT)
 
 #define ZONETABLE_SHIFT		(NODES_SHIFT + ZONES_SHIFT)
 #define PGFLAGS_ZONETABLE_SHIFT	(FLAGS_SHIFT - ZONETABLE_SHIFT)
 
-#if NODES_SHIFT+ZONES_SHIFT > FLAGS_TOTAL_SHIFT
-#error NODES_SHIFT+ZONES_SHIFT > FLAGS_TOTAL_SHIFT
+#define ZONETABLE(section, node, zone) \
+			((node << ZONES_SHIFT) | zone)
+
+#else
+
+/* SECTION:ZONE */
+#define PGFLAGS_SECTIONS_SHIFT	(FLAGS_SHIFT - SECTIONS_SHIFT)
+#define PGFLAGS_ZONES_SHIFT	(PGFLAGS_SECTIONS_SHIFT - ZONES_SHIFT)
+
+#define FLAGS_USED_SHIFT	(SECTIONS_SHIFT + ZONES_SHIFT)
+
+#define ZONETABLE_SHIFT		(SECTIONS_SHIFT + ZONES_SHIFT)
+#define PGFLAGS_ZONETABLE_SHIFT	(FLAGS_SHIFT - ZONETABLE_SHIFT)
+
+#define ZONETABLE(section, node, zone) \
+			((section << ZONES_SHIFT) | zone)
+
+#endif
+
+#else /* !CONFIG_NONLINEAR */
+
+/* NODE:ZONE */
+#define PGFLAGS_NODES_SHIFT	(FLAGS_SHIFT - NODES_SHIFT)
+#define PGFLAGS_ZONES_SHIFT	(PGFLAGS_NODES_SHIFT - ZONES_SHIFT)
+
+#define ZONETABLE_SHIFT		(NODES_SHIFT + ZONES_SHIFT)
+#define PGFLAGS_ZONETABLE_SHIFT	(FLAGS_SHIFT - ZONETABLE_SHIFT)
+
+#define FLAGS_USED_SHIFT	(NODES_SHIFT + ZONES_SHIFT)
+
+#endif /* !CONFIG_NONLINEAR */
+
+#if FLAGS_USED_SHIFT > FLAGS_TOTAL_SHIFT
+#error SECTIONS_SHIFT+NODES_SHIFT+ZONES_SHIFT > FLAGS_TOTAL_SHIFT
 #endif
 
 #define NODEZONE(node, zone)		((node << ZONES_SHIFT) | zone)
 
 #define ZONES_MASK		(~((~0UL) << ZONES_SHIFT))
 #define NODES_MASK		(~((~0UL) << NODES_SHIFT))
+#define SECTIONS_MASK		(~((~0UL) << SECTIONS_SHIFT))
 #define ZONETABLE_MASK		(~((~0UL) << ZONETABLE_SHIFT))
 
-#define PGFLAGS_MASK		(~((~0UL) << PGFLAGS_ZONETABLE_SHIFT)
+#define ZONETABLE_SIZE  	(1 << ZONETABLE_SHIFT)
+
+#define PGFLAGS_MASK		(~((~0UL) << PGFLAGS_ZONETABLE_SHIFT))
 
 static inline unsigned long page_zonenum(struct page *page)
 {
@@ -405,13 +457,34 @@ static inline unsigned long page_zonenum
  	else
  		return (page->flags >> PGFLAGS_ZONES_SHIFT) & ZONES_MASK;
 }
+#ifdef PGFLAGS_NODES_SHIFT
 static inline unsigned long page_to_nid(struct page *page)
 {
+#if NODES_SHIFT == 0
+	return 0;
+#else 
 	if (FLAGS_SHIFT == (PGFLAGS_NODES_SHIFT + NODES_SHIFT))
 		return (page->flags >> PGFLAGS_NODES_SHIFT);
 	else
 		return (page->flags >> PGFLAGS_NODES_SHIFT) & NODES_MASK;
+#endif
 }
+#else
+static inline struct zone *page_zone(struct page *page);
+static inline unsigned long page_to_nid(struct page *page)
+{
+	return page_zone(page)->zone_pgdat->node_id;
+}
+#endif
+#ifdef PGFLAGS_SECTIONS_SHIFT
+static inline unsigned long page_to_section(struct page *page)
+{
+	if (FLAGS_SHIFT == (PGFLAGS_SECTIONS_SHIFT + SECTIONS_SHIFT))
+ 		return (page->flags >> PGFLAGS_SECTIONS_SHIFT);
+ 	else
+ 		return (page->flags >> PGFLAGS_SECTIONS_SHIFT) & SECTIONS_MASK;
+}
+#endif
 
 struct zone;
 extern struct zone *zone_table[];
@@ -425,13 +498,27 @@ static inline struct zone *page_zone(str
 			ZONETABLE_MASK];
 }
 
-static inline void set_page_zone(struct page *page, unsigned long nodezone_num)
+static inline void set_page_zone(struct page *page, unsigned long zone)
+{
+	page->flags &= ~(ZONES_MASK << PGFLAGS_ZONES_SHIFT);
+	page->flags |= zone << PGFLAGS_ZONES_SHIFT;
+}
+static inline void set_page_node(struct page *page, unsigned long node)
 {
-	page->flags &= PGFLAGS_MASK;
-	page->flags |= nodezone_num << PGFLAGS_ZONETABLE_SHIFT;
+#if defined(PGFLAGS_NODES_SHIFT) && NODES_SHIFT != 0
+	page->flags &= ~(NODES_MASK << PGFLAGS_NODES_SHIFT);
+	page->flags |= node << PGFLAGS_NODES_SHIFT;
+#endif
+}
+static inline void set_page_section(struct page *page, unsigned long section)
+{
+#ifdef PGFLAGS_SECTIONS_SHIFT
+	page->flags &= ~(SECTIONS_MASK << PGFLAGS_SECTIONS_SHIFT);
+	page->flags |= section << PGFLAGS_SECTIONS_SHIFT;
+#endif
 }
 
-#ifndef CONFIG_DISCONTIGMEM
+#ifdef CONFIG_FLATMEM
 /* The array of struct pages - for discontigmem use pgdat->lmem_map */
 extern struct page *mem_map;
 #endif
diff -upN reference/include/linux/mmzone.h current/include/linux/mmzone.h
--- reference/include/linux/mmzone.h
+++ current/include/linux/mmzone.h
@@ -372,7 +372,7 @@ int lower_zone_protection_sysctl_handler
 /* Returns the number of the current Node. */
 #define numa_node_id()		(cpu_to_node(smp_processor_id()))
 
-#ifndef CONFIG_DISCONTIGMEM
+#ifdef CONFIG_FLATMEM
 
 extern struct pglist_data contig_page_data;
 #define NODE_DATA(nid)		(&contig_page_data)
@@ -384,6 +384,8 @@ extern struct pglist_data contig_page_da
 
 #include <asm/mmzone.h>
 
+#endif /* CONFIG_FLATMEM */
+
 #if BITS_PER_LONG == 32 || defined(ARCH_HAS_ATOMIC_UNSIGNED)
 /*
  * with 32 bit page->flags field, we reserve 8 bits for node/zone info.
@@ -395,10 +397,13 @@ extern struct pglist_data contig_page_da
 /*
  * with 64 bit flags field, there's plenty of room.
  */
-#define FLAGS_TOTAL_SHIFT	12
-#endif
+#define FLAGS_TOTAL_SHIFT	32
+
+#else
 
-#endif /* !CONFIG_DISCONTIGMEM */
+#error BITS_PER_LONG not set
+
+#endif
 
 extern DECLARE_BITMAP(node_online_map, MAX_NUMNODES);
 
@@ -429,6 +434,133 @@ static inline unsigned int num_online_no
 #define num_online_nodes()	1
 
 #endif /* CONFIG_DISCONTIGMEM || CONFIG_NUMA */
+
+#ifdef CONFIG_NONLINEAR
+
+/*
+ * SECTION_SHIFT                #bits space required to store a section #
+ * PHYS_SECTION_SHIFT           #bits required to store a physical section #
+ *
+ * PA_SECTION_SHIFT             physical address to/from section number
+ * PFN_SECTION_SHIFT            pfn to/from section number
+ */
+#define SECTIONS_SHIFT          (MAX_PHYSMEM_BITS - SECTION_SIZE_BITS)
+#define PHYS_SECTION_SHIFT      (MAX_PHYSADDR_BITS - SECTION_SIZE_BITS)
+
+#define PA_SECTION_SHIFT        (SECTION_SIZE_BITS)
+#define PFN_SECTION_SHIFT       (SECTION_SIZE_BITS - PAGE_SHIFT)
+
+#define NR_MEM_SECTIONS        	(1 << SECTIONS_SHIFT)
+#define NR_PHYS_SECTIONS        (1 << PHYS_SECTION_SHIFT)
+
+#define PAGES_PER_SECTION       (1 << PFN_SECTION_SHIFT)
+#define PAGE_SECTION_MASK	(~(PAGES_PER_SECTION-1))
+
+#if NR_MEM_SECTIONS == NR_PHYS_SECTIONS
+#define NONLINEAR_OPTIMISE 1
+#endif
+
+struct page;
+struct mem_section {
+	short section_nid;
+	struct page *section_mem_map;
+};
+
+#ifndef NONLINEAR_OPTIMISE
+extern short phys_section[NR_PHYS_SECTIONS];
+#endif
+extern struct mem_section mem_section[NR_MEM_SECTIONS];
+
+/*
+ * Given a kernel address, find the home node of the underlying memory.
+ */
+#define kvaddr_to_nid(kaddr)	pfn_to_nid(__pa(kaddr) >> PAGE_SHIFT)
+
+#if 0
+#define node_mem_map(nid)	(NODE_DATA(nid)->node_mem_map)
+
+#define node_start_pfn(nid)	(NODE_DATA(nid)->node_start_pfn)
+#define node_end_pfn(nid)						\
+({									\
+	pg_data_t *__pgdat = NODE_DATA(nid);				\
+	__pgdat->node_start_pfn + __pgdat->node_spanned_pages;		\
+})
+
+#define local_mapnr(kvaddr)						\
+({									\
+	unsigned long __pfn = __pa(kvaddr) >> PAGE_SHIFT;		\
+	(__pfn - node_start_pfn(pfn_to_nid(__pfn)));			\
+})
+#endif
+
+#if 0
+/* XXX: FIXME -- wli */
+#define kern_addr_valid(kaddr)	(0)
+#endif
+
+static inline struct mem_section *__pfn_to_section(unsigned long pfn)
+{
+#ifdef NONLINEAR_OPTIMISE
+	return &mem_section[pfn >> PFN_SECTION_SHIFT];
+#else
+	return &mem_section[phys_section[pfn >> PFN_SECTION_SHIFT]];
+#endif
+}
+
+#define pfn_to_page(pfn) 						\
+({ 									\
+	unsigned long __pfn = (pfn);					\
+	__pfn_to_section(__pfn)->section_mem_map + __pfn;		\
+})
+#define page_to_pfn(page)						\
+({									\
+	page - mem_section[page_to_section(page)].section_mem_map;	\
+})
+
+/* APW/XXX: this is not generic??? */
+#if 0
+#define pmd_page(pmd)		(pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
+#endif
+
+static inline int pfn_valid(unsigned long pfn)
+{
+	if ((pfn >> PFN_SECTION_SHIFT) >= NR_PHYS_SECTIONS) 
+		return 0;
+#ifdef NONLINEAR_OPTIMISE
+	return mem_section[pfn >> PFN_SECTION_SHIFT].section_mem_map != 0;
+#else
+	return phys_section[pfn >> PFN_SECTION_SHIFT] != -1;
+#endif
+}
+
+/*
+ * APW/XXX: these are _only_ used during initialisation, therefore they
+ * can use __initdata ... they should have names to indicate this
+ * restriction.
+ */
+#ifdef CONFIG_NUMA
+extern unsigned long phys_section_nid[NR_PHYS_SECTIONS];
+#define pfn_to_nid(pfn)							\
+({									\
+	unsigned long __pfn = (pfn);					\
+	phys_section_nid[__pfn >> PFN_SECTION_SHIFT];			\
+})
+#else
+	__pfn_to_section(__pfn)->section_nid;				\
+#define pfn_to_nid(pfn) 0
+#endif
+
+#define pfn_to_pgdat(pfn)						\
+({									\
+	NODE_DATA(pfn_to_nid(pfn));					\
+})
+
+int nonlinear_add(int nid, unsigned long start, unsigned long end);
+int nonlinear_calculate(int nid);
+void nonlinear_allocate(void);
+
+#endif /* CONFIG_NONLINEAR */
+
 #endif /* !__ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _LINUX_MMZONE_H */
diff -upN reference/include/linux/numa.h current/include/linux/numa.h
--- reference/include/linux/numa.h
+++ current/include/linux/numa.h
@@ -3,7 +3,7 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_DISCONTIGMEM
+#ifndef CONFIG_FLATMEM
 #include <asm/numnodes.h>
 #endif
 
diff -upN reference/init/main.c current/init/main.c
--- reference/init/main.c
+++ current/init/main.c
@@ -480,6 +480,7 @@ asmlinkage void __init start_kernel(void
 {
 	char * command_line;
 	extern struct kernel_param __start___param[], __stop___param[];
+
 /*
  * Interrupts are still disabled. Do necessary setups, then
  * enable them
diff -upN reference/mm/bootmem.c current/mm/bootmem.c
--- reference/mm/bootmem.c
+++ current/mm/bootmem.c
@@ -255,6 +255,7 @@ found:
 static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat)
 {
 	struct page *page;
+	unsigned long pfn;
 	bootmem_data_t *bdata = pgdat->bdata;
 	unsigned long i, count, total = 0;
 	unsigned long idx;
@@ -265,15 +266,26 @@ static unsigned long __init free_all_boo
 
 	count = 0;
 	/* first extant page of the node */
-	page = virt_to_page(phys_to_virt(bdata->node_boot_start));
+	pfn = bdata->node_boot_start >> PAGE_SHIFT;
 	idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT);
 	map = bdata->node_bootmem_map;
 	/* Check physaddr is O(LOG2(BITS_PER_LONG)) page aligned */
 	if (bdata->node_boot_start == 0 ||
 	    ffs(bdata->node_boot_start) - PAGE_SHIFT > ffs(BITS_PER_LONG))
 		gofast = 1;
+	page = pfn_to_page(pfn);
 	for (i = 0; i < idx; ) {
 		unsigned long v = ~map[i / BITS_PER_LONG];
+
+		/*
+		 * Makes use of the guarentee that *_mem_map will be
+		 * contigious in sections aligned at MAX_ORDER.
+		 * APW/XXX: we are making an assumption that our node_boot_start
+		 * is aligned to BITS_PER_LONG ... is this valid/enforced.
+		 */
+		if ((pfn & ((1 << MAX_ORDER) - 1)) == 0)
+			page = pfn_to_page(pfn);
+
 		if (gofast && v == ~0UL) {
 			int j;
 
@@ -302,6 +314,7 @@ static unsigned long __init free_all_boo
 			i+=BITS_PER_LONG;
 			page += BITS_PER_LONG;
 		}
+		pfn += BITS_PER_LONG;
 	}
 	total += count;
 
diff -upN reference/mm/Makefile current/mm/Makefile
--- reference/mm/Makefile
+++ current/mm/Makefile
@@ -15,6 +15,6 @@ obj-y			:= bootmem.o filemap.o mempool.o
 obj-$(CONFIG_SWAP)	+= page_io.o swap_state.o swapfile.o thrash.o
 obj-$(CONFIG_HUGETLBFS)	+= hugetlb.o
 obj-$(CONFIG_NUMA) 	+= mempolicy.o
+obj-$(CONFIG_NONLINEAR)       += nonlinear.o
 obj-$(CONFIG_SHMEM) += shmem.o
 obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
-
diff -upN reference/mm/memory.c current/mm/memory.c
--- reference/mm/memory.c
+++ current/mm/memory.c
@@ -56,7 +56,7 @@
 #include <linux/swapops.h>
 #include <linux/elf.h>
 
-#ifndef CONFIG_DISCONTIGMEM
+#ifdef CONFIG_FLATMEM
 /* use the per-pgdat data instead for discontigmem - mbligh */
 unsigned long max_mapnr;
 struct page *mem_map;
diff -upN /dev/null current/mm/nonlinear.c
--- /dev/null
+++ current/mm/nonlinear.c
@@ -0,0 +1,137 @@
+/*
+ * Non-linear memory mappings.
+ */
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+#include <asm/dma.h>
+
+/*
+ * Permenant non-linear data:
+ *
+ * 1) phys_section	- valid physical memory sections (in mem_section)
+ * 2) mem_section	- memory sections, mem_map's for valid memory
+ */
+#ifndef NONLINEAR_OPTIMISE
+short phys_section[NR_PHYS_SECTIONS] = { [ 0 ... NR_PHYS_SECTIONS-1] = -1 };
+EXPORT_SYMBOL(phys_section);
+#endif
+struct mem_section mem_section[NR_MEM_SECTIONS];
+EXPORT_SYMBOL(mem_section);
+
+
+/*
+ * Initialisation time data:
+ *
+ * 1) phys_section_nid  - physical section node id
+ * 2) phys_section_pfn  - physical section base page frame
+ */
+unsigned long phys_section_nid[NR_PHYS_SECTIONS] __initdata =
+	{ [ 0 ... NR_PHYS_SECTIONS-1] = -1 };
+static unsigned long phys_section_pfn[NR_PHYS_SECTIONS] __initdata;
+
+/* Record a non-linear memory area for a node. */
+int nonlinear_add(int nid, unsigned long start, unsigned long end)
+{
+	unsigned long pfn = start;
+
+printk(KERN_WARNING "APW: nonlinear_add: nid<%d> start<%08lx:%ld> end<%08lx:%ld>\n",
+		nid, start, start >> PFN_SECTION_SHIFT, end, end >> PFN_SECTION_SHIFT);
+	start &= PAGE_SECTION_MASK;
+	for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) {
+/*printk(KERN_WARNING "  APW: nonlinear_add: section<%d> pfn<%08lx>\n", 
+	pfn >> PFN_SECTION_SHIFT, pfn);*/
+		phys_section_nid[pfn >> PFN_SECTION_SHIFT] = nid;
+		phys_section_pfn[pfn >> PFN_SECTION_SHIFT] = pfn;
+	}
+
+	return 1;
+}
+
+/*
+ * Calculate the space required on a per node basis for the mmap.
+ */
+int nonlinear_calculate(int nid)
+{
+	int pnum;
+	int sections = 0;
+
+	for (pnum = 0; pnum < NR_PHYS_SECTIONS; pnum++) {
+		if (phys_section_nid[pnum] == nid)
+			sections++;
+	}
+
+	return (sections * PAGES_PER_SECTION * sizeof(struct page));
+}
+
+
+/* XXX/APW: NO! */
+void *alloc_remap(int nid, unsigned long size);
+
+/*
+ * Allocate the accumulated non-linear sections, allocate a mem_map
+ * for each and record the physical to section mapping.
+ */
+void nonlinear_allocate(void)
+{
+	int snum = 0;
+	int pnum;
+	struct page *map;
+
+	for (pnum = 0; pnum < NR_PHYS_SECTIONS; pnum++) {
+		if (phys_section_nid[pnum] == -1)
+			continue;
+
+		/* APW/XXX: this is a dumbo name for this feature, should
+		 * be something like alloc_really_really_early. */
+#ifdef HAVE_ARCH_ALLOC_REMAP
+		map = alloc_remap(phys_section_nid[pnum],
+				sizeof(struct page) * PAGES_PER_SECTION);
+#else
+		map = 0;
+#endif
+		if (!map)
+			map = alloc_bootmem_node(NODE_DATA(phys_section_nid[pnum]),
+				sizeof(struct page) * PAGES_PER_SECTION);
+		if (!map)
+			continue;
+
+		/*
+		 * Subtle, we encode the real pfn into the mem_map such that
+		 * the identity pfn - section_mem_map will return the actual
+		 * physical page frame number.
+		 */
+#ifdef NONLINEAR_OPTIMISE
+		snum = pnum;
+#else
+		phys_section[pnum] = snum;
+#endif
+		mem_section[snum].section_mem_map = map -
+			phys_section_pfn[pnum];
+
+if ((pnum % 32) == 0)
+printk(KERN_WARNING "APW: nonlinear_allocate: section<%d> map<%p> ms<%p> pfn<%08lx>\n", pnum, map, mem_section[snum].section_mem_map,  phys_section_pfn[pnum]);
+
+
+		snum++;
+	}
+
+#if 0
+#define X(x)	printk(KERN_WARNING "APW: " #x "<%08lx>\n", x)
+	X(FLAGS_SHIFT);
+	X(SECTIONS_SHIFT);
+	X(ZONES_SHIFT);
+	X(PGFLAGS_SECTIONS_SHIFT);
+	X(PGFLAGS_ZONES_SHIFT);
+	X(ZONETABLE_SHIFT);
+	X(PGFLAGS_ZONETABLE_SHIFT);
+	X(FLAGS_USED_SHIFT);
+	X(ZONES_MASK);
+	X(NODES_MASK);
+	X(SECTIONS_MASK);
+	X(ZONETABLE_MASK);
+	X(ZONETABLE_SIZE);
+	X(PGFLAGS_MASK);
+#endif
+}
diff -upN reference/mm/page_alloc.c current/mm/page_alloc.c
--- reference/mm/page_alloc.c
+++ current/mm/page_alloc.c
@@ -49,7 +49,7 @@ EXPORT_SYMBOL(nr_swap_pages);
  * Used by page_zone() to look up the address of the struct zone whose
  * id is encoded in the upper bits of page->flags
  */
-struct zone *zone_table[1 << (ZONES_SHIFT + NODES_SHIFT)];
+struct zone *zone_table[ZONETABLE_SIZE];
 EXPORT_SYMBOL(zone_table);
 
 static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" };
@@ -63,6 +63,7 @@ unsigned long __initdata nr_all_pages;
  */
 static int bad_range(struct zone *zone, struct page *page)
 {
+	/* printk(KERN_WARNING "bad_range: page<%p> pfn<%08lx> s<%08lx> e<%08lx> zone<%p><%p>\n", page, page_to_pfn(page), zone->zone_start_pfn,  zone->zone_start_pfn + zone->spanned_pages, zone, page_zone(page)); */
 	if (page_to_pfn(page) >= zone->zone_start_pfn + zone->spanned_pages)
 		return 1;
 	if (page_to_pfn(page) < zone->zone_start_pfn)
@@ -187,7 +188,11 @@ static inline void __free_pages_bulk (st
 	if (order)
 		destroy_compound_page(page, order);
 	mask = (~0UL) << order;
+#ifdef CONFIG_NONLINEAR
+	page_idx = page_to_pfn(page) - zone->zone_start_pfn;
+#else
 	page_idx = page - base;
+#endif
 	if (page_idx & ~mask)
 		BUG();
 	index = page_idx >> (1 + order);
@@ -204,8 +209,35 @@ static inline void __free_pages_bulk (st
 			break;
 
 		/* Move the buddy up one level. */
+#ifdef CONFIG_NONLINEAR
+		/*
+		 * Locate the struct page for both the matching buddy in our
+		 * pair (buddy1) and the combined O(n+1) page they form (page).
+		 * 
+		 * 1) Any buddy B1 will have an order O twin B2 which satisfies
+		 * the following equasion:
+		 *     B2 = B1 ^ (1 << O)
+		 * For example, if the starting buddy (buddy2) is #8 its order
+		 * 1 buddy is #10:
+		 *     B2 = 8 ^ (1 << 1) = 8 ^ 2 = 10
+		 *
+		 * 2) Any buddy B will have an order O+1 parent P which
+		 * satisfies the following equasion:
+		 *     P = B & ~(1 << O)
+		 *
+		 * Assumption: *_mem_map is contigious at least up to MAX_ORDER
+		 */
+		buddy1 = page + ((page_idx ^ (1 << order)) - page_idx);
+		buddy2 = page;
+
+		page = page - (page_idx - (page_idx & ~(1 << order)));
+
+		if (bad_range(zone, buddy1))
+		printk(KERN_WARNING "__free_pages_bulk: buddy1<%p> buddy2<%p> page<%p> page_idx<%ld> off<%ld>\n", buddy1, buddy2, page, page_idx, (page_idx - (page_idx & ~(1 << order)))); 
+#else
 		buddy1 = base + (page_idx ^ (1 << order));
 		buddy2 = base + page_idx;
+#endif
 		BUG_ON(bad_range(zone, buddy1));
 		BUG_ON(bad_range(zone, buddy2));
 		list_del(&buddy1->lru);
@@ -215,7 +247,11 @@ static inline void __free_pages_bulk (st
 		index >>= 1;
 		page_idx &= mask;
 	}
+#ifdef CONFIG_NONLINEAR
+	list_add(&page->lru, &area->free_list);
+#else
 	list_add(&(base + page_idx)->lru, &area->free_list);
+#endif
 }
 
 static inline void free_pages_check(const char *function, struct page *page)
@@ -380,7 +416,11 @@ static struct page *__rmqueue(struct zon
 
 		page = list_entry(area->free_list.next, struct page, lru);
 		list_del(&page->lru);
+#ifdef CONFIG_NONLINEAR
+		index = page_to_pfn(page) - zone->zone_start_pfn;
+#else
 		index = page - zone->zone_mem_map;
+#endif
 		if (current_order != MAX_ORDER-1)
 			MARK_USED(index, current_order, area);
 		zone->free_pages -= 1UL << order;
@@ -1401,9 +1441,39 @@ void __init memmap_init_zone(unsigned lo
 {
 	struct page *start = pfn_to_page(start_pfn);
 	struct page *page;
+	struct zone *zonep = &NODE_DATA(nid)->node_zones[zone];
+#ifdef CONFIG_NONLINEAR
+	int pfn;
+#endif
+
+	/* APW/XXX: this is the place to both allocate the memory for the
+	 * section; scan the range offered relative to the zone and
+	 * instantiate the page's.
+	 */
+	printk(KERN_WARNING "APW: zone<%p> start<%08lx> pgdat<%p>\n",
+			zonep, start_pfn, zonep->zone_pgdat);
 
+#ifdef CONFIG_NONLINEAR
+	for (pfn = start_pfn; pfn < (start_pfn + size); pfn++) {
+		if (!pfn_valid(pfn))
+			continue;
+		page = pfn_to_page(pfn);
+
+		/*
+		 * Record the CHUNKZONE for this page and the install the
+		 * zone_table link for it also.
+		 */
+		set_page_node(page, nid);
+		set_page_zone(page, zone);
+		set_page_section(page, pfn >> PFN_SECTION_SHIFT);
+		zone_table[ZONETABLE(pfn >> PFN_SECTION_SHIFT, nid, zone)] =
+			zonep;
+#else
 	for (page = start; page < (start + size); page++) {
-		set_page_zone(page, NODEZONE(nid, zone));
+		set_page_node(page, nid);
+		set_page_zone(page, zone);
+#endif
+
 		set_page_count(page, 0);
 		reset_page_mapcount(page);
 		SetPageReserved(page);
@@ -1413,8 +1483,15 @@ void __init memmap_init_zone(unsigned lo
 		if (!is_highmem_idx(zone))
 			set_page_address(page, __va(start_pfn << PAGE_SHIFT));
 #endif
+		
+#ifdef CONFIG_NONLINEAR
+	}
+#else
 		start_pfn++;
 	}
+#endif
+	printk(KERN_WARNING "APW: zone<%p> start<%08lx> pgdat<%p>\n",
+			zonep, start_pfn, zonep->zone_pgdat);
 }
 
 /*
@@ -1509,7 +1586,9 @@ static void __init free_area_init_core(s
 		unsigned long size, realsize;
 		unsigned long batch;
 
+#ifndef CONFIG_NONLINEAR
 		zone_table[NODEZONE(nid, j)] = zone;
+#endif
 		realsize = size = zones_size[j];
 		if (zholes_size)
 			realsize -= zholes_size[j];
@@ -1613,7 +1692,7 @@ void __init node_alloc_mem_map(struct pg
 #endif
 		map = alloc_bootmem_node(pgdat, size);
 	pgdat->node_mem_map = map;
-#ifndef CONFIG_DISCONTIGMEM
+#ifdef CONFIG_FLATMEM
 	mem_map = contig_page_data.node_mem_map;
 #endif
 }
@@ -1632,7 +1711,7 @@ void __init free_area_init_node(int nid,
 	free_area_init_core(pgdat, zones_size, zholes_size);
 }
 
-#ifndef CONFIG_DISCONTIGMEM
+#ifdef CONFIG_FLATMEM
 static bootmem_data_t contig_bootmem_data;
 struct pglist_data contig_page_data = { .bdata = &contig_bootmem_data };
 
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"aart@kvack.org"> aart@kvack.org </a>

  parent reply	other threads:[~2004-10-18 14:35 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-10-18 14:24 CONFIG_NONLINEAR for small systems Andy Whitcroft
2004-10-18 14:32 ` 050 bootmem use NODE_DATA Andy Whitcroft
2004-10-26 18:16   ` Dave Hansen
2004-10-18 14:33 ` 060 refactor setup_memory i386 Andy Whitcroft
2004-10-18 14:34 ` 080 alloc_remap i386 Andy Whitcroft
2004-10-18 14:35 ` 100 cleanup node zone Andy Whitcroft
2004-10-18 14:35 ` Andy Whitcroft [this message]
2004-10-26 18:36   ` 150 nonlinear Dave Hansen
2004-10-26 19:07     ` [Lhms-devel] " Mika Penttilä
2004-10-26 19:42       ` Dave Hansen
2004-10-26 20:41         ` Mika Penttilä
2004-10-26 20:55           ` Dave Hansen
2004-10-26 21:20             ` Mika Penttilä
2004-10-26 21:27               ` Dave Hansen
2004-10-26 21:38                 ` Mika Penttilä
2004-10-26 21:41                   ` Dave Hansen
2004-10-26 21:55                     ` Mika Penttilä
2004-10-26 21:53                       ` Dave Hansen
2004-10-26 22:01                         ` Mika Penttilä
2004-10-28 11:07     ` Andy Whitcroft
2004-10-18 14:36 ` 160 nonlinear i386 Andy Whitcroft
2004-10-18 14:36 ` 170 nonlinear ppc64 Andy Whitcroft
2004-10-18 15:17 ` [Lhms-devel] CONFIG_NONLINEAR for small systems Hirokazu Takahashi
2004-10-18 15:29   ` Andy Whitcroft
2004-10-19  4:30 ` Hiroyuki KAMEZAWA
2004-10-19  8:16   ` Andy Whitcroft

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=E1CJYc0-0000aK-A8@ladymac.shadowen.org \
    --to=apw@shadowen.org \
    --cc=lhms-devel@lists.sourceforge.net \
    --cc=linux-mm@kvack.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox