diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2005-09-22 03:12:35 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2005-09-22 03:12:35 -0400 |
commit | 405599bd98b01d648becb020efb503abf19f9c9f (patch) | |
tree | ccf791e5a40f8c550103b0f7db054dca2973ae79 | |
parent | b206fc4c0997ee858bc3ed35f157d7c3cda54cfd (diff) |
[SPARC64]: Break up inherit_prom_mappings() into it's constituent parts.
This thing was just a huge monolithic mess, so chop it up.
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | arch/sparc64/mm/init.c | 301 |
1 files changed, 160 insertions, 141 deletions
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 141d4cc5fc53..11d2187990d4 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c | |||
@@ -362,84 +362,107 @@ unsigned long prom_virt_to_phys(unsigned long promva, int *error) | |||
362 | return(base + (promva & (BASE_PAGE_SIZE - 1))); | 362 | return(base + (promva & (BASE_PAGE_SIZE - 1))); |
363 | } | 363 | } |
364 | 364 | ||
365 | static void inherit_prom_mappings(void) | 365 | static inline int in_obp_range(unsigned long vaddr) |
366 | { | 366 | { |
367 | unsigned long phys_page, tte_vaddr, tte_data; | 367 | return (vaddr >= LOW_OBP_ADDRESS && |
368 | void (*remap_func)(unsigned long, unsigned long, int); | 368 | vaddr < HI_OBP_ADDRESS); |
369 | pmd_t *pmdp; | 369 | } |
370 | pte_t *ptep; | ||
371 | int node, n, i, tsz; | ||
372 | 370 | ||
373 | node = prom_finddevice("/virtual-memory"); | 371 | /* The obp translations are saved based on 8k pagesize, since obp can |
374 | n = prom_getproplen(node, "translations"); | 372 | * use a mixture of pagesizes. Misses to the LOW_OBP_ADDRESS -> |
375 | if (n == 0 || n == -1) { | 373 | * HI_OBP_ADDRESS range are handled in entry.S and do not use the vpte |
376 | prom_printf("prom_mappings: Couldn't get size.\n"); | 374 | * scheme (also, see rant in inherit_locked_prom_mappings()). |
377 | prom_halt(); | 375 | */ |
378 | } | 376 | static void build_obp_range(unsigned long start, unsigned long end, unsigned long data) |
379 | n += 24 * sizeof(struct linux_prom_translation); | 377 | { |
380 | if (n > sizeof(prom_trans)) { | 378 | unsigned long vaddr; |
381 | prom_printf("prom_mappings: prom_trans too small, " | 379 | |
382 | "need %Zd bytes\n", n); | 380 | for (vaddr = start; vaddr < end; vaddr += BASE_PAGE_SIZE) { |
383 | prom_halt(); | 381 | unsigned long val; |
384 | } | 382 | pmd_t *pmdp; |
385 | tsz = n; | 383 | pte_t *ptep; |
386 | if ((n = prom_getproperty(node, "translations", | 384 | |
387 | (char *)&prom_trans[0], tsz)) == -1) { | 385 | pmdp = prompmd + ((vaddr >> 23) & 0x7ff); |
388 | prom_printf("prom_mappings: Couldn't get property.\n"); | 386 | if (pmd_none(*pmdp)) { |
389 | prom_halt(); | 387 | ptep = __alloc_bootmem(BASE_PAGE_SIZE, |
388 | BASE_PAGE_SIZE, | ||
389 | bootmap_base); | ||
390 | if (ptep == NULL) | ||
391 | early_pgtable_allocfail("pte"); | ||
392 | memset(ptep, 0, BASE_PAGE_SIZE); | ||
393 | pmd_set(pmdp, ptep); | ||
394 | } | ||
395 | ptep = (pte_t *)__pmd_page(*pmdp) + | ||
396 | ((vaddr >> 13) & 0x3ff); | ||
397 | |||
398 | val = data; | ||
399 | |||
400 | /* Clear diag TTE bits. */ | ||
401 | if (tlb_type == spitfire) | ||
402 | val &= ~0x0003fe0000000000UL; | ||
403 | |||
404 | set_pte_at(&init_mm, vaddr, | ||
405 | ptep, __pte(val | _PAGE_MODIFIED)); | ||
406 | data += BASE_PAGE_SIZE; | ||
390 | } | 407 | } |
391 | n = n / sizeof(struct linux_prom_translation); | 408 | } |
392 | 409 | ||
393 | /* The obp translations are saved based on 8k pagesize, since obp | ||
394 | * can use a mixture of pagesizes. Misses to the 0xf0000000 -> | ||
395 | * 0x100000000, ie obp range, are handled in entry.S and do not | ||
396 | * use the vpte scheme (see rant: inherit_locked_prom_mappings). | ||
397 | */ | ||
398 | #define OBP_PMD_SIZE 2048 | 410 | #define OBP_PMD_SIZE 2048 |
399 | prompmd = __alloc_bootmem(OBP_PMD_SIZE, OBP_PMD_SIZE, bootmap_base); | 411 | static void build_obp_pgtable(int prom_trans_ents) |
412 | { | ||
413 | int i; | ||
414 | |||
415 | prompmd = __alloc_bootmem(OBP_PMD_SIZE, OBP_PMD_SIZE, | ||
416 | bootmap_base); | ||
400 | if (prompmd == NULL) | 417 | if (prompmd == NULL) |
401 | early_pgtable_allocfail("pmd"); | 418 | early_pgtable_allocfail("pmd"); |
402 | memset(prompmd, 0, OBP_PMD_SIZE); | 419 | memset(prompmd, 0, OBP_PMD_SIZE); |
403 | for (i = 0; i < n; i++) { | 420 | for (i = 0; i < prom_trans_ents; i++) { |
404 | unsigned long vaddr; | 421 | unsigned long start, end; |
405 | |||
406 | if (prom_trans[i].virt >= LOW_OBP_ADDRESS && prom_trans[i].virt < HI_OBP_ADDRESS) { | ||
407 | for (vaddr = prom_trans[i].virt; | ||
408 | ((vaddr < prom_trans[i].virt + prom_trans[i].size) && | ||
409 | (vaddr < HI_OBP_ADDRESS)); | ||
410 | vaddr += BASE_PAGE_SIZE) { | ||
411 | unsigned long val; | ||
412 | |||
413 | pmdp = prompmd + ((vaddr >> 23) & 0x7ff); | ||
414 | if (pmd_none(*pmdp)) { | ||
415 | ptep = __alloc_bootmem(BASE_PAGE_SIZE, | ||
416 | BASE_PAGE_SIZE, | ||
417 | bootmap_base); | ||
418 | if (ptep == NULL) | ||
419 | early_pgtable_allocfail("pte"); | ||
420 | memset(ptep, 0, BASE_PAGE_SIZE); | ||
421 | pmd_set(pmdp, ptep); | ||
422 | } | ||
423 | ptep = (pte_t *)__pmd_page(*pmdp) + | ||
424 | ((vaddr >> 13) & 0x3ff); | ||
425 | 422 | ||
426 | val = prom_trans[i].data; | 423 | if (!in_obp_range(prom_trans[i].virt)) |
424 | continue; | ||
427 | 425 | ||
428 | /* Clear diag TTE bits. */ | 426 | start = prom_trans[i].virt; |
429 | if (tlb_type == spitfire) | 427 | end = start + prom_trans[i].size; |
430 | val &= ~0x0003fe0000000000UL; | 428 | if (end > HI_OBP_ADDRESS) |
429 | end = HI_OBP_ADDRESS; | ||
431 | 430 | ||
432 | set_pte_at(&init_mm, vaddr, | 431 | build_obp_range(start, end, prom_trans[i].data); |
433 | ptep, __pte(val | _PAGE_MODIFIED)); | ||
434 | prom_trans[i].data += BASE_PAGE_SIZE; | ||
435 | } | ||
436 | } | ||
437 | } | 432 | } |
438 | prom_pmd_phys = __pa(prompmd); | 433 | prom_pmd_phys = __pa(prompmd); |
434 | } | ||
439 | 435 | ||
440 | /* Now fixup OBP's idea about where we really are mapped. */ | 436 | /* Read OBP translations property into 'prom_trans[]'. |
441 | prom_printf("Remapping the kernel... "); | 437 | * Return the number of entries. |
438 | */ | ||
439 | static int read_obp_translations(void) | ||
440 | { | ||
441 | int n, node; | ||
442 | 442 | ||
443 | node = prom_finddevice("/virtual-memory"); | ||
444 | n = prom_getproplen(node, "translations"); | ||
445 | if (unlikely(n == 0 || n == -1)) { | ||
446 | prom_printf("prom_mappings: Couldn't get size.\n"); | ||
447 | prom_halt(); | ||
448 | } | ||
449 | if (unlikely(n > sizeof(prom_trans))) { | ||
450 | prom_printf("prom_mappings: Size %Zd is too big.\n", n); | ||
451 | prom_halt(); | ||
452 | } | ||
453 | |||
454 | if ((n = prom_getproperty(node, "translations", | ||
455 | (char *)&prom_trans[0], | ||
456 | sizeof(prom_trans))) == -1) { | ||
457 | prom_printf("prom_mappings: Couldn't get property.\n"); | ||
458 | prom_halt(); | ||
459 | } | ||
460 | n = n / sizeof(struct linux_prom_translation); | ||
461 | return n; | ||
462 | } | ||
463 | |||
464 | static inline void early_spitfire_errata32(void) | ||
465 | { | ||
443 | /* Spitfire Errata #32 workaround */ | 466 | /* Spitfire Errata #32 workaround */ |
444 | /* NOTE: Using plain zero for the context value is | 467 | /* NOTE: Using plain zero for the context value is |
445 | * correct here, we are not using the Linux trap | 468 | * correct here, we are not using the Linux trap |
@@ -449,23 +472,13 @@ static void inherit_prom_mappings(void) | |||
449 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | 472 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" |
450 | "flush %%g6" | 473 | "flush %%g6" |
451 | : /* No outputs */ | 474 | : /* No outputs */ |
452 | : "r" (0), "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | 475 | : "r" (0), "r" (PRIMARY_CONTEXT), |
453 | 476 | "i" (ASI_DMMU)); | |
454 | switch (tlb_type) { | 477 | } |
455 | default: | ||
456 | case spitfire: | ||
457 | phys_page = spitfire_get_dtlb_data(sparc64_highest_locked_tlbent()); | ||
458 | break; | ||
459 | |||
460 | case cheetah: | ||
461 | case cheetah_plus: | ||
462 | phys_page = cheetah_get_litlb_data(sparc64_highest_locked_tlbent()); | ||
463 | break; | ||
464 | }; | ||
465 | 478 | ||
466 | phys_page &= _PAGE_PADDR; | 479 | static void lock_remap_func_page(unsigned long phys_page) |
467 | phys_page += ((unsigned long)&prom_boot_page - | 480 | { |
468 | (unsigned long)KERNBASE); | 481 | unsigned long tte_data = (phys_page | pgprot_val(PAGE_KERNEL)); |
469 | 482 | ||
470 | if (tlb_type == spitfire) { | 483 | if (tlb_type == spitfire) { |
471 | /* Lock this into i/d tlb entry 59 */ | 484 | /* Lock this into i/d tlb entry 59 */ |
@@ -478,13 +491,12 @@ static void inherit_prom_mappings(void) | |||
478 | "stxa %0, [%1] %6\n\t" | 491 | "stxa %0, [%1] %6\n\t" |
479 | "membar #Sync\n\t" | 492 | "membar #Sync\n\t" |
480 | "flush %%g6" | 493 | "flush %%g6" |
481 | : : "r" (phys_page | _PAGE_VALID | _PAGE_SZ8K | _PAGE_CP | | 494 | : /* no outputs */ |
482 | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), | 495 | : "r" (tte_data), "r" (59 << 3), "r" (TLB_TAG_ACCESS), |
483 | "r" (59 << 3), "r" (TLB_TAG_ACCESS), | 496 | "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), |
484 | "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), | 497 | "i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS) |
485 | "i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS) | 498 | : "memory"); |
486 | : "memory"); | 499 | } else { |
487 | } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { | ||
488 | /* Lock this into i/d tlb-0 entry 11 */ | 500 | /* Lock this into i/d tlb-0 entry 11 */ |
489 | __asm__ __volatile__( | 501 | __asm__ __volatile__( |
490 | "stxa %%g0, [%2] %3\n\t" | 502 | "stxa %%g0, [%2] %3\n\t" |
@@ -495,87 +507,80 @@ static void inherit_prom_mappings(void) | |||
495 | "stxa %0, [%1] %6\n\t" | 507 | "stxa %0, [%1] %6\n\t" |
496 | "membar #Sync\n\t" | 508 | "membar #Sync\n\t" |
497 | "flush %%g6" | 509 | "flush %%g6" |
498 | : : "r" (phys_page | _PAGE_VALID | _PAGE_SZ8K | _PAGE_CP | | 510 | : /* no outputs */ |
499 | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), | 511 | : "r" (tte_data), "r" ((0 << 16) | (11 << 3)), |
500 | "r" ((0 << 16) | (11 << 3)), "r" (TLB_TAG_ACCESS), | 512 | "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU), |
501 | "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), | 513 | "i" (ASI_DTLB_DATA_ACCESS), "i" (ASI_IMMU), |
502 | "i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS) | 514 | "i" (ASI_ITLB_DATA_ACCESS) |
503 | : "memory"); | 515 | : "memory"); |
504 | } else { | ||
505 | /* Implement me :-) */ | ||
506 | BUG(); | ||
507 | } | 516 | } |
517 | } | ||
518 | |||
519 | static void remap_kernel(void) | ||
520 | { | ||
521 | unsigned long phys_page, tte_vaddr, tte_data; | ||
522 | void (*remap_func)(unsigned long, unsigned long, int); | ||
523 | int tlb_ent = sparc64_highest_locked_tlbent(); | ||
524 | |||
525 | early_spitfire_errata32(); | ||
526 | |||
527 | if (tlb_type == spitfire) | ||
528 | phys_page = spitfire_get_dtlb_data(tlb_ent); | ||
529 | else | ||
530 | phys_page = cheetah_get_ldtlb_data(tlb_ent); | ||
531 | |||
532 | phys_page &= _PAGE_PADDR; | ||
533 | phys_page += ((unsigned long)&prom_boot_page - | ||
534 | (unsigned long)KERNBASE); | ||
535 | |||
536 | lock_remap_func_page(phys_page); | ||
508 | 537 | ||
509 | tte_vaddr = (unsigned long) KERNBASE; | 538 | tte_vaddr = (unsigned long) KERNBASE; |
510 | 539 | ||
511 | /* Spitfire Errata #32 workaround */ | 540 | early_spitfire_errata32(); |
512 | /* NOTE: Using plain zero for the context value is | ||
513 | * correct here, we are not using the Linux trap | ||
514 | * tables yet so we should not use the special | ||
515 | * UltraSPARC-III+ page size encodings yet. | ||
516 | */ | ||
517 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
518 | "flush %%g6" | ||
519 | : /* No outputs */ | ||
520 | : "r" (0), | ||
521 | "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | ||
522 | 541 | ||
523 | if (tlb_type == spitfire) | 542 | if (tlb_type == spitfire) |
524 | tte_data = spitfire_get_dtlb_data(sparc64_highest_locked_tlbent()); | 543 | tte_data = spitfire_get_dtlb_data(tlb_ent); |
525 | else | 544 | else |
526 | tte_data = cheetah_get_ldtlb_data(sparc64_highest_locked_tlbent()); | 545 | tte_data = cheetah_get_ldtlb_data(tlb_ent); |
527 | 546 | ||
528 | kern_locked_tte_data = tte_data; | 547 | kern_locked_tte_data = tte_data; |
529 | 548 | ||
530 | remap_func = (void *) ((unsigned long) &prom_remap - | 549 | remap_func = (void *) ((unsigned long) &prom_remap - |
531 | (unsigned long) &prom_boot_page); | 550 | (unsigned long) &prom_boot_page); |
532 | 551 | ||
552 | early_spitfire_errata32(); | ||
533 | 553 | ||
534 | /* Spitfire Errata #32 workaround */ | 554 | phys_page = tte_data & _PAGE_PADDR; |
535 | /* NOTE: Using plain zero for the context value is | 555 | remap_func(phys_page, KERNBASE, prom_get_mmu_ihandle()); |
536 | * correct here, we are not using the Linux trap | ||
537 | * tables yet so we should not use the special | ||
538 | * UltraSPARC-III+ page size encodings yet. | ||
539 | */ | ||
540 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
541 | "flush %%g6" | ||
542 | : /* No outputs */ | ||
543 | : "r" (0), | ||
544 | "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | ||
545 | |||
546 | remap_func((tlb_type == spitfire ? | ||
547 | (spitfire_get_dtlb_data(sparc64_highest_locked_tlbent()) & _PAGE_PADDR) : | ||
548 | (cheetah_get_litlb_data(sparc64_highest_locked_tlbent()) & _PAGE_PADDR)), | ||
549 | (unsigned long) KERNBASE, | ||
550 | prom_get_mmu_ihandle()); | ||
551 | |||
552 | if (bigkernel) | 556 | if (bigkernel) |
553 | remap_func(((tte_data + 0x400000) & _PAGE_PADDR), | 557 | remap_func(phys_page + 0x400000, |
554 | (unsigned long) KERNBASE + 0x400000, prom_get_mmu_ihandle()); | 558 | KERNBASE + 0x400000, |
559 | prom_get_mmu_ihandle()); | ||
555 | 560 | ||
556 | /* Flush out that temporary mapping. */ | 561 | /* Flush out that temporary mapping. */ |
557 | spitfire_flush_dtlb_nucleus_page(0x0); | 562 | spitfire_flush_dtlb_nucleus_page(0x0); |
558 | spitfire_flush_itlb_nucleus_page(0x0); | 563 | spitfire_flush_itlb_nucleus_page(0x0); |
559 | 564 | ||
560 | /* Now lock us back into the TLBs via OBP. */ | 565 | /* Now lock us back into the TLBs via OBP. */ |
561 | prom_dtlb_load(sparc64_highest_locked_tlbent(), tte_data, tte_vaddr); | 566 | prom_dtlb_load(tlb_ent, tte_data, tte_vaddr); |
562 | prom_itlb_load(sparc64_highest_locked_tlbent(), tte_data, tte_vaddr); | 567 | prom_itlb_load(tlb_ent, tte_data, tte_vaddr); |
563 | if (bigkernel) { | 568 | if (bigkernel) { |
564 | prom_dtlb_load(sparc64_highest_locked_tlbent()-1, tte_data + 0x400000, | 569 | prom_dtlb_load(tlb_ent - 1, |
565 | tte_vaddr + 0x400000); | 570 | tte_data + 0x400000, |
566 | prom_itlb_load(sparc64_highest_locked_tlbent()-1, tte_data + 0x400000, | 571 | tte_vaddr + 0x400000); |
567 | tte_vaddr + 0x400000); | 572 | prom_itlb_load(tlb_ent - 1, |
573 | tte_data + 0x400000, | ||
574 | tte_vaddr + 0x400000); | ||
568 | } | 575 | } |
576 | } | ||
569 | 577 | ||
570 | /* Re-read translations property. */ | 578 | static void readjust_prom_translations(void) |
571 | if ((n = prom_getproperty(node, "translations", | 579 | { |
572 | (char *)&prom_trans[0], tsz)) == -1) { | 580 | int nents, i; |
573 | prom_printf("prom_mappings: Can't reread prom_trans.\n"); | ||
574 | prom_halt(); | ||
575 | } | ||
576 | n = n / sizeof(struct linux_prom_translation); | ||
577 | 581 | ||
578 | for (i = 0; i < n; i++) { | 582 | nents = read_obp_translations(); |
583 | for (i = 0; i < nents; i++) { | ||
579 | unsigned long vaddr = prom_trans[i].virt; | 584 | unsigned long vaddr = prom_trans[i].virt; |
580 | unsigned long size = prom_trans[i].size; | 585 | unsigned long size = prom_trans[i].size; |
581 | 586 | ||
@@ -601,6 +606,20 @@ static void inherit_prom_mappings(void) | |||
601 | } | 606 | } |
602 | } | 607 | } |
603 | } | 608 | } |
609 | } | ||
610 | |||
611 | static void inherit_prom_mappings(void) | ||
612 | { | ||
613 | int n; | ||
614 | |||
615 | n = read_obp_translations(); | ||
616 | build_obp_pgtable(n); | ||
617 | |||
618 | /* Now fixup OBP's idea about where we really are mapped. */ | ||
619 | prom_printf("Remapping the kernel... "); | ||
620 | remap_kernel(); | ||
621 | |||
622 | readjust_prom_translations(); | ||
604 | 623 | ||
605 | prom_printf("done.\n"); | 624 | prom_printf("done.\n"); |
606 | 625 | ||