linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / arch / ppc / kernel / head.S
index 100052a..53ea845 100644 (file)
@@ -22,6 +22,7 @@
  *
  */
 
+#include <linux/config.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/mmu.h>
 #include <asm/amigappc.h>
 #endif
 
+#ifdef CONFIG_PPC64BRIDGE
+#define LOAD_BAT(n, reg, RA, RB)       \
+       ld      RA,(n*32)+0(reg);       \
+       ld      RB,(n*32)+8(reg);       \
+       mtspr   SPRN_IBAT##n##U,RA;     \
+       mtspr   SPRN_IBAT##n##L,RB;     \
+       ld      RA,(n*32)+16(reg);      \
+       ld      RB,(n*32)+24(reg);      \
+       mtspr   SPRN_DBAT##n##U,RA;     \
+       mtspr   SPRN_DBAT##n##L,RB;     \
+
+#else /* CONFIG_PPC64BRIDGE */
+
 /* 601 only have IBAT; cr0.eq is set on 601 when using this macro */
 #define LOAD_BAT(n, reg, RA, RB)       \
        /* see the comment for clear_bats() -- Cort */ \
@@ -52,6 +66,7 @@
        mtspr   SPRN_DBAT##n##U,RA;     \
        mtspr   SPRN_DBAT##n##L,RB;     \
 1:
+#endif /* CONFIG_PPC64BRIDGE */
 
        .text
        .stabs  "arch/ppc/kernel/",N_SO,0,0,0f
@@ -114,6 +129,11 @@ _start:
 
        .globl  __start
 __start:
+/*
+ * We have to do any OF calls before we map ourselves to KERNELBASE,
+ * because OF may have I/O devices mapped into that area
+ * (particularly on CHRP).
+ */
        mr      r31,r3                  /* save parameters */
        mr      r30,r4
        mr      r29,r5
@@ -128,6 +148,14 @@ __start:
  */
        bl      early_init
 
+/*
+ * On POWER4, we first need to tweak some CPU configuration registers
+ * like real mode cache inhibit or exception base
+ */
+#ifdef CONFIG_POWER4
+       bl      __970_cpu_preinit
+#endif /* CONFIG_POWER4 */
+
 #ifdef CONFIG_APUS
 /* On APUS the __va/__pa constants need to be set to the correct
  * values before continuing.
@@ -141,6 +169,7 @@ __start:
  */
        bl      mmu_off
 __after_mmu_off:
+#ifndef CONFIG_POWER4
        bl      clear_bats
        bl      flush_tlbs
 
@@ -148,6 +177,10 @@ __after_mmu_off:
 #if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
        bl      setup_disp_bat
 #endif
+#else /* CONFIG_POWER4 */
+       bl      reloc_offset
+       bl      initial_mm_power4
+#endif /* CONFIG_POWER4 */
 
 /*
  * Call setup_cpu for CPU 0 and initialize 6xx Idle
@@ -159,11 +192,18 @@ __after_mmu_off:
        bl      reloc_offset
        bl      init_idle_6xx
 #endif /* CONFIG_6xx */
+#ifdef CONFIG_POWER4
+       bl      reloc_offset
+       bl      init_idle_power4
+#endif /* CONFIG_POWER4 */
 
 
 #ifndef CONFIG_APUS
 /*
  * We need to run with _start at physical address 0.
+ * On CHRP, we are loaded at 0x10000 since OF on CHRP uses
+ * the exception vectors at 0 (and therefore this copy
+ * overwrites OF's exception vectors with our own).
  * If the MMU is already turned on, we copy stuff to KERNELBASE,
  * otherwise we copy it to 0.
  */
@@ -318,19 +358,51 @@ i##n:                                                             \
 #endif
 
 /* Machine check */
+/*
+ * On CHRP, this is complicated by the fact that we could get a
+ * machine check inside RTAS, and we have no guarantee that certain
+ * critical registers will have the values we expect.  The set of
+ * registers that might have bad values includes all the GPRs
+ * and all the BATs.  We indicate that we are in RTAS by putting
+ * a non-zero value, the address of the exception frame to use,
+ * in SPRG2.  The machine check handler checks SPRG2 and uses its
+ * value if it is non-zero.  If we ever needed to free up SPRG2,
+ * we could use a field in the thread_info or thread_struct instead.
+ * (Other exception handlers assume that r1 is a valid kernel stack
+ * pointer when we take an exception from supervisor mode.)
+ *     -- paulus.
+ */
        . = 0x200
        mtspr   SPRN_SPRG0,r10
        mtspr   SPRN_SPRG1,r11
        mfcr    r10
+#ifdef CONFIG_PPC_CHRP
+       mfspr   r11,SPRN_SPRG2
+       cmpwi   0,r11,0
+       bne     7f
+#endif /* CONFIG_PPC_CHRP */
        EXCEPTION_PROLOG_1
 7:     EXCEPTION_PROLOG_2
        addi    r3,r1,STACK_FRAME_OVERHEAD
+#ifdef CONFIG_PPC_CHRP
+       mfspr   r4,SPRN_SPRG2
+       cmpwi   cr1,r4,0
+       bne     cr1,1f
+#endif
        EXC_XFER_STD(0x200, machine_check_exception)
+#ifdef CONFIG_PPC_CHRP
+1:     b       machine_check_in_rtas
+#endif
 
 /* Data access exception. */
        . = 0x300
+#ifdef CONFIG_PPC64BRIDGE
+       b       DataAccess
+DataAccessCont:
+#else
 DataAccess:
        EXCEPTION_PROLOG
+#endif /* CONFIG_PPC64BRIDGE */
        mfspr   r10,SPRN_DSISR
        andis.  r0,r10,0xa470           /* weird error? */
        bne     1f                      /* if not, try to put a PTE */
@@ -342,10 +414,21 @@ DataAccess:
        mfspr   r4,SPRN_DAR
        EXC_XFER_EE_LITE(0x300, handle_page_fault)
 
+#ifdef CONFIG_PPC64BRIDGE
+/* SLB fault on data access. */
+       . = 0x380
+       b       DataSegment
+#endif /* CONFIG_PPC64BRIDGE */
+
 /* Instruction access exception. */
        . = 0x400
+#ifdef CONFIG_PPC64BRIDGE
+       b       InstructionAccess
+InstructionAccessCont:
+#else
 InstructionAccess:
        EXCEPTION_PROLOG
+#endif /* CONFIG_PPC64BRIDGE */
        andis.  r0,r9,0x4000            /* no pte found? */
        beq     1f                      /* if so, try to put a PTE */
        li      r3,0                    /* into the hash table */
@@ -355,6 +438,12 @@ InstructionAccess:
        mr      r5,r9
        EXC_XFER_EE_LITE(0x400, handle_page_fault)
 
+#ifdef CONFIG_PPC64BRIDGE
+/* SLB fault on instruction access. */
+       . = 0x480
+       b       InstructionSegment
+#endif /* CONFIG_PPC64BRIDGE */
+
 /* External interrupt */
        EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
 
@@ -619,9 +708,15 @@ DataStoreTLBMiss:
        EXCEPTION(0x1300, Trap_13, instruction_breakpoint_exception, EXC_XFER_EE)
        EXCEPTION(0x1400, SMI, SMIException, EXC_XFER_EE)
        EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_EE)
+#ifdef CONFIG_POWER4
+       EXCEPTION(0x1600, Trap_16, unknown_exception, EXC_XFER_EE)
+       EXCEPTION(0x1700, Trap_17, altivec_assist_exception, EXC_XFER_EE)
+       EXCEPTION(0x1800, Trap_18, TAUException, EXC_XFER_STD)
+#else /* !CONFIG_POWER4 */
        EXCEPTION(0x1600, Trap_16, altivec_assist_exception, EXC_XFER_EE)
        EXCEPTION(0x1700, Trap_17, TAUException, EXC_XFER_STD)
        EXCEPTION(0x1800, Trap_18, unknown_exception, EXC_XFER_EE)
+#endif /* CONFIG_POWER4 */
        EXCEPTION(0x1900, Trap_19, unknown_exception, EXC_XFER_EE)
        EXCEPTION(0x1a00, Trap_1a, unknown_exception, EXC_XFER_EE)
        EXCEPTION(0x1b00, Trap_1b, unknown_exception, EXC_XFER_EE)
@@ -659,6 +754,28 @@ AltiVecUnavailable:
        addi    r3,r1,STACK_FRAME_OVERHEAD
        EXC_XFER_EE_LITE(0xf20, altivec_unavailable_exception)
 
+#ifdef CONFIG_PPC64BRIDGE
+DataAccess:
+       EXCEPTION_PROLOG
+       b       DataAccessCont
+
+InstructionAccess:
+       EXCEPTION_PROLOG
+       b       InstructionAccessCont
+
+DataSegment:
+       EXCEPTION_PROLOG
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       mfspr   r4,SPRN_DAR
+       stw     r4,_DAR(r11)
+       EXC_XFER_STD(0x380, unknown_exception)
+
+InstructionSegment:
+       EXCEPTION_PROLOG
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       EXC_XFER_STD(0x480, unknown_exception)
+#endif /* CONFIG_PPC64BRIDGE */
+
 #ifdef CONFIG_ALTIVEC
 /* Note that the AltiVec support is closely modeled after the FP
  * support.  Changes to one are likely to be applicable to the
@@ -931,6 +1048,13 @@ __secondary_start_pmac_0:
 
        .globl  __secondary_start
 __secondary_start:
+#ifdef CONFIG_PPC64BRIDGE
+       mfmsr   r0
+       clrldi  r0,r0,1                 /* make sure it's in 32-bit mode */
+       SYNC
+       MTMSRD(r0)
+       isync
+#endif
        /* Copy some CPU settings from CPU 0 */
        bl      __restore_cpu_setup
 
@@ -941,6 +1065,10 @@ __secondary_start:
        lis     r3,-KERNELBASE@h
        bl      init_idle_6xx
 #endif /* CONFIG_6xx */
+#ifdef CONFIG_POWER4
+       lis     r3,-KERNELBASE@h
+       bl      init_idle_power4
+#endif /* CONFIG_POWER4 */
 
        /* get current_thread_info and current */
        lis     r1,secondary_ti@ha
@@ -981,12 +1109,12 @@ __secondary_start:
  * Those generic dummy functions are kept for CPUs not
  * included in CONFIG_6xx
  */
-#if !defined(CONFIG_6xx)
+#if !defined(CONFIG_6xx) && !defined(CONFIG_POWER4)
 _GLOBAL(__save_cpu_setup)
        blr
 _GLOBAL(__restore_cpu_setup)
        blr
-#endif /* !defined(CONFIG_6xx) */
+#endif /* !defined(CONFIG_6xx) && !defined(CONFIG_POWER4) */
 
 
 /*
@@ -1004,6 +1132,11 @@ load_up_mmu:
        tophys(r6,r6)
        lwz     r6,_SDR1@l(r6)
        mtspr   SPRN_SDR1,r6
+#ifdef CONFIG_PPC64BRIDGE
+       /* clear the ASR so we only use the pseudo-segment registers. */
+       li      r6,0
+       mtasr   r6
+#endif /* CONFIG_PPC64BRIDGE */
        li      r0,16           /* load up segment register values */
        mtctr   r0              /* for context 0 */
        lis     r3,0x2000       /* Ku = 1, VSID = 0 */
@@ -1012,7 +1145,7 @@ load_up_mmu:
        addi    r3,r3,0x111     /* increment VSID */
        addis   r4,r4,0x1000    /* address of next segment */
        bdnz    3b
-
+#ifndef CONFIG_POWER4
 /* Load the BAT registers with the values set up by MMU_init.
    MMU_init takes care of whether we're on a 601 or not. */
        mfpvr   r3
@@ -1025,7 +1158,7 @@ load_up_mmu:
        LOAD_BAT(1,r3,r4,r5)
        LOAD_BAT(2,r3,r4,r5)
        LOAD_BAT(3,r3,r4,r5)
-
+#endif /* CONFIG_POWER4 */
        blr
 
 /*
@@ -1136,6 +1269,9 @@ _GLOBAL(set_context)
        li      r4,0
        isync
 3:
+#ifdef CONFIG_PPC64BRIDGE
+       slbie   r4
+#endif /* CONFIG_PPC64BRIDGE */
        mtsrin  r3,r4
        addi    r3,r3,0x111     /* next VSID */
        rlwinm  r3,r3,0,8,3     /* clear out any overflow from VSID field */
@@ -1222,6 +1358,7 @@ mmu_off:
        sync
        RFI
 
+#ifndef CONFIG_POWER4
 /*
  * Use the first pair of BAT registers to map the 1st 16MB
  * of RAM to KERNELBASE.  From this point on we can't safely
@@ -1229,6 +1366,7 @@ mmu_off:
  */
 initial_bats:
        lis     r11,KERNELBASE@h
+#ifndef CONFIG_PPC64BRIDGE
        mfspr   r9,SPRN_PVR
        rlwinm  r9,r9,16,16,31          /* r9 = 1 for 601, 4 for 604 */
        cmpwi   0,r9,1
@@ -1243,6 +1381,7 @@ initial_bats:
        mtspr   SPRN_IBAT1L,r10
        isync
        blr
+#endif /* CONFIG_PPC64BRIDGE */
 
 4:     tophys(r8,r11)
 #ifdef CONFIG_SMP
@@ -1256,6 +1395,11 @@ initial_bats:
        ori     r11,r11,BL_256M<<2|0x2  /* set up BAT registers for 604 */
 #endif /* CONFIG_APUS */
 
+#ifdef CONFIG_PPC64BRIDGE
+       /* clear out the high 32 bits in the BAT */
+       clrldi  r11,r11,32
+       clrldi  r8,r8,32
+#endif /* CONFIG_PPC64BRIDGE */
        mtspr   SPRN_DBAT0L,r8          /* N.B. 6xx (not 601) have valid */
        mtspr   SPRN_DBAT0U,r11         /* bit in upper BAT register */
        mtspr   SPRN_IBAT0L,r8
@@ -1288,6 +1432,38 @@ setup_disp_bat:
 
 #endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */
 
+#else /* CONFIG_POWER4 */
+/*
+ * Load up the SDR1 and segment register values now
+ * since we don't have the BATs.
+ * Also make sure we are running in 32-bit mode.
+ */
+
+initial_mm_power4:
+       addis   r14,r3,_SDR1@ha         /* get the value from _SDR1 */
+       lwz     r14,_SDR1@l(r14)        /* assume hash table below 4GB */
+       mtspr   SPRN_SDR1,r14
+       slbia
+       lis     r4,0x2000               /* set pseudo-segment reg 12 */
+       ori     r5,r4,0x0ccc
+       mtsr    12,r5
+#if 0
+       ori     r5,r4,0x0888            /* set pseudo-segment reg 8 */
+       mtsr    8,r5                    /* (for access to serial port) */
+#endif
+#ifdef CONFIG_BOOTX_TEXT
+       ori     r5,r4,0x0999            /* set pseudo-segment reg 9 */
+       mtsr    9,r5                    /* (for access to screen) */
+#endif
+       mfmsr   r0
+       clrldi  r0,r0,1
+       sync
+       mtmsr   r0
+       isync
+       blr
+
+#endif /* CONFIG_POWER4 */
+
 #ifdef CONFIG_8260
 /* Jump into the system reset for the rom.
  * We first disable the MMU, and then jump to the ROM reset address.