summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel
diff options
context:
space:
mode:
authorKumar Gala <galak@freescale.com>2005-06-25 14:54:37 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-25 16:24:26 -0700
commit33d9e9b56d5ccd7776fdfe3ecce4a2793dee6fd3 (patch)
treee2ecb071823cc9ffe2755ed117bfabe04a35e1fc /arch/ppc/kernel
parent62aa751d16399637325852bc0a1fcf13c2476dd7 (diff)
downloadlinux-33d9e9b56d5ccd7776fdfe3ecce4a2793dee6fd3.tar.bz2
[PATCH] ppc32: Add support for Freescale e200 (Book-E) core
The e200 core is a Book-E core (similar to e500) that has a unified L1 cache and is not cache coherent on the bus. The e200 core also adds a separate exception level for debug exceptions. Part of this patch helps to cleanup a few cases that are true for all Freescale Book-E parts, not just e500. Signed-off-by: Kim Phillips <kim.phillips@freescale.com> Signed-off-by: Kumar Gala <kumar.gala@freescale.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/ppc/kernel')
-rw-r--r--arch/ppc/kernel/Makefile2
-rw-r--r--arch/ppc/kernel/cputable.c25
-rw-r--r--arch/ppc/kernel/entry.S9
-rw-r--r--arch/ppc/kernel/head_booke.h64
-rw-r--r--arch/ppc/kernel/head_fsl_booke.S51
-rw-r--r--arch/ppc/kernel/misc.S8
-rw-r--r--arch/ppc/kernel/perfmon.c2
-rw-r--r--arch/ppc/kernel/traps.c24
8 files changed, 179 insertions, 6 deletions
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index b284451802c9..8276c0b551d2 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -26,7 +26,9 @@ obj-$(CONFIG_KGDB) += ppc-stub.o
obj-$(CONFIG_SMP) += smp.o smp-tbsync.o
obj-$(CONFIG_TAU) += temp.o
obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
+ifndef CONFIG_E200
obj-$(CONFIG_FSL_BOOKE) += perfmon_fsl_booke.o
+endif
ifndef CONFIG_MATH_EMULATION
obj-$(CONFIG_8xx) += softemu8xx.o
diff --git a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c
index 01c226008dbf..50936cda0af9 100644
--- a/arch/ppc/kernel/cputable.c
+++ b/arch/ppc/kernel/cputable.c
@@ -903,7 +903,30 @@ struct cpu_spec cpu_specs[] = {
.dcache_bsize = 32,
},
#endif /* CONFIG_44x */
-#ifdef CONFIG_E500
+#ifdef CONFIG_FSL_BOOKE
+ { /* e200z5 */
+ .pvr_mask = 0xfff00000,
+ .pvr_value = 0x81000000,
+ .cpu_name = "e200z5",
+ /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
+ .cpu_features = CPU_FTR_USE_TB,
+ .cpu_user_features = PPC_FEATURE_32 |
+ PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_EFP_SINGLE |
+ PPC_FEATURE_UNIFIED_CACHE,
+ .dcache_bsize = 32,
+ },
+ { /* e200z6 */
+ .pvr_mask = 0xfff00000,
+ .pvr_value = 0x81100000,
+ .cpu_name = "e200z6",
+ /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
+ .cpu_features = CPU_FTR_USE_TB,
+ .cpu_user_features = PPC_FEATURE_32 |
+ PPC_FEATURE_HAS_MMU | PPC_FEATURE_SPE_COMP |
+ PPC_FEATURE_HAS_EFP_SINGLE |
+ PPC_FEATURE_UNIFIED_CACHE,
+ .dcache_bsize = 32,
+ },
{ /* e500 */
.pvr_mask = 0xffff0000,
.pvr_value = 0x80200000,
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
index 8377b6ca26da..d4df68629cc6 100644
--- a/arch/ppc/kernel/entry.S
+++ b/arch/ppc/kernel/entry.S
@@ -60,6 +60,11 @@ mcheck_transfer_to_handler:
TRANSFER_TO_HANDLER_EXC_LEVEL(MCHECK)
b transfer_to_handler_full
+ .globl debug_transfer_to_handler
+debug_transfer_to_handler:
+ TRANSFER_TO_HANDLER_EXC_LEVEL(DEBUG)
+ b transfer_to_handler_full
+
.globl crit_transfer_to_handler
crit_transfer_to_handler:
TRANSFER_TO_HANDLER_EXC_LEVEL(CRIT)
@@ -835,6 +840,10 @@ ret_from_crit_exc:
RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI)
#ifdef CONFIG_BOOKE
+ .globl ret_from_debug_exc
+ret_from_debug_exc:
+ RET_FROM_EXC_LEVEL(SPRN_DSRR0, SPRN_DSRR1, RFDI)
+
.globl ret_from_mcheck_exc
ret_from_mcheck_exc:
RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, RFMCI)
diff --git a/arch/ppc/kernel/head_booke.h b/arch/ppc/kernel/head_booke.h
index 9c50f9d2657c..9342acf12e72 100644
--- a/arch/ppc/kernel/head_booke.h
+++ b/arch/ppc/kernel/head_booke.h
@@ -49,6 +49,7 @@
*
* On 40x critical is the only additional level
* On 44x/e500 we have critical and machine check
+ * On e200 we have critical and debug (machine check occurs via critical)
*
* Additionally we reserve a SPRG for each priority level so we can free up a
* GPR to use as the base for indirect access to the exception stacks. This
@@ -60,12 +61,16 @@
/* CRIT_SPRG only used in critical exception handling */
#define CRIT_SPRG SPRN_SPRG2
-/* MCHECK_SPRG only used in critical exception handling */
+/* MCHECK_SPRG only used in machine check exception handling */
#define MCHECK_SPRG SPRN_SPRG6W
#define MCHECK_STACK_TOP (exception_stack_top - 4096)
#define CRIT_STACK_TOP (exception_stack_top)
+/* only on e200 for now */
+#define DEBUG_STACK_TOP (exception_stack_top - 4096)
+#define DEBUG_SPRG SPRN_SPRG6W
+
#ifdef CONFIG_SMP
#define BOOKE_LOAD_EXC_LEVEL_STACK(level) \
mfspr r8,SPRN_PIR; \
@@ -124,6 +129,8 @@
#define CRITICAL_EXCEPTION_PROLOG \
EXC_LEVEL_EXCEPTION_PROLOG(CRIT, SPRN_CSRR0, SPRN_CSRR1)
+#define DEBUG_EXCEPTION_PROLOG \
+ EXC_LEVEL_EXCEPTION_PROLOG(DEBUG, SPRN_DSRR0, SPRN_DSRR1)
#define MCHECK_EXCEPTION_PROLOG \
EXC_LEVEL_EXCEPTION_PROLOG(MCHECK, SPRN_MCSRR0, SPRN_MCSRR1)
@@ -205,6 +212,60 @@ label:
* save (and later restore) the MSR via SPRN_CSRR1, which will still have
* the MSR_DE bit set.
*/
+#ifdef CONFIG_E200
+#define DEBUG_EXCEPTION \
+ START_EXCEPTION(Debug); \
+ DEBUG_EXCEPTION_PROLOG; \
+ \
+ /* \
+ * If there is a single step or branch-taken exception in an \
+ * exception entry sequence, it was probably meant to apply to \
+ * the code where the exception occurred (since exception entry \
+ * doesn't turn off DE automatically). We simulate the effect \
+ * of turning off DE on entry to an exception handler by turning \
+ * off DE in the CSRR1 value and clearing the debug status. \
+ */ \
+ mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \
+ andis. r10,r10,DBSR_IC@h; \
+ beq+ 2f; \
+ \
+ lis r10,KERNELBASE@h; /* check if exception in vectors */ \
+ ori r10,r10,KERNELBASE@l; \
+ cmplw r12,r10; \
+ blt+ 2f; /* addr below exception vectors */ \
+ \
+ lis r10,Debug@h; \
+ ori r10,r10,Debug@l; \
+ cmplw r12,r10; \
+ bgt+ 2f; /* addr above exception vectors */ \
+ \
+ /* here it looks like we got an inappropriate debug exception. */ \
+1: rlwinm r9,r9,0,~MSR_DE; /* clear DE in the CDRR1 value */ \
+ lis r10,DBSR_IC@h; /* clear the IC event */ \
+ mtspr SPRN_DBSR,r10; \
+ /* restore state and get out */ \
+ lwz r10,_CCR(r11); \
+ lwz r0,GPR0(r11); \
+ lwz r1,GPR1(r11); \
+ mtcrf 0x80,r10; \
+ mtspr SPRN_DSRR0,r12; \
+ mtspr SPRN_DSRR1,r9; \
+ lwz r9,GPR9(r11); \
+ lwz r12,GPR12(r11); \
+ mtspr DEBUG_SPRG,r8; \
+ BOOKE_LOAD_EXC_LEVEL_STACK(DEBUG); /* r8 points to the debug stack */ \
+ lwz r10,GPR10-INT_FRAME_SIZE(r8); \
+ lwz r11,GPR11-INT_FRAME_SIZE(r8); \
+ mfspr r8,DEBUG_SPRG; \
+ \
+ RFDI; \
+ b .; \
+ \
+ /* continue normal handling for a critical exception... */ \
+2: mfspr r4,SPRN_DBSR; \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, debug_transfer_to_handler, ret_from_debug_exc)
+#else
#define DEBUG_EXCEPTION \
START_EXCEPTION(Debug); \
CRITICAL_EXCEPTION_PROLOG; \
@@ -257,6 +318,7 @@ label:
2: mfspr r4,SPRN_DBSR; \
addi r3,r1,STACK_FRAME_OVERHEAD; \
EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
+#endif
#define INSTRUCTION_STORAGE_EXCEPTION \
START_EXCEPTION(InstructionStorage) \
diff --git a/arch/ppc/kernel/head_fsl_booke.S b/arch/ppc/kernel/head_fsl_booke.S
index ce36e88ba627..eb804b7a3cb2 100644
--- a/arch/ppc/kernel/head_fsl_booke.S
+++ b/arch/ppc/kernel/head_fsl_booke.S
@@ -102,6 +102,7 @@ invstr: mflr r6 /* Make it accessible */
or r7,r7,r4
mtspr SPRN_MAS6,r7
tlbsx 0,r6 /* search MSR[IS], SPID=PID0 */
+#ifndef CONFIG_E200
mfspr r7,SPRN_MAS1
andis. r7,r7,MAS1_VALID@h
bne match_TLB
@@ -118,6 +119,7 @@ invstr: mflr r6 /* Make it accessible */
or r7,r7,r4
mtspr SPRN_MAS6,r7
tlbsx 0,r6 /* Fall through, we had to match */
+#endif
match_TLB:
mfspr r7,SPRN_MAS0
rlwinm r3,r7,16,20,31 /* Extract MAS0(Entry) */
@@ -196,8 +198,10 @@ skpinv: addi r6,r6,1 /* Increment */
/* 4. Clear out PIDs & Search info */
li r6,0
mtspr SPRN_PID0,r6
+#ifndef CONFIG_E200
mtspr SPRN_PID1,r6
mtspr SPRN_PID2,r6
+#endif
mtspr SPRN_MAS6,r6
/* 5. Invalidate mapping we started in */
@@ -277,7 +281,9 @@ skpinv: addi r6,r6,1 /* Increment */
SET_IVOR(32, SPEUnavailable);
SET_IVOR(33, SPEFloatingPointData);
SET_IVOR(34, SPEFloatingPointRound);
+#ifndef CONFIG_E200
SET_IVOR(35, PerformanceMonitor);
+#endif
/* Establish the interrupt vector base */
lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */
@@ -285,6 +291,9 @@ skpinv: addi r6,r6,1 /* Increment */
/* Setup the defaults for TLB entries */
li r2,(MAS4_TSIZED(BOOKE_PAGESZ_4K))@l
+#ifdef CONFIG_E200
+ oris r2,r2,MAS4_TLBSELD(1)@h
+#endif
mtspr SPRN_MAS4, r2
#if 0
@@ -293,6 +302,12 @@ skpinv: addi r6,r6,1 /* Increment */
oris r2,r2,HID0_DOZE@h
mtspr SPRN_HID0, r2
#endif
+#ifdef CONFIG_E200
+ /* enable dedicated debug exception handling resources (Debug APU) */
+ mfspr r2,SPRN_HID0
+ ori r2,r2,HID0_DAPUEN@l
+ mtspr SPRN_HID0,r2
+#endif
#if !defined(CONFIG_BDI_SWITCH)
/*
@@ -414,7 +429,12 @@ interrupt_base:
CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException)
/* Machine Check Interrupt */
+#ifdef CONFIG_E200
+ /* no RFMCI, MCSRRs on E200 */
+ CRITICAL_EXCEPTION(0x0200, MachineCheck, MachineCheckException)
+#else
MCHECK_EXCEPTION(0x0200, MachineCheck, MachineCheckException)
+#endif
/* Data Storage Interrupt */
START_EXCEPTION(DataStorage)
@@ -520,8 +540,13 @@ interrupt_base:
#ifdef CONFIG_PPC_FPU
FP_UNAVAILABLE_EXCEPTION
#else
+#ifdef CONFIG_E200
+ /* E200 treats 'normal' floating point instructions as FP Unavail exception */
+ EXCEPTION(0x0800, FloatingPointUnavailable, ProgramCheckException, EXC_XFER_EE)
+#else
EXCEPTION(0x0800, FloatingPointUnavailable, UnknownException, EXC_XFER_EE)
#endif
+#endif
/* System Call Interrupt */
START_EXCEPTION(SystemCall)
@@ -691,6 +716,7 @@ interrupt_base:
/*
* Local functions
*/
+
/*
* Data TLB exceptions will bail out to this point
* if they can't resolve the lightweight TLB fault.
@@ -761,6 +787,31 @@ END_FTR_SECTION_IFSET(CPU_FTR_BIG_PHYS)
2: rlwimi r11, r12, 0, 20, 31 /* Extract RPN from PTE and merge with perms */
mtspr SPRN_MAS3, r11
#endif
+#ifdef CONFIG_E200
+ /* Round robin TLB1 entries assignment */
+ mfspr r12, SPRN_MAS0
+
+ /* Extract TLB1CFG(NENTRY) */
+ mfspr r11, SPRN_TLB1CFG
+ andi. r11, r11, 0xfff
+
+ /* Extract MAS0(NV) */
+ andi. r13, r12, 0xfff
+ addi r13, r13, 1
+ cmpw 0, r13, r11
+ addi r12, r12, 1
+
+ /* check if we need to wrap */
+ blt 7f
+
+ /* wrap back to first free tlbcam entry */
+ lis r13, tlbcam_index@ha
+ lwz r13, tlbcam_index@l(r13)
+ rlwimi r12, r13, 0, 20, 31
+7:
+ mtspr SPRN_MAS0,r12
+#endif /* CONFIG_E200 */
+
tlbwe
/* Done...restore registers and get out of here. */
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index 7329ef177a18..a3132f8e799c 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -593,6 +593,14 @@ _GLOBAL(flush_instruction_cache)
iccci 0,r3
#endif
#elif CONFIG_FSL_BOOKE
+BEGIN_FTR_SECTION
+ mfspr r3,SPRN_L1CSR0
+ ori r3,r3,L1CSR0_CFI|L1CSR0_CLFC
+ /* msync; isync recommended here */
+ mtspr SPRN_L1CSR0,r3
+ isync
+ blr
+END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
mfspr r3,SPRN_L1CSR1
ori r3,r3,L1CSR1_ICFI|L1CSR1_ICLFR
mtspr SPRN_L1CSR1,r3
diff --git a/arch/ppc/kernel/perfmon.c b/arch/ppc/kernel/perfmon.c
index 918f6b252e45..fa1dad96b830 100644
--- a/arch/ppc/kernel/perfmon.c
+++ b/arch/ppc/kernel/perfmon.c
@@ -36,7 +36,7 @@
/* A lock to regulate grabbing the interrupt */
DEFINE_SPINLOCK(perfmon_lock);
-#ifdef CONFIG_FSL_BOOKE
+#if defined (CONFIG_FSL_BOOKE) && !defined (CONFIG_E200)
static void dummy_perf(struct pt_regs *regs)
{
unsigned int pmgc0 = mfpmr(PMRN_PMGC0);
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 2ca8ecfeefd9..9e6ae5696650 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -173,13 +173,13 @@ static inline int check_io_access(struct pt_regs *regs)
/* On 4xx, the reason for the machine check or program exception
is in the ESR. */
#define get_reason(regs) ((regs)->dsisr)
-#ifndef CONFIG_E500
+#ifndef CONFIG_FSL_BOOKE
#define get_mc_reason(regs) ((regs)->dsisr)
#else
#define get_mc_reason(regs) (mfspr(SPRN_MCSR))
#endif
#define REASON_FP ESR_FP
-#define REASON_ILLEGAL ESR_PIL
+#define REASON_ILLEGAL (ESR_PIL | ESR_PUO)
#define REASON_PRIVILEGED ESR_PPR
#define REASON_TRAP ESR_PTR
@@ -302,7 +302,25 @@ void MachineCheckException(struct pt_regs *regs)
printk("Bus - Instruction Parity Error\n");
if (reason & MCSR_BUS_RPERR)
printk("Bus - Read Parity Error\n");
-#else /* !CONFIG_4xx && !CONFIG_E500 */
+#elif defined (CONFIG_E200)
+ printk("Machine check in kernel mode.\n");
+ printk("Caused by (from MCSR=%lx): ", reason);
+
+ if (reason & MCSR_MCP)
+ printk("Machine Check Signal\n");
+ if (reason & MCSR_CP_PERR)
+ printk("Cache Push Parity Error\n");
+ if (reason & MCSR_CPERR)
+ printk("Cache Parity Error\n");
+ if (reason & MCSR_EXCP_ERR)
+ printk("ISI, ITLB, or Bus Error on first instruction fetch for an exception handler\n");
+ if (reason & MCSR_BUS_IRERR)
+ printk("Bus - Read Bus Error on instruction fetch\n");
+ if (reason & MCSR_BUS_DRERR)
+ printk("Bus - Read Bus Error on data load\n");
+ if (reason & MCSR_BUS_WRERR)
+ printk("Bus - Write Bus Error on buffered store or cache line push\n");
+#else /* !CONFIG_4xx && !CONFIG_E500 && !CONFIG_E200 */
printk("Machine check in kernel mode.\n");
printk("Caused by (from SRR1=%lx): ", reason);
switch (reason & 0x601F0000) {