patch-2.2.4 linux/arch/ppc/kernel/head.S
Next file: linux/arch/ppc/kernel/idle.c
Previous file: linux/arch/ppc/kernel/feature.c
Back to the patch index
Back to the overall index
- Lines: 623
- Date:
Fri Mar 19 10:50:03 1999
- Orig file:
v2.2.3/linux/arch/ppc/kernel/head.S
- Orig date:
Thu Dec 31 10:28:59 1998
diff -u --recursive --new-file v2.2.3/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
@@ -1,7 +1,7 @@
/*
* arch/ppc/kernel/head.S
*
- * $Id: head.S,v 1.114 1998/12/28 10:28:45 paulus Exp $
+ * $Id: head.S,v 1.121 1999/03/16 10:40:29 cort Exp $
*
* PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -44,8 +44,13 @@
/* optimization for 603 to load the tlb directly from the linux table */
#define NO_RELOAD_HTAB 1
+#ifndef CONFIG_8xx
CACHE_LINE_SIZE = 32
LG_CACHE_LINE_SIZE = 5
+#else
+CACHE_LINE_SIZE = 16
+LG_CACHE_LINE_SIZE = 4
+#endif
#define TOPHYS(x) (x - KERNELBASE)
@@ -81,7 +86,6 @@
sync; \
isync
-/* This instruction is not implemented on the PPC 603 or 601 */
#ifndef CONFIG_8xx
/* This instruction is not implemented on the PPC 603 or 601 */
#define tlbia \
@@ -212,6 +216,7 @@
mr r29,r5
mr r28,r6
mr r27,r7
+ li r24,0 /* cpu # */
#ifndef CONFIG_8xx
bl prom_init
.globl __secondary_start
@@ -236,15 +241,33 @@
mtspr IBAT1L,r10
b 5f
4:
-#ifndef CONFIG_APUS
- ori r11,r11,0x1fe /* set up BAT registers for 604 */
- li r8,2 /* R/W access */
-#else
+#ifdef CONFIG_APUS
+ ori r11,r11,BL_8M<<2|0x2 /* set up an 8MB mapping */
ori r11,r11,0xfe /* set up an 8MB mapping */
lis r8,CYBERBASEp@h
lwz r8,0(r8)
addis r8,r8,KERNELBASE@h
addi r8,r8,2
+#else
+ ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */
+ li r8,2 /* R/W access */
+ /*
+ * allow secondary cpus to get at all of ram in early bootup
+ * since their init_task may be up there -- Cort
+ */
+ oris r18,r8,0x10000000@h
+ oris r21,r11,(KERNELBASE+0x10000000)@h
+ mtspr DBAT1L,r18 /* N.B. 6xx (not 601) have valid */
+ mtspr DBAT1U,r21 /* bit in upper BAT register */
+ mtspr IBAT1L,r18
+ mtspr IBAT1U,r21
+
+ oris r18,r8,0x20000000@h
+ oris r21,r11,(KERNELBASE+0x20000000)@h
+ mtspr DBAT2L,r18 /* N.B. 6xx (not 601) have valid */
+ mtspr DBAT2U,r21 /* bit in upper BAT register */
+ mtspr IBAT2L,r28
+ mtspr IBAT2U,r21
#endif
mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */
mtspr DBAT0U,r11 /* bit in upper BAT register */
@@ -327,20 +350,28 @@
lis r8, MI_Kp@h /* Set the protection mode */
mtspr MI_AP, r8
mtspr MD_AP, r8
-#ifdef CONFIG_MBX
+
+/* We will get these from a configuration file as soon as I verify
+ * the extraneous bits don't cause problems in the TLB.
+ */
+#if defined(CONFIG_MBX) || defined(CONFIG_RPXLITE)
+#define BOOT_IMMR 0xfa000000
+#endif
+#ifdef CONFIG_BSEIP
+#define BOOT_IMMR 0xff000000
+#endif
/* Map another 8 MByte at 0xfa000000 to get the processor
* internal registers (among other things).
*/
- lis r8, 0xfa000000@h /* Create vaddr for TLB */
+ lis r8, BOOT_IMMR@h /* Create vaddr for TLB */
ori r8, r8, MD_EVALID /* Mark it valid */
mtspr MD_EPN, r8
li r8, MD_PS8MEG /* Set 8M byte page */
ori r8, r8, MD_SVALID /* Make it valid */
mtspr MD_TWC, r8
- lis r8, 0xfa000000@h /* Create paddr for TLB */
+ lis r8, BOOT_IMMR@h /* Create paddr for TLB */
ori r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */
mtspr MD_RPN, r8
-#endif
/* Since the cache is enabled according to the information we
* just loaded into the TLB, invalidate and enable the caches here.
@@ -354,9 +385,8 @@
#if 0
mtspr DC_CST, r8
#else
- /* I still have a bug somewhere because the Ethernet driver
- * does not want to work with copyback enabled. For now,
- * at least enable write through.
+ /* For a debug option, I left this here to easily enable
+ * the write through cache mode
*/
lis r8, DC_SFWT@h
mtspr DC_CST, r8
@@ -442,7 +472,11 @@
.long int_return
/* System reset */
+#ifdef CONFIG_SMP /* MVME/MTX start the secondary here */
+ STD_EXCEPTION(0x100, Reset, __secondary_start_psurge)
+#else
STD_EXCEPTION(0x100, Reset, UnknownException)
+#endif
/* Machine check */
STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
@@ -1148,6 +1182,8 @@
mflr r23
andi. r24,r23,0x3f00 /* get vector offset */
stw r24,TRAP(r21)
+ li r22,RESULT
+ stwcx. r22,r22,r21 /* to clear the reservation */
li r22,0
stw r22,RESULT(r21)
mtspr SPRG2,r22 /* r1 is now kernel sp */
@@ -1155,7 +1191,7 @@
cmplw 0,r1,r2
cmplw 1,r1,r24
crand 1,1,4
- bgt stack_ovf /* if r2 < r1 < r2+TASK_STRUCT_SIZE */
+ bgt- stack_ovf /* if r2 < r1 < r2+TASK_STRUCT_SIZE */
lwz r24,0(r23) /* virtual address of handler */
lwz r23,4(r23) /* where to go when done */
mtspr SRR0,r24
@@ -1204,13 +1240,10 @@
Hash_bits = 12 /* e.g. 256kB hash table */
Hash_msk = (((1 << Hash_bits) - 1) * 64)
- .globl hash_table_lock
-hash_table_lock:
-.long 0
-
.globl hash_page
hash_page:
#ifdef __SMP__
+ eieio
lis r2,hash_table_lock@h
ori r2,r2,hash_table_lock@l
tophys(r2,r2,r6)
@@ -1226,7 +1259,7 @@
12: cmpw r6,r0
bdnzf 2,10b
tw 31,31,31
-11:
+11: eieio
#endif
/* Get PTE (linux-style) and check access */
lwz r5,PG_TABLES(r5)
@@ -1234,13 +1267,25 @@
rlwimi r5,r3,12,20,29 /* insert top 10 bits of address */
lwz r5,0(r5) /* get pmd entry */
rlwinm. r5,r5,0,0,19 /* extract address of pte page */
+#ifdef __SMP__
beq- hash_page_out /* return if no mapping */
+#else
+ /* XXX it seems like the 601 will give a machine fault on the
+ rfi if its alignment is wrong (bottom 4 bits of address are
+ 8 or 0xc) and we have had a not-taken conditional branch
+ to the address following the rfi. */
+ beqlr-
+#endif
tophys(r2,r5,r2)
rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */
lwz r6,0(r2) /* get linux-style pte */
ori r4,r4,1 /* set _PAGE_PRESENT bit in access */
andc. r0,r4,r6 /* check access & ~permission */
+#ifdef __SMP__
bne- hash_page_out /* return if access not permitted */
+#else
+ bnelr-
+#endif
ori r6,r6,0x100 /* set _PAGE_ACCESSED in pte */
rlwinm r5,r4,5,24,24 /* _PAGE_RW access -> _PAGE_DIRTY */
@@ -1257,7 +1302,9 @@
/* Construct the high word of the PPC-style PTE */
mfsrin r5,r3 /* get segment reg for segment */
rlwinm r5,r5,7,1,24 /* put VSID in 0x7fffff80 bits */
+#ifndef __SMP__ /* do this later for SMP */
oris r5,r5,0x8000 /* set V (valid) bit */
+#endif
rlwimi r5,r3,10,26,31 /* put in API (abbrev page index) */
/* Get the address of the primary PTE group in the hash table */
@@ -1274,9 +1321,6 @@
li r2,8 /* PTEs/group */
bne 10f /* no PTE: go look for an empty slot */
tlbie r3 /* invalidate TLB entry */
-#ifdef __SMP__
- tlbsync
-#endif
/* Search the primary PTEG for a PTE whose 1st word matches r5 */
mtctr r2
@@ -1345,18 +1389,43 @@
addi r4,r4,1
stw r4,0(r2)
+#ifndef __SMP__
/* Store PTE in PTEG */
found_empty:
stw r5,0(r3)
found_slot:
stw r6,4(r3)
- SYNC
+ sync
+
+#else /* __SMP__ */
/*
- * These nop's seem to be necessary to avoid getting a machine
- * check on the rfi on 601 processors.
+ * Between the tlbie above and updating the hash table entry below,
+ * another CPU could read the hash table entry and put it in its TLB.
+ * There are 3 cases:
+ * 1. using an empty slot
+ * 2. updating an earlier entry to change permissions (i.e. enable write)
+ * 3. taking over the PTE for an unrelated address
+ *
+ * In each case it doesn't really matter if the other CPUs have the old
+ * PTE in their TLB. So we don't need to bother with another tlbie here,
+ * which is convenient as we've overwritten the register that had the
+ * address. :-) The tlbie above is mainly to make sure that this CPU comes
+ * and gets the new PTE from the hash table.
+ *
+ * We do however have to make sure that the PTE is never in an invalid
+ * state with the V bit set.
*/
- nop
- nop
+found_empty:
+found_slot:
+ stw r5,0(r3) /* clear V (valid) bit in PTE */
+ sync
+ tlbsync
+ sync
+ stw r6,4(r3) /* put in correct RPN, WIMG, PP bits */
+ sync
+ oris r5,r5,0x8000
+ stw r5,0(r3) /* finally set V bit in PTE */
+#endif /* __SMP__ */
/*
* Update the hash table miss count. We only want misses here
@@ -1380,6 +1449,7 @@
tophys(r2,r2,r6)
li r0,0
stw r0,hash_table_lock@l(r2)
+ eieio
#endif
/* Return from the exception */
@@ -1398,17 +1468,22 @@
REST_GPR(20, r21)
REST_2GPRS(22, r21)
lwz r21,GPR21(r21)
- SYNC
rfi
-hash_page_out:
#ifdef __SMP__
+hash_page_out:
lis r2,hash_table_lock@ha
tophys(r2,r2,r6)
li r0,0
stw r0,hash_table_lock@l(r2)
-#endif
+ eieio
blr
+
+ .globl hash_table_lock
+hash_table_lock:
+ .long 0
+#endif
+
next_slot:
.long 0
@@ -1600,10 +1675,38 @@
. = 0x4000
#endif
+#ifdef CONFIG_SMP
+ .globl __secondary_start_psurge
+__secondary_start_psurge:
+ li r24,1 /* cpu # */
+ b __secondary_start
+
+ .globl __secondary_hold
+__secondary_hold:
+ /* tell the master we're here */
+ lis r5,0x4@h
+ ori r5,r5,0x4@l
+ stw r3,0(r5)
+ dcbf 0,r5
+100:
+ lis r5,0
+ dcbi 0,r5
+ lwz r4,0(r5)
+ /* wait until we're told to start */
+ cmp 0,r4,r3
+ bne 100b
+ /* our cpu # was at addr 0 - go */
+ lis r5,__secondary_start@h
+ ori r5,r5,__secondary_start@l
+ tophys(r5,r5,r4)
+ mtlr r5
+ mr r24,r3 /* cpu # */
+ blr
+#endif /* CONFIG_SMP */
+
/*
* This is where the main kernel code starts.
*/
-
start_here:
#ifndef CONFIG_8xx
/*
@@ -1650,9 +1753,9 @@
/* get current */
lis r2,current_set@h
ori r2,r2,current_set@l
- addi r2,r2,4
+ slwi r24,r24,2 /* cpu # to current_set[cpu#] */
+ add r2,r2,r24
lwz r2,0(r2)
-
b 10f
99:
#endif /* __SMP__ */
@@ -1677,12 +1780,10 @@
#ifdef __SMP__
10:
#endif /* __SMP__ */
-
/* stack */
addi r1,r2,TASK_UNION_SIZE
li r0,0
stwu r0,-STACK_FRAME_OVERHEAD(r1)
-
/*
* Decide what sort of machine this is and initialize the MMU.
*/
@@ -1693,7 +1794,6 @@
mr r7,r27
bl identify_machine
bl MMU_init
-
/*
* Go back to running unmapped so we can load up new values
* for SDR1 (hash table pointer) and the segment registers
@@ -1725,8 +1825,10 @@
2:
SYNC /* Force all PTE updates to finish */
tlbia /* Clear all TLB entries */
+ sync /* wait for tlbia/tlbie to finish */
#ifdef __SMP__
- tlbsync
+ tlbsync /* ... on all CPUs */
+ sync
#endif
#ifndef CONFIG_8xx
mtspr SDR1,r6
@@ -1976,7 +2078,7 @@
/* Set up segment registers for new task */
rlwinm r5,r5,4,8,27 /* VSID = context << 4 */
addis r5,r5,0x6000 /* Set Ks, Ku bits */
- li r0,8 /* TASK_SIZE / SEGMENT_SIZE */
+ li r0,12 /* TASK_SIZE / SEGMENT_SIZE */
mtctr r0
li r3,0
3: mtsrin r5,r3
@@ -2118,7 +2220,7 @@
_GLOBAL(set_context)
rlwinm r3,r3,4,8,27 /* VSID = context << 4 */
addis r3,r3,0x6000 /* Set Ks, Ku bits */
- li r0,8 /* TASK_SIZE / SEGMENT_SIZE */
+ li r0,12 /* TASK_SIZE / SEGMENT_SIZE */
mtctr r0
li r4,0
3: mtsrin r3,r4
@@ -2177,6 +2279,27 @@
blr
/*
+ * Like above, but only do the D-cache. This is used by the 8xx
+ * to push the cache so the CPM doesn't get stale data.
+ *
+ * flush_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(flush_dcache_range)
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,LG_CACHE_LINE_SIZE
+ beqlr
+ mtctr r4
+
+1: dcbst 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ blr
+
+/*
* Flush a particular page from the DATA cache
* Note: this is necessary because the instruction cache does *not*
* snoop from the data cache.
@@ -2207,25 +2330,35 @@
blr
/*
+ * Clear a page using the dcbz instruction, which doesn't cause any
+ * memory traffic (except to write out any cache lines which get
+ * displaced). This only works on cacheable memory.
+ */
+_GLOBAL(clear_page)
+ li r0,4096/CACHE_LINE_SIZE
+ mtctr r0
+1: dcbz 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ blr
+
+/*
* Flush entries from the hash table with VSIDs in the range
* given.
*/
#ifndef CONFIG_8xx
_GLOBAL(flush_hash_segments)
+ lis r5,Hash@ha
+ lwz r5,Hash@l(r5) /* base of hash table */
#ifdef NO_RELOAD_HTAB
-/*
- * Bitmask of PVR numbers of 603-like chips,
- * for which we don't use the hash table at all.
- */
-#define PVR_603_LIKE 0x13000000 /* bits 3, 6, 7 set */
-
- mfspr r0,PVR
- rlwinm r0,r0,16,27,31
- lis r9,PVR_603_LIKE@h
- rlwnm. r0,r9,r0,0,0
- beq+ 99f
+ cmpwi 0,r5,0
+ bne+ 99f
tlbia
- isync
+ sync
+#ifdef __SMP__
+ tlbsync
+ sync
+#endif
blr
99:
#endif /* NO_RELOAD_HTAB */
@@ -2247,14 +2380,13 @@
bne- 10b
stwcx. r8,0,r9
bne- 10b
+ eieio
#endif
rlwinm r3,r3,7,1,24 /* put VSID lower limit in position */
oris r3,r3,0x8000 /* set V bit */
rlwinm r4,r4,7,1,24 /* put VSID upper limit in position */
oris r4,r4,0x8000
ori r4,r4,0x7f
- lis r5,Hash@ha
- lwz r5,Hash@l(r5) /* base of hash table */
lis r6,Hash_size@ha
lwz r6,Hash_size@l(r6) /* size in bytes */
srwi r6,r6,3 /* # PTEs */
@@ -2270,11 +2402,11 @@
2: bdnz 1b /* continue with loop */
sync
tlbia
- isync
+ sync
#ifdef __SMP__
tlbsync
+ sync
lis r3,hash_table_lock@ha
- li r0,0
stw r0,hash_table_lock@l(r3)
mtmsr r10
SYNC
@@ -2287,14 +2419,17 @@
* flush_hash_page(unsigned context, unsigned long va)
*/
_GLOBAL(flush_hash_page)
+ lis r6,Hash@ha
+ lwz r6,Hash@l(r6) /* hash table base */
#ifdef NO_RELOAD_HTAB
- mfspr r0,PVR
- rlwinm r0,r0,16,27,31
- lis r9,PVR_603_LIKE@h
- rlwnm. r0,r9,r0,0,0
- beq+ 99f
+ cmpwi 0,r6,0 /* hash table in use? */
+ bne+ 99f
tlbie r4 /* in hw tlb too */
- isync
+ sync
+#ifdef __SMP__
+ tlbsync
+ sync
+#endif
blr
99:
#endif /* NO_RELOAD_HTAB */
@@ -2311,11 +2446,12 @@
ori r9,r9,hash_table_lock@l
lwz r8,PROCESSOR(r2)
oris r8,r8,9
-10: lwarx r6,0,r9
- cmpi 0,r6,0
+10: lwarx r7,0,r9
+ cmpi 0,r7,0
bne- 10b
stwcx. r8,0,r9
bne- 10b
+ eieio
#endif
rlwinm r3,r3,11,1,20 /* put context into vsid */
rlwimi r3,r4,11,21,24 /* put top 4 bits of va into vsid */
@@ -2328,8 +2464,6 @@
lwz r5,Hash_mask@l(r5) /* hash mask */
slwi r5,r5,6 /* << 6 */
and r7,r7,r5
- lis r6,Hash@ha
- lwz r6,Hash@l(r6) /* hash table base */
add r6,r6,r7 /* address of primary PTEG */
li r8,8
mtctr r8
@@ -2350,9 +2484,10 @@
stw r0,0(r7) /* invalidate entry */
4: sync
tlbie r4 /* in hw tlb too */
- isync
+ sync
#ifdef __SMP__
tlbsync
+ sync
lis r3,hash_table_lock@h
li r0,0
stw r0,hash_table_lock@l(r3)
@@ -2418,30 +2553,27 @@
rfi /* return to caller */
#endif /* CONFIG_8xx */
-#ifdef CONFIG_MBX
-/* Jump into the system reset for the MBX rom.
+#ifdef CONFIG_8xx
+/* Jump into the system reset for the rom.
* We first disable the MMU, and then jump to the ROM reset address.
*
- * This does not work, don't bother trying. There is no place in
- * the ROM we can jump to cause a reset. We will have to program
- * a watchdog of some type that we don't service to cause a processor
- * reset.
- */
- .globl MBX_gorom
-MBX_gorom:
- li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
- lis r4,2f@h
- addis r4,r4,-KERNELBASE@h
- ori r4,r4,2f@l
- mtspr SRR0,r4
- mtspr SRR1,r3
- rfi
+ * r3 is the board info structure, r4 is the location for starting.
+ * I use this for building a small kernel that can load other kernels,
+ * rather than trying to write or rely on a rom monitor that can tftp load.
+ */
+ .globl m8xx_gorom
+m8xx_gorom:
+ li r5,MSR_KERNEL & ~(MSR_IR|MSR_DR)
+ lis r6,2f@h
+ addis r6,r6,-KERNELBASE@h
+ ori r6,r6,2f@l
+ mtspr SRR0,r6
+ mtspr SRR1,r5
+ rfi
2:
- lis r4, 0xfe000000@h
- addi r4, r4, 0xfe000000@l
- mtlr r4
- blr
-#endif /* CONFIG_MBX */
+ mtlr r4
+ blr
+#endif /* CONFIG_8xx */
/*
* We put a few things here that have to be page-aligned.
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)