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.c187
1 files changed, 74 insertions, 113 deletions
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 0d2e967c7200..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
@@ -367,8 +367,11 @@ struct linux_prom_translation {
367 unsigned long size; 367 unsigned long size;
368 unsigned long data; 368 unsigned long data;
369}; 369};
370static struct linux_prom_translation prom_trans[512] __initdata; 370
371static unsigned int prom_trans_ents __initdata; 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;
372 375
373extern unsigned long prom_boot_page; 376extern unsigned long prom_boot_page;
374extern 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);
@@ -378,122 +381,57 @@ extern void register_prom_callbacks(void);
378/* Exported for SMP bootup purposes. */ 381/* Exported for SMP bootup purposes. */
379unsigned long kern_locked_tte_data; 382unsigned long kern_locked_tte_data;
380 383
381/* Exported for kernel TLB miss handling in ktlb.S */
382unsigned long prom_pmd_phys __read_mostly;
383unsigned int swapper_pgd_zero __read_mostly;
384
385static pmd_t *prompmd __read_mostly;
386
387#define BASE_PAGE_SIZE 8192
388
389/* 384/*
390 * 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.
391 * The second parameter is only set from prom_callback() invocations. 386 * The second parameter is only set from prom_callback() invocations.
392 */ 387 */
393unsigned long prom_virt_to_phys(unsigned long promva, int *error) 388unsigned long prom_virt_to_phys(unsigned long promva, int *error)
394{ 389{
395 pmd_t *pmdp = prompmd + ((promva >> 23) & 0x7ff); 390 int i;
396 pte_t *ptep;
397 unsigned long base;
398
399 if (pmd_none(*pmdp)) {
400 if (error)
401 *error = 1;
402 return 0;
403 }
404 ptep = (pte_t *)__pmd_page(*pmdp) + ((promva >> 13) & 0x3ff);
405 if (!pte_present(*ptep)) {
406 if (error)
407 *error = 1;
408 return 0;
409 }
410 if (error) {
411 *error = 0;
412 return pte_val(*ptep);
413 }
414 base = pte_val(*ptep) & _PAGE_PADDR;
415
416 return base + (promva & (BASE_PAGE_SIZE - 1));
417}
418 391
419/* The obp translations are saved based on 8k pagesize, since obp can 392 for (i = 0; i < prom_trans_ents; i++) {
420 * use a mixture of pagesizes. Misses to the LOW_OBP_ADDRESS -> 393 struct linux_prom_translation *p = &prom_trans[i];
421 * HI_OBP_ADDRESS range are handled in entry.S and do not use the vpte
422 * scheme (also, see rant in inherit_locked_prom_mappings()).
423 */
424static void __init build_obp_range(unsigned long start, unsigned long end, unsigned long data)
425{
426 unsigned long vaddr;
427 394
428 for (vaddr = start; vaddr < end; vaddr += BASE_PAGE_SIZE) { 395 if (promva >= p->virt &&
429 unsigned long val; 396 promva < (p->virt + p->size)) {
430 pmd_t *pmd; 397 unsigned long base = p->data & _PAGE_PADDR;
431 pte_t *pte;
432 398
433 pmd = prompmd + ((vaddr >> 23) & 0x7ff); 399 if (error)
434 if (pmd_none(*pmd)) { 400 *error = 0;
435 pte = __alloc_bootmem(BASE_PAGE_SIZE, BASE_PAGE_SIZE, 401 return base + (promva & (8192 - 1));
436 PAGE_SIZE);
437 if (!pte)
438 prom_halt();
439 memset(pte, 0, BASE_PAGE_SIZE);
440 pmd_set(pmd, pte);
441 } 402 }
442 pte = (pte_t *) __pmd_page(*pmd) + ((vaddr >> 13) & 0x3ff);
443
444 val = data;
445
446 /* Clear diag TTE bits. */
447 if (tlb_type == spitfire)
448 val &= ~0x0003fe0000000000UL;
449
450 set_pte_at(&init_mm, vaddr, pte,
451 __pte(val | _PAGE_MODIFIED));
452
453 data += BASE_PAGE_SIZE;
454 } 403 }
404 if (error)
405 *error = 1;
406 return 0UL;
455} 407}
456 408
409/* The obp translations are saved based on 8k pagesize, since obp can
410 * use a mixture of pagesizes. Misses to the LOW_OBP_ADDRESS ->
411 * HI_OBP_ADDRESS range are handled in ktlb.S and do not use the vpte
412 * scheme (also, see rant in inherit_locked_prom_mappings()).
413 */
457static inline int in_obp_range(unsigned long vaddr) 414static inline int in_obp_range(unsigned long vaddr)
458{ 415{
459 return (vaddr >= LOW_OBP_ADDRESS && 416 return (vaddr >= LOW_OBP_ADDRESS &&
460 vaddr < HI_OBP_ADDRESS); 417 vaddr < HI_OBP_ADDRESS);
461} 418}
462 419
463#define OBP_PMD_SIZE 2048 420static int cmp_ptrans(const void *a, const void *b)
464static void __init build_obp_pgtable(void)
465{ 421{
466 unsigned long i; 422 const struct linux_prom_translation *x = a, *y = b;
467
468 prompmd = __alloc_bootmem(OBP_PMD_SIZE, OBP_PMD_SIZE, PAGE_SIZE);
469 if (!prompmd)
470 prom_halt();
471
472 memset(prompmd, 0, OBP_PMD_SIZE);
473
474 prom_pmd_phys = __pa(prompmd);
475
476 for (i = 0; i < prom_trans_ents; i++) {
477 unsigned long start, end;
478
479 if (!in_obp_range(prom_trans[i].virt))
480 continue;
481 423
482 start = prom_trans[i].virt; 424 if (x->virt > y->virt)
483 end = start + prom_trans[i].size; 425 return 1;
484 if (end > HI_OBP_ADDRESS) 426 if (x->virt < y->virt)
485 end = HI_OBP_ADDRESS; 427 return -1;
486 428 return 0;
487 build_obp_range(start, end, prom_trans[i].data);
488 }
489} 429}
490 430
491/* Read OBP translations property into 'prom_trans[]'. 431/* Read OBP translations property into 'prom_trans[]'. */
492 * Return the number of entries.
493 */
494static void __init read_obp_translations(void) 432static void __init read_obp_translations(void)
495{ 433{
496 int n, node; 434 int n, node, ents, first, last, i;
497 435
498 node = prom_finddevice("/virtual-memory"); 436 node = prom_finddevice("/virtual-memory");
499 n = prom_getproplen(node, "translations"); 437 n = prom_getproplen(node, "translations");
@@ -515,7 +453,41 @@ static void __init read_obp_translations(void)
515 453
516 n = n / sizeof(struct linux_prom_translation); 454 n = n / sizeof(struct linux_prom_translation);
517 455
518 prom_trans_ents = n; 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 }
519} 491}
520 492
521static void __init remap_kernel(void) 493static void __init remap_kernel(void)
@@ -553,21 +525,18 @@ static void __init remap_kernel(void)
553} 525}
554 526
555 527
556static void __init inherit_prom_mappings_pre(void) 528static void __init inherit_prom_mappings(void)
557{ 529{
558 read_obp_translations(); 530 read_obp_translations();
559 531
560 /* Now fixup OBP's idea about where we really are mapped. */ 532 /* Now fixup OBP's idea about where we really are mapped. */
561 prom_printf("Remapping the kernel... "); 533 prom_printf("Remapping the kernel... ");
562 remap_kernel(); 534 remap_kernel();
563
564 prom_printf("done.\n"); 535 prom_printf("done.\n");
565}
566 536
567static void __init inherit_prom_mappings_post(void) 537 prom_printf("Registering callbacks... ");
568{
569 build_obp_pgtable();
570 register_prom_callbacks(); 538 register_prom_callbacks();
539 prom_printf("done.\n");
571} 540}
572 541
573/* The OBP specifications for sun4u mark 0xfffffffc00000000 and 542/* The OBP specifications for sun4u mark 0xfffffffc00000000 and
@@ -1519,7 +1488,7 @@ void __init paging_init(void)
1519 1488
1520 swapper_pgd_zero = pgd_val(swapper_pg_dir[0]); 1489 swapper_pgd_zero = pgd_val(swapper_pg_dir[0]);
1521 1490
1522 inherit_prom_mappings_pre(); 1491 inherit_prom_mappings();
1523 1492
1524 /* 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.
1525 * We need to do a quick peek here to see if we are on StarFire 1494 * We need to do a quick peek here to see if we are on StarFire
@@ -1530,23 +1499,15 @@ void __init paging_init(void)
1530 extern void setup_tba(int); 1499 extern void setup_tba(int);
1531 setup_tba(this_is_starfire); 1500 setup_tba(this_is_starfire);
1532 } 1501 }
1533 __flush_tlb_all();
1534 1502
1535 /* Everything from this point forward, until we are done with 1503 inherit_locked_prom_mappings(1);
1536 * inherit_prom_mappings_post(), must complete successfully 1504
1537 * without calling into the firmware. The firwmare page tables 1505 __flush_tlb_all();
1538 * have not been built, but we are running on the Linux kernel's
1539 * trap table.
1540 */
1541 1506
1542 /* Setup bootmem... */ 1507 /* Setup bootmem... */
1543 pages_avail = 0; 1508 pages_avail = 0;
1544 last_valid_pfn = end_pfn = bootmem_init(&pages_avail); 1509 last_valid_pfn = end_pfn = bootmem_init(&pages_avail);
1545 1510
1546 inherit_prom_mappings_post();
1547
1548 inherit_locked_prom_mappings(1);
1549
1550#ifdef CONFIG_DEBUG_PAGEALLOC 1511#ifdef CONFIG_DEBUG_PAGEALLOC
1551 kernel_physical_mapping_init(); 1512 kernel_physical_mapping_init();
1552#endif 1513#endif