diff options
-rw-r--r-- | mm/bootmem.c | 82 |
1 files changed, 45 insertions, 37 deletions
diff --git a/mm/bootmem.c b/mm/bootmem.c index e136c086fd98..23c3317c09ed 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c | |||
@@ -9,6 +9,7 @@ | |||
9 | * system memory and memory holes as well. | 9 | * system memory and memory holes as well. |
10 | */ | 10 | */ |
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/pfn.h> | ||
12 | #include <linux/bootmem.h> | 13 | #include <linux/bootmem.h> |
13 | #include <linux/module.h> | 14 | #include <linux/module.h> |
14 | 15 | ||
@@ -68,6 +69,18 @@ static void __init link_bootmem(bootmem_data_t *bdata) | |||
68 | return; | 69 | return; |
69 | } | 70 | } |
70 | 71 | ||
72 | /* | ||
73 | * Given an initialised bdata, it returns the size of the boot bitmap | ||
74 | */ | ||
75 | static unsigned long __init get_mapsize(bootmem_data_t *bdata) | ||
76 | { | ||
77 | unsigned long mapsize; | ||
78 | unsigned long start = PFN_DOWN(bdata->node_boot_start); | ||
79 | unsigned long end = bdata->node_low_pfn; | ||
80 | |||
81 | mapsize = ((end - start) + 7) / 8; | ||
82 | return ALIGN(mapsize, sizeof(long)); | ||
83 | } | ||
71 | 84 | ||
72 | /* | 85 | /* |
73 | * Called once to set up the allocator itself. | 86 | * Called once to set up the allocator itself. |
@@ -76,11 +89,10 @@ static unsigned long __init init_bootmem_core (pg_data_t *pgdat, | |||
76 | unsigned long mapstart, unsigned long start, unsigned long end) | 89 | unsigned long mapstart, unsigned long start, unsigned long end) |
77 | { | 90 | { |
78 | bootmem_data_t *bdata = pgdat->bdata; | 91 | bootmem_data_t *bdata = pgdat->bdata; |
79 | unsigned long mapsize = ((end - start)+7)/8; | 92 | unsigned long mapsize; |
80 | 93 | ||
81 | mapsize = ALIGN(mapsize, sizeof(long)); | 94 | bdata->node_bootmem_map = phys_to_virt(PFN_PHYS(mapstart)); |
82 | bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT); | 95 | bdata->node_boot_start = PFN_PHYS(start); |
83 | bdata->node_boot_start = (start << PAGE_SHIFT); | ||
84 | bdata->node_low_pfn = end; | 96 | bdata->node_low_pfn = end; |
85 | link_bootmem(bdata); | 97 | link_bootmem(bdata); |
86 | 98 | ||
@@ -88,6 +100,7 @@ static unsigned long __init init_bootmem_core (pg_data_t *pgdat, | |||
88 | * Initially all pages are reserved - setup_arch() has to | 100 | * Initially all pages are reserved - setup_arch() has to |
89 | * register free RAM areas explicitly. | 101 | * register free RAM areas explicitly. |
90 | */ | 102 | */ |
103 | mapsize = get_mapsize(bdata); | ||
91 | memset(bdata->node_bootmem_map, 0xff, mapsize); | 104 | memset(bdata->node_bootmem_map, 0xff, mapsize); |
92 | 105 | ||
93 | return mapsize; | 106 | return mapsize; |
@@ -101,20 +114,19 @@ static unsigned long __init init_bootmem_core (pg_data_t *pgdat, | |||
101 | static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long addr, | 114 | static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long addr, |
102 | unsigned long size) | 115 | unsigned long size) |
103 | { | 116 | { |
117 | unsigned long sidx, eidx; | ||
104 | unsigned long i; | 118 | unsigned long i; |
119 | |||
105 | /* | 120 | /* |
106 | * round up, partially reserved pages are considered | 121 | * round up, partially reserved pages are considered |
107 | * fully reserved. | 122 | * fully reserved. |
108 | */ | 123 | */ |
109 | unsigned long sidx = (addr - bdata->node_boot_start)/PAGE_SIZE; | ||
110 | unsigned long eidx = (addr + size - bdata->node_boot_start + | ||
111 | PAGE_SIZE-1)/PAGE_SIZE; | ||
112 | unsigned long end = (addr + size + PAGE_SIZE-1)/PAGE_SIZE; | ||
113 | |||
114 | BUG_ON(!size); | 124 | BUG_ON(!size); |
115 | BUG_ON(sidx >= eidx); | 125 | BUG_ON(PFN_DOWN(addr) >= bdata->node_low_pfn); |
116 | BUG_ON((addr >> PAGE_SHIFT) >= bdata->node_low_pfn); | 126 | BUG_ON(PFN_UP(addr + size) > bdata->node_low_pfn); |
117 | BUG_ON(end > bdata->node_low_pfn); | 127 | |
128 | sidx = PFN_DOWN(addr - bdata->node_boot_start); | ||
129 | eidx = PFN_UP(addr + size - bdata->node_boot_start); | ||
118 | 130 | ||
119 | for (i = sidx; i < eidx; i++) | 131 | for (i = sidx; i < eidx; i++) |
120 | if (test_and_set_bit(i, bdata->node_bootmem_map)) { | 132 | if (test_and_set_bit(i, bdata->node_bootmem_map)) { |
@@ -127,18 +139,15 @@ static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long add | |||
127 | static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, | 139 | static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, |
128 | unsigned long size) | 140 | unsigned long size) |
129 | { | 141 | { |
142 | unsigned long sidx, eidx; | ||
130 | unsigned long i; | 143 | unsigned long i; |
131 | unsigned long start; | 144 | |
132 | /* | 145 | /* |
133 | * round down end of usable mem, partially free pages are | 146 | * round down end of usable mem, partially free pages are |
134 | * considered reserved. | 147 | * considered reserved. |
135 | */ | 148 | */ |
136 | unsigned long sidx; | ||
137 | unsigned long eidx = (addr + size - bdata->node_boot_start)/PAGE_SIZE; | ||
138 | unsigned long end = (addr + size)/PAGE_SIZE; | ||
139 | |||
140 | BUG_ON(!size); | 149 | BUG_ON(!size); |
141 | BUG_ON(end > bdata->node_low_pfn); | 150 | BUG_ON(PFN_DOWN(addr + size) > bdata->node_low_pfn); |
142 | 151 | ||
143 | if (addr < bdata->last_success) | 152 | if (addr < bdata->last_success) |
144 | bdata->last_success = addr; | 153 | bdata->last_success = addr; |
@@ -146,8 +155,8 @@ static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, | |||
146 | /* | 155 | /* |
147 | * Round up the beginning of the address. | 156 | * Round up the beginning of the address. |
148 | */ | 157 | */ |
149 | start = (addr + PAGE_SIZE-1) / PAGE_SIZE; | 158 | sidx = PFN_UP(addr) - PFN_DOWN(bdata->node_boot_start); |
150 | sidx = start - (bdata->node_boot_start/PAGE_SIZE); | 159 | eidx = PFN_DOWN(addr + size - bdata->node_boot_start); |
151 | 160 | ||
152 | for (i = sidx; i < eidx; i++) { | 161 | for (i = sidx; i < eidx; i++) { |
153 | if (unlikely(!test_and_clear_bit(i, bdata->node_bootmem_map))) | 162 | if (unlikely(!test_and_clear_bit(i, bdata->node_bootmem_map))) |
@@ -173,7 +182,7 @@ __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size, | |||
173 | unsigned long align, unsigned long goal, unsigned long limit) | 182 | unsigned long align, unsigned long goal, unsigned long limit) |
174 | { | 183 | { |
175 | unsigned long offset, remaining_size, areasize, preferred; | 184 | unsigned long offset, remaining_size, areasize, preferred; |
176 | unsigned long i, start = 0, incr, eidx, end_pfn = bdata->node_low_pfn; | 185 | unsigned long i, start = 0, incr, eidx, end_pfn; |
177 | void *ret; | 186 | void *ret; |
178 | 187 | ||
179 | if(!size) { | 188 | if(!size) { |
@@ -185,23 +194,22 @@ __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size, | |||
185 | if (limit && bdata->node_boot_start >= limit) | 194 | if (limit && bdata->node_boot_start >= limit) |
186 | return NULL; | 195 | return NULL; |
187 | 196 | ||
188 | limit >>=PAGE_SHIFT; | 197 | end_pfn = bdata->node_low_pfn; |
198 | limit = PFN_DOWN(limit); | ||
189 | if (limit && end_pfn > limit) | 199 | if (limit && end_pfn > limit) |
190 | end_pfn = limit; | 200 | end_pfn = limit; |
191 | 201 | ||
192 | eidx = end_pfn - (bdata->node_boot_start >> PAGE_SHIFT); | 202 | eidx = end_pfn - PFN_DOWN(bdata->node_boot_start); |
193 | offset = 0; | 203 | offset = 0; |
194 | if (align && | 204 | if (align && (bdata->node_boot_start & (align - 1UL)) != 0) |
195 | (bdata->node_boot_start & (align - 1UL)) != 0) | 205 | offset = align - (bdata->node_boot_start & (align - 1UL)); |
196 | offset = (align - (bdata->node_boot_start & (align - 1UL))); | 206 | offset = PFN_DOWN(offset); |
197 | offset >>= PAGE_SHIFT; | ||
198 | 207 | ||
199 | /* | 208 | /* |
200 | * We try to allocate bootmem pages above 'goal' | 209 | * We try to allocate bootmem pages above 'goal' |
201 | * first, then we try to allocate lower pages. | 210 | * first, then we try to allocate lower pages. |
202 | */ | 211 | */ |
203 | if (goal && (goal >= bdata->node_boot_start) && | 212 | if (goal && goal >= bdata->node_boot_start && PFN_DOWN(goal) < end_pfn) { |
204 | ((goal >> PAGE_SHIFT) < end_pfn)) { | ||
205 | preferred = goal - bdata->node_boot_start; | 213 | preferred = goal - bdata->node_boot_start; |
206 | 214 | ||
207 | if (bdata->last_success >= preferred) | 215 | if (bdata->last_success >= preferred) |
@@ -210,9 +218,8 @@ __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size, | |||
210 | } else | 218 | } else |
211 | preferred = 0; | 219 | preferred = 0; |
212 | 220 | ||
213 | preferred = ALIGN(preferred, align) >> PAGE_SHIFT; | 221 | preferred = PFN_DOWN(ALIGN(preferred, align)) + offset; |
214 | preferred += offset; | 222 | areasize = (size + PAGE_SIZE-1) / PAGE_SIZE; |
215 | areasize = (size+PAGE_SIZE-1)/PAGE_SIZE; | ||
216 | incr = align >> PAGE_SHIFT ? : 1; | 223 | incr = align >> PAGE_SHIFT ? : 1; |
217 | 224 | ||
218 | restart_scan: | 225 | restart_scan: |
@@ -243,7 +250,7 @@ restart_scan: | |||
243 | return NULL; | 250 | return NULL; |
244 | 251 | ||
245 | found: | 252 | found: |
246 | bdata->last_success = start << PAGE_SHIFT; | 253 | bdata->last_success = PFN_PHYS(start); |
247 | BUG_ON(start >= eidx); | 254 | BUG_ON(start >= eidx); |
248 | 255 | ||
249 | /* | 256 | /* |
@@ -301,8 +308,8 @@ static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat) | |||
301 | 308 | ||
302 | count = 0; | 309 | count = 0; |
303 | /* first extant page of the node */ | 310 | /* first extant page of the node */ |
304 | pfn = bdata->node_boot_start >> PAGE_SHIFT; | 311 | pfn = PFN_DOWN(bdata->node_boot_start); |
305 | idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT); | 312 | idx = bdata->node_low_pfn - pfn; |
306 | map = bdata->node_bootmem_map; | 313 | map = bdata->node_bootmem_map; |
307 | /* Check physaddr is O(LOG2(BITS_PER_LONG)) page aligned */ | 314 | /* Check physaddr is O(LOG2(BITS_PER_LONG)) page aligned */ |
308 | if (bdata->node_boot_start == 0 || | 315 | if (bdata->node_boot_start == 0 || |
@@ -343,9 +350,10 @@ static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat) | |||
343 | */ | 350 | */ |
344 | page = virt_to_page(bdata->node_bootmem_map); | 351 | page = virt_to_page(bdata->node_bootmem_map); |
345 | count = 0; | 352 | count = 0; |
346 | for (i = 0; i < ((bdata->node_low_pfn-(bdata->node_boot_start >> PAGE_SHIFT))/8 + PAGE_SIZE-1)/PAGE_SIZE; i++,page++) { | 353 | idx = (get_mapsize(bdata) + PAGE_SIZE-1) >> PAGE_SHIFT; |
347 | count++; | 354 | for (i = 0; i < idx; i++, page++) { |
348 | __free_pages_bootmem(page, 0); | 355 | __free_pages_bootmem(page, 0); |
356 | count++; | ||
349 | } | 357 | } |
350 | total += count; | 358 | total += count; |
351 | bdata->node_bootmem_map = NULL; | 359 | bdata->node_bootmem_map = NULL; |