aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/mm/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/mm/init.c')
-rw-r--r--arch/sparc64/mm/init.c255
1 files changed, 93 insertions, 162 deletions
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 5db50524f20d..1e44ee26cee8 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -105,7 +105,7 @@ static void __init read_obp_memory(const char *property,
105 regs[i].phys_addr = base; 105 regs[i].phys_addr = base;
106 regs[i].reg_size = size; 106 regs[i].reg_size = size;
107 } 107 }
108 sort(regs, ents, sizeof(struct linux_prom64_registers), 108 sort(regs, ents, sizeof(struct linux_prom64_registers),
109 cmp_p64, NULL); 109 cmp_p64, NULL);
110} 110}
111 111
@@ -133,6 +133,12 @@ extern unsigned int sparc_ramdisk_size;
133 133
134struct page *mem_map_zero __read_mostly; 134struct page *mem_map_zero __read_mostly;
135 135
136unsigned int sparc64_highest_unlocked_tlb_ent __read_mostly;
137
138unsigned long sparc64_kern_pri_context __read_mostly;
139unsigned long sparc64_kern_pri_nuc_bits __read_mostly;
140unsigned long sparc64_kern_sec_context __read_mostly;
141
136int bigkernel = 0; 142int bigkernel = 0;
137 143
138/* XXX Tune this... */ 144/* XXX Tune this... */
@@ -361,7 +367,11 @@ struct linux_prom_translation {
361 unsigned long size; 367 unsigned long size;
362 unsigned long data; 368 unsigned long data;
363}; 369};
364static struct linux_prom_translation prom_trans[512] __initdata; 370
371/* Exported for kernel TLB miss handling in ktlb.S */
372struct linux_prom_translation prom_trans[512] __read_mostly;
373unsigned int prom_trans_ents __read_mostly;
374unsigned int swapper_pgd_zero __read_mostly;
365 375
366extern unsigned long prom_boot_page; 376extern unsigned long prom_boot_page;
367extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle); 377extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle);
@@ -371,178 +381,57 @@ extern void register_prom_callbacks(void);
371/* Exported for SMP bootup purposes. */ 381/* Exported for SMP bootup purposes. */
372unsigned long kern_locked_tte_data; 382unsigned long kern_locked_tte_data;
373 383
374/* Exported for kernel TLB miss handling in ktlb.S */
375unsigned long prom_pmd_phys __read_mostly;
376unsigned int swapper_pgd_zero __read_mostly;
377
378/* Allocate power-of-2 aligned chunks from the end of the
379 * kernel image. Return physical address.
380 */
381static 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
394static 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
405static 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
416static 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
423static 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
430#define BASE_PAGE_SIZE 8192
431
432/* 384/*
433 * Translate PROM's mapping we capture at boot time into physical address. 385 * Translate PROM's mapping we capture at boot time into physical address.
434 * The second parameter is only set from prom_callback() invocations. 386 * The second parameter is only set from prom_callback() invocations.
435 */ 387 */
436unsigned long prom_virt_to_phys(unsigned long promva, int *error) 388unsigned long prom_virt_to_phys(unsigned long promva, int *error)
437{ 389{
438 unsigned long pmd_phys = (prom_pmd_phys + 390 int i;
439 ((promva >> 23) & 0x7ff) * sizeof(pmd_t));
440 unsigned long pte_phys;
441 pmd_t pmd_ent;
442 pte_t pte_ent;
443 unsigned long base;
444
445 pmd_val(pmd_ent) = load_phys32(pmd_phys);
446 if (pmd_none(pmd_ent)) {
447 if (error)
448 *error = 1;
449 return 0;
450 }
451 391
452 pte_phys = (unsigned long)pmd_val(pmd_ent) << 11UL; 392 for (i = 0; i < prom_trans_ents; i++) {
453 pte_phys += ((promva >> 13) & 0x3ff) * sizeof(pte_t); 393 struct linux_prom_translation *p = &prom_trans[i];
454 pte_val(pte_ent) = load_phys64(pte_phys); 394
455 if (!pte_present(pte_ent)) { 395 if (promva >= p->virt &&
456 if (error) 396 promva < (p->virt + p->size)) {
457 *error = 1; 397 unsigned long base = p->data & _PAGE_PADDR;
458 return 0; 398
459 } 399 if (error)
460 if (error) { 400 *error = 0;
461 *error = 0; 401 return base + (promva & (8192 - 1));
462 return pte_val(pte_ent); 402 }
463 } 403 }
464 base = pte_val(pte_ent) & _PAGE_PADDR; 404 if (error)
465 return (base + (promva & (BASE_PAGE_SIZE - 1))); 405 *error = 1;
406 return 0UL;
466} 407}
467 408
468/* The obp translations are saved based on 8k pagesize, since obp can 409/* The obp translations are saved based on 8k pagesize, since obp can
469 * use a mixture of pagesizes. Misses to the LOW_OBP_ADDRESS -> 410 * use a mixture of pagesizes. Misses to the LOW_OBP_ADDRESS ->
470 * HI_OBP_ADDRESS range are handled in entry.S and do not use the vpte 411 * HI_OBP_ADDRESS range are handled in ktlb.S and do not use the vpte
471 * scheme (also, see rant in inherit_locked_prom_mappings()). 412 * scheme (also, see rant in inherit_locked_prom_mappings()).
472 */ 413 */
473static void __init build_obp_range(unsigned long start, unsigned long end, unsigned long data)
474{
475 unsigned long vaddr;
476
477 for (vaddr = start; vaddr < end; vaddr += BASE_PAGE_SIZE) {
478 unsigned long val, pte_phys, pmd_phys;
479 pmd_t pmd_ent;
480 int i;
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
491 pmd_val(pmd_ent) = pte_phys >> 11UL;
492 store_phys32(pmd_phys, pmd_val(pmd_ent));
493 }
494
495 pte_phys = (unsigned long)pmd_val(pmd_ent) << 11UL;
496 pte_phys += (((vaddr >> 13) & 0x3ff) * sizeof(pte_t));
497
498 val = data;
499
500 /* Clear diag TTE bits. */
501 if (tlb_type == spitfire)
502 val &= ~0x0003fe0000000000UL;
503
504 store_phys64(pte_phys, val | _PAGE_MODIFIED);
505
506 data += BASE_PAGE_SIZE;
507 }
508}
509
510static inline int in_obp_range(unsigned long vaddr) 414static inline int in_obp_range(unsigned long vaddr)
511{ 415{
512 return (vaddr >= LOW_OBP_ADDRESS && 416 return (vaddr >= LOW_OBP_ADDRESS &&
513 vaddr < HI_OBP_ADDRESS); 417 vaddr < HI_OBP_ADDRESS);
514} 418}
515 419
516#define OBP_PMD_SIZE 2048 420static int cmp_ptrans(const void *a, const void *b)
517static void __init build_obp_pgtable(int prom_trans_ents)
518{ 421{
519 unsigned long i; 422 const struct linux_prom_translation *x = a, *y = b;
520
521 prom_pmd_phys = early_alloc_phys(OBP_PMD_SIZE);
522 for (i = 0; i < OBP_PMD_SIZE; i += 4)
523 store_phys32(prom_pmd_phys + i, 0);
524 423
525 for (i = 0; i < prom_trans_ents; i++) { 424 if (x->virt > y->virt)
526 unsigned long start, end; 425 return 1;
527 426 if (x->virt < y->virt)
528 if (!in_obp_range(prom_trans[i].virt)) 427 return -1;
529 continue; 428 return 0;
530
531 start = prom_trans[i].virt;
532 end = start + prom_trans[i].size;
533 if (end > HI_OBP_ADDRESS)
534 end = HI_OBP_ADDRESS;
535
536 build_obp_range(start, end, prom_trans[i].data);
537 }
538} 429}
539 430
540/* Read OBP translations property into 'prom_trans[]'. 431/* Read OBP translations property into 'prom_trans[]'. */
541 * Return the number of entries. 432static void __init read_obp_translations(void)
542 */
543static int __init read_obp_translations(void)
544{ 433{
545 int n, node; 434 int n, node, ents, first, last, i;
546 435
547 node = prom_finddevice("/virtual-memory"); 436 node = prom_finddevice("/virtual-memory");
548 n = prom_getproplen(node, "translations"); 437 n = prom_getproplen(node, "translations");
@@ -561,8 +450,44 @@ static int __init read_obp_translations(void)
561 prom_printf("prom_mappings: Couldn't get property.\n"); 450 prom_printf("prom_mappings: Couldn't get property.\n");
562 prom_halt(); 451 prom_halt();
563 } 452 }
453
564 n = n / sizeof(struct linux_prom_translation); 454 n = n / sizeof(struct linux_prom_translation);
565 return n; 455
456 ents = n;
457
458 sort(prom_trans, ents, sizeof(struct linux_prom_translation),
459 cmp_ptrans, NULL);
460
461 /* Now kick out all the non-OBP entries. */
462 for (i = 0; i < ents; i++) {
463 if (in_obp_range(prom_trans[i].virt))
464 break;
465 }
466 first = i;
467 for (; i < ents; i++) {
468 if (!in_obp_range(prom_trans[i].virt))
469 break;
470 }
471 last = i;
472
473 for (i = 0; i < (last - first); i++) {
474 struct linux_prom_translation *src = &prom_trans[i + first];
475 struct linux_prom_translation *dest = &prom_trans[i];
476
477 *dest = *src;
478 }
479 for (; i < ents; i++) {
480 struct linux_prom_translation *dest = &prom_trans[i];
481 dest->virt = dest->size = dest->data = 0x0UL;
482 }
483
484 prom_trans_ents = last - first;
485
486 if (tlb_type == spitfire) {
487 /* Clear diag TTE bits. */
488 for (i = 0; i < prom_trans_ents; i++)
489 prom_trans[i].data &= ~0x0003fe0000000000UL;
490 }
566} 491}
567 492
568static void __init remap_kernel(void) 493static void __init remap_kernel(void)
@@ -582,29 +507,36 @@ static void __init remap_kernel(void)
582 prom_dtlb_load(tlb_ent, tte_data, tte_vaddr); 507 prom_dtlb_load(tlb_ent, tte_data, tte_vaddr);
583 prom_itlb_load(tlb_ent, tte_data, tte_vaddr); 508 prom_itlb_load(tlb_ent, tte_data, tte_vaddr);
584 if (bigkernel) { 509 if (bigkernel) {
585 prom_dtlb_load(tlb_ent - 1, 510 tlb_ent -= 1;
511 prom_dtlb_load(tlb_ent,
586 tte_data + 0x400000, 512 tte_data + 0x400000,
587 tte_vaddr + 0x400000); 513 tte_vaddr + 0x400000);
588 prom_itlb_load(tlb_ent - 1, 514 prom_itlb_load(tlb_ent,
589 tte_data + 0x400000, 515 tte_data + 0x400000,
590 tte_vaddr + 0x400000); 516 tte_vaddr + 0x400000);
591 } 517 }
518 sparc64_highest_unlocked_tlb_ent = tlb_ent - 1;
519 if (tlb_type == cheetah_plus) {
520 sparc64_kern_pri_context = (CTX_CHEETAH_PLUS_CTX0 |
521 CTX_CHEETAH_PLUS_NUC);
522 sparc64_kern_pri_nuc_bits = CTX_CHEETAH_PLUS_NUC;
523 sparc64_kern_sec_context = CTX_CHEETAH_PLUS_CTX0;
524 }
592} 525}
593 526
527
594static void __init inherit_prom_mappings(void) 528static void __init inherit_prom_mappings(void)
595{ 529{
596 int n; 530 read_obp_translations();
597
598 n = read_obp_translations();
599 build_obp_pgtable(n);
600 531
601 /* Now fixup OBP's idea about where we really are mapped. */ 532 /* Now fixup OBP's idea about where we really are mapped. */
602 prom_printf("Remapping the kernel... "); 533 prom_printf("Remapping the kernel... ");
603 remap_kernel(); 534 remap_kernel();
604
605 prom_printf("done.\n"); 535 prom_printf("done.\n");
606 536
537 prom_printf("Registering callbacks... ");
607 register_prom_callbacks(); 538 register_prom_callbacks();
539 prom_printf("done.\n");
608} 540}
609 541
610/* The OBP specifications for sun4u mark 0xfffffffc00000000 and 542/* The OBP specifications for sun4u mark 0xfffffffc00000000 and
@@ -788,8 +720,8 @@ void inherit_locked_prom_mappings(int save_p)
788 } 720 }
789 } 721 }
790 if (tlb_type == spitfire) { 722 if (tlb_type == spitfire) {
791 int high = SPITFIRE_HIGHEST_LOCKED_TLBENT - bigkernel; 723 int high = sparc64_highest_unlocked_tlb_ent;
792 for (i = 0; i < high; i++) { 724 for (i = 0; i <= high; i++) {
793 unsigned long data; 725 unsigned long data;
794 726
795 /* Spitfire Errata #32 workaround */ 727 /* Spitfire Errata #32 workaround */
@@ -877,9 +809,9 @@ void inherit_locked_prom_mappings(int save_p)
877 } 809 }
878 } 810 }
879 } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { 811 } else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
880 int high = CHEETAH_HIGHEST_LOCKED_TLBENT - bigkernel; 812 int high = sparc64_highest_unlocked_tlb_ent;
881 813
882 for (i = 0; i < high; i++) { 814 for (i = 0; i <= high; i++) {
883 unsigned long data; 815 unsigned long data;
884 816
885 data = cheetah_get_ldtlb_data(i); 817 data = cheetah_get_ldtlb_data(i);
@@ -1556,7 +1488,6 @@ void __init paging_init(void)
1556 1488
1557 swapper_pgd_zero = pgd_val(swapper_pg_dir[0]); 1489 swapper_pgd_zero = pgd_val(swapper_pg_dir[0]);
1558 1490
1559 /* Inherit non-locked OBP mappings. */
1560 inherit_prom_mappings(); 1491 inherit_prom_mappings();
1561 1492
1562 /* Ok, we can use our TLB miss and window trap handlers safely. 1493 /* Ok, we can use our TLB miss and window trap handlers safely.