diff options
| author | Tony Luck <tony.luck@intel.com> | 2005-09-08 15:39:59 -0400 |
|---|---|---|
| committer | Tony Luck <tony.luck@intel.com> | 2005-09-08 15:39:59 -0400 |
| commit | d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7 (patch) | |
| tree | cb71557f43084027559762f58e51f2df5d5e5c46 | |
| parent | 4706df3d3c42af802597d82c8b1542c3d52eab23 (diff) | |
[IA64] simplified efi memory map parsing
New version leaves the original memory map unmodified.
Also saves any granule trimmings for use by the uncached
memory allocator.
Inspired by Khalid Aziz (various traces of his patch still
remain). Fixes to uncached_build_memmap() and sn2 testing
by Martin Hicks.
Signed-off-by: Tony Luck <tony.luck@intel.com>
| -rw-r--r-- | arch/ia64/kernel/efi.c | 423 | ||||
| -rw-r--r-- | arch/ia64/kernel/setup.c | 3 | ||||
| -rw-r--r-- | arch/ia64/kernel/uncached.c | 17 | ||||
| -rw-r--r-- | include/asm-ia64/meminit.h | 4 |
4 files changed, 254 insertions, 193 deletions
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index 179f230816ed..1291db581721 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c | |||
| @@ -239,57 +239,30 @@ is_available_memory (efi_memory_desc_t *md) | |||
| 239 | return 0; | 239 | return 0; |
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | /* | 242 | typedef struct kern_memdesc { |
| 243 | * Trim descriptor MD so its starts at address START_ADDR. If the descriptor covers | 243 | u64 attribute; |
| 244 | * memory that is normally available to the kernel, issue a warning that some memory | 244 | u64 start; |
| 245 | * is being ignored. | 245 | u64 num_pages; |
| 246 | */ | 246 | } kern_memdesc_t; |
| 247 | static void | ||
| 248 | trim_bottom (efi_memory_desc_t *md, u64 start_addr) | ||
| 249 | { | ||
| 250 | u64 num_skipped_pages; | ||
| 251 | |||
| 252 | if (md->phys_addr >= start_addr || !md->num_pages) | ||
| 253 | return; | ||
| 254 | |||
| 255 | num_skipped_pages = (start_addr - md->phys_addr) >> EFI_PAGE_SHIFT; | ||
| 256 | if (num_skipped_pages > md->num_pages) | ||
| 257 | num_skipped_pages = md->num_pages; | ||
| 258 | 247 | ||
| 259 | if (is_available_memory(md)) | 248 | static kern_memdesc_t *kern_memmap; |
| 260 | printk(KERN_NOTICE "efi.%s: ignoring %luKB of memory at 0x%lx due to granule hole " | ||
| 261 | "at 0x%lx\n", __FUNCTION__, | ||
| 262 | (num_skipped_pages << EFI_PAGE_SHIFT) >> 10, | ||
| 263 | md->phys_addr, start_addr - IA64_GRANULE_SIZE); | ||
| 264 | /* | ||
| 265 | * NOTE: Don't set md->phys_addr to START_ADDR because that could cause the memory | ||
| 266 | * descriptor list to become unsorted. In such a case, md->num_pages will be | ||
| 267 | * zero, so the Right Thing will happen. | ||
| 268 | */ | ||
| 269 | md->phys_addr += num_skipped_pages << EFI_PAGE_SHIFT; | ||
| 270 | md->num_pages -= num_skipped_pages; | ||
| 271 | } | ||
| 272 | 249 | ||
| 273 | static void | 250 | static void |
| 274 | trim_top (efi_memory_desc_t *md, u64 end_addr) | 251 | walk (efi_freemem_callback_t callback, void *arg, u64 attr) |
| 275 | { | 252 | { |
| 276 | u64 num_dropped_pages, md_end_addr; | 253 | kern_memdesc_t *k; |
| 254 | u64 start, end, voff; | ||
| 277 | 255 | ||
| 278 | md_end_addr = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT); | 256 | voff = (attr == EFI_MEMORY_WB) ? PAGE_OFFSET : __IA64_UNCACHED_OFFSET; |
| 279 | 257 | for (k = kern_memmap; k->start != ~0UL; k++) { | |
| 280 | if (md_end_addr <= end_addr || !md->num_pages) | 258 | if (k->attribute != attr) |
| 281 | return; | 259 | continue; |
| 282 | 260 | start = PAGE_ALIGN(k->start); | |
| 283 | num_dropped_pages = (md_end_addr - end_addr) >> EFI_PAGE_SHIFT; | 261 | end = (k->start + (k->num_pages << EFI_PAGE_SHIFT)) & PAGE_MASK; |
| 284 | if (num_dropped_pages > md->num_pages) | 262 | if (start < end) |
| 285 | num_dropped_pages = md->num_pages; | 263 | if ((*callback)(start + voff, end + voff, arg) < 0) |
| 286 | 264 | return; | |
| 287 | if (is_available_memory(md)) | 265 | } |
| 288 | printk(KERN_NOTICE "efi.%s: ignoring %luKB of memory at 0x%lx due to granule hole " | ||
| 289 | "at 0x%lx\n", __FUNCTION__, | ||
| 290 | (num_dropped_pages << EFI_PAGE_SHIFT) >> 10, | ||
| 291 | md->phys_addr, end_addr); | ||
| 292 | md->num_pages -= num_dropped_pages; | ||
| 293 | } | 266 | } |
| 294 | 267 | ||
| 295 | /* | 268 | /* |
| @@ -299,148 +272,19 @@ trim_top (efi_memory_desc_t *md, u64 end_addr) | |||
| 299 | void | 272 | void |
| 300 | efi_memmap_walk (efi_freemem_callback_t callback, void *arg) | 273 | efi_memmap_walk (efi_freemem_callback_t callback, void *arg) |
| 301 | { | 274 | { |
| 302 | int prev_valid = 0; | 275 | walk(callback, arg, EFI_MEMORY_WB); |
| 303 | struct range { | ||
| 304 | u64 start; | ||
| 305 | u64 end; | ||
| 306 | } prev, curr; | ||
| 307 | void *efi_map_start, *efi_map_end, *p, *q; | ||
| 308 | efi_memory_desc_t *md, *check_md; | ||
| 309 | u64 efi_desc_size, start, end, granule_addr, last_granule_addr, first_non_wb_addr = 0; | ||
| 310 | unsigned long total_mem = 0; | ||
| 311 | |||
| 312 | efi_map_start = __va(ia64_boot_param->efi_memmap); | ||
| 313 | efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; | ||
| 314 | efi_desc_size = ia64_boot_param->efi_memdesc_size; | ||
| 315 | |||
| 316 | for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { | ||
| 317 | md = p; | ||
| 318 | |||
| 319 | /* skip over non-WB memory descriptors; that's all we're interested in... */ | ||
| 320 | if (!(md->attribute & EFI_MEMORY_WB)) | ||
| 321 | continue; | ||
| 322 | |||
| 323 | /* | ||
| 324 | * granule_addr is the base of md's first granule. | ||
| 325 | * [granule_addr - first_non_wb_addr) is guaranteed to | ||
| 326 | * be contiguous WB memory. | ||
| 327 | */ | ||
| 328 | granule_addr = GRANULEROUNDDOWN(md->phys_addr); | ||
| 329 | first_non_wb_addr = max(first_non_wb_addr, granule_addr); | ||
| 330 | |||
| 331 | if (first_non_wb_addr < md->phys_addr) { | ||
| 332 | trim_bottom(md, granule_addr + IA64_GRANULE_SIZE); | ||
| 333 | granule_addr = GRANULEROUNDDOWN(md->phys_addr); | ||
| 334 | first_non_wb_addr = max(first_non_wb_addr, granule_addr); | ||
| 335 | } | ||
| 336 | |||
| 337 | for (q = p; q < efi_map_end; q += efi_desc_size) { | ||
| 338 | check_md = q; | ||
| 339 | |||
| 340 | if ((check_md->attribute & EFI_MEMORY_WB) && | ||
| 341 | (check_md->phys_addr == first_non_wb_addr)) | ||
| 342 | first_non_wb_addr += check_md->num_pages << EFI_PAGE_SHIFT; | ||
| 343 | else | ||
| 344 | break; /* non-WB or hole */ | ||
| 345 | } | ||
| 346 | |||
| 347 | last_granule_addr = GRANULEROUNDDOWN(first_non_wb_addr); | ||
| 348 | if (last_granule_addr < md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) | ||
| 349 | trim_top(md, last_granule_addr); | ||
| 350 | |||
| 351 | if (is_available_memory(md)) { | ||
| 352 | if (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) >= max_addr) { | ||
| 353 | if (md->phys_addr >= max_addr) | ||
| 354 | continue; | ||
| 355 | md->num_pages = (max_addr - md->phys_addr) >> EFI_PAGE_SHIFT; | ||
| 356 | first_non_wb_addr = max_addr; | ||
| 357 | } | ||
| 358 | |||
| 359 | if (total_mem >= mem_limit) | ||
| 360 | continue; | ||
| 361 | |||
| 362 | if (total_mem + (md->num_pages << EFI_PAGE_SHIFT) > mem_limit) { | ||
| 363 | unsigned long limit_addr = md->phys_addr; | ||
| 364 | |||
| 365 | limit_addr += mem_limit - total_mem; | ||
| 366 | limit_addr = GRANULEROUNDDOWN(limit_addr); | ||
| 367 | |||
| 368 | if (md->phys_addr > limit_addr) | ||
| 369 | continue; | ||
| 370 | |||
| 371 | md->num_pages = (limit_addr - md->phys_addr) >> | ||
| 372 | EFI_PAGE_SHIFT; | ||
| 373 | first_non_wb_addr = max_addr = md->phys_addr + | ||
| 374 | (md->num_pages << EFI_PAGE_SHIFT); | ||
| 375 | } | ||
| 376 | total_mem += (md->num_pages << EFI_PAGE_SHIFT); | ||
| 377 | |||
| 378 | if (md->num_pages == 0) | ||
| 379 | continue; | ||
| 380 | |||
| 381 | curr.start = PAGE_OFFSET + md->phys_addr; | ||
| 382 | curr.end = curr.start + (md->num_pages << EFI_PAGE_SHIFT); | ||
| 383 | |||
| 384 | if (!prev_valid) { | ||
| 385 | prev = curr; | ||
| 386 | prev_valid = 1; | ||
| 387 | } else { | ||
| 388 | if (curr.start < prev.start) | ||
| 389 | printk(KERN_ERR "Oops: EFI memory table not ordered!\n"); | ||
| 390 | |||
| 391 | if (prev.end == curr.start) { | ||
| 392 | /* merge two consecutive memory ranges */ | ||
| 393 | prev.end = curr.end; | ||
| 394 | } else { | ||
| 395 | start = PAGE_ALIGN(prev.start); | ||
| 396 | end = prev.end & PAGE_MASK; | ||
| 397 | if ((end > start) && (*callback)(start, end, arg) < 0) | ||
| 398 | return; | ||
| 399 | prev = curr; | ||
| 400 | } | ||
| 401 | } | ||
| 402 | } | ||
| 403 | } | ||
| 404 | if (prev_valid) { | ||
