diff options
author | Michael Ellerman <michael@ellerman.id.au> | 2005-12-05 16:49:00 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-01-08 22:52:25 -0500 |
commit | 758438a7b8da593c9116e95cc7fdff6e9e0b0c40 (patch) | |
tree | 5343d8ec40016294902278c27a9f5647bd061890 | |
parent | 0cc4746cadda16826a1b3214c042a2f75445b71c (diff) |
[PATCH] powerpc: Fixups for kernel linked at 32 MB
There's a few places where we need to fix things up for the kernel to work
if it's linked at 32MB:
- platforms/powermac/smp.c
To start secondary cpus on pmac we patch the reset vector, which is fine.
Except if we're above 32MB we don't have enough bits for an absolute branch,
it needs to relative.
- kernel/head_64.s
- A few branches in the cpu hold code need to load the full target address
and do a bctr.
- after_prom_start needs to load PHYSICAL_START as the dest address, not 0.
- The exception prolog needs to load the low word of the target adddress,
not just the low halfword.
- Fixup handling of the initial stab address.
- kernel/setup_64.c
smp_release_cpus() needs to write 1 to the spinloop flag near 0, not 32 MB.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/kernel/head_64.S | 30 | ||||
-rw-r--r-- | arch/powerpc/kernel/setup_64.c | 5 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/smp.c | 16 | ||||
-rw-r--r-- | include/asm-powerpc/mmu.h | 3 |
4 files changed, 37 insertions, 17 deletions
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index f4194f5fd2e5..0763dd632b78 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S | |||
@@ -154,11 +154,15 @@ _GLOBAL(__secondary_hold) | |||
154 | bne 100b | 154 | bne 100b |
155 | 155 | ||
156 | #ifdef CONFIG_HMT | 156 | #ifdef CONFIG_HMT |
157 | b .hmt_init | 157 | LOADADDR(r4, .hmt_init) |
158 | mtctr r4 | ||
159 | bctr | ||
158 | #else | 160 | #else |
159 | #ifdef CONFIG_SMP | 161 | #ifdef CONFIG_SMP |
162 | LOADADDR(r4, .pSeries_secondary_smp_init) | ||
163 | mtctr r4 | ||
160 | mr r3,r24 | 164 | mr r3,r24 |
161 | b .pSeries_secondary_smp_init | 165 | bctr |
162 | #else | 166 | #else |
163 | BUG_OPCODE | 167 | BUG_OPCODE |
164 | #endif | 168 | #endif |
@@ -200,6 +204,20 @@ exception_marker: | |||
200 | #define EX_R3 64 | 204 | #define EX_R3 64 |
201 | #define EX_LR 72 | 205 | #define EX_LR 72 |
202 | 206 | ||
207 | /* | ||
208 | * We're short on space and time in the exception prolog, so we can't use | ||
209 | * the normal LOADADDR macro. Normally we just need the low halfword of the | ||
210 | * address, but for Kdump we need the whole low word. | ||
211 | */ | ||
212 | #ifdef CONFIG_CRASH_DUMP | ||
213 | #define LOAD_HANDLER(reg, label) \ | ||
214 | oris reg,reg,(label)@h; /* virt addr of handler ... */ \ | ||
215 | ori reg,reg,(label)@l; /* .. and the rest */ | ||
216 | #else | ||
217 | #define LOAD_HANDLER(reg, label) \ | ||
218 | ori reg,reg,(label)@l; /* virt addr of handler ... */ | ||
219 | #endif | ||
220 | |||
203 | #define EXCEPTION_PROLOG_PSERIES(area, label) \ | 221 | #define EXCEPTION_PROLOG_PSERIES(area, label) \ |
204 | mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ | 222 | mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ |
205 | std r9,area+EX_R9(r13); /* save r9 - r12 */ \ | 223 | std r9,area+EX_R9(r13); /* save r9 - r12 */ \ |
@@ -212,7 +230,7 @@ exception_marker: | |||
212 | clrrdi r12,r13,32; /* get high part of &label */ \ | 230 | clrrdi r12,r13,32; /* get high part of &label */ \ |
213 | mfmsr r10; \ | 231 | mfmsr r10; \ |
214 | mfspr r11,SPRN_SRR0; /* save SRR0 */ \ | 232 | mfspr r11,SPRN_SRR0; /* save SRR0 */ \ |
215 | ori r12,r12,(label)@l; /* virt addr of handler */ \ | 233 | LOAD_HANDLER(r12,label) \ |
216 | ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \ | 234 | ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \ |
217 | mtspr SPRN_SRR0,r12; \ | 235 | mtspr SPRN_SRR0,r12; \ |
218 | mfspr r12,SPRN_SRR1; /* and SRR1 */ \ | 236 | mfspr r12,SPRN_SRR1; /* and SRR1 */ \ |
@@ -1348,7 +1366,7 @@ _GLOBAL(do_stab_bolted) | |||
1348 | * fixed address (the linker can't compute (u64)&initial_stab >> | 1366 | * fixed address (the linker can't compute (u64)&initial_stab >> |
1349 | * PAGE_SHIFT). | 1367 | * PAGE_SHIFT). |
1350 | */ | 1368 | */ |
1351 | . = STAB0_PHYS_ADDR /* 0x6000 */ | 1369 | . = STAB0_OFFSET /* 0x6000 */ |
1352 | .globl initial_stab | 1370 | .globl initial_stab |
1353 | initial_stab: | 1371 | initial_stab: |
1354 | .space 4096 | 1372 | .space 4096 |
@@ -1553,7 +1571,7 @@ _STATIC(__boot_from_prom) | |||
1553 | _STATIC(__after_prom_start) | 1571 | _STATIC(__after_prom_start) |
1554 | 1572 | ||
1555 | /* | 1573 | /* |
1556 | * We need to run with __start at physical address 0. | 1574 | * We need to run with __start at physical address PHYSICAL_START. |
1557 | * This will leave some code in the first 256B of | 1575 | * This will leave some code in the first 256B of |
1558 | * real memory, which are reserved for software use. | 1576 | * real memory, which are reserved for software use. |
1559 | * The remainder of the first page is loaded with the fixed | 1577 | * The remainder of the first page is loaded with the fixed |
@@ -1568,7 +1586,7 @@ _STATIC(__after_prom_start) | |||
1568 | mr r26,r3 | 1586 | mr r26,r3 |
1569 | SET_REG_TO_CONST(r27,KERNELBASE) | 1587 | SET_REG_TO_CONST(r27,KERNELBASE) |
1570 | 1588 | ||
1571 | li r3,0 /* target addr */ | 1589 | LOADADDR(r3, PHYSICAL_START) /* target addr */ |
1572 | 1590 | ||
1573 | // XXX FIXME: Use phys returned by OF (r30) | 1591 | // XXX FIXME: Use phys returned by OF (r30) |
1574 | add r4,r27,r26 /* source addr */ | 1592 | add r4,r27,r26 /* source addr */ |
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index e67120e34652..419e0b974b96 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
@@ -322,6 +322,7 @@ void early_setup_secondary(void) | |||
322 | void smp_release_cpus(void) | 322 | void smp_release_cpus(void) |
323 | { | 323 | { |
324 | extern unsigned long __secondary_hold_spinloop; | 324 | extern unsigned long __secondary_hold_spinloop; |
325 | unsigned long *ptr; | ||
325 | 326 | ||
326 | DBG(" -> smp_release_cpus()\n"); | 327 | DBG(" -> smp_release_cpus()\n"); |
327 | 328 | ||
@@ -332,7 +333,9 @@ void smp_release_cpus(void) | |||
332 | * This is useless but harmless on iSeries, secondaries are already | 333 | * This is useless but harmless on iSeries, secondaries are already |
333 | * waiting on their paca spinloops. */ | 334 | * waiting on their paca spinloops. */ |
334 | 335 | ||
335 | __secondary_hold_spinloop = 1; | 336 | ptr = (unsigned long *)((unsigned long)&__secondary_hold_spinloop |
337 | - PHYSICAL_START); | ||
338 | *ptr = 1; | ||
336 | mb(); | 339 | mb(); |
337 | 340 | ||
338 | DBG(" <- smp_release_cpus()\n"); | 341 | DBG(" <- smp_release_cpus()\n"); |
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index fb2a7c798e82..862f1e985c19 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c | |||
@@ -753,14 +753,15 @@ static int __init smp_core99_probe(void) | |||
753 | static void __devinit smp_core99_kick_cpu(int nr) | 753 | static void __devinit smp_core99_kick_cpu(int nr) |
754 | { | 754 | { |
755 | unsigned int save_vector; | 755 | unsigned int save_vector; |
756 | unsigned long new_vector; | 756 | unsigned long target, flags; |
757 | unsigned long flags; | ||
758 | volatile unsigned int *vector | 757 | volatile unsigned int *vector |
759 | = ((volatile unsigned int *)(KERNELBASE+0x100)); | 758 | = ((volatile unsigned int *)(KERNELBASE+0x100)); |
760 | 759 | ||
761 | if (nr < 0 || nr > 3) | 760 | if (nr < 0 || nr > 3) |
762 | return; | 761 | return; |
763 | if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346); | 762 | |
763 | if (ppc_md.progress) | ||
764 | ppc_md.progress("smp_core99_kick_cpu", 0x346); | ||
764 | 765 | ||
765 | local_irq_save(flags); | 766 | local_irq_save(flags); |
766 | local_irq_disable(); | 767 | local_irq_disable(); |
@@ -768,14 +769,11 @@ static void __devinit smp_core99_kick_cpu(int nr) | |||
768 | /* Save reset vector */ | 769 | /* Save reset vector */ |
769 | save_vector = *vector; | 770 | save_vector = *vector; |
770 | 771 | ||
771 | /* Setup fake reset vector that does | 772 | /* Setup fake reset vector that does |
772 | * b __secondary_start_pmac_0 + nr*8 - KERNELBASE | 773 | * b __secondary_start_pmac_0 + nr*8 - KERNELBASE |
773 | */ | 774 | */ |
774 | new_vector = (unsigned long) __secondary_start_pmac_0 + nr * 8; | 775 | target = (unsigned long) __secondary_start_pmac_0 + nr * 8; |
775 | *vector = 0x48000002 + new_vector - KERNELBASE; | 776 | create_branch((unsigned long)vector, target, BRANCH_SET_LINK); |
776 | |||
777 | /* flush data cache and inval instruction cache */ | ||
778 | flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); | ||
779 | 777 | ||
780 | /* Put some life in our friend */ | 778 | /* Put some life in our friend */ |
781 | pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0); | 779 | pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0); |
diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h index 29613500c2c2..0a7323f0083b 100644 --- a/include/asm-powerpc/mmu.h +++ b/include/asm-powerpc/mmu.h | |||
@@ -33,7 +33,8 @@ | |||
33 | 33 | ||
34 | /* Location of cpu0's segment table */ | 34 | /* Location of cpu0's segment table */ |
35 | #define STAB0_PAGE 0x6 | 35 | #define STAB0_PAGE 0x6 |
36 | #define STAB0_PHYS_ADDR (STAB0_PAGE<<12) | 36 | #define STAB0_OFFSET (STAB0_PAGE << 12) |
37 | #define STAB0_PHYS_ADDR (STAB0_OFFSET + PHYSICAL_START) | ||
37 | 38 | ||
38 | #ifndef __ASSEMBLY__ | 39 | #ifndef __ASSEMBLY__ |
39 | extern char initial_stab[]; | 40 | extern char initial_stab[]; |