00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <linux/config.h>
00019 #include <linux/mm.h>
00020 #include <linux/kernel_stat.h>
00021 #include <linux/swap.h>
00022 #include <linux/swapctl.h>
00023 #include <linux/interrupt.h>
00024 #include <linux/init.h>
00025 #include <linux/bootmem.h>
00026 #include <linux/mmzone.h>
00027 #include <asm/dma.h>
00028
00029 #include <system_data_cells.h>
00030
00031 #undef OLDINT
00032 #define OLDINT
00033
00034 #ifdef __x86_64__
00035 #undef OLDINT
00036 #endif
00037
00038
00039
00040
00041
00042 unsigned long max_low_pfn;
00043 unsigned long min_low_pfn;
00044
00045
00046 unsigned long __init bootmem_bootmap_pages (unsigned long pages)
00047 {
00048 unsigned long mapsize;
00049
00050 mapsize = (pages+7)/8;
00051 mapsize = (mapsize + ~PAGE_MASK) & PAGE_MASK;
00052 mapsize >>= PAGE_SHIFT;
00053
00054 return mapsize;
00055 }
00056
00057
00058
00059
00060 static unsigned long __init init_bootmem_core (pg_data_t *pgdat,
00061 unsigned long mapstart, unsigned long start, unsigned long end)
00062 {
00063 bootmem_data_t *bdata = pgdat->bdata;
00064 unsigned long mapsize = ((end - start)+7)/8;
00065
00066 pgdat->node_next = pgdat_list;
00067 pgdat_list = pgdat;
00068
00069 mapsize = (mapsize + (sizeof(long) - 1UL)) & ~(sizeof(long) - 1UL);
00070 bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT);
00071 bdata->node_boot_start = (start << PAGE_SHIFT);
00072 bdata->node_low_pfn = end;
00073
00074
00075
00076
00077
00078 memset(bdata->node_bootmem_map, 0xff, mapsize);
00079
00080 return mapsize;
00081 }
00082
00083
00084
00085
00086
00087
00088 static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size)
00089 {
00090 unsigned long i;
00091
00092
00093
00094
00095 unsigned long sidx = (addr - bdata->node_boot_start)/PAGE_SIZE;
00096 unsigned long eidx = (addr + size - bdata->node_boot_start +
00097 PAGE_SIZE-1)/PAGE_SIZE;
00098 unsigned long end = (addr + size + PAGE_SIZE-1)/PAGE_SIZE;
00099
00100 if (!size) BUG();
00101
00102 if (sidx < 0)
00103 BUG();
00104 if (eidx < 0)
00105 BUG();
00106 if (sidx >= eidx)
00107 BUG();
00108 if ((addr >> PAGE_SHIFT) >= bdata->node_low_pfn)
00109 BUG();
00110 if (end > bdata->node_low_pfn)
00111 BUG();
00112 for (i = sidx; i < eidx; i++)
00113 if (test_and_set_bit(i, bdata->node_bootmem_map))
00114 printk("hm, page %08lx reserved twice.\n", i*PAGE_SIZE);
00115 }
00116
00117 static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size)
00118 {
00119 unsigned long i;
00120 unsigned long start;
00121
00122
00123
00124
00125 unsigned long sidx;
00126 unsigned long eidx = (addr + size - bdata->node_boot_start)/PAGE_SIZE;
00127 unsigned long end = (addr + size)/PAGE_SIZE;
00128
00129 if (!size) BUG();
00130 if (end > bdata->node_low_pfn)
00131 BUG();
00132
00133
00134
00135
00136 start = (addr + PAGE_SIZE-1) / PAGE_SIZE;
00137 sidx = start - (bdata->node_boot_start/PAGE_SIZE);
00138
00139 for (i = sidx; i < eidx; i++) {
00140 if (!test_and_clear_bit(i, bdata->node_bootmem_map))
00141 BUG();
00142 }
00143 }
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158 static void * __init __alloc_bootmem_core (bootmem_data_t *bdata,
00159 unsigned long size, unsigned long align, unsigned long goal)
00160 {
00161 unsigned long i, start = 0;
00162 void *ret;
00163 unsigned long offset, remaining_size;
00164 unsigned long areasize, preferred, incr;
00165 unsigned long eidx = bdata->node_low_pfn - (bdata->node_boot_start >>
00166 PAGE_SHIFT);
00167
00168 if (!size) BUG();
00169
00170 if (align & (align-1))
00171 BUG();
00172
00173 offset = 0;
00174 if (align &&
00175 (bdata->node_boot_start & (align - 1UL)) != 0)
00176 offset = (align - (bdata->node_boot_start & (align - 1UL)));
00177 offset >>= PAGE_SHIFT;
00178
00179
00180
00181
00182
00183 if (goal && (goal >= bdata->node_boot_start) &&
00184 ((goal >> PAGE_SHIFT) < bdata->node_low_pfn)) {
00185 preferred = goal - bdata->node_boot_start;
00186 } else
00187 preferred = 0;
00188
00189 preferred = ((preferred + align - 1) & ~(align - 1)) >> PAGE_SHIFT;
00190 preferred += offset;
00191 areasize = (size+PAGE_SIZE-1)/PAGE_SIZE;
00192 incr = align >> PAGE_SHIFT ? : 1;
00193
00194 restart_scan:
00195 for (i = preferred; i < eidx; i += incr) {
00196 unsigned long j;
00197 if (test_bit(i, bdata->node_bootmem_map))
00198 continue;
00199 for (j = i + 1; j < i + areasize; ++j) {
00200 if (j >= eidx)
00201 goto fail_block;
00202 if (test_bit (j, bdata->node_bootmem_map))
00203 goto fail_block;
00204 }
00205 start = i;
00206 goto found;
00207 fail_block:;
00208 }
00209 if (preferred) {
00210 preferred = offset;
00211 goto restart_scan;
00212 }
00213 return NULL;
00214 found:
00215 if (start >= eidx)
00216 BUG();
00217
00218
00219
00220
00221
00222
00223 if (align <= PAGE_SIZE
00224 && bdata->last_offset && bdata->last_pos+1 == start) {
00225 offset = (bdata->last_offset+align-1) & ~(align-1);
00226 if (offset > PAGE_SIZE)
00227 BUG();
00228 remaining_size = PAGE_SIZE-offset;
00229 if (size < remaining_size) {
00230 areasize = 0;
00231
00232 bdata->last_offset = offset+size;
00233 ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset +
00234 bdata->node_boot_start);
00235 } else {
00236 remaining_size = size - remaining_size;
00237 areasize = (remaining_size+PAGE_SIZE-1)/PAGE_SIZE;
00238 ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset +
00239 bdata->node_boot_start);
00240 bdata->last_pos = start+areasize-1;
00241 bdata->last_offset = remaining_size;
00242 }
00243 bdata->last_offset &= ~PAGE_MASK;
00244 } else {
00245 bdata->last_pos = start + areasize - 1;
00246 bdata->last_offset = size & ~PAGE_MASK;
00247 ret = phys_to_virt(start * PAGE_SIZE + bdata->node_boot_start);
00248 }
00249
00250
00251
00252 for (i = start; i < start+areasize; i++)
00253 if (test_and_set_bit(i, bdata->node_bootmem_map))
00254 BUG();
00255 memset(ret, 0, size);
00256 printk("alloc_bootmem_core %x %x\n",ret,size);
00257 return ret;
00258 }
00259
00260 int in_free_all_bootmem_core=0;
00261
00262 static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat)
00263 {
00264 struct page *page = pgdat->node_mem_map;
00265 bootmem_data_t *bdata = pgdat->bdata;
00266 unsigned long i, count, total = 0;
00267 unsigned long idx;
00268 struct page * prev;
00269
00270 in_free_all_bootmem_core=1;
00271
00272 if (!bdata->node_bootmem_map) BUG();
00273
00274 count = 0;
00275 idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT);
00276 for (i = 0; i < idx; i++, page++) {
00277 if (!test_bit(i, bdata->node_bootmem_map)) {
00278 count++;
00279 ClearPageReserved(page);
00280 set_page_count(page, 1);
00281 __free_page(page);
00282 }
00283 }
00284 total += count;
00285
00286
00287
00288
00289
00290 page = virt_to_page(bdata->node_bootmem_map);
00291 count = 0;
00292 for (i = 0; i < ((bdata->node_low_pfn-(bdata->node_boot_start >> PAGE_SHIFT))/8 + PAGE_SIZE-1)/PAGE_SIZE; i++,page++) {
00293 count++;
00294 ClearPageReserved(page);
00295 set_page_count(page, 1);
00296 __free_page(page);
00297 }
00298 total += count;
00299 bdata->node_bootmem_map = NULL;
00300
00301 prev = 0;
00302 #ifndef OLDINT
00303 int previ = 0;
00304 #endif
00305 page = pgdat->node_mem_map;
00306 page++;
00307 for (i = 1; i < idx; i++, page++) {
00308 if (!PageReserved(page)) {
00309 sch_gl_freecnt++;
00310 if (prev) {
00311 #ifdef OLDINT
00312 prev->pfn_l_flink=page;
00313 #else
00314 prev->pfn_l_flink=i;
00315 #endif
00316 } else {
00317 #ifdef OLDINT
00318 pfn_al_head[PFN$C_FREPAGLST]=page;
00319 #else
00320 pfn_al_head[PFN$C_FREPAGLST]=i;
00321 #endif
00322 }
00323 {
00324 #ifdef OLDINT
00325 unsigned long * prev2=&page->pfn_l_flink;
00326 #else
00327 unsigned int * prev2=&page->pfn_l_flink;
00328 #endif
00329 prev2++;
00330 #ifdef OLDINT
00331 *prev2=prev;
00332 #else
00333 *prev2=previ;
00334 #endif
00335
00336
00337
00338 }
00339 #ifdef OLDINT
00340 prev=page;
00341 #else
00342 prev=page;
00343 previ=i;
00344 #endif
00345 page->pfn_v_loc=PFN$C_FREPAGLST;
00346 page->pfn_v_pagtyp=PFN$C_SYSTEM;
00347 }
00348 }
00349 prev->pfn_l_flink=0;
00350 #ifdef OLDINT
00351 pfn_al_tail[PFN$C_FREPAGLST]=prev;
00352 #else
00353 pfn_al_tail[PFN$C_FREPAGLST]=i;
00354 #endif
00355 if (0) {
00356 int k,l,m[24];
00357 l=pfn_al_head[0];
00358 for(k=0;k<24;k++) {
00359 printk("%lx ",l);
00360 m[k]=mem_map[l].pfn_l_blink;
00361 l=mem_map[l].pfn_l_flink;
00362 }
00363 printk("\n");
00364 l=pfn_al_head[0];
00365 for(k=0;k<24;k++) {
00366 printk("%lx ",m[k]);
00367 }
00368 printk("\n");
00369 }
00370
00371 pfn_al_head[PFN$C_MFYPAGLST]=0;
00372 pfn_al_tail[PFN$C_MFYPAGLST]=0;
00373 pfn_al_head[PFN$C_BADPAGLST]=0;
00374 pfn_al_tail[PFN$C_BADPAGLST]=0;
00375
00376 in_free_all_bootmem_core=0;
00377
00378 return total;
00379 }
00380
00381 unsigned long __init init_bootmem_node (pg_data_t *pgdat, unsigned long freepfn, unsigned long startpfn, unsigned long endpfn)
00382 {
00383 return(init_bootmem_core(pgdat, freepfn, startpfn, endpfn));
00384 }
00385
00386 void __init reserve_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size)
00387 {
00388 reserve_bootmem_core(pgdat->bdata, physaddr, size);
00389 }
00390
00391 void __init free_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size)
00392 {
00393 return(free_bootmem_core(pgdat->bdata, physaddr, size));
00394 }
00395
00396 unsigned long __init free_all_bootmem_node (pg_data_t *pgdat)
00397 {
00398 return(free_all_bootmem_core(pgdat));
00399 }
00400
00401 unsigned long __init init_bootmem (unsigned long start, unsigned long pages)
00402 {
00403 max_low_pfn = pages;
00404 min_low_pfn = start;
00405 return(init_bootmem_core(&contig_page_data, start, 0, pages));
00406 }
00407
00408 void __init reserve_bootmem (unsigned long addr, unsigned long size)
00409 {
00410 reserve_bootmem_core(contig_page_data.bdata, addr, size);
00411 }
00412
00413 void __init free_bootmem (unsigned long addr, unsigned long size)
00414 {
00415 return(free_bootmem_core(contig_page_data.bdata, addr, size));
00416 }
00417
00418 unsigned long __init free_all_bootmem (void)
00419 {
00420 return(free_all_bootmem_core(&contig_page_data));
00421 }
00422
00423 void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal)
00424 {
00425 pg_data_t *pgdat = pgdat_list;
00426 void *ptr;
00427
00428 while (pgdat) {
00429 if ((ptr = __alloc_bootmem_core(pgdat->bdata, size,
00430 align, goal)))
00431 return(ptr);
00432 pgdat = pgdat->node_next;
00433 }
00434
00435
00436
00437 printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size);
00438 panic("Out of memory");
00439 return NULL;
00440 }
00441
00442 void * __init __alloc_bootmem_node (pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal)
00443 {
00444 void *ptr;
00445
00446 ptr = __alloc_bootmem_core(pgdat->bdata, size, align, goal);
00447 if (ptr)
00448 return (ptr);
00449
00450
00451
00452
00453 printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size);
00454 panic("Out of memory");
00455 return NULL;
00456 }
00457