aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2005-12-05 16:49:00 -0500
committerPaul Mackerras <paulus@samba.org>2006-01-08 22:52:25 -0500
commit758438a7b8da593c9116e95cc7fdff6e9e0b0c40 (patch)
tree5343d8ec40016294902278c27a9f5647bd061890 /arch
parent0cc4746cadda16826a1b3214c042a2f75445b71c (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>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/kernel/head_64.S30
-rw-r--r--arch/powerpc/kernel/setup_64.c5
-rw-r--r--arch/powerpc/platforms/powermac/smp.c16
3 files changed, 35 insertions, 16 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
1353initial_stab: 1371initial_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)
322void smp_release_cpus(void) 322void 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)
753static void __devinit smp_core99_kick_cpu(int nr) 753static 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);