aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2005-09-22 03:45:41 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2005-09-22 03:45:41 -0400
commit5085b4a5492f4f8bd32d0cc5b1cad4bf522c2e1a (patch)
treeea8ecb5d0a99f577b6517fe13583d63d8a8e800e /arch
parent405599bd98b01d648becb020efb503abf19f9c9f (diff)
[SPARC64]: Do not allocate OBP page tables using bootmem
Just allocate them physically starting from the end of the kernel image. This incredibly simplifies our MM bootstrap in that we don't need any mappings in the linear PAGE_OFFSET area working in order to bootstrap ourselves and take over the trap table from the firmware. Many further simplifications are possible now, and this also sets the stage for CONFIG_DEBUG_PAGEALLOC support. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch')
-rw-r--r--arch/sparc64/mm/init.c147
1 files changed, 100 insertions, 47 deletions
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 11d2187990d4..598bfb3b0053 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -324,14 +324,59 @@ unsigned long kern_locked_tte_data;
324unsigned long prom_pmd_phys __read_mostly; 324unsigned long prom_pmd_phys __read_mostly;
325unsigned int swapper_pgd_zero __read_mostly; 325unsigned int swapper_pgd_zero __read_mostly;
326 326
327void __init early_pgtable_allocfail(char *type) 327/* Allocate power-of-2 aligned chunks from the end of the
328 * kernel image. Return physical address.
329 */
330static inline unsigned long early_alloc_phys(unsigned long size)
328{ 331{
329 prom_printf("inherit_prom_mappings: Cannot alloc kernel %s.\n", type); 332 unsigned long base;
330 prom_halt(); 333
334 BUILD_BUG_ON(size & (size - 1));
335
336 kern_size = (kern_size + (size - 1)) & ~(size - 1);
337 base = kern_base + kern_size;
338 kern_size += size;
339
340 return base;
341}
342
343static inline unsigned long load_phys32(unsigned long pa)
344{
345 unsigned long val;
346
347 __asm__ __volatile__("lduwa [%1] %2, %0"
348 : "=&r" (val)
349 : "r" (pa), "i" (ASI_PHYS_USE_EC));
350
351 return val;
352}
353
354static inline unsigned long load_phys64(unsigned long pa)
355{
356 unsigned long val;
357
358 __asm__ __volatile__("ldxa [%1] %2, %0"
359 : "=&r" (val)
360 : "r" (pa), "i" (ASI_PHYS_USE_EC));
361
362 return val;
363}
364
365static inline void store_phys32(unsigned long pa, unsigned long val)
366{
367 __asm__ __volatile__("stwa %0, [%1] %2"
368 : /* no outputs */
369 : "r" (val), "r" (pa), "i" (ASI_PHYS_USE_EC));
370}
371
372static inline void store_phys64(unsigned long pa, unsigned long val)
373{
374 __asm__ __volatile__("stxa %0, [%1] %2"
375 : /* no outputs */
376 : "r" (val), "r" (pa), "i" (ASI_PHYS_USE_EC));
331} 377}
332 378
333#define BASE_PAGE_SIZE 8192 379#define BASE_PAGE_SIZE 8192
334static pmd_t *prompmd;
335 380
336/* 381/*
337 * Translate PROM's mapping we capture at boot time into physical address. 382 * Translate PROM's mapping we capture at boot time into physical address.
@@ -339,33 +384,34 @@ static pmd_t *prompmd;
339 */ 384 */
340unsigned long prom_virt_to_phys(unsigned long promva, int *error) 385unsigned long prom_virt_to_phys(unsigned long promva, int *error)
341{ 386{
342 pmd_t *pmdp = prompmd + ((promva >> 23) & 0x7ff); 387 unsigned long pmd_phys = (prom_pmd_phys +
343 pte_t *ptep; 388 ((promva >> 23) & 0x7ff) * sizeof(pmd_t));
389 unsigned long pte_phys;
390 pmd_t pmd_ent;
391 pte_t pte_ent;
344 unsigned long base; 392 unsigned long base;
345 393
346 if (pmd_none(*pmdp)) { 394 pmd_val(pmd_ent) = load_phys32(pmd_phys);
395 if (pmd_none(pmd_ent)) {
347 if (error) 396 if (error)
348 *error = 1; 397 *error = 1;
349 return(0); 398 return 0;
350 } 399 }
351 ptep = (pte_t *)__pmd_page(*pmdp) + ((promva >> 13) & 0x3ff); 400
352 if (!pte_present(*ptep)) { 401 pte_phys = (unsigned long)pmd_val(pmd_ent) << 11UL;
402 pte_phys += ((promva >> 13) & 0x3ff) * sizeof(pte_t);
403 pte_val(pte_ent) = load_phys64(pte_phys);
404 if (!pte_present(pte_ent)) {
353 if (error) 405 if (error)
354 *error = 1; 406 *error = 1;
355 return(0); 407 return 0;
356 } 408 }
357 if (error) { 409 if (error) {
358 *error = 0; 410 *error = 0;
359 return(pte_val(*ptep)); 411 return pte_val(pte_ent);
360 } 412 }
361 base = pte_val(*ptep) & _PAGE_PADDR; 413 base = pte_val(pte_ent) & _PAGE_PADDR;
362 return(base + (promva & (BASE_PAGE_SIZE - 1))); 414 return (base + (promva & (BASE_PAGE_SIZE - 1)));
363}
364
365static inline int in_obp_range(unsigned long vaddr)
366{
367 return (vaddr >= LOW_OBP_ADDRESS &&
368 vaddr < HI_OBP_ADDRESS);
369} 415}
370 416
371/* The obp translations are saved based on 8k pagesize, since obp can 417/* The obp translations are saved based on 8k pagesize, since obp can
@@ -378,22 +424,25 @@ static void build_obp_range(unsigned long start, unsigned long end, unsigned lon
378 unsigned long vaddr; 424 unsigned long vaddr;
379 425
380 for (vaddr = start; vaddr < end; vaddr += BASE_PAGE_SIZE) { 426 for (vaddr = start; vaddr < end; vaddr += BASE_PAGE_SIZE) {
381 unsigned long val; 427 unsigned long val, pte_phys, pmd_phys;
382 pmd_t *pmdp; 428 pmd_t pmd_ent;
383 pte_t *ptep; 429 int i;
384 430
385 pmdp = prompmd + ((vaddr >> 23) & 0x7ff); 431 pmd_phys = (prom_pmd_phys +
386 if (pmd_none(*pmdp)) { 432 (((vaddr >> 23) & 0x7ff) * sizeof(pmd_t)));
387 ptep = __alloc_bootmem(BASE_PAGE_SIZE, 433 pmd_val(pmd_ent) = load_phys32(pmd_phys);
388 BASE_PAGE_SIZE, 434 if (pmd_none(pmd_ent)) {
389 bootmap_base); 435 pte_phys = early_alloc_phys(BASE_PAGE_SIZE);
390 if (ptep == NULL) 436
391 early_pgtable_allocfail("pte"); 437 for (i = 0; i < BASE_PAGE_SIZE / sizeof(pte_t); i++)
392 memset(ptep, 0, BASE_PAGE_SIZE); 438 store_phys64(pte_phys+i*sizeof(pte_t),0);
393 pmd_set(pmdp, ptep); 439
440 pmd_val(pmd_ent) = pte_phys >> 11UL;
441 store_phys32(pmd_phys, pmd_val(pmd_ent));
394 } 442 }
395 ptep = (pte_t *)__pmd_page(*pmdp) + 443
396 ((vaddr >> 13) & 0x3ff); 444 pte_phys = (unsigned long)pmd_val(pmd_ent) << 11UL;
445 pte_phys += (((vaddr >> 13) & 0x3ff) * sizeof(pte_t));
397 446
398 val = data; 447 val = data;
399 448
@@ -401,22 +450,27 @@ static void build_obp_range(unsigned long start, unsigned long end, unsigned lon
401 if (tlb_type == spitfire) 450 if (tlb_type == spitfire)
402 val &= ~0x0003fe0000000000UL; 451 val &= ~0x0003fe0000000000UL;
403 452
404 set_pte_at(&init_mm, vaddr, 453 store_phys64(pte_phys, val | _PAGE_MODIFIED);
405 ptep, __pte(val | _PAGE_MODIFIED)); 454
406 data += BASE_PAGE_SIZE; 455 data += BASE_PAGE_SIZE;
407 } 456 }
408} 457}
409 458
459static inline int in_obp_range(unsigned long vaddr)
460{
461 return (vaddr >= LOW_OBP_ADDRESS &&
462 vaddr < HI_OBP_ADDRESS);
463}
464
410#define OBP_PMD_SIZE 2048 465#define OBP_PMD_SIZE 2048
411static void build_obp_pgtable(int prom_trans_ents) 466static void build_obp_pgtable(int prom_trans_ents)
412{ 467{
413 int i; 468 unsigned long i;
469
470 prom_pmd_phys = early_alloc_phys(OBP_PMD_SIZE);
471 for (i = 0; i < OBP_PMD_SIZE; i += 4)
472 store_phys32(prom_pmd_phys + i, 0);
414 473
415 prompmd = __alloc_bootmem(OBP_PMD_SIZE, OBP_PMD_SIZE,
416 bootmap_base);
417 if (prompmd == NULL)
418 early_pgtable_allocfail("pmd");
419 memset(prompmd, 0, OBP_PMD_SIZE);
420 for (i = 0; i < prom_trans_ents; i++) { 474 for (i = 0; i < prom_trans_ents; i++) {
421 unsigned long start, end; 475 unsigned long start, end;
422 476
@@ -430,7 +484,6 @@ static void build_obp_pgtable(int prom_trans_ents)
430 484
431 build_obp_range(start, end, prom_trans[i].data); 485 build_obp_range(start, end, prom_trans[i].data);
432 } 486 }
433 prom_pmd_phys = __pa(prompmd);
434} 487}
435 488
436/* Read OBP translations property into 'prom_trans[]'. 489/* Read OBP translations property into 'prom_trans[]'.
@@ -1517,13 +1570,13 @@ void __init paging_init(void)
1517 1570
1518 swapper_pgd_zero = pgd_val(init_mm.pgd[0]); 1571 swapper_pgd_zero = pgd_val(init_mm.pgd[0]);
1519 1572
1573 /* Inherit non-locked OBP mappings. */
1574 inherit_prom_mappings();
1575
1520 /* Setup bootmem... */ 1576 /* Setup bootmem... */
1521 pages_avail = 0; 1577 pages_avail = 0;
1522 last_valid_pfn = end_pfn = bootmem_init(&pages_avail); 1578 last_valid_pfn = end_pfn = bootmem_init(&pages_avail);
1523 1579
1524 /* Inherit non-locked OBP mappings. */
1525 inherit_prom_mappings();
1526
1527 /* Ok, we can use our TLB miss and window trap handlers safely. 1580 /* Ok, we can use our TLB miss and window trap handlers safely.
1528 * We need to do a quick peek here to see if we are on StarFire 1581 * We need to do a quick peek here to see if we are on StarFire
1529 * or not, so setup_tba can setup the IRQ globals correctly (it 1582 * or not, so setup_tba can setup the IRQ globals correctly (it