diff options
Diffstat (limited to 'arch/sparc64/mm/init.c')
-rw-r--r-- | arch/sparc64/mm/init.c | 295 |
1 files changed, 10 insertions, 285 deletions
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 1e8a5a33639d..f4d22ccb4cf0 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c | |||
@@ -555,294 +555,12 @@ static void __init inherit_prom_mappings(void) | |||
555 | prom_printf("done.\n"); | 555 | prom_printf("done.\n"); |
556 | } | 556 | } |
557 | 557 | ||
558 | static int prom_ditlb_set; | ||
559 | struct prom_tlb_entry { | ||
560 | int tlb_ent; | ||
561 | unsigned long tlb_tag; | ||
562 | unsigned long tlb_data; | ||
563 | }; | ||
564 | struct prom_tlb_entry prom_itlb[16], prom_dtlb[16]; | ||
565 | |||
566 | void prom_world(int enter) | 558 | void prom_world(int enter) |
567 | { | 559 | { |
568 | unsigned long pstate; | ||
569 | int i; | ||
570 | |||
571 | if (!enter) | 560 | if (!enter) |
572 | set_fs((mm_segment_t) { get_thread_current_ds() }); | 561 | set_fs((mm_segment_t) { get_thread_current_ds() }); |
573 | 562 | ||
574 | if (!prom_ditlb_set) | 563 | __asm__ __volatile__("flushw"); |
575 | return; | ||
576 | |||
577 | /* Make sure the following runs atomically. */ | ||
578 | __asm__ __volatile__("flushw\n\t" | ||
579 | "rdpr %%pstate, %0\n\t" | ||
580 | "wrpr %0, %1, %%pstate" | ||
581 | : "=r" (pstate) | ||
582 | : "i" (PSTATE_IE)); | ||
583 | |||
584 | if (enter) { | ||
585 | /* Install PROM world. */ | ||
586 | for (i = 0; i < 16; i++) { | ||
587 | if (prom_dtlb[i].tlb_ent != -1) { | ||
588 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
589 | "membar #Sync" | ||
590 | : : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS), | ||
591 | "i" (ASI_DMMU)); | ||
592 | if (tlb_type == spitfire) | ||
593 | spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, | ||
594 | prom_dtlb[i].tlb_data); | ||
595 | else if (tlb_type == cheetah || tlb_type == cheetah_plus) | ||
596 | cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent, | ||
597 | prom_dtlb[i].tlb_data); | ||
598 | } | ||
599 | if (prom_itlb[i].tlb_ent != -1) { | ||
600 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
601 | "membar #Sync" | ||
602 | : : "r" (prom_itlb[i].tlb_tag), | ||
603 | "r" (TLB_TAG_ACCESS), | ||
604 | "i" (ASI_IMMU)); | ||
605 | if (tlb_type == spitfire) | ||
606 | spitfire_put_itlb_data(prom_itlb[i].tlb_ent, | ||
607 | prom_itlb[i].tlb_data); | ||
608 | else if (tlb_type == cheetah || tlb_type == cheetah_plus) | ||
609 | cheetah_put_litlb_data(prom_itlb[i].tlb_ent, | ||
610 | prom_itlb[i].tlb_data); | ||
611 | } | ||
612 | } | ||
613 | } else { | ||
614 | for (i = 0; i < 16; i++) { | ||
615 | if (prom_dtlb[i].tlb_ent != -1) { | ||
616 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
617 | "membar #Sync" | ||
618 | : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); | ||
619 | if (tlb_type == spitfire) | ||
620 | spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, 0x0UL); | ||
621 | else | ||
622 | cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent, 0x0UL); | ||
623 | } | ||
624 | if (prom_itlb[i].tlb_ent != -1) { | ||
625 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
626 | "membar #Sync" | ||
627 | : : "r" (TLB_TAG_ACCESS), | ||
628 | "i" (ASI_IMMU)); | ||
629 | if (tlb_type == spitfire) | ||
630 | spitfire_put_itlb_data(prom_itlb[i].tlb_ent, 0x0UL); | ||
631 | else | ||
632 | cheetah_put_litlb_data(prom_itlb[i].tlb_ent, 0x0UL); | ||
633 | } | ||
634 | } | ||
635 | } | ||
636 | __asm__ __volatile__("wrpr %0, 0, %%pstate" | ||
637 | : : "r" (pstate)); | ||
638 | } | ||
639 | |||
640 | void inherit_locked_prom_mappings(int save_p) | ||
641 | { | ||
642 | int i; | ||
643 | int dtlb_seen = 0; | ||
644 | int itlb_seen = 0; | ||
645 | |||
646 | /* Fucking losing PROM has more mappings in the TLB, but | ||
647 | * it (conveniently) fails to mention any of these in the | ||
648 | * translations property. The only ones that matter are | ||
649 | * the locked PROM tlb entries, so we impose the following | ||
650 | * irrecovable rule on the PROM, it is allowed 8 locked | ||
651 | * entries in the ITLB and 8 in the DTLB. | ||
652 | * | ||
653 | * Supposedly the upper 16GB of the address space is | ||
654 | * reserved for OBP, BUT I WISH THIS WAS DOCUMENTED | ||
655 | * SOMEWHERE!!!!!!!!!!!!!!!!! Furthermore the entire interface | ||
656 | * used between the client program and the firmware on sun5 | ||
657 | * systems to coordinate mmu mappings is also COMPLETELY | ||
658 | * UNDOCUMENTED!!!!!! Thanks S(t)un! | ||
659 | */ | ||
660 | if (save_p) { | ||
661 | for (i = 0; i < 16; i++) { | ||
662 | prom_itlb[i].tlb_ent = -1; | ||
663 | prom_dtlb[i].tlb_ent = -1; | ||
664 | } | ||
665 | } | ||
666 | if (tlb_type == spitfire) { | ||
667 | int high = sparc64_highest_unlocked_tlb_ent; | ||
668 | for (i = 0; i <= high; i++) { | ||
669 | unsigned long data; | ||
670 | |||
671 | /* Spitfire Errata #32 workaround */ | ||
672 | /* NOTE: Always runs on spitfire, so no cheetah+ | ||
673 | * page size encodings. | ||
674 | */ | ||
675 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
676 | "flush %%g6" | ||
677 | : /* No outputs */ | ||
678 | : "r" (0), | ||
679 | "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | ||
680 | |||
681 | data = spitfire_get_dtlb_data(i); | ||
682 | if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { | ||
683 | unsigned long tag; | ||
684 | |||
685 | /* Spitfire Errata #32 workaround */ | ||
686 | /* NOTE: Always runs on spitfire, so no | ||
687 | * cheetah+ page size encodings. | ||
688 | */ | ||
689 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
690 | "flush %%g6" | ||
691 | : /* No outputs */ | ||
692 | : "r" (0), | ||
693 | "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | ||
694 | |||
695 | tag = spitfire_get_dtlb_tag(i); | ||
696 | if (save_p) { | ||
697 | prom_dtlb[dtlb_seen].tlb_ent = i; | ||
698 | prom_dtlb[dtlb_seen].tlb_tag = tag; | ||
699 | prom_dtlb[dtlb_seen].tlb_data = data; | ||
700 | } | ||
701 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
702 | "membar #Sync" | ||
703 | : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); | ||
704 | spitfire_put_dtlb_data(i, 0x0UL); | ||
705 | |||
706 | dtlb_seen++; | ||
707 | if (dtlb_seen > 15) | ||
708 | break; | ||
709 | } | ||
710 | } | ||
711 | |||
712 | for (i = 0; i < high; i++) { | ||
713 | unsigned long data; | ||
714 | |||
715 | /* Spitfire Errata #32 workaround */ | ||
716 | /* NOTE: Always runs on spitfire, so no | ||
717 | * cheetah+ page size encodings. | ||
718 | */ | ||
719 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
720 | "flush %%g6" | ||
721 | : /* No outputs */ | ||
722 | : "r" (0), | ||
723 | "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | ||
724 | |||
725 | data = spitfire_get_itlb_data(i); | ||
726 | if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { | ||
727 | unsigned long tag; | ||
728 | |||
729 | /* Spitfire Errata #32 workaround */ | ||
730 | /* NOTE: Always runs on spitfire, so no | ||
731 | * cheetah+ page size encodings. | ||
732 | */ | ||
733 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
734 | "flush %%g6" | ||
735 | : /* No outputs */ | ||
736 | : "r" (0), | ||
737 | "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | ||
738 | |||
739 | tag = spitfire_get_itlb_tag(i); | ||
740 | if (save_p) { | ||
741 | prom_itlb[itlb_seen].tlb_ent = i; | ||
742 | prom_itlb[itlb_seen].tlb_tag = tag; | ||
743 | prom_itlb[itlb_seen].tlb_data = data; | ||
744 | } | ||
745 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
746 | "membar #Sync" | ||
747 | : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); | ||
748 | spitfire_put_itlb_data(i, 0x0UL); | ||
749 | |||
750 | itlb_seen++; | ||
751 | if (itlb_seen > 15) | ||
752 | break; | ||
753 | } | ||
754 | } | ||
755 | } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { | ||
756 | int high = sparc64_highest_unlocked_tlb_ent; | ||
757 | |||
758 | for (i = 0; i <= high; i++) { | ||
759 | unsigned long data; | ||
760 | |||
761 | data = cheetah_get_ldtlb_data(i); | ||
762 | if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { | ||
763 | unsigned long tag; | ||
764 | |||
765 | tag = cheetah_get_ldtlb_tag(i); | ||
766 | if (save_p) { | ||
767 | prom_dtlb[dtlb_seen].tlb_ent = i; | ||
768 | prom_dtlb[dtlb_seen].tlb_tag = tag; | ||
769 | prom_dtlb[dtlb_seen].tlb_data = data; | ||
770 | } | ||
771 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
772 | "membar #Sync" | ||
773 | : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); | ||
774 | cheetah_put_ldtlb_data(i, 0x0UL); | ||
775 | |||
776 | dtlb_seen++; | ||
777 | if (dtlb_seen > 15) | ||
778 | break; | ||
779 | } | ||
780 | } | ||
781 | |||
782 | for (i = 0; i < high; i++) { | ||
783 | unsigned long data; | ||
784 | |||
785 | data = cheetah_get_litlb_data(i); | ||
786 | if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { | ||
787 | unsigned long tag; | ||
788 | |||
789 | tag = cheetah_get_litlb_tag(i); | ||
790 | if (save_p) { | ||
791 | prom_itlb[itlb_seen].tlb_ent = i; | ||
792 | prom_itlb[itlb_seen].tlb_tag = tag; | ||
793 | prom_itlb[itlb_seen].tlb_data = data; | ||
794 | } | ||
795 | __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" | ||
796 | "membar #Sync" | ||
797 | : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); | ||
798 | cheetah_put_litlb_data(i, 0x0UL); | ||
799 | |||
800 | itlb_seen++; | ||
801 | if (itlb_seen > 15) | ||
802 | break; | ||
803 | } | ||
804 | } | ||
805 | } else { | ||
806 | /* Implement me :-) */ | ||
807 | BUG(); | ||
808 | } | ||
809 | if (save_p) | ||
810 | prom_ditlb_set = 1; | ||
811 | } | ||
812 | |||
813 | /* Give PROM back his world, done during reboots... */ | ||
814 | void prom_reload_locked(void) | ||
815 | { | ||
816 | int i; | ||
817 | |||
818 | for (i = 0; i < 16; i++) { | ||
819 | if (prom_dtlb[i].tlb_ent != -1) { | ||
820 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
821 | "membar #Sync" | ||
822 | : : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS), | ||
823 | "i" (ASI_DMMU)); | ||
824 | if (tlb_type == spitfire) | ||
825 | spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, | ||
826 | prom_dtlb[i].tlb_data); | ||
827 | else if (tlb_type == cheetah || tlb_type == cheetah_plus) | ||
828 | cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent, | ||
829 | prom_dtlb[i].tlb_data); | ||
830 | } | ||
831 | |||
832 | if (prom_itlb[i].tlb_ent != -1) { | ||
833 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
834 | "membar #Sync" | ||
835 | : : "r" (prom_itlb[i].tlb_tag), | ||
836 | "r" (TLB_TAG_ACCESS), | ||
837 | "i" (ASI_IMMU)); | ||
838 | if (tlb_type == spitfire) | ||
839 | spitfire_put_itlb_data(prom_itlb[i].tlb_ent, | ||
840 | prom_itlb[i].tlb_data); | ||
841 | else | ||
842 | cheetah_put_litlb_data(prom_itlb[i].tlb_ent, | ||
843 | prom_itlb[i].tlb_data); | ||
844 | } | ||
845 | } | ||
846 | } | 564 | } |
847 | 565 | ||
848 | #ifdef DCACHE_ALIASING_POSSIBLE | 566 | #ifdef DCACHE_ALIASING_POSSIBLE |
@@ -1066,6 +784,15 @@ void sparc_ultra_dump_dtlb(void) | |||
1066 | } | 784 | } |
1067 | } | 785 | } |
1068 | 786 | ||
787 | static inline void spitfire_errata32(void) | ||
788 | { | ||
789 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
790 | "flush %%g6" | ||
791 | : /* No outputs */ | ||
792 | : "r" (0), | ||
793 | "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); | ||
794 | } | ||
795 | |||
1069 | extern unsigned long cmdline_memory_size; | 796 | extern unsigned long cmdline_memory_size; |
1070 | 797 | ||
1071 | unsigned long __init bootmem_init(unsigned long *pages_avail) | 798 | unsigned long __init bootmem_init(unsigned long *pages_avail) |
@@ -1375,8 +1102,6 @@ void __init paging_init(void) | |||
1375 | setup_tba(this_is_starfire); | 1102 | setup_tba(this_is_starfire); |
1376 | } | 1103 | } |
1377 | 1104 | ||
1378 | inherit_locked_prom_mappings(1); | ||
1379 | |||
1380 | __flush_tlb_all(); | 1105 | __flush_tlb_all(); |
1381 | 1106 | ||
1382 | /* Setup bootmem... */ | 1107 | /* Setup bootmem... */ |