summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/kernel')
-rw-r--r--arch/ppc/kernel/Makefile3
-rw-r--r--arch/ppc/kernel/cputable.c45
-rw-r--r--arch/ppc/kernel/entry.S10
-rw-r--r--arch/ppc/kernel/head_44x.S24
-rw-r--r--arch/ppc/kernel/head_8xx.S12
-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/machine_kexec.c124
-rw-r--r--arch/ppc/kernel/misc.S16
-rw-r--r--arch/ppc/kernel/pci.c36
-rw-r--r--arch/ppc/kernel/perfmon.c2
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c2
-rw-r--r--arch/ppc/kernel/relocate_kernel.S123
-rw-r--r--arch/ppc/kernel/setup.c6
-rw-r--r--arch/ppc/kernel/signal.c3
-rw-r--r--arch/ppc/kernel/time.c13
-rw-r--r--arch/ppc/kernel/traps.c24
17 files changed, 522 insertions, 36 deletions
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index b284451802c..b1457a8a9c0 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -26,7 +26,10 @@ 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
+obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
ifndef CONFIG_MATH_EMULATION
obj-$(CONFIG_8xx) += softemu8xx.o
diff --git a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c
index 01c226008db..8a3d74f2531 100644
--- a/arch/ppc/kernel/cputable.c
+++ b/arch/ppc/kernel/cputable.c
@@ -852,6 +852,26 @@ struct cpu_spec cpu_specs[] = {
#endif /* CONFIG_40x */
#ifdef CONFIG_44x
+ {
+ .pvr_mask = 0xf0000fff,
+ .pvr_value = 0x40000850,
+ .cpu_name = "440EP Rev. A",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB,
+ .cpu_user_features = COMMON_PPC, /* 440EP has an FPU */
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ },
+ {
+ .pvr_mask = 0xf0000fff,
+ .pvr_value = 0x400008d3,
+ .cpu_name = "440EP Rev. B",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB,
+ .cpu_user_features = COMMON_PPC, /* 440EP has an FPU */
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ },
{ /* 440GP Rev. B */
.pvr_mask = 0xf0000fff,
.pvr_value = 0x40000440,
@@ -903,7 +923,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 8377b6ca26d..cb83045e2ed 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)
@@ -210,6 +215,7 @@ syscall_dotrace_cont:
lwzx r10,r10,r0 /* Fetch system call handler [ptr] */
mtlr r10
addi r9,r1,STACK_FRAME_OVERHEAD
+ PPC440EP_ERR42
blrl /* Call handler */
.globl ret_from_syscall
ret_from_syscall:
@@ -835,6 +841,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_44x.S b/arch/ppc/kernel/head_44x.S
index 6c7ae605246..69ff3a9961e 100644
--- a/arch/ppc/kernel/head_44x.S
+++ b/arch/ppc/kernel/head_44x.S
@@ -179,24 +179,26 @@ skpinv: addi r4,r4,1 /* Increment */
4:
#ifdef CONFIG_SERIAL_TEXT_DEBUG
/*
- * Add temporary UART mapping for early debug. This
- * mapping must be identical to that used by the early
- * bootloader code since the same asm/serial.h parameters
- * are used for polled operation.
+ * Add temporary UART mapping for early debug.
+ * We can map UART registers wherever we want as long as they don't
+ * interfere with other system mappings (e.g. with pinned entries).
+ * For an example of how we handle this - see ocotea.h. --ebs
*/
/* pageid fields */
lis r3,UART0_IO_BASE@h
- ori r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_256M
+ ori r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_4K
/* xlat fields */
lis r4,UART0_PHYS_IO_BASE@h /* RPN depends on SoC */
+#ifndef CONFIG_440EP
ori r4,r4,0x0001 /* ERPN is 1 for second 4GB page */
+#endif
/* attrib fields */
li r5,0
ori r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_I | PPC44x_TLB_G)
- li r0,1 /* TLB slot 1 */
+ li r0,0 /* TLB slot 0 */
tlbwe r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */
tlbwe r4,r0,PPC44x_TLB_XLAT /* Load the translation fields */
@@ -228,6 +230,16 @@ skpinv: addi r4,r4,1 /* Increment */
lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */
mtspr SPRN_IVPR,r4
+#ifdef CONFIG_440EP
+ /* Clear DAPUIB flag in CCR0 (enable APU between CPU and FPU) */
+ mfspr r2,SPRN_CCR0
+ lis r3,0xffef
+ ori r3,r3,0xffff
+ and r2,r2,r3
+ mtspr SPRN_CCR0,r2
+ isync
+#endif
+
/*
* This is where the main kernel code starts.
*/
diff --git a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S
index 5a7a64e91fc..eb18cadb375 100644
--- a/arch/ppc/kernel/head_8xx.S
+++ b/arch/ppc/kernel/head_8xx.S
@@ -288,13 +288,11 @@ SystemCall:
* For the MPC8xx, this is a software tablewalk to load the instruction
* TLB. It is modelled after the example in the Motorola manual. The task
* switch loads the M_TWB register with the pointer to the first level table.
- * If we discover there is no second level table (the value is zero), the
- * plan was to load that into the TLB, which causes another fault into the
- * TLB Error interrupt where we can handle such problems. However, that did
- * not work, so if we discover there is no second level table, we restore
- * registers and branch to the error exception. We have to use the MD_xxx
- * registers for the tablewalk because the equivalent MI_xxx registers
- * only perform the attribute functions.
+ * If we discover there is no second level table (value is zero) or if there
+ * is an invalid pte, we load that into the TLB, which causes another fault
+ * into the TLB Error interrupt where we can handle such problems.
+ * We have to use the MD_xxx registers for the tablewalk because the
+ * equivalent MI_xxx registers only perform the attribute functions.
*/
InstructionTLBMiss:
#ifdef CONFIG_8xx_CPU6
diff --git a/arch/ppc/kernel/head_booke.h b/arch/ppc/kernel/head_booke.h
index 9c50f9d2657..9342acf12e7 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 ce36e88ba62..eb804b7a3cb 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/machine_kexec.c b/arch/ppc/kernel/machine_kexec.c
new file mode 100644
index 00000000000..a72787747df
--- /dev/null
+++ b/arch/ppc/kernel/machine_kexec.c
@@ -0,0 +1,124 @@
+/*
+ * machine_kexec.c - handle transition of Linux booting another kernel
+ * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com>
+ *
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/kexec.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/mmu_context.h>
+#include <asm/io.h>
+#include <asm/hw_irq.h>
+#include <asm/cacheflush.h>
+#include <asm/machdep.h>
+
+typedef NORET_TYPE void (*relocate_new_kernel_t)(
+ unsigned long indirection_page,
+ unsigned long reboot_code_buffer,
+ unsigned long start_address) ATTRIB_NORET;
+
+const extern unsigned char relocate_new_kernel[];
+const extern unsigned int relocate_new_kernel_size;
+
+/*
+ * Provide a dummy crash_notes definition while crash dump arrives to ppc.
+ * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
+ */
+void *crash_notes = NULL;
+
+void machine_shutdown(void)
+{
+ if (ppc_md.machine_shutdown)
+ ppc_md.machine_shutdown();
+}
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+ if (ppc_md.machine_crash_shutdown)
+ ppc_md.machine_crash_shutdown();
+}
+
+/*
+ * Do what every setup is needed on image and the
+ * reboot code buffer to allow us to avoid allocations
+ * later.
+ */
+int machine_kexec_prepare(struct kimage *image)
+{
+ if (ppc_md.machine_kexec_prepare)
+ return ppc_md.machine_kexec_prepare(image);
+ /*
+ * Fail if platform doesn't provide its own machine_kexec_prepare
+ * implementation.
+ */
+ return -ENOSYS;
+}
+
+void machine_kexec_cleanup(struct kimage *image)
+{
+ if (ppc_md.machine_kexec_cleanup)
+ ppc_md.machine_kexec_cleanup(image);
+}
+
+/*
+ * Do not allocate memory (or fail in any way) in machine_kexec().
+ * We are past the point of no return, committed to rebooting now.
+ */
+NORET_TYPE void machine_kexec(struct kimage *image)
+{
+ if (ppc_md.machine_kexec)
+ ppc_md.machine_kexec(image);
+ else {
+ /*
+ * Fall back to normal restart if platform doesn't provide
+ * its own kexec function, and user insist to kexec...
+ */
+ machine_restart(NULL);
+ }
+ for(;;);
+}
+
+/*
+ * This is a generic machine_kexec function suitable at least for
+ * non-OpenFirmware embedded platforms.
+ * It merely copies the image relocation code to the control page and
+ * jumps to it.
+ * A platform specific function may just call this one.
+ */
+void machine_kexec_simple(struct kimage *image)
+{
+ unsigned long page_list;
+ unsigned long reboot_code_buffer, reboot_code_buffer_phys;
+ relocate_new_kernel_t rnk;
+
+ /* Interrupts aren't acceptable while we reboot */
+ local_irq_disable();
+
+ page_list = image->head;
+
+ /* we need both effective and real address here */
+ reboot_code_buffer =
+ (unsigned long)page_address(image->control_code_page);
+ reboot_code_buffer_phys = virt_to_phys((void *)reboot_code_buffer);
+
+ /* copy our kernel relocation code to the control code page */
+ memcpy((void *)reboot_code_buffer, relocate_new_kernel,
+ relocate_new_kernel_size);
+
+ flush_icache_range(reboot_code_buffer,
+ reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE);
+ printk(KERN_INFO "Bye!\n");
+
+ /* now call it */
+ rnk = (relocate_new_kernel_t) reboot_code_buffer;
+ (*rnk)(page_list, reboot_code_buffer_phys, image->start);
+}
+
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index 7329ef177a1..ce71b4a0158 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
@@ -1137,6 +1145,7 @@ _GLOBAL(kernel_thread)
stwu r0,-16(r1)
mtlr r30 /* fn addr in lr */
mr r3,r31 /* load arg and call fn */
+ PPC440EP_ERR42
blrl
li r0,__NR_exit /* exit if function returns */
li r3,0
@@ -1436,8 +1445,13 @@ _GLOBAL(sys_call_table)
.long sys_mq_timedreceive /* 265 */
.long sys_mq_notify
.long sys_mq_getsetattr
- .long sys_ni_syscall /* 268 reserved for sys_kexec_load */
+ .long sys_kexec_load
.long sys_add_key
.long sys_request_key /* 270 */
.long sys_keyctl
.long sys_waitid
+ .long sys_ioprio_set
+ .long sys_ioprio_get
+ .long sys_inotify_init /* 275 */
+ .long sys_inotify_add_watch
+ .long sys_inotify_rm_watch
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 6d7b92d7245..7b3586a3bf3 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -160,6 +160,21 @@ void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
}
EXPORT_SYMBOL(pcibios_resource_to_bus);
+void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+ struct pci_bus_region *region)
+{
+ unsigned long offset = 0;
+ struct pci_controller *hose = dev->sysdata;
+
+ if (hose && res->flags & IORESOURCE_IO)
+ offset = (unsigned long)hose->io_base_virt - isa_io_base;
+ else if (hose && res->flags & IORESOURCE_MEM)
+ offset = hose->pci_mem_offset;
+ res->start = region->start + offset;
+ res->end = region->end + offset;
+}
+EXPORT_SYMBOL(pcibios_bus_to_resource);
+
/*
* We need to avoid collisions with `mirrored' VGA ports
* and other strange ISA hardware, so we always want the
@@ -1495,7 +1510,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
*offset += hose->pci_mem_offset;
res_bit = IORESOURCE_MEM;
} else {
- io_offset = (unsigned long)hose->io_base_virt;
+ io_offset = hose->io_base_virt - ___IO_BASE;
*offset += io_offset;
res_bit = IORESOURCE_IO;
}
@@ -1522,7 +1537,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
/* found it! construct the final physical address */
if (mmap_state == pci_mmap_io)
- *offset += hose->io_base_phys - _IO_BASE;
+ *offset += hose->io_base_phys - io_offset;
return rp;
}
@@ -1739,6 +1754,23 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
return result;
}
+void pci_resource_to_user(const struct pci_dev *dev, int bar,
+ const struct resource *rsrc,
+ u64 *start, u64 *end)
+{
+ struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
+ unsigned long offset = 0;
+
+ if (hose == NULL)
+ return;
+
+ if (rsrc->flags & IORESOURCE_IO)
+ offset = ___IO_BASE - hose->io_base_virt + hose->io_base_phys;
+
+ *start = rsrc->start + offset;
+ *end = rsrc->end + offset;
+}
+
void __init
pci_init_resource(struct resource *res, unsigned long start, unsigned long end,
int flags, char *name)
diff --git a/arch/ppc/kernel/perfmon.c b/arch/ppc/kernel/perfmon.c
index 918f6b252e4..fa1dad96b83 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/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index d59ad07de8e..e7d40cc6c1b 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -324,7 +324,7 @@ EXPORT_SYMBOL(__res);
EXPORT_SYMBOL(next_mmu_context);
EXPORT_SYMBOL(set_context);
-EXPORT_SYMBOL(handle_mm_fault); /* For MOL */
+EXPORT_SYMBOL_GPL(__handle_mm_fault); /* For MOL */
EXPORT_SYMBOL(disarm_decr);
#ifdef CONFIG_PPC_STD_MMU
extern long mol_trampoline;
diff --git a/arch/ppc/kernel/relocate_kernel.S b/arch/ppc/kernel/relocate_kernel.S
new file mode 100644
index 00000000000..9b2ad48e988
--- /dev/null
+++ b/arch/ppc/kernel/relocate_kernel.S
@@ -0,0 +1,123 @@
+/*
+ * relocate_kernel.S - put the kernel image in place to boot
+ * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com>
+ *
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <asm/reg.h>
+#include <asm/ppc_asm.h>
+#include <asm/processor.h>
+
+#include <asm/kexec.h>
+
+#define PAGE_SIZE 4096 /* must be same value as in <asm/page.h> */
+
+ /*
+ * Must be relocatable PIC code callable as a C function.
+ */
+ .globl relocate_new_kernel
+relocate_new_kernel:
+ /* r3 = page_list */
+ /* r4 = reboot_code_buffer */
+ /* r5 = start_address */
+
+ li r0, 0
+
+ /*
+ * Set Machine Status Register to a known status,
+ * switch the MMU off and jump to 1: in a single step.
+ */
+
+ mr r8, r0
+ ori r8, r8, MSR_RI|MSR_ME
+ mtspr SPRN_SRR1, r8
+ addi r8, r4, 1f - relocate_new_kernel
+ mtspr SPRN_SRR0, r8
+ sync
+ rfi
+
+1:
+ /* from this point address translation is turned off */
+ /* and interrupts are disabled */
+
+ /* set a new stack at the bottom of our page... */
+ /* (not really needed now) */
+ addi r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */
+ stw r0, 0(r1)
+
+ /* Do the copies */
+ li r6, 0 /* checksum */
+ mr r0, r3
+ b 1f
+
+0: /* top, read another word for the indirection page */
+ lwzu r0, 4(r3)
+
+1:
+ /* is it a destination page? (r8) */
+ rlwinm. r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */
+ beq 2f
+
+ rlwinm r8, r0, 0, 0, 19 /* clear kexec flags, page align */
+ b 0b
+
+2: /* is it an indirection page? (r3) */
+ rlwinm. r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */
+ beq 2f
+
+ rlwinm r3, r0, 0, 0, 19 /* clear kexec flags, page align */
+ subi r3, r3, 4
+ b 0b
+
+2: /* are we done? */
+ rlwinm. r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */
+ beq 2f
+ b 3f
+
+2: /* is it a source page? (r9) */
+ rlwinm. r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */
+ beq 0b
+
+ rlwinm r9, r0, 0, 0, 19 /* clear kexec flags, page align */
+
+ li r7, PAGE_SIZE / 4
+ mtctr r7
+ subi r9, r9, 4
+ subi r8, r8, 4
+9:
+ lwzu r0, 4(r9) /* do the copy */
+ xor r6, r6, r0
+ stwu r0, 4(r8)
+ dcbst 0, r8
+ sync
+ icbi 0, r8
+ bdnz 9b
+
+ addi r9, r9, 4
+ addi r8, r8, 4
+ b 0b
+
+3:
+
+ /* To be certain of avoiding problems with self-modifying code
+ * execute a serializing instruction here.
+ */
+ isync
+ sync
+
+ /* jump to the entry point, usually the setup routine */
+ mtlr r5
+ blrl
+
+1: b 1b
+
+relocate_new_kernel_end:
+
+ .globl relocate_new_kernel_size
+relocate_new_kernel_size:
+ .long relocate_new_kernel_end - relocate_new_kernel
+
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index c42f7532693..929e5d1cc7f 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -121,8 +121,6 @@ void machine_restart(char *cmd)
ppc_md.restart(cmd);
}
-EXPORT_SYMBOL(machine_restart);
-
void machine_power_off(void)
{
#ifdef CONFIG_NVRAM
@@ -131,8 +129,6 @@ void machine_power_off(void)
ppc_md.power_off();
}
-EXPORT_SYMBOL(machine_power_off);
-
void machine_halt(void)
{
#ifdef CONFIG_NVRAM
@@ -141,8 +137,6 @@ void machine_halt(void)
ppc_md.halt();
}
-EXPORT_SYMBOL(machine_halt);
-
void (*pm_power_off)(void) = machine_power_off;
#ifdef CONFIG_TAU
diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
index 7c8437da09d..8aaeb6f4e75 100644
--- a/arch/ppc/kernel/signal.c
+++ b/arch/ppc/kernel/signal.c
@@ -705,8 +705,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
unsigned long frame, newsp;
int signr, ret;
- if (current->flags & PF_FREEZE) {
- refrigerator(PF_FREEZE);
+ if (try_to_freeze()) {
signr = 0;
if (!signal_pending(current))
goto no_signal;
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
index 73586655919..bf4ddca5e85 100644
--- a/arch/ppc/kernel/time.c
+++ b/arch/ppc/kernel/time.c
@@ -89,6 +89,9 @@ unsigned long tb_to_ns_scale;
extern unsigned long wall_jiffies;
+/* used for timezone offset */
+static long timezone_offset;
+
DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL(rtc_lock);
@@ -170,7 +173,7 @@ void timer_interrupt(struct pt_regs * regs)
xtime.tv_sec - last_rtc_update >= 659 &&
abs((xtime.tv_nsec / 1000) - (1000000-1000000/HZ)) < 500000/HZ &&
jiffies - wall_jiffies == 1) {
- if (ppc_md.set_rtc_time(xtime.tv_sec+1 + time_offset) == 0)
+ if (ppc_md.set_rtc_time(xtime.tv_sec+1 + timezone_offset) == 0)
last_rtc_update = xtime.tv_sec+1;
else
/* Try again one minute later */
@@ -286,7 +289,7 @@ void __init time_init(void)
unsigned old_stamp, stamp, elapsed;
if (ppc_md.time_init != NULL)
- time_offset = ppc_md.time_init();
+ timezone_offset = ppc_md.time_init();
if (__USE_RTC()) {
/* 601 processor: dec counts down by 128 every 128ns */
@@ -331,10 +334,10 @@ void __init time_init(void)
set_dec(tb_ticks_per_jiffy);
/* If platform provided a timezone (pmac), we correct the time */
- if (time_offset) {
- sys_tz.tz_minuteswest = -time_offset / 60;
+ if (timezone_offset) {
+ sys_tz.tz_minuteswest = -timezone_offset / 60;
sys_tz.tz_dsttime = 0;
- xtime.tv_sec -= time_offset;
+ xtime.tv_sec -= timezone_offset;
}
set_normalized_timespec(&wall_to_monotonic,
-xtime.tv_sec, -xtime.tv_nsec);
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 2ca8ecfeefd..9e6ae569665 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) {