powerpc/mm: Don't clear _PAGE_COHERENT when _PAGE_SAO is set
[safe/jmp/linux-2.6] / arch / powerpc / kernel / head_fsl_booke.S
index 66877bd..c426850 100644 (file)
@@ -2,27 +2,27 @@
  * Kernel execution entry point code.
  *
  *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
- *      Initial PowerPC version.
+ *     Initial PowerPC version.
  *    Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu>
- *      Rewritten for PReP
+ *     Rewritten for PReP
  *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
- *      Low-level exception handers, MMU support, and rewrite.
+ *     Low-level exception handers, MMU support, and rewrite.
  *    Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
- *      PowerPC 8xx modifications.
+ *     PowerPC 8xx modifications.
  *    Copyright (c) 1998-1999 TiVo, Inc.
- *      PowerPC 403GCX modifications.
+ *     PowerPC 403GCX modifications.
  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
- *      PowerPC 403GCX/405GP modifications.
+ *     PowerPC 403GCX/405GP modifications.
  *    Copyright 2000 MontaVista Software Inc.
  *     PPC405 modifications
- *      PowerPC 403GCX/405GP modifications.
- *     Author: MontaVista Software, Inc.
- *             frank_rowand@mvista.com or source@mvista.com
- *             debbie_chu@mvista.com
+ *     PowerPC 403GCX/405GP modifications.
+ *     Author: MontaVista Software, Inc.
+ *             frank_rowand@mvista.com or source@mvista.com
+ *             debbie_chu@mvista.com
  *    Copyright 2002-2004 MontaVista Software, Inc.
- *      PowerPC 44x support, Matt Porter <mporter@kernel.crashing.org>
+ *     PowerPC 44x support, Matt Porter <mporter@kernel.crashing.org>
  *    Copyright 2004 Freescale Semiconductor, Inc
- *      PowerPC e500 modifications, Kumar Gala <galak@kernel.crashing.org>
+ *     PowerPC e500 modifications, Kumar Gala <galak@kernel.crashing.org>
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
@@ -39,6 +39,7 @@
 #include <asm/thread_info.h>
 #include <asm/ppc_asm.h>
 #include <asm/asm-offsets.h>
+#include <asm/cache.h>
 #include "head_booke.h"
 
 /* As with the other PowerPC ports, it is expected that when code
@@ -52,9 +53,9 @@
  *   r7 - End of kernel command line string
  *
  */
-       .text
-_GLOBAL(_stext)
-_GLOBAL(_start)
+       .section        .text.head, "ax"
+_ENTRY(_stext);
+_ENTRY(_start);
        /*
         * Reserve a word at a fixed location to store the address
         * of abatron_pteptrs
@@ -68,13 +69,15 @@ _GLOBAL(_start)
        mr      r29,r5
        mr      r28,r6
        mr      r27,r7
+       li      r25,0           /* phys kernel start (low) */
        li      r24,0           /* CPU number */
+       li      r23,0           /* phys kernel start (high) */
 
 /* We try to not make any assumptions about how the boot loader
  * setup or used the TLBs.  We invalidate all mappings from the
  * boot loader and load a single entry in TLB1[0] to map the
- * first 16M of kernel memory.  Any boot info passed from the
- * bootloader needs to live in this first 16M.
+ * first 64M of kernel memory.  Any boot info passed from the
+ * bootloader needs to live in this first 64M.
  *
  * Requirement on bootloader:
  *  - The page we're executing in needs to reside in TLB1 and
@@ -146,13 +149,13 @@ skpinv:   addi    r6,r6,1                         /* Increment */
        bne     1b                              /* If not, repeat */
 
        /* Invalidate TLB0 */
-       li      r6,0x04
+       li      r6,0x04
        tlbivax 0,r6
 #ifdef CONFIG_SMP
        tlbsync
 #endif
        /* Invalidate TLB1 */
-       li      r6,0x0c
+       li      r6,0x0c
        tlbivax 0,r6
 #ifdef CONFIG_SMP
        tlbsync
@@ -167,6 +170,27 @@ skpinv:    addi    r6,r6,1                         /* Increment */
        mtspr   SPRN_MAS0,r7
        tlbre
 
+       /* grab and fixup the RPN */
+       mfspr   r6,SPRN_MAS1    /* extract MAS1[SIZE] */
+       rlwinm  r6,r6,25,27,30
+       li      r8,-1
+       addi    r6,r6,10
+       slw     r6,r8,r6        /* convert to mask */
+
+       bl      1f              /* Find our address */
+1:     mflr    r7
+
+       mfspr   r8,SPRN_MAS3
+#ifdef CONFIG_PHYS_64BIT
+       mfspr   r23,SPRN_MAS7
+#endif
+       and     r8,r6,r8
+       subfic  r9,r6,-4096
+       and     r9,r9,r7
+
+       or      r25,r8,r9
+       ori     r8,r25,(MAS3_SX|MAS3_SW|MAS3_SR)
+
        /* Just modify the entry ID and EPN for the temp mapping */
        lis     r7,0x1000       /* Set MAS0(TLBSEL) = 1 */
        rlwimi  r7,r5,16,4,15   /* Setup MAS0 = TLBSEL | ESEL(r5) */
@@ -180,6 +204,7 @@ skpinv:     addi    r6,r6,1                         /* Increment */
        li      r7,0            /* temp EPN = 0 */
        rlwimi  r7,r6,0,20,31
        mtspr   SPRN_MAS2,r7
+       mtspr   SPRN_MAS3,r8
        tlbwe
 
        xori    r6,r4,1
@@ -206,11 +231,12 @@ skpinv:   addi    r6,r6,1                         /* Increment */
        rlwimi  r7,r3,16,4,15   /* Setup MAS0 = TLBSEL | ESEL(r3) */
        mtspr   SPRN_MAS0,r7
        tlbre
-       li      r6,0
+       mfspr   r6,SPRN_MAS1
+       rlwinm  r6,r6,0,2,0     /* clear IPROT */
        mtspr   SPRN_MAS1,r6
        tlbwe
        /* Invalidate TLB1 */
-       li      r9,0x0c
+       li      r9,0x0c
        tlbivax 0,r9
 #ifdef CONFIG_SMP
        tlbsync
@@ -221,18 +247,20 @@ skpinv:   addi    r6,r6,1                         /* Increment */
        lis     r6,0x1000               /* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */
        mtspr   SPRN_MAS0,r6
        lis     r6,(MAS1_VALID|MAS1_IPROT)@h
-       ori     r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_16M))@l
+       ori     r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_64M))@l
        mtspr   SPRN_MAS1,r6
        li      r7,0
-       lis     r6,KERNELBASE@h
-       ori     r6,r6,KERNELBASE@l
+       lis     r6,PAGE_OFFSET@h
+       ori     r6,r6,PAGE_OFFSET@l
        rlwimi  r6,r7,0,20,31
        mtspr   SPRN_MAS2,r6
-       li      r7,(MAS3_SX|MAS3_SW|MAS3_SR)
-       mtspr   SPRN_MAS3,r7
+       mtspr   SPRN_MAS3,r8
        tlbwe
 
 /* 7. Jump to KERNELBASE mapping */
+       lis     r6,KERNELBASE@h
+       ori     r6,r6,KERNELBASE@l
+       rlwimi  r6,r7,0,20,31
        lis     r7,MSR_KERNEL@h
        ori     r7,r7,MSR_KERNEL@l
        bl      1f                      /* Find our address */
@@ -248,10 +276,12 @@ skpinv:   addi    r6,r6,1                         /* Increment */
        rlwimi  r7,r5,16,4,15   /* Setup MAS0 = TLBSEL | ESEL(r5) */
        mtspr   SPRN_MAS0,r7
        tlbre
+       mfspr   r8,SPRN_MAS1
+       rlwinm  r8,r8,0,2,0     /* clear IPROT */
        mtspr   SPRN_MAS1,r8
        tlbwe
        /* Invalidate TLB1 */
-       li      r9,0x0c
+       li      r9,0x0c
        tlbivax 0,r9
 #ifdef CONFIG_SMP
        tlbsync
@@ -274,13 +304,19 @@ skpinv:   addi    r6,r6,1                         /* Increment */
        SET_IVOR(12, WatchdogTimer);
        SET_IVOR(13, DataTLBError);
        SET_IVOR(14, InstructionTLBError);
-       SET_IVOR(15, Debug);
+       SET_IVOR(15, DebugDebug);
+#if defined(CONFIG_E500) && !defined(CONFIG_PPC_E500MC)
+       SET_IVOR(15, DebugCrit);
+#endif
        SET_IVOR(32, SPEUnavailable);
        SET_IVOR(33, SPEFloatingPointData);
        SET_IVOR(34, SPEFloatingPointRound);
 #ifndef CONFIG_E200
        SET_IVOR(35, PerformanceMonitor);
 #endif
+#ifdef CONFIG_PPC_E500MC
+       SET_IVOR(36, Doorbell);
+#endif
 
        /* Establish the interrupt vector base */
        lis     r4,interrupt_base@h     /* IVPR only uses the high 16-bits */
@@ -291,7 +327,7 @@ skpinv:     addi    r6,r6,1                         /* Increment */
 #ifdef CONFIG_E200
        oris    r2,r2,MAS4_TLBSELD(1)@h
 #endif
-       mtspr   SPRN_MAS4, r2
+       mtspr   SPRN_MAS4, r2
 
 #if 0
        /* Enable DOZE */
@@ -302,7 +338,7 @@ skpinv:     addi    r6,r6,1                         /* Increment */
 #ifdef CONFIG_E200
        /* enable dedicated debug exception handling resources (Debug APU) */
        mfspr   r2,SPRN_HID0
-       ori     r2,r2,HID0_DAPUEN@l
+       ori     r2,r2,HID0_DAPUEN@l
        mtspr   SPRN_HID0,r2
 #endif
 
@@ -339,6 +375,17 @@ skpinv:    addi    r6,r6,1                         /* Increment */
 
        bl      early_init
 
+#ifdef CONFIG_RELOCATABLE
+       lis     r3,kernstart_addr@ha
+       la      r3,kernstart_addr@l(r3)
+#ifdef CONFIG_PHYS_64BIT
+       stw     r23,0(r3)
+       stw     r25,4(r3)
+#else
+       stw     r25,0(r3)
+#endif
+#endif
+
        mfspr   r3,SPRN_TLB1CFG
        andi.   r3,r3,0xfff
        lis     r4,num_tlbcam_entries@ha
@@ -388,7 +435,7 @@ skpinv:     addi    r6,r6,1                         /* Increment */
 #ifdef CONFIG_PTE_64BIT
 #define PTE_FLAGS_OFFSET       4
 #define FIND_PTE       \
-       rlwinm  r12, r10, 13, 19, 29;   /* Compute pgdir/pmd offset */  \
+       rlwinm  r12, r10, 13, 19, 29;   /* Compute pgdir/pmd offset */  \
        lwzx    r11, r12, r11;          /* Get pgd/pmd entry */         \
        rlwinm. r12, r11, 0, 0, 20;     /* Extract pt base address */   \
        beq     2f;                     /* Bail if no table */          \
@@ -458,8 +505,7 @@ interrupt_base:
        /* If we are faulting a kernel address, we have to use the
         * kernel page tables.
         */
-       lis     r11, TASK_SIZE@h
-       ori     r11, r11, TASK_SIZE@l
+       lis     r11, PAGE_OFFSET@h
        cmplw   0, r10, r11
        bge     2f
 
@@ -484,7 +530,7 @@ interrupt_base:
         */
        andi.   r11, r11, _PAGE_HWEXEC
        rlwimi  r11, r11, 31, 27, 27    /* SX <- _PAGE_HWEXEC */
-       ori     r11, r11, (MAS3_UW|MAS3_SW|MAS3_UR|MAS3_SR)@l /* set static perms */
+       ori     r11, r11, (MAS3_UW|MAS3_SW|MAS3_UR|MAS3_SR)@l /* set static perms */
 
        /* update search PID in MAS6, AS = 0 */
        mfspr   r12, SPRN_PID0
@@ -581,8 +627,7 @@ interrupt_base:
        /* If we are faulting a kernel address, we have to use the
         * kernel page tables.
         */
-       lis     r11, TASK_SIZE@h
-       ori     r11, r11, TASK_SIZE@l
+       lis     r11, PAGE_OFFSET@h
        cmplw   5, r10, r11
        blt     5, 3f
        lis     r11, swapper_pg_dir@h
@@ -642,8 +687,7 @@ interrupt_base:
        /* If we are faulting a kernel address, we have to use the
         * kernel page tables.
         */
-       lis     r11, TASK_SIZE@h
-       ori     r11, r11, TASK_SIZE@l
+       lis     r11, PAGE_OFFSET@h
        cmplw   5, r10, r11
        blt     5, 3f
        lis     r11, swapper_pg_dir@h
@@ -691,7 +735,7 @@ interrupt_base:
        START_EXCEPTION(SPEUnavailable)
        NORMAL_EXCEPTION_PROLOG
        bne     load_up_spe
-       addi    r3,r1,STACK_FRAME_OVERHEAD
+       addi    r3,r1,STACK_FRAME_OVERHEAD
        EXC_XFER_EE_LITE(0x2010, KernelSPE)
 #else
        EXCEPTION(0x2020, SPEUnavailable, unknown_exception, EXC_XFER_EE)
@@ -710,9 +754,15 @@ interrupt_base:
        /* Performance Monitor */
        EXCEPTION(0x2060, PerformanceMonitor, performance_monitor_exception, EXC_XFER_STD)
 
+#ifdef CONFIG_PPC_E500MC
+       EXCEPTION(0x2070, Doorbell, unknown_exception, EXC_XFER_EE)
+#endif
 
        /* Debug Interrupt */
-       DEBUG_EXCEPTION
+       DEBUG_DEBUG_EXCEPTION
+#if defined(CONFIG_E500) && !defined(CONFIG_PPC_E500MC)
+       DEBUG_CRIT_EXCEPTION
+#endif
 
 /*
  * Local functions
@@ -738,10 +788,10 @@ data_access:
 
  * Both the instruction and data TLB miss get to this
  * point to load the TLB.
- *     r10 - EA of fault
- *     r11 - TLB (info from Linux PTE)
- *     r12, r13 - available to use
- *     CR5 - results of addr < TASK_SIZE
+ *     r10 - EA of fault
+ *     r11 - TLB (info from Linux PTE)
+ *     r12, r13 - available to use
+ *     CR5 - results of addr >= PAGE_OFFSET
  *     MAS0, MAS1 - loaded with proper value when we get here
  *     MAS2, MAS3 - will need additional info from Linux PTE
  *     Upon exit, we reload everything and RFI.
@@ -810,7 +860,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_BIG_PHYS)
        lwz     r13, tlbcam_index@l(r13)
        rlwimi  r12, r13, 0, 20, 31
 7:
-       mtspr   SPRN_MAS0,r12
+       mtspr   SPRN_MAS0,r12
 #endif /* CONFIG_E200 */
 
        tlbwe
@@ -852,17 +902,17 @@ load_up_spe:
        beq     1f
        addi    r4,r4,THREAD    /* want THREAD of last_task_used_spe */
        SAVE_32EVRS(0,r10,r4)
-       evxor   evr10, evr10, evr10     /* clear out evr10 */
+       evxor   evr10, evr10, evr10     /* clear out evr10 */
        evmwumiaa evr10, evr10, evr10   /* evr10 <- ACC = 0 * 0 + ACC */
        li      r5,THREAD_ACC
-       evstddx evr10, r4, r5           /* save off accumulator */
+       evstddx evr10, r4, r5           /* save off accumulator */
        lwz     r5,PT_REGS(r4)
        lwz     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
        lis     r10,MSR_SPE@h
        andc    r4,r4,r10       /* disable SPE for previous task */
        stw     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 1:
-#endif /* CONFIG_SMP */
+#endif /* !CONFIG_SMP */
        /* enable use of SPE after return */
        oris    r9,r9,MSR_SPE@h
        mfspr   r5,SPRN_SPRG3           /* current task's THREAD (phys) */
@@ -875,7 +925,7 @@ load_up_spe:
 #ifndef CONFIG_SMP
        subi    r4,r5,THREAD
        stw     r4,last_task_used_spe@l(r3)
-#endif /* CONFIG_SMP */
+#endif /* !CONFIG_SMP */
        /* restore registers and return */
 2:     REST_4GPRS(3, r11)
        lwz     r10,_CCR(r11)
@@ -889,7 +939,6 @@ load_up_spe:
        REST_GPR(9, r11)
        REST_GPR(12, r11)
        lwz     r11,GPR11(r11)
-       SYNC
        rfi
 
 /*
@@ -953,7 +1002,6 @@ _GLOBAL(giveup_altivec)
 _GLOBAL(giveup_spe)
        mfmsr   r5
        oris    r5,r5,MSR_SPE@h
-       SYNC
        mtmsr   r5                      /* enable use of SPE now */
        isync
        cmpi    0,r3,0
@@ -962,10 +1010,10 @@ _GLOBAL(giveup_spe)
        lwz     r5,PT_REGS(r3)
        cmpi    0,r5,0
        SAVE_32EVRS(0, r4, r3)
-       evxor   evr6, evr6, evr6        /* clear out evr6 */
+       evxor   evr6, evr6, evr6        /* clear out evr6 */
        evmwumiaa evr6, evr6, evr6      /* evr6 <- ACC = 0 * 0 + ACC */
        li      r4,THREAD_ACC
-       evstddx evr6, r4, r3            /* save off accumulator */
+       evstddx evr6, r4, r3            /* save off accumulator */
        mfspr   r6,SPRN_SPEFSCR
        stw     r6,THREAD_SPEFSCR(r3)   /* save spefscr register value */
        beq     1f
@@ -978,7 +1026,7 @@ _GLOBAL(giveup_spe)
        li      r5,0
        lis     r4,last_task_used_spe@ha
        stw     r5,last_task_used_spe@l(r4)
-#endif /* CONFIG_SMP */
+#endif /* !CONFIG_SMP */
        blr
 #endif /* CONFIG_SPE */
 
@@ -999,15 +1047,15 @@ _GLOBAL(giveup_fpu)
  */
 _GLOBAL(abort)
        li      r13,0
-        mtspr   SPRN_DBCR0,r13         /* disable all debug events */
+       mtspr   SPRN_DBCR0,r13          /* disable all debug events */
        isync
        mfmsr   r13
        ori     r13,r13,MSR_DE@l        /* Enable Debug Events */
        mtmsr   r13
        isync
-        mfspr   r13,SPRN_DBCR0
-        lis    r13,(DBCR0_IDM|DBCR0_RST_CHIP)@h
-        mtspr   SPRN_DBCR0,r13
+       mfspr   r13,SPRN_DBCR0
+       lis     r13,(DBCR0_IDM|DBCR0_RST_CHIP)@h
+       mtspr   SPRN_DBCR0,r13
        isync
 
 _GLOBAL(set_context)
@@ -1024,6 +1072,52 @@ _GLOBAL(set_context)
        isync                   /* Force context change */
        blr
 
+_GLOBAL(flush_dcache_L1)
+       mfspr   r3,SPRN_L1CFG0
+
+       rlwinm  r5,r3,9,3       /* Extract cache block size */
+       twlgti  r5,1            /* Only 32 and 64 byte cache blocks
+                                * are currently defined.
+                                */
+       li      r4,32
+       subfic  r6,r5,2         /* r6 = log2(1KiB / cache block size) -
+                                *      log2(number of ways)
+                                */
+       slw     r5,r4,r5        /* r5 = cache block size */
+
+       rlwinm  r7,r3,0,0xff    /* Extract number of KiB in the cache */
+       mulli   r7,r7,13        /* An 8-way cache will require 13
+                                * loads per set.
+                                */
+       slw     r7,r7,r6
+
+       /* save off HID0 and set DCFA */
+       mfspr   r8,SPRN_HID0
+       ori     r9,r8,HID0_DCFA@l
+       mtspr   SPRN_HID0,r9
+       isync
+
+       lis     r4,KERNELBASE@h
+       mtctr   r7
+
+1:     lwz     r3,0(r4)        /* Load... */
+       add     r4,r4,r5
+       bdnz    1b
+
+       msync
+       lis     r4,KERNELBASE@h
+       mtctr   r7
+
+1:     dcbf    0,r4            /* ...and flush. */
+       add     r4,r4,r5
+       bdnz    1b
+       
+       /* restore HID0 */
+       mtspr   SPRN_HID0,r8
+       isync
+
+       blr
+
 /*
  * We put a few things here that have to be page-aligned. This stuff
  * goes at the beginning of the data segment, which is page-aligned.
@@ -1037,24 +1131,7 @@ empty_zero_page:
        .space  4096
        .globl  swapper_pg_dir
 swapper_pg_dir:
-       .space  4096
-
-/* Reserved 4k for the critical exception stack & 4k for the machine
- * check stack per CPU for kernel mode exceptions */
-       .section .bss
-        .align 12
-exception_stack_bottom:
-       .space  BOOKE_EXCEPTION_STACK_SIZE * NR_CPUS
-       .globl  exception_stack_top
-exception_stack_top:
-
-/*
- * This space gets a copy of optional info passed to us by the bootstrap
- * which is used to pass parameters into the kernel like root=/dev/sda1, etc.
- */
-       .globl  cmd_line
-cmd_line:
-       .space  512
+       .space  PGD_TABLE_SIZE
 
 /*
  * Room for two PTE pointers, usually the kernel and current user pointers