diff options
Diffstat (limited to 'arch/sparc64/mm/init.c')
-rw-r--r-- | arch/sparc64/mm/init.c | 182 |
1 files changed, 76 insertions, 106 deletions
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 5db50524f20d..0d2e967c7200 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c | |||
@@ -133,6 +133,12 @@ extern unsigned int sparc_ramdisk_size; | |||
133 | 133 | ||
134 | struct page *mem_map_zero __read_mostly; | 134 | struct page *mem_map_zero __read_mostly; |
135 | 135 | ||
136 | unsigned int sparc64_highest_unlocked_tlb_ent __read_mostly; | ||
137 | |||
138 | unsigned long sparc64_kern_pri_context __read_mostly; | ||
139 | unsigned long sparc64_kern_pri_nuc_bits __read_mostly; | ||
140 | unsigned long sparc64_kern_sec_context __read_mostly; | ||
141 | |||
136 | int bigkernel = 0; | 142 | int bigkernel = 0; |
137 | 143 | ||
138 | /* XXX Tune this... */ | 144 | /* XXX Tune this... */ |
@@ -362,6 +368,7 @@ struct linux_prom_translation { | |||
362 | unsigned long data; | 368 | unsigned long data; |
363 | }; | 369 | }; |
364 | static struct linux_prom_translation prom_trans[512] __initdata; | 370 | static struct linux_prom_translation prom_trans[512] __initdata; |
371 | static unsigned int prom_trans_ents __initdata; | ||
365 | 372 | ||
366 | extern unsigned long prom_boot_page; | 373 | extern unsigned long prom_boot_page; |
367 | extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle); | 374 | extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle); |
@@ -375,57 +382,7 @@ unsigned long kern_locked_tte_data; | |||
375 | unsigned long prom_pmd_phys __read_mostly; | 382 | unsigned long prom_pmd_phys __read_mostly; |
376 | unsigned int swapper_pgd_zero __read_mostly; | 383 | unsigned int swapper_pgd_zero __read_mostly; |
377 | 384 | ||
378 | /* Allocate power-of-2 aligned chunks from the end of the | 385 | static pmd_t *prompmd __read_mostly; |
379 | * kernel image. Return physical address. | ||
380 | */ | ||
381 | static inline unsigned long early_alloc_phys(unsigned long size) | ||
382 | { | ||
383 | unsigned long base; | ||
384 | |||
385 | BUILD_BUG_ON(size & (size - 1)); | ||
386 | |||
387 | kern_size = (kern_size + (size - 1)) & ~(size - 1); | ||
388 | base = kern_base + kern_size; | ||
389 | kern_size += size; | ||
390 | |||
391 | return base; | ||
392 | } | ||
393 | |||
394 | static inline unsigned long load_phys32(unsigned long pa) | ||
395 | { | ||
396 | unsigned long val; | ||
397 | |||
398 | __asm__ __volatile__("lduwa [%1] %2, %0" | ||
399 | : "=&r" (val) | ||
400 | : "r" (pa), "i" (ASI_PHYS_USE_EC)); | ||
401 | |||
402 | return val; | ||
403 | } | ||
404 | |||
405 | static inline unsigned long load_phys64(unsigned long pa) | ||
406 | { | ||
407 | unsigned long val; | ||
408 | |||
409 | __asm__ __volatile__("ldxa [%1] %2, %0" | ||
410 | : "=&r" (val) | ||
411 | : "r" (pa), "i" (ASI_PHYS_USE_EC)); | ||
412 | |||
413 | return val; | ||
414 | } | ||
415 | |||
416 | static inline void store_phys32(unsigned long pa, unsigned long val) | ||
417 | { | ||
418 | __asm__ __volatile__("stwa %0, [%1] %2" | ||
419 | : /* no outputs */ | ||
420 | : "r" (val), "r" (pa), "i" (ASI_PHYS_USE_EC)); | ||
421 | } | ||
422 | |||
423 | static inline void store_phys64(unsigned long pa, unsigned long val) | ||
424 | { | ||
425 | __asm__ __volatile__("stxa %0, [%1] %2" | ||
426 | : /* no outputs */ | ||
427 | : "r" (val), "r" (pa), "i" (ASI_PHYS_USE_EC)); | ||
428 | } | ||
429 | 386 | ||
430 | #define BASE_PAGE_SIZE 8192 | 387 | #define BASE_PAGE_SIZE 8192 |
431 | 388 | ||
@@ -435,34 +392,28 @@ static inline void store_phys64(unsigned long pa, unsigned long val) | |||
435 | */ | 392 | */ |
436 | unsigned long prom_virt_to_phys(unsigned long promva, int *error) | 393 | unsigned long prom_virt_to_phys(unsigned long promva, int *error) |
437 | { | 394 | { |
438 | unsigned long pmd_phys = (prom_pmd_phys + | 395 | pmd_t *pmdp = prompmd + ((promva >> 23) & 0x7ff); |
439 | ((promva >> 23) & 0x7ff) * sizeof(pmd_t)); | 396 | pte_t *ptep; |
440 | unsigned long pte_phys; | ||
441 | pmd_t pmd_ent; | ||
442 | pte_t pte_ent; | ||
443 | unsigned long base; | 397 | unsigned long base; |
444 | 398 | ||
445 | pmd_val(pmd_ent) = load_phys32(pmd_phys); | 399 | if (pmd_none(*pmdp)) { |
446 | if (pmd_none(pmd_ent)) { | ||
447 | if (error) | 400 | if (error) |
448 | *error = 1; | 401 | *error = 1; |
449 | return 0; | 402 | return 0; |
450 | } | 403 | } |
451 | 404 | ptep = (pte_t *)__pmd_page(*pmdp) + ((promva >> 13) & 0x3ff); | |
452 | pte_phys = (unsigned long)pmd_val(pmd_ent) << 11UL; | 405 | if (!pte_present(*ptep)) { |
453 | pte_phys += ((promva >> 13) & 0x3ff) * sizeof(pte_t); | ||
454 | pte_val(pte_ent) = load_phys64(pte_phys); | ||
455 | if (!pte_present(pte_ent)) { | ||
456 | if (error) | 406 | if (error) |
457 | *error = 1; | 407 | *error = 1; |
458 | return 0; | 408 | return 0; |
459 | } | 409 | } |
460 | if (error) { | 410 | if (error) { |
461 | *error = 0; | 411 | *error = 0; |
462 | return pte_val(pte_ent); | 412 | return pte_val(*ptep); |
463 | } | 413 | } |
464 | base = pte_val(pte_ent) & _PAGE_PADDR; | 414 | base = pte_val(*ptep) & _PAGE_PADDR; |
465 | return (base + (promva & (BASE_PAGE_SIZE - 1))); | 415 | |
416 | return base + (promva & (BASE_PAGE_SIZE - 1)); | ||
466 | } | 417 | } |
467 | 418 | ||
468 | /* The obp translations are saved based on 8k pagesize, since obp can | 419 | /* The obp translations are saved based on 8k pagesize, since obp can |
@@ -475,25 +426,20 @@ static void __init build_obp_range(unsigned long start, unsigned long end, unsig | |||
475 | unsigned long vaddr; | 426 | unsigned long vaddr; |
476 | 427 | ||
477 | for (vaddr = start; vaddr < end; vaddr += BASE_PAGE_SIZE) { | 428 | for (vaddr = start; vaddr < end; vaddr += BASE_PAGE_SIZE) { |
478 | unsigned long val, pte_phys, pmd_phys; | 429 | unsigned long val; |
479 | pmd_t pmd_ent; | 430 | pmd_t *pmd; |
480 | int i; | 431 | pte_t *pte; |
481 | |||
482 | pmd_phys = (prom_pmd_phys + | ||
483 | (((vaddr >> 23) & 0x7ff) * sizeof(pmd_t))); | ||
484 | pmd_val(pmd_ent) = load_phys32(pmd_phys); | ||
485 | if (pmd_none(pmd_ent)) { | ||
486 | pte_phys = early_alloc_phys(BASE_PAGE_SIZE); | ||
487 | |||
488 | for (i = 0; i < BASE_PAGE_SIZE / sizeof(pte_t); i++) | ||
489 | store_phys64(pte_phys+i*sizeof(pte_t),0); | ||
490 | 432 | ||
491 | pmd_val(pmd_ent) = pte_phys >> 11UL; | 433 | pmd = prompmd + ((vaddr >> 23) & 0x7ff); |
492 | store_phys32(pmd_phys, pmd_val(pmd_ent)); | 434 | if (pmd_none(*pmd)) { |
435 | pte = __alloc_bootmem(BASE_PAGE_SIZE, BASE_PAGE_SIZE, | ||
436 | PAGE_SIZE); | ||
437 | if (!pte) | ||
438 | prom_halt(); | ||
439 | memset(pte, 0, BASE_PAGE_SIZE); | ||
440 | pmd_set(pmd, pte); | ||
493 | } | 441 | } |
494 | 442 | pte = (pte_t *) __pmd_page(*pmd) + ((vaddr >> 13) & 0x3ff); | |
495 | pte_phys = (unsigned long)pmd_val(pmd_ent) << 11UL; | ||
496 | pte_phys += (((vaddr >> 13) & 0x3ff) * sizeof(pte_t)); | ||
497 | 443 | ||
498 | val = data; | 444 | val = data; |
499 | 445 | ||
@@ -501,7 +447,8 @@ static void __init build_obp_range(unsigned long start, unsigned long end, unsig | |||
501 | if (tlb_type == spitfire) | 447 | if (tlb_type == spitfire) |
502 | val &= ~0x0003fe0000000000UL; | 448 | val &= ~0x0003fe0000000000UL; |
503 | 449 | ||
504 | store_phys64(pte_phys, val | _PAGE_MODIFIED); | 450 | set_pte_at(&init_mm, vaddr, pte, |
451 | __pte(val | _PAGE_MODIFIED)); | ||
505 | 452 | ||
506 | data += BASE_PAGE_SIZE; | 453 | data += BASE_PAGE_SIZE; |
507 | } | 454 | } |
@@ -514,13 +461,17 @@ static inline int in_obp_range(unsigned long vaddr) | |||
514 | } | 461 | } |
515 | 462 | ||
516 | #define OBP_PMD_SIZE 2048 | 463 | #define OBP_PMD_SIZE 2048 |
517 | static void __init build_obp_pgtable(int prom_trans_ents) | 464 | static void __init build_obp_pgtable(void) |
518 | { | 465 | { |
519 | unsigned long i; | 466 | unsigned long i; |
520 | 467 | ||
521 | prom_pmd_phys = early_alloc_phys(OBP_PMD_SIZE); | 468 | prompmd = __alloc_bootmem(OBP_PMD_SIZE, OBP_PMD_SIZE, PAGE_SIZE); |
522 | for (i = 0; i < OBP_PMD_SIZE; i += 4) | 469 | if (!prompmd) |
523 | store_phys32(prom_pmd_phys + i, 0); | 470 | prom_halt(); |
471 | |||
472 | memset(prompmd, 0, OBP_PMD_SIZE); | ||
473 | |||
474 | prom_pmd_phys = __pa(prompmd); | ||
524 | 475 | ||
525 | for (i = 0; i < prom_trans_ents; i++) { | 476 | for (i = 0; i < prom_trans_ents; i++) { |
526 | unsigned long start, end; | 477 | unsigned long start, end; |
@@ -540,7 +491,7 @@ static void __init build_obp_pgtable(int prom_trans_ents) | |||
540 | /* Read OBP translations property into 'prom_trans[]'. | 491 | /* Read OBP translations property into 'prom_trans[]'. |
541 | * Return the number of entries. | 492 | * Return the number of entries. |
542 | */ | 493 | */ |
543 | static int __init read_obp_translations(void) | 494 | static void __init read_obp_translations(void) |
544 | { | 495 | { |
545 | int n, node; | 496 | int n, node; |
546 | 497 | ||
@@ -561,8 +512,10 @@ static int __init read_obp_translations(void) | |||
561 | prom_printf("prom_mappings: Couldn't get property.\n"); | 512 | prom_printf("prom_mappings: Couldn't get property.\n"); |
562 | prom_halt(); | 513 | prom_halt(); |
563 | } | 514 | } |
515 | |||
564 | n = n / sizeof(struct linux_prom_translation); | 516 | n = n / sizeof(struct linux_prom_translation); |
565 | return n; | 517 | |
518 | prom_trans_ents = n; | ||
566 | } | 519 | } |
567 | 520 | ||
568 | static void __init remap_kernel(void) | 521 | static void __init remap_kernel(void) |
@@ -582,28 +535,38 @@ static void __init remap_kernel(void) | |||
582 | prom_dtlb_load(tlb_ent, tte_data, tte_vaddr); | 535 | prom_dtlb_load(tlb_ent, tte_data, tte_vaddr); |
583 | prom_itlb_load(tlb_ent, tte_data, tte_vaddr); | 536 | prom_itlb_load(tlb_ent, tte_data, tte_vaddr); |
584 | if (bigkernel) { | 537 | if (bigkernel) { |
585 | prom_dtlb_load(tlb_ent - 1, | 538 | tlb_ent -= 1; |
539 | prom_dtlb_load(tlb_ent, | ||
586 | tte_data + 0x400000, | 540 | tte_data + 0x400000, |
587 | tte_vaddr + 0x400000); | 541 | tte_vaddr + 0x400000); |
588 | prom_itlb_load(tlb_ent - 1, | 542 | prom_itlb_load(tlb_ent, |
589 | tte_data + 0x400000, | 543 | tte_data + 0x400000, |
590 | tte_vaddr + 0x400000); | 544 | tte_vaddr + 0x400000); |
591 | } | 545 | } |
546 | sparc64_highest_unlocked_tlb_ent = tlb_ent - 1; | ||
547 | if (tlb_type == cheetah_plus) { | ||
548 | sparc64_kern_pri_context = (CTX_CHEETAH_PLUS_CTX0 | | ||
549 | CTX_CHEETAH_PLUS_NUC); | ||
550 | sparc64_kern_pri_nuc_bits = CTX_CHEETAH_PLUS_NUC; | ||
551 | sparc64_kern_sec_context = CTX_CHEETAH_PLUS_CTX0; | ||
552 | } | ||
592 | } | 553 | } |
593 | 554 | ||
594 | static void __init inherit_prom_mappings(void) | ||
595 | { | ||
596 | int n; | ||
597 | 555 | ||
598 | n = read_obp_translations(); | 556 | static void __init inherit_prom_mappings_pre(void) |
599 | build_obp_pgtable(n); | 557 | { |
558 | read_obp_translations(); | ||
600 | 559 | ||
601 | /* Now fixup OBP's idea about where we really are mapped. */ | 560 | /* Now fixup OBP's idea about where we really are mapped. */ |
602 | prom_printf("Remapping the kernel... "); | 561 | prom_printf("Remapping the kernel... "); |
603 | remap_kernel(); | 562 | remap_kernel(); |
604 | 563 | ||
605 | prom_printf("done.\n"); | 564 | prom_printf("done.\n"); |
565 | } | ||
606 | 566 | ||
567 | static void __init inherit_prom_mappings_post(void) | ||
568 | { | ||
569 | build_obp_pgtable(); | ||
607 | register_prom_callbacks(); | 570 | register_prom_callbacks(); |
608 | } | 571 | } |
609 | 572 | ||
@@ -788,8 +751,8 @@ void inherit_locked_prom_mappings(int save_p) | |||
788 | } | 751 | } |
789 | } | 752 | } |
790 | if (tlb_type == spitfire) { | 753 | if (tlb_type == spitfire) { |
791 | int high = SPITFIRE_HIGHEST_LOCKED_TLBENT - bigkernel; | 754 | int high = sparc64_highest_unlocked_tlb_ent; |
792 | for (i = 0; i < high; i++) { | 755 | for (i = 0; i <= high; i++) { |
793 | unsigned long data; | 756 | unsigned long data; |
794 | 757 | ||
795 | /* Spitfire Errata #32 workaround */ | 758 | /* Spitfire Errata #32 workaround */ |
@@ -877,9 +840,9 @@ void inherit_locked_prom_mappings(int save_p) | |||
877 | } | 840 | } |
878 | } | 841 | } |
879 | } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { | 842 | } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { |
880 | int high = CHEETAH_HIGHEST_LOCKED_TLBENT - bigkernel; | 843 | int high = sparc64_highest_unlocked_tlb_ent; |
881 | 844 | ||
882 | for (i = 0; i < high; i++) { | 845 | for (i = 0; i <= high; i++) { |
883 | unsigned long data; | 846 | unsigned long data; |
884 | 847 | ||
885 | data = cheetah_get_ldtlb_data(i); | 848 | data = cheetah_get_ldtlb_data(i); |
@@ -1556,8 +1519,7 @@ void __init paging_init(void) | |||
1556 | 1519 | ||
1557 | swapper_pgd_zero = pgd_val(swapper_pg_dir[0]); | 1520 | swapper_pgd_zero = pgd_val(swapper_pg_dir[0]); |
1558 | 1521 | ||
1559 | /* Inherit non-locked OBP mappings. */ | 1522 | inherit_prom_mappings_pre(); |
1560 | inherit_prom_mappings(); | ||
1561 | 1523 | ||
1562 | /* Ok, we can use our TLB miss and window trap handlers safely. | 1524 | /* Ok, we can use our TLB miss and window trap handlers safely. |
1563 | * We need to do a quick peek here to see if we are on StarFire | 1525 | * We need to do a quick peek here to see if we are on StarFire |
@@ -1568,15 +1530,23 @@ void __init paging_init(void) | |||
1568 | extern void setup_tba(int); | 1530 | extern void setup_tba(int); |
1569 | setup_tba(this_is_starfire); | 1531 | setup_tba(this_is_starfire); |
1570 | } | 1532 | } |
1571 | |||
1572 | inherit_locked_prom_mappings(1); | ||
1573 | |||
1574 | __flush_tlb_all(); | 1533 | __flush_tlb_all(); |
1575 | 1534 | ||
1535 | /* Everything from this point forward, until we are done with | ||
1536 | * inherit_prom_mappings_post(), must complete successfully | ||
1537 | * without calling into the firmware. The firwmare page tables | ||
1538 | * have not been built, but we are running on the Linux kernel's | ||
1539 | * trap table. | ||
1540 | */ | ||
1541 | |||
1576 | /* Setup bootmem... */ | 1542 | /* Setup bootmem... */ |
1577 | pages_avail = 0; | 1543 | pages_avail = 0; |
1578 | last_valid_pfn = end_pfn = bootmem_init(&pages_avail); | 1544 | last_valid_pfn = end_pfn = bootmem_init(&pages_avail); |
1579 | 1545 | ||
1546 | inherit_prom_mappings_post(); | ||
1547 | |||
1548 | inherit_locked_prom_mappings(1); | ||
1549 | |||
1580 | #ifdef CONFIG_DEBUG_PAGEALLOC | 1550 | #ifdef CONFIG_DEBUG_PAGEALLOC |
1581 | kernel_physical_mapping_init(); | 1551 | kernel_physical_mapping_init(); |
1582 | #endif | 1552 | #endif |