[PATCH] SPARSEMEM EXTREME
[linux-2.6.git] / mm / sparse.c
1 /*
2  * sparse memory mappings.
3  */
4 #include <linux/config.h>
5 #include <linux/mm.h>
6 #include <linux/mmzone.h>
7 #include <linux/bootmem.h>
8 #include <linux/module.h>
9 #include <asm/dma.h>
10
11 /*
12  * Permanent SPARSEMEM data:
13  *
14  * 1) mem_section       - memory sections, mem_map's for valid memory
15  */
16 #ifdef CONFIG_ARCH_SPARSEMEM_EXTREME
17 struct mem_section *mem_section[NR_SECTION_ROOTS]
18         ____cacheline_maxaligned_in_smp;
19
20 static void sparse_index_init(unsigned long section, int nid)
21 {
22         unsigned long root = SECTION_TO_ROOT(section);
23
24         if (mem_section[root])
25                 return;
26         mem_section[root] = alloc_bootmem_node(NODE_DATA(nid), PAGE_SIZE);
27         if (mem_section[root])
28                 memset(mem_section[root], 0, PAGE_SIZE);
29         else
30                 panic("memory_present: NO MEMORY\n");
31 }
32 #else
33 struct mem_section mem_section[NR_MEM_SECTIONS]
34         ____cacheline_maxaligned_in_smp;
35 #endif
36 EXPORT_SYMBOL(mem_section);
37
38 /* Record a memory area against a node. */
39 void memory_present(int nid, unsigned long start, unsigned long end)
40 {
41         unsigned long pfn;
42
43         start &= PAGE_SECTION_MASK;
44         for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) {
45                 unsigned long section = pfn_to_section_nr(pfn);
46                 struct mem_section *ms;
47
48                 sparse_index_init(section, nid);
49
50                 ms = __nr_to_section(section);
51                 if (!ms->section_mem_map)
52                         ms->section_mem_map = SECTION_MARKED_PRESENT;
53         }
54 }
55
56 /*
57  * Only used by the i386 NUMA architecures, but relatively
58  * generic code.
59  */
60 unsigned long __init node_memmap_size_bytes(int nid, unsigned long start_pfn,
61                                                      unsigned long end_pfn)
62 {
63         unsigned long pfn;
64         unsigned long nr_pages = 0;
65
66         for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
67                 if (nid != early_pfn_to_nid(pfn))
68                         continue;
69
70                 if (pfn_valid(pfn))
71                         nr_pages += PAGES_PER_SECTION;
72         }
73
74         return nr_pages * sizeof(struct page);
75 }
76
77 /*
78  * Subtle, we encode the real pfn into the mem_map such that
79  * the identity pfn - section_mem_map will return the actual
80  * physical page frame number.
81  */
82 static unsigned long sparse_encode_mem_map(struct page *mem_map, unsigned long pnum)
83 {
84         return (unsigned long)(mem_map - (section_nr_to_pfn(pnum)));
85 }
86
87 /*
88  * We need this if we ever free the mem_maps.  While not implemented yet,
89  * this function is included for parity with its sibling.
90  */
91 static __attribute((unused))
92 struct page *sparse_decode_mem_map(unsigned long coded_mem_map, unsigned long pnum)
93 {
94         return ((struct page *)coded_mem_map) + section_nr_to_pfn(pnum);
95 }
96
97 static int sparse_init_one_section(struct mem_section *ms,
98                 unsigned long pnum, struct page *mem_map)
99 {
100         if (!valid_section(ms))
101                 return -EINVAL;
102
103         ms->section_mem_map |= sparse_encode_mem_map(mem_map, pnum);
104
105         return 1;
106 }
107
108 static struct page *sparse_early_mem_map_alloc(unsigned long pnum)
109 {
110         struct page *map;
111         int nid = early_pfn_to_nid(section_nr_to_pfn(pnum));
112         struct mem_section *ms = __nr_to_section(pnum);
113
114         map = alloc_remap(nid, sizeof(struct page) * PAGES_PER_SECTION);
115         if (map)
116                 return map;
117
118         map = alloc_bootmem_node(NODE_DATA(nid),
119                         sizeof(struct page) * PAGES_PER_SECTION);
120         if (map)
121                 return map;
122
123         printk(KERN_WARNING "%s: allocation failed\n", __FUNCTION__);
124         ms->section_mem_map = 0;
125         return NULL;
126 }
127
128 /*
129  * Allocate the accumulated non-linear sections, allocate a mem_map
130  * for each and record the physical to section mapping.
131  */
132 void sparse_init(void)
133 {
134         unsigned long pnum;
135         struct page *map;
136
137         for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) {
138                 if (!valid_section_nr(pnum))
139                         continue;
140
141                 map = sparse_early_mem_map_alloc(pnum);
142                 if (!map)
143                         continue;
144                 sparse_init_one_section(__nr_to_section(pnum), pnum, map);
145         }
146 }
147
148 /*
149  * returns the number of sections whose mem_maps were properly
150  * set.  If this is <=0, then that means that the passed-in
151  * map was not consumed and must be freed.
152  */
153 int sparse_add_one_section(unsigned long start_pfn, int nr_pages, struct page *map)
154 {
155         struct mem_section *ms = __pfn_to_section(start_pfn);
156
157         if (ms->section_mem_map & SECTION_MARKED_PRESENT)
158                 return -EEXIST;
159
160         ms->section_mem_map |= SECTION_MARKED_PRESENT;
161
162         return sparse_init_one_section(ms, pfn_to_section_nr(start_pfn), map);
163 }