diff options
author | Dave Kleikamp <shaggy@linux.vnet.ibm.com> | 2010-03-05 05:43:07 -0500 |
---|---|---|
committer | Josh Boyer <jwboyer@linux.vnet.ibm.com> | 2010-05-05 08:04:36 -0400 |
commit | 795033c344d88dc6aa5106d0cc358656f29bd722 (patch) | |
tree | 0dd6eebb3626a093bd1e20af09c0d25925397788 /arch | |
parent | 471c70ff39809af783c7718defe574a9ba81dd26 (diff) |
powerpc/44x: break out cpu init code into stand-alone function
The 47x platform supports multiple cores and shares code with 44x.
Break out code that is common for initializing the primary and secondary
cpus into a function which can be called for both.
Signed-off-by: Dave Kleikamp <shaggy@linux.vnet.ibm.com>
Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/kernel/head_44x.S | 330 |
1 files changed, 171 insertions, 159 deletions
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index 711368b993f2..39be049a7850 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S | |||
@@ -69,165 +69,7 @@ _ENTRY(_start); | |||
69 | mr r27,r7 | 69 | mr r27,r7 |
70 | li r24,0 /* CPU number */ | 70 | li r24,0 /* CPU number */ |
71 | 71 | ||
72 | /* | 72 | bl init_cpu_state |
73 | * In case the firmware didn't do it, we apply some workarounds | ||
74 | * that are good for all 440 core variants here | ||
75 | */ | ||
76 | mfspr r3,SPRN_CCR0 | ||
77 | rlwinm r3,r3,0,0,27 /* disable icache prefetch */ | ||
78 | isync | ||
79 | mtspr SPRN_CCR0,r3 | ||
80 | isync | ||
81 | sync | ||
82 | |||
83 | /* | ||
84 | * Set up the initial MMU state | ||
85 | * | ||
86 | * We are still executing code at the virtual address | ||
87 | * mappings set by the firmware for the base of RAM. | ||
88 | * | ||
89 | * We first invalidate all TLB entries but the one | ||
90 | * we are running from. We then load the KERNELBASE | ||
91 | * mappings so we can begin to use kernel addresses | ||
92 | * natively and so the interrupt vector locations are | ||
93 | * permanently pinned (necessary since Book E | ||
94 | * implementations always have translation enabled). | ||
95 | * | ||
96 | * TODO: Use the known TLB entry we are running from to | ||
97 | * determine which physical region we are located | ||
98 | * in. This can be used to determine where in RAM | ||
99 | * (on a shared CPU system) or PCI memory space | ||
100 | * (on a DRAMless system) we are located. | ||
101 | * For now, we assume a perfect world which means | ||
102 | * we are located at the base of DRAM (physical 0). | ||
103 | */ | ||
104 | |||
105 | /* | ||
106 | * Search TLB for entry that we are currently using. | ||
107 | * Invalidate all entries but the one we are using. | ||
108 | */ | ||
109 | /* Load our current PID->MMUCR TID and MSR IS->MMUCR STS */ | ||
110 | mfspr r3,SPRN_PID /* Get PID */ | ||
111 | mfmsr r4 /* Get MSR */ | ||
112 | andi. r4,r4,MSR_IS@l /* TS=1? */ | ||
113 | beq wmmucr /* If not, leave STS=0 */ | ||
114 | oris r3,r3,PPC44x_MMUCR_STS@h /* Set STS=1 */ | ||
115 | wmmucr: mtspr SPRN_MMUCR,r3 /* Put MMUCR */ | ||
116 | sync | ||
117 | |||
118 | bl invstr /* Find our address */ | ||
119 | invstr: mflr r5 /* Make it accessible */ | ||
120 | tlbsx r23,0,r5 /* Find entry we are in */ | ||
121 | li r4,0 /* Start at TLB entry 0 */ | ||
122 | li r3,0 /* Set PAGEID inval value */ | ||
123 | 1: cmpw r23,r4 /* Is this our entry? */ | ||
124 | beq skpinv /* If so, skip the inval */ | ||
125 | tlbwe r3,r4,PPC44x_TLB_PAGEID /* If not, inval the entry */ | ||
126 | skpinv: addi r4,r4,1 /* Increment */ | ||
127 | cmpwi r4,64 /* Are we done? */ | ||
128 | bne 1b /* If not, repeat */ | ||
129 | isync /* If so, context change */ | ||
130 | |||
131 | /* | ||
132 | * Configure and load pinned entry into TLB slot 63. | ||
133 | */ | ||
134 | |||
135 | lis r3,PAGE_OFFSET@h | ||
136 | ori r3,r3,PAGE_OFFSET@l | ||
137 | |||
138 | /* Kernel is at the base of RAM */ | ||
139 | li r4, 0 /* Load the kernel physical address */ | ||
140 | |||
141 | /* Load the kernel PID = 0 */ | ||
142 | li r0,0 | ||
143 | mtspr SPRN_PID,r0 | ||
144 | sync | ||
145 | |||
146 | /* Initialize MMUCR */ | ||
147 | li r5,0 | ||
148 | mtspr SPRN_MMUCR,r5 | ||
149 | sync | ||
150 | |||
151 | /* pageid fields */ | ||
152 | clrrwi r3,r3,10 /* Mask off the effective page number */ | ||
153 | ori r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_256M | ||
154 | |||
155 | /* xlat fields */ | ||
156 | clrrwi r4,r4,10 /* Mask off the real page number */ | ||
157 | /* ERPN is 0 for first 4GB page */ | ||
158 | |||
159 | /* attrib fields */ | ||
160 | /* Added guarded bit to protect against speculative loads/stores */ | ||
161 | li r5,0 | ||
162 | ori r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G) | ||
163 | |||
164 | li r0,63 /* TLB slot 63 */ | ||
165 | |||
166 | tlbwe r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */ | ||
167 | tlbwe r4,r0,PPC44x_TLB_XLAT /* Load the translation fields */ | ||
168 | tlbwe r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */ | ||
169 | |||
170 | /* Force context change */ | ||
171 | mfmsr r0 | ||
172 | mtspr SPRN_SRR1, r0 | ||
173 | lis r0,3f@h | ||
174 | ori r0,r0,3f@l | ||
175 | mtspr SPRN_SRR0,r0 | ||
176 | sync | ||
177 | rfi | ||
178 | |||
179 | /* If necessary, invalidate original entry we used */ | ||
180 | 3: cmpwi r23,63 | ||
181 | beq 4f | ||
182 | li r6,0 | ||
183 | tlbwe r6,r23,PPC44x_TLB_PAGEID | ||
184 | isync | ||
185 | |||
186 | 4: | ||
187 | #ifdef CONFIG_PPC_EARLY_DEBUG_44x | ||
188 | /* Add UART mapping for early debug. */ | ||
189 | |||
190 | /* pageid fields */ | ||
191 | lis r3,PPC44x_EARLY_DEBUG_VIRTADDR@h | ||
192 | ori r3,r3,PPC44x_TLB_VALID|PPC44x_TLB_TS|PPC44x_TLB_64K | ||
193 | |||
194 | /* xlat fields */ | ||
195 | lis r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW@h | ||
196 | ori r4,r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH | ||
197 | |||
198 | /* attrib fields */ | ||
199 | li r5,(PPC44x_TLB_SW|PPC44x_TLB_SR|PPC44x_TLB_I|PPC44x_TLB_G) | ||
200 | li r0,62 /* TLB slot 0 */ | ||
201 | |||
202 | tlbwe r3,r0,PPC44x_TLB_PAGEID | ||
203 | tlbwe r4,r0,PPC44x_TLB_XLAT | ||
204 | tlbwe r5,r0,PPC44x_TLB_ATTRIB | ||
205 | |||
206 | /* Force context change */ | ||
207 | isync | ||
208 | #endif /* CONFIG_PPC_EARLY_DEBUG_44x */ | ||
209 | |||
210 | /* Establish the interrupt vector offsets */ | ||
211 | SET_IVOR(0, CriticalInput); | ||
212 | SET_IVOR(1, MachineCheck); | ||
213 | SET_IVOR(2, DataStorage); | ||
214 | SET_IVOR(3, InstructionStorage); | ||
215 | SET_IVOR(4, ExternalInput); | ||
216 | SET_IVOR(5, Alignment); | ||
217 | SET_IVOR(6, Program); | ||
218 | SET_IVOR(7, FloatingPointUnavailable); | ||
219 | SET_IVOR(8, SystemCall); | ||
220 | SET_IVOR(9, AuxillaryProcessorUnavailable); | ||
221 | SET_IVOR(10, Decrementer); | ||
222 | SET_IVOR(11, FixedIntervalTimer); | ||
223 | SET_IVOR(12, WatchdogTimer); | ||
224 | SET_IVOR(13, DataTLBError); | ||
225 | SET_IVOR(14, InstructionTLBError); | ||
226 | SET_IVOR(15, DebugCrit); | ||
227 | |||
228 | /* Establish the interrupt vector base */ | ||
229 | lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ | ||
230 | mtspr SPRN_IVPR,r4 | ||
231 | 73 | ||
232 | /* | 74 | /* |
233 | * This is where the main kernel code starts. | 75 | * This is where the main kernel code starts. |
@@ -647,6 +489,176 @@ _GLOBAL(set_context) | |||
647 | blr | 489 | blr |
648 | 490 | ||
649 | /* | 491 | /* |
492 | * Init CPU state. This is called at boot time or for secondary CPUs | ||
493 | * to setup initial TLB entries, setup IVORs, etc... | ||
494 | */ | ||
495 | _GLOBAL(init_cpu_state) | ||
496 | mflr r22 | ||
497 | /* | ||
498 | * In case the firmware didn't do it, we apply some workarounds | ||
499 | * that are good for all 440 core variants here | ||
500 | */ | ||
501 | mfspr r3,SPRN_CCR0 | ||
502 | rlwinm r3,r3,0,0,27 /* disable icache prefetch */ | ||
503 | isync | ||
504 | mtspr SPRN_CCR0,r3 | ||
505 | isync | ||
506 | sync | ||
507 | |||
508 | /* | ||
509 | * Set up the initial MMU state | ||
510 | * | ||
511 | * We are still executing code at the virtual address | ||
512 | * mappings set by the firmware for the base of RAM. | ||
513 | * | ||
514 | * We first invalidate all TLB entries but the one | ||
515 | * we are running from. We then load the KERNELBASE | ||
516 | * mappings so we can begin to use kernel addresses | ||
517 | * natively and so the interrupt vector locations are | ||
518 | * permanently pinned (necessary since Book E | ||
519 | * implementations always have translation enabled). | ||
520 | * | ||
521 | * TODO: Use the known TLB entry we are running from to | ||
522 | * determine which physical region we are located | ||
523 | * in. This can be used to determine where in RAM | ||
524 | * (on a shared CPU system) or PCI memory space | ||
525 | * (on a DRAMless system) we are located. | ||
526 | * For now, we assume a perfect world which means | ||
527 | * we are located at the base of DRAM (physical 0). | ||
528 | */ | ||
529 | |||
530 | /* | ||
531 | * Search TLB for entry that we are currently using. | ||
532 | * Invalidate all entries but the one we are using. | ||
533 | */ | ||
534 | /* Load our current PID->MMUCR TID and MSR IS->MMUCR STS */ | ||
535 | mfspr r3,SPRN_PID /* Get PID */ | ||
536 | mfmsr r4 /* Get MSR */ | ||
537 | andi. r4,r4,MSR_IS@l /* TS=1? */ | ||
538 | beq wmmucr /* If not, leave STS=0 */ | ||
539 | oris r3,r3,PPC44x_MMUCR_STS@h /* Set STS=1 */ | ||
540 | wmmucr: mtspr SPRN_MMUCR,r3 /* Put MMUCR */ | ||
541 | sync | ||
542 | |||
543 | bl invstr /* Find our address */ | ||
544 | invstr: mflr r5 /* Make it accessible */ | ||
545 | tlbsx r23,0,r5 /* Find entry we are in */ | ||
546 | li r4,0 /* Start at TLB entry 0 */ | ||
547 | li r3,0 /* Set PAGEID inval value */ | ||
548 | 1: cmpw r23,r4 /* Is this our entry? */ | ||
549 | beq skpinv /* If so, skip the inval */ | ||
550 | tlbwe r3,r4,PPC44x_TLB_PAGEID /* If not, inval the entry */ | ||
551 | skpinv: addi r4,r4,1 /* Increment */ | ||
552 | cmpwi r4,64 /* Are we done? */ | ||
553 | bne 1b /* If not, repeat */ | ||
554 | isync /* If so, context change */ | ||
555 | |||
556 | /* | ||
557 | * Configure and load pinned entry into TLB slot 63. | ||
558 | */ | ||
559 | |||
560 | lis r3,PAGE_OFFSET@h | ||
561 | ori r3,r3,PAGE_OFFSET@l | ||
562 | |||
563 | /* Kernel is at the base of RAM */ | ||
564 | li r4, 0 /* Load the kernel physical address */ | ||
565 | |||
566 | /* Load the kernel PID = 0 */ | ||
567 | li r0,0 | ||
568 | mtspr SPRN_PID,r0 | ||
569 | sync | ||
570 | |||
571 | /* Initialize MMUCR */ | ||
572 | li r5,0 | ||
573 | mtspr SPRN_MMUCR,r5 | ||
574 | sync | ||
575 | |||
576 | /* pageid fields */ | ||
577 | clrrwi r3,r3,10 /* Mask off the effective page number */ | ||
578 | ori r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_256M | ||
579 | |||
580 | /* xlat fields */ | ||
581 | clrrwi r4,r4,10 /* Mask off the real page number */ | ||
582 | /* ERPN is 0 for first 4GB page */ | ||
583 | |||
584 | /* attrib fields */ | ||
585 | /* Added guarded bit to protect against speculative loads/stores */ | ||
586 | li r5,0 | ||
587 | ori r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G) | ||
588 | |||
589 | li r0,63 /* TLB slot 63 */ | ||
590 | |||
591 | tlbwe r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */ | ||
592 | tlbwe r4,r0,PPC44x_TLB_XLAT /* Load the translation fields */ | ||
593 | tlbwe r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */ | ||
594 | |||
595 | /* Force context change */ | ||
596 | mfmsr r0 | ||
597 | mtspr SPRN_SRR1, r0 | ||
598 | lis r0,3f@h | ||
599 | ori r0,r0,3f@l | ||
600 | mtspr SPRN_SRR0,r0 | ||
601 | sync | ||
602 | rfi | ||
603 | |||
604 | /* If necessary, invalidate original entry we used */ | ||
605 | 3: cmpwi r23,63 | ||
606 | beq 4f | ||
607 | li r6,0 | ||
608 | tlbwe r6,r23,PPC44x_TLB_PAGEID | ||
609 | isync | ||
610 | |||
611 | 4: | ||
612 | #ifdef CONFIG_PPC_EARLY_DEBUG_44x | ||
613 | /* Add UART mapping for early debug. */ | ||
614 | |||
615 | /* pageid fields */ | ||
616 | lis r3,PPC44x_EARLY_DEBUG_VIRTADDR@h | ||
617 | ori r3,r3,PPC44x_TLB_VALID|PPC44x_TLB_TS|PPC44x_TLB_64K | ||
618 | |||
619 | /* xlat fields */ | ||
620 | lis r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW@h | ||
621 | ori r4,r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH | ||
622 | |||
623 | /* attrib fields */ | ||
624 | li r5,(PPC44x_TLB_SW|PPC44x_TLB_SR|PPC44x_TLB_I|PPC44x_TLB_G) | ||
625 | li r0,62 /* TLB slot 0 */ | ||
626 | |||
627 | tlbwe r3,r0,PPC44x_TLB_PAGEID | ||
628 | tlbwe r4,r0,PPC44x_TLB_XLAT | ||
629 | tlbwe r5,r0,PPC44x_TLB_ATTRIB | ||
630 | |||
631 | /* Force context change */ | ||
632 | isync | ||
633 | #endif /* CONFIG_PPC_EARLY_DEBUG_44x */ | ||
634 | |||
635 | /* Establish the interrupt vector offsets */ | ||
636 | SET_IVOR(0, CriticalInput); | ||
637 | SET_IVOR(1, MachineCheck); | ||
638 | SET_IVOR(2, DataStorage); | ||
639 | SET_IVOR(3, InstructionStorage); | ||
640 | SET_IVOR(4, ExternalInput); | ||
641 | SET_IVOR(5, Alignment); | ||
642 | SET_IVOR(6, Program); | ||
643 | SET_IVOR(7, FloatingPointUnavailable); | ||
644 | SET_IVOR(8, SystemCall); | ||
645 | SET_IVOR(9, AuxillaryProcessorUnavailable); | ||
646 | SET_IVOR(10, Decrementer); | ||
647 | SET_IVOR(11, FixedIntervalTimer); | ||
648 | SET_IVOR(12, WatchdogTimer); | ||
649 | SET_IVOR(13, DataTLBError); | ||
650 | SET_IVOR(14, InstructionTLBError); | ||
651 | SET_IVOR(15, DebugCrit); | ||
652 | |||
653 | /* Establish the interrupt vector base */ | ||
654 | lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ | ||
655 | mtspr SPRN_IVPR,r4 | ||
656 | |||
657 | addis r22,r22,KERNELBASE@h | ||
658 | mtlr r22 | ||
659 | blr | ||
660 | |||
661 | /* | ||
650 | * We put a few things here that have to be page-aligned. This stuff | 662 | * We put a few things here that have to be page-aligned. This stuff |
651 | * goes at the beginning of the data segment, which is page-aligned. | 663 | * goes at the beginning of the data segment, which is page-aligned. |
652 | */ | 664 | */ |