summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/kernel')
-rw-r--r--arch/ppc/kernel/Makefile8
-rw-r--r--arch/ppc/kernel/apus_setup.c244
-rw-r--r--arch/ppc/kernel/chrp_setup.c26
-rw-r--r--arch/ppc/kernel/entry.S2
-rw-r--r--arch/ppc/kernel/head.S157
-rw-r--r--arch/ppc/kernel/irq.c38
-rw-r--r--arch/ppc/kernel/mk_defs.c3
-rw-r--r--arch/ppc/kernel/pmac_setup.c6
-rw-r--r--arch/ppc/kernel/pmac_support.c4
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c3
-rw-r--r--arch/ppc/kernel/prep_setup.c2
-rw-r--r--arch/ppc/kernel/process.c117
-rw-r--r--arch/ppc/kernel/setup.c7
-rw-r--r--arch/ppc/kernel/traps.c36
14 files changed, 465 insertions, 188 deletions
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index 2f190db09..3677276b5 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -60,15 +60,12 @@ ifdef CONFIG_MBX
O_OBJS += i8259.o
endif
else
-ifeq ($(CONFIG_APUS),y)
-O_OBJS += apus_setup.o prom.o open_pic.o
-else
-ifneq ($(CONFIG_8xx),y)
O_OBJS += chrp_setup.o chrp_pci.o chrp_time.o \
pmac_time.o pmac_pci.o pmac_setup.o \
prom.o open_pic.o feature.o \
i8259.o pmac_pic.o indirect_pci.o \
gemini_pci.o gemini_prom.o gemini_setup.o
+
ifeq ($(CONFIG_NVRAM),y)
O_OBJS += pmac_support.o
endif
@@ -83,7 +80,8 @@ endif
ifeq ($(CONFIG_PMAC), y)
endif
-endif
+ifdef CONFIG_APUS
+O_OBJS += apus_setup.o
endif
endif
diff --git a/arch/ppc/kernel/apus_setup.c b/arch/ppc/kernel/apus_setup.c
index 353482a18..a7b057fa1 100644
--- a/arch/ppc/kernel/apus_setup.c
+++ b/arch/ppc/kernel/apus_setup.c
@@ -32,7 +32,10 @@
#include <linux/ide.h>
#define ide_init_hwif_ports m68k_ide_init_hwif_ports
#define ide_default_irq m68k_ide_default_irq
+#undef ide_request_irq
#define ide_request_irq m68k_ide_request_irq
+#undef ide_free_irq
+#define ide_free_irq m68k_ide_free_irq
#define ide_default_io_base m68k_ide_default_io_base
#define ide_check_region m68k_ide_check_region
#define ide_request_region m68k_ide_request_region
@@ -40,7 +43,6 @@
#define ide_fix_driveid m68k_ide_fix_driveid
#define ide_init_default_hwifs m68k_ide_init_default_hwifs
#define select_t m68k_select_t
-#define ide_free_irq m68k_ide_free_irq
//#include <asm/hdreg.h>
#include <asm-m68k/ide.h>
#undef ide_free_irq
@@ -59,6 +61,7 @@
#include <asm/bootinfo.h>
#include <asm/setup.h>
#include <asm/amigahw.h>
+#include <asm/amigaints.h>
#include <asm/amigappc.h>
#include <asm/pgtable.h>
#include <asm/io.h>
@@ -71,6 +74,8 @@
unsigned long m68k_machtype __apusdata;
char debug_device[6] __apusdata = "";
+extern void amiga_init_IRQ(void);
+
void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata;
/* machine dependent keyboard functions */
int (*mach_keyb_init) (void) __initdata;
@@ -162,57 +167,6 @@ int apus_set_rtc_time(unsigned long nowtime)
#endif
}
-__apus
-int apus_request_irq(unsigned int irq,
- void (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *devname,
- void *dev_id)
-{
-#ifdef CONFIG_APUS
- extern int amiga_request_irq(unsigned int irq,
- void (*handler)(int, void *,
- struct pt_regs *),
- unsigned long flags,
- const char *devname,
- void *dev_id);
-
- return amiga_request_irq (irq, handler, flags, devname, dev_id);
-#else
- return 0;
-#endif
-}
-
-__apus
-void apus_free_irq(unsigned int irq, void *dev_id)
-{
-#ifdef CONFIG_APUS
- extern void amiga_free_irq(unsigned int irq, void *dev_id);
-
- amiga_free_irq (irq, dev_id);
-#endif
-}
-
-__apus
-void apus_process_int(unsigned long vec, void *fp)
-{
-#ifdef CONFIG_APUS
- extern void process_int(unsigned long vec, struct pt_regs *fp);
-
- process_int (vec, (struct pt_regs*)fp);
-#endif
-}
-
-__apus
-int apus_get_irq_list(char *buf)
-{
-#ifdef CONFIG_APUS
- extern int m68k_get_irq_list (char*);
-
- return m68k_get_irq_list (buf);
-#else
- return 0;
-#endif
-}
/* Here some functions we don't support, but which the other ports reference */
@@ -297,6 +251,7 @@ void __init apus_setup_arch(void)
config_amiga();
+#if 0 /* Enable for logging - also include logging.o in Makefile rule */
{
#define LOG_SIZE 4096
void* base;
@@ -310,6 +265,7 @@ void __init apus_setup_arch(void)
LOG_INIT(base, base+sizeof(klog_data_t), LOG_SIZE);
}
#endif
+#endif
}
__apus
@@ -760,67 +716,122 @@ void apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port,
m68k_ide_init_hwif_ports(hw, data_port, ctrl_port, irq);
}
#endif
-/****************************************************** from irq.c */
-#define VEC_SPUR (24)
+/****************************************************** IRQ stuff */
-void
-apus_do_IRQ(struct pt_regs *regs,
- int cpu,
- int isfake)
+__apus
+int apus_get_irq_list(char *buf)
{
- int old_level, new_level;
+#ifdef CONFIG_APUS
+ extern int amiga_get_irq_list(char *buf);
+
+ return amiga_get_irq_list (buf);
+#else
+ return 0;
+#endif
+}
- new_level = (~(regs->mq) >> 3) & IPLEMU_IPLMASK;
-
- if (0 != new_level && 7 != new_level) {
- old_level = ~(regs->mq) & IPLEMU_IPLMASK;
+/* IPL must be between 0 and 7 */
+__apus
+static inline void apus_set_IPL(int ipl)
+{
+ APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
+ APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
+ APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | ((~ipl) & IPLEMU_IPLMASK));
+ APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
+}
- apus_process_int (VEC_SPUR+new_level, regs);
-
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
- APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
- | (~(old_level) & IPLEMU_IPLMASK)));
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
- }
+__apus
+static inline unsigned long apus_get_IPL(void)
+{
+ unsigned short __f;
+ APUS_READ(APUS_IPL_EMU, __f);
+ return ((~__f) & IPLEMU_IPLMASK);
}
__apus
-static void apus_save_flags(unsigned long* flags)
+static inline unsigned long apus_get_prev_IPL(void)
{
unsigned short __f;
APUS_READ(APUS_IPL_EMU, __f);
- return ((~__f) & IPLEMU_IPLMASK) << 8;
+ return ((~__f >> 3) & IPLEMU_IPLMASK);
+}
+
+
+__apus
+static void apus_save_flags(unsigned long* flags)
+{
+ *flags = apus_get_IPL();
}
__apus
static void apus_restore_flags(unsigned long flags)
{
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET
- | (~(flags >> 8) & IPLEMU_IPLMASK));
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
+ apus_set_IPL(flags);
}
__apus
static void apus_sti(void)
{
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_IPLMASK);
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
+ apus_set_IPL(0);
}
__apus
static void apus_cli(void)
{
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET);
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
+ apus_set_IPL(7);
+}
+
+
+#ifdef CONFIG_APUS
+void free_irq(unsigned int irq, void *dev_id)
+{
+ extern void amiga_free_irq(unsigned int irq, void *dev_id);
+
+ amiga_free_irq (irq, dev_id);
+}
+
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags, const char * devname, void *dev_id)
+{
+ extern int amiga_request_irq(unsigned int irq,
+ void (*handler)(int, void *,
+ struct pt_regs *),
+ unsigned long flags,
+ const char *devname,
+ void *dev_id);
+
+ return amiga_request_irq (irq, handler, irqflags, devname, dev_id);
+}
+#endif
+
+__apus
+int apus_get_irq(struct pt_regs* regs)
+{
+#ifdef CONFIG_APUS
+ int level = apus_get_IPL();
+ unsigned short ints = custom.intreqr & custom.intenar;
+
+ if (0 == level)
+ return -1;
+ if (7 == level)
+ return -2;
+
+ return level;
+#else
+ return 0;
+#endif
+}
+
+
+__apus
+void apus_post_irq(int level)
+{
+ /* Restore IPL to the previous value */
+ apus_set_IPL(apus_get_IPL());
}
+
+
/****************************************************** keyboard */
__apus
static int apus_kbd_setkeycode(unsigned int scancode, unsigned int keycode)
@@ -859,36 +870,54 @@ static void apus_kbd_init_hw(void)
#ifdef CONFIG_APUS
extern int amiga_keyb_init(void);
-printk("**** " __FUNCTION__ "\n");
amiga_keyb_init();
#endif
}
/****************************************************** init */
-extern void amiga_disable_irq(unsigned int irq);
-extern void amiga_enable_irq(unsigned int irq);
-extern void m68k_init_IRQ (void);
-
-struct hw_interrupt_type amiga_irq_ctl = {
- " Amiga ",
- NULL,
- NULL,
- NULL,
- amiga_enable_irq,
- amiga_disable_irq,
- NULL,
- 0
+
+/* The number of spurious interrupts */
+volatile unsigned int num_spurious;
+
+#define NUM_IRQ_NODES 100
+static irq_node_t nodes[NUM_IRQ_NODES];
+
+extern void (*amiga_default_handler[AUTO_IRQS])(int, void *, struct pt_regs *);
+
+static const char *default_names[SYS_IRQS] = {
+ "spurious int", "int1 handler", "int2 handler", "int3 handler",
+ "int4 handler", "int5 handler", "int6 handler", "int7 handler"
};
+irq_node_t *new_irq_node(void)
+{
+ irq_node_t *node;
+ short i;
+
+ for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--)
+ if (!node->handler)
+ return node;
+
+ printk ("new_irq_node: out of nodes\n");
+ return NULL;
+}
+
__init
void apus_init_IRQ(void)
{
int i;
- for (i = 0; i < NR_IRQS; i++)
- irq_desc[i].ctl = &amiga_irq_ctl;
- m68k_init_IRQ ();
+ for (i = 0; i < NUM_IRQ_NODES; i++)
+ nodes[i].handler = NULL;
+
+ for (i = 0; i < AUTO_IRQS; i++) {
+ if (amiga_default_handler[i] != NULL)
+ sys_request_irq(i, amiga_default_handler[i],
+ 0, default_names[i], NULL);
+ }
+
+ amiga_init_IRQ();
int_control.int_sti = apus_sti;
int_control.int_cli = apus_cli;
@@ -924,7 +953,8 @@ void apus_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.get_cpuinfo = apus_get_cpuinfo;
ppc_md.irq_cannonicalize = NULL;
ppc_md.init_IRQ = apus_init_IRQ;
- ppc_md.do_IRQ = apus_do_IRQ;
+ ppc_md.get_irq = apus_get_irq;
+ ppc_md.post_irq = apus_post_irq;
#ifdef CONFIG_HEARTBEAT
ppc_md.heartbeat = apus_heartbeat;
ppc_md.heartbeat_count = 1;
@@ -969,3 +999,9 @@ void apus_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_ide_md.io_base = _IO_BASE;
#endif
}
+
+
+/*************************************************** coexistence */
+void __init adbdev_init(void)
+{
+}
diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c
index e70ba4dca..938cea36d 100644
--- a/arch/ppc/kernel/chrp_setup.c
+++ b/arch/ppc/kernel/chrp_setup.c
@@ -11,7 +11,6 @@
*/
#include <linux/config.h>
-#include <linux/module.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -576,9 +575,10 @@ void __init
ppc_md.calibrate_decr = chrp_calibrate_decr;
#ifdef CONFIG_VT
-#ifdef CONFIG_MAC_KEYBOAD
+#ifdef CONFIG_MAC_KEYBOARD
if (adb_driver == NULL)
{
+#endif /* CONFIG_MAC_KEYBOAD */
ppc_md.kbd_setkeycode = pckbd_setkeycode;
ppc_md.kbd_getkeycode = pckbd_getkeycode;
ppc_md.kbd_translate = pckbd_translate;
@@ -588,7 +588,8 @@ void __init
#ifdef CONFIG_MAGIC_SYSRQ
ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
SYSRQ_KEY = 0x54;
-#endif
+#endif /* CONFIG_MAGIC_SYSRQ */
+#ifdef CONFIG_MAC_KEYBOARD
}
else
{
@@ -601,24 +602,13 @@ void __init
#ifdef CONFIG_MAGIC_SYSRQ
ppc_md.ppc_kbd_sysrq_xlate = mackbd_sysrq_xlate;
SYSRQ_KEY = 0x69;
-#endif
+#endif /* CONFIG_MAGIC_SYSRQ */
}
-#else
- ppc_md.kbd_setkeycode = pckbd_setkeycode;
- ppc_md.kbd_getkeycode = pckbd_getkeycode;
- ppc_md.kbd_translate = pckbd_translate;
- ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
- ppc_md.kbd_leds = pckbd_leds;
- ppc_md.kbd_init_hw = pckbd_init_hw;
-#ifdef CONFIG_MAGIC_SYSRQ
- ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
- SYSRQ_KEY = 0x54;
-#endif
+#endif /* CONFIG_MAC_KEYBOARD */
+#endif /* CONFIG_VT */
if ( rtas_data )
ppc_md.progress = chrp_progress;
-#endif
-#endif
-
+
#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
ppc_ide_md.insw = chrp_ide_insw;
ppc_ide_md.outsw = chrp_ide_outsw;
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
index 9c940a037..6133f32ca 100644
--- a/arch/ppc/kernel/entry.S
+++ b/arch/ppc/kernel/entry.S
@@ -411,9 +411,9 @@ enter_rtas:
addis r7,r7,-KERNELBASE@h
lis r8,rtas_entry@ha
lwz r8,rtas_entry@l(r8)
- addis r5,r8,-KERNELBASE@h
mfmsr r9
stw r9,8(r1)
+ li r0,0
ori r0,r0,MSR_EE|MSR_SE|MSR_BE
andc r0,r9,r0
andi. r9,r9,MSR_ME|MSR_RI
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index b3b07a003..57ff53992 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -365,10 +365,10 @@ InstructionAccess:
/* External interrupt */
. = 0x500;
HardwareInterrupt:
-#ifndef CONFIG_APUS
EXCEPTION_PROLOG;
addi r3,r1,STACK_FRAME_OVERHEAD
li r20,MSR_KERNEL
+#ifndef CONFIG_APUS
li r4,0
bl transfer_to_handler
.globl do_IRQ_intercept
@@ -376,9 +376,6 @@ do_IRQ_intercept:
.long do_IRQ;
.long ret_from_except
#else
- EXCEPTION_PROLOG;
- addi r3,r1,STACK_FRAME_OVERHEAD
- li r20,MSR_KERNEL
bl apus_interrupt_entry
#endif /* CONFIG_APUS */
@@ -447,7 +444,7 @@ SystemCall:
STD_EXCEPTION(0xd00, SingleStep, SingleStepException)
STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
- STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+ STD_EXCEPTION(0xf20, AltiVec, AltiVecUnavailable)
/*
* Handle TLB miss for instruction on 603/603e.
@@ -807,6 +804,73 @@ KernelFP:
.align 4
/*
+ * Take away the altivec regs.
+ *
+ * For now, ignore the vrsave regs and save them all
+ * -- Cort
+ */
+ .globl giveup_altivec
+giveup_altivec:
+#ifdef CONFIG_ALTIVEC
+ /* check for altivec */
+ mfspr r4,PVR
+ srwi r4,r4,16
+ cmpi 0,r4,12
+ bnelr
+
+ /* enable altivec so we can save */
+ mfmsr r4
+ oris r4,r4,MSR_VEC@h
+ mtmsr r4
+
+ /* make sure our tsk pointer is valid */
+ cmpi 0,r3,0
+ beqlr
+
+ /* save altivec regs */
+ addi r4,r3,THREAD+THREAD_VRSAVE
+ mfspr r5,256 /* vrsave */
+ stw r5,0(r4)
+
+ /* get regs for the task */
+ addi r4,r3,THREAD+PT_REGS
+ /* turn off the altivec bit in the tasks regs */
+ lwz r5,_MSR(r4)
+ lis r6,MSR_VEC@h
+ andi. r5,r5,r6
+ stw r5,_MSR(r4)
+
+ /* we've given up the altivec - clear the pointer */
+ li r3,0
+ lis r4,last_task_used_altivec@h
+ stw r3,last_task_used_altivec@l(r4)
+#endif /* CONFIG_ALTIVEC */
+ blr
+
+ .globl load_up_altivec
+load_up_altivec:
+#ifdef CONFIG_ALTIVEC
+ /* check for altivec */
+ mfspr r4,PVR
+ srwi r4,r4,16
+ cmpi 0,r4,12
+ bnelr
+
+ /* restore altivec regs */
+ addi r4,r3,THREAD+THREAD_VRSAVE
+ lwz r5,0(r4)
+ mtspr 256,r5 /* vrsave */
+
+ /* get regs for the task */
+ addi r4,r3,THREAD+PT_REGS
+ /* turn on the altivec bit in the tasks regs */
+ lwz r5,_MSR(r4)
+ oris r5,r5,MSR_VEC@h
+ stw r5,_MSR(r4)
+#endif /* CONFIG_ALTIVEC */
+ blr
+
+/*
* giveup_fpu(tsk)
* Disable FP for the task given as the argument,
* and save the floating-point registers in its thread_struct.
@@ -957,14 +1021,69 @@ fix_mem_constants:
isync /* No speculative loading until now */
blr
+
+apus_interrupt_entry:
+ /* This is horrible, but there's no way around it. Enable the
+ * data cache so the IRQ hardware register can be accessed
+ * without cache intervention. Then disable interrupts and get
+ * the current emulated m68k IPL value.
+ */
+
+ mfmsr 20
+ xori r20,r20,MSR_DR
+ sync
+ mtmsr r20
+ sync
- /* On APUS the first 0x4000 bytes of the kernel will be mapped
- * at a different physical address than the rest. For this
- * reason, the exception code cannot use relative branches to
- * access the code below.
- */
- . = 0x4000
-#endif
+ lis r4,APUS_IPL_EMU@h
+
+ li r20,(IPLEMU_SETRESET|IPLEMU_DISABLEINT)
+ stb r20,APUS_IPL_EMU@l(r4)
+ eieio
+
+ lbz r3,APUS_IPL_EMU@l(r4)
+
+ li r2,IPLEMU_IPLMASK
+ rlwinm. r20,r3,32-3,29,31
+ bne 2f
+ mr r20,r2 /* lvl7! Need to reset state machine. */
+ b 3f
+2: cmp 0,r20,r2
+ beq 1f
+3: eieio
+ stb r2,APUS_IPL_EMU@l(r4)
+ ori r20,r20,IPLEMU_SETRESET
+ eieio
+ stb r20,APUS_IPL_EMU@l(r4)
+1: eieio
+ li r20,IPLEMU_DISABLEINT
+ stb r20,APUS_IPL_EMU@l(r4)
+
+ /* At this point we could do some magic to avoid the overhead
+ * of calling the C interrupt handler in case of a spurious
+ * interrupt. Could not get a simple hack to work though.
+ */
+
+ mfmsr r20
+ xori r20,r20,MSR_DR
+ sync
+ mtmsr r20
+ sync
+
+ stw r3,(_CCR+4)(r21);
+
+ addi r3,r1,STACK_FRAME_OVERHEAD;
+ li r20,MSR_KERNEL;
+ bl transfer_to_handler;
+ .long do_IRQ;
+ .long ret_from_except
+
+/***********************************************************************
+ * Please note that on APUS the exception handlers are located at the
+ * physical address 0xfff0000. For this reason, the exception handlers
+ * cannot use relative branches to access the code below.
+ ***********************************************************************/
+#endif /* CONFIG_APUS */
#ifdef CONFIG_SMP
.globl __secondary_hold
@@ -1165,6 +1284,19 @@ start_here:
bl identify_machine
bl MMU_init
+#ifdef CONFIG_APUS
+ /* Copy exception code to exception vector base on APUS. */
+ lis r4,KERNELBASE@h
+#ifdef CONFIG_APUS_FAST_EXCEPT
+ lis r3,0xfff0 /* Copy to 0xfff00000 */
+#else
+ lis r3,0 /* Copy to 0x00000000 */
+#endif
+ li r5,0x4000 /* # bytes of memory to copy */
+ li r6,0
+ bl copy_and_flush /* copy the first 0x4000 bytes */
+#endif /* CONFIG_APUS */
+
/*
* Go back to running unmapped so we can load up new values
* for SDR1 (hash table pointer) and the segment registers
@@ -1283,3 +1415,4 @@ clear_bats:
mtspr IBAT3L,r20
blr
+
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index d851569d5..4427e801f 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -67,14 +67,6 @@ void disable_irq(unsigned int irq_nr);
volatile unsigned char *chrp_int_ack_special;
-#ifdef CONFIG_APUS
-/* Rename a few functions. Requires the CONFIG_APUS protection. */
-#define request_irq nop_ppc_request_irq
-#define free_irq nop_ppc_free_irq
-#define get_irq_list nop_get_irq_list
-#define VEC_SPUR (24)
-#endif
-
#define MAXCOUNT 10000000
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
@@ -94,8 +86,9 @@ atomic_t ppc_n_lost_interrupts;
* this needs to be removed.
* -- Cort
*/
-static char cache_bitmask = 0;
-static struct irqaction malloc_cache[8];
+#define IRQ_KMALLOC_ENTRIES 8
+static int cache_bitmask = 0;
+static struct irqaction malloc_cache[IRQ_KMALLOC_ENTRIES];
extern int mem_init_done;
void *irq_kmalloc(size_t size, int pri)
@@ -103,7 +96,7 @@ void *irq_kmalloc(size_t size, int pri)
unsigned int i;
if ( mem_init_done )
return kmalloc(size,pri);
- for ( i = 0; i <= 3 ; i++ )
+ for ( i = 0; i < IRQ_KMALLOC_ENTRIES ; i++ )
if ( ! ( cache_bitmask & (1<<i) ) )
{
cache_bitmask |= (1<<i);
@@ -115,7 +108,7 @@ void *irq_kmalloc(size_t size, int pri)
void irq_kfree(void *ptr)
{
unsigned int i;
- for ( i = 0 ; i <= 3 ; i++ )
+ for ( i = 0 ; i < IRQ_KMALLOC_ENTRIES ; i++ )
if ( ptr == &malloc_cache[i] )
{
cache_bitmask &= ~(1<<i);
@@ -124,15 +117,17 @@ void irq_kfree(void *ptr)
kfree(ptr);
}
-#ifndef CONFIG_8xx
-int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-#else
+#ifdef CONFIG_8xx
/* Name change so we can catch standard drivers that potentially mess up
* the internal interrupt controller on 8xx and 82xx. Just bear with me,
* I don't like this either and I am searching a better solution. For
* now, this is what I need. -- Dan
*/
int request_8xxirq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+#elif defined(CONFIG_APUS)
+int sys_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+#else
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
#endif
unsigned long irqflags, const char * devname, void *dev_id)
{
@@ -191,6 +186,12 @@ int request_8xxirq(unsigned int irq, void (*handler)(int, void *, struct pt_regs
return 0;
}
+#ifdef CONFIG_APUS
+void sys_free_irq(unsigned int irq, void *dev_id)
+{
+ sys_request_irq(irq, NULL, 0, NULL, dev_id);
+}
+#else
void free_irq(unsigned int irq, void *dev_id)
{
#ifndef CONFIG_8xx
@@ -199,6 +200,7 @@ void free_irq(unsigned int irq, void *dev_id)
request_8xxirq(irq, NULL, 0, NULL, dev_id);
#endif
}
+#endif
/* XXX should implement irq disable depth like on intel */
void disable_irq_nosync(unsigned int irq_nr)
@@ -219,6 +221,9 @@ void enable_irq(unsigned int irq_nr)
int get_irq_list(char *buf)
{
+#ifdef CONFIG_APUS
+ return apus_get_irq_list (buf);
+#else
int i, len = 0, j;
struct irqaction * action;
@@ -255,6 +260,7 @@ int get_irq_list(char *buf)
#endif
len += sprintf(buf+len, "BAD: %10u\n", ppc_spurious_interrupts);
return len;
+#endif /* CONFIG_APUS */
}
/*
@@ -266,7 +272,7 @@ void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq)
int status;
struct irqaction *action;
int cpu = smp_processor_id();
-
+
mask_and_ack_irq(irq);
status = 0;
action = irq_desc[irq].action;
diff --git a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c
index 38f38ca92..849e268fe 100644
--- a/arch/ppc/kernel/mk_defs.c
+++ b/arch/ppc/kernel/mk_defs.c
@@ -48,6 +48,9 @@ main(void)
DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched));
DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr));
+ DEFINE(THREAD_VRF, offsetof(struct thread_struct, vrf));
+ DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr));
+ DEFINE(THREAD_VRSAVE, offsetof(struct thread_struct, vrsave));
/* Interrupt register frame */
DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c
index 0a23c4473..4c3e9a790 100644
--- a/arch/ppc/kernel/pmac_setup.c
+++ b/arch/ppc/kernel/pmac_setup.c
@@ -39,7 +39,6 @@
#include <linux/ioport.h>
#include <linux/major.h>
#include <linux/blk.h>
-#include <linux/ide.h>
#include <linux/vt_kern.h>
#include <linux/console.h>
#include <linux/ide.h>
@@ -96,6 +95,7 @@ unsigned char drive_info;
int ppc_override_l2cr = 0;
int ppc_override_l2cr_value;
+int has_l2cache = 0;
extern char saved_command_line[];
@@ -147,6 +147,7 @@ pmac_get_cpuinfo(char *buffer)
unsigned int *dc = (unsigned int *)
get_property(np, "d-cache-size", NULL);
len += sprintf(buffer+len, "L2 cache\t:");
+ has_l2cache = 1;
if (get_property(np, "cache-unified", NULL) != 0 && dc) {
len += sprintf(buffer+len, " %dK unified", *dc / 1024);
} else {
@@ -359,7 +360,8 @@ static void __init ohare_init(void)
sysctrl_regs[4] |= 0x04000020;
else
sysctrl_regs[4] |= 0x04000000;
- printk(KERN_INFO "Level 2 cache enabled\n");
+ if(has_l2cache)
+ printk(KERN_INFO "Level 2 cache enabled\n");
}
}
}
diff --git a/arch/ppc/kernel/pmac_support.c b/arch/ppc/kernel/pmac_support.c
index abbec2ee0..cf3d1711a 100644
--- a/arch/ppc/kernel/pmac_support.c
+++ b/arch/ppc/kernel/pmac_support.c
@@ -60,6 +60,7 @@ unsigned char nvram_read_byte(int addr)
struct adb_request req;
switch (nvram_naddrs) {
+#ifdef CONFIG_ADB_PMU
case -1:
if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM,
(addr >> 8) & 0xff, addr & 0xff))
@@ -67,6 +68,7 @@ unsigned char nvram_read_byte(int addr)
while (!req.complete)
pmu_poll();
return req.reply[1];
+#endif
case 1:
return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
case 2:
@@ -82,6 +84,7 @@ void nvram_write_byte(unsigned char val, int addr)
struct adb_request req;
switch (nvram_naddrs) {
+#ifdef CONFIG_ADB_PMU
case -1:
if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM,
(addr >> 8) & 0xff, addr & 0xff, val))
@@ -89,6 +92,7 @@ void nvram_write_byte(unsigned char val, int addr)
while (!req.complete)
pmu_poll();
break;
+#endif
case 1:
nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val;
break;
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 399b99052..7bd21c277 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -209,8 +209,10 @@ EXPORT_SYMBOL(adb_request);
EXPORT_SYMBOL(adb_register);
EXPORT_SYMBOL(cuda_request);
EXPORT_SYMBOL(cuda_poll);
+#ifdef CONFIG_ADB_PMU
EXPORT_SYMBOL(pmu_request);
EXPORT_SYMBOL(pmu_poll);
+#endif /* CONFIG_ADB_PMU */
#endif /* CONFIG_ADB */
#ifdef CONFIG_PMAC_PBOOK
EXPORT_SYMBOL(pmu_register_sleep_notifier);
@@ -266,3 +268,4 @@ EXPORT_SYMBOL(irq_desc);
void ppc_irq_dispatch_handler(struct pt_regs *, int);
EXPORT_SYMBOL(ppc_irq_dispatch_handler);
EXPORT_SYMBOL(decrementer_count);
+EXPORT_SYMBOL(get_wchan);
diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c
index fe7043206..1bfc63c63 100644
--- a/arch/ppc/kernel/prep_setup.c
+++ b/arch/ppc/kernel/prep_setup.c
@@ -210,7 +210,7 @@ no_l2:
}
void __init
-prep_setup_arch()
+prep_setup_arch(void)
{
extern char cmd_line[];
unsigned char reg;
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index d71029b25..adeeefe33 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -45,6 +45,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
extern unsigned long _get_SP(void);
struct task_struct *last_task_used_math = NULL;
+struct task_struct *last_task_used_altivec = NULL;
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
static struct files_struct init_files = INIT_FILES;
@@ -60,6 +61,7 @@ struct task_struct *current_set[NR_CPUS] = {&init_task, };
#undef SHOW_TASK_SWITCHES 1
#undef CHECK_STACK 1
+#if defined(CHECK_STACK)
unsigned long
kernel_stack_top(struct task_struct *tsk)
{
@@ -72,28 +74,6 @@ task_top(struct task_struct *tsk)
return ((unsigned long)tsk) + sizeof(struct task_struct);
}
-int
-dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
-{
- if (regs->msr & MSR_FP)
- giveup_fpu(current);
- memcpy(fpregs, &current->thread.fpr[0], sizeof(*fpregs));
- return 1;
-}
-
-void
-enable_kernel_fp(void)
-{
-#ifdef __SMP__
- if (current->thread.regs && (current->thread.regs->msr & MSR_FP))
- giveup_fpu(current);
- else
- giveup_fpu(NULL); /* just enables FP for kernel */
-#else
- giveup_fpu(last_task_used_math);
-#endif /* __SMP__ */
-}
-
/* check to make sure the kernel stack is healthy */
int check_stack(struct task_struct *tsk)
{
@@ -156,6 +136,29 @@ int check_stack(struct task_struct *tsk)
}
return(ret);
}
+#endif /* defined(CHECK_STACK) */
+
+int
+dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
+{
+ if (regs->msr & MSR_FP)
+ giveup_fpu(current);
+ memcpy(fpregs, &current->thread.fpr[0], sizeof(*fpregs));
+ return 1;
+}
+
+void
+enable_kernel_fp(void)
+{
+#ifdef __SMP__
+ if (current->thread.regs && (current->thread.regs->msr & MSR_FP))
+ giveup_fpu(current);
+ else
+ giveup_fpu(NULL); /* just enables FP for kernel */
+#else
+ giveup_fpu(last_task_used_math);
+#endif /* __SMP__ */
+}
void
_switch_to(struct task_struct *prev, struct task_struct *new,
@@ -187,12 +190,31 @@ _switch_to(struct task_struct *prev, struct task_struct *new,
* every switch, just a save.
* -- Cort
*/
- if (prev->thread.regs && (prev->thread.regs->msr & MSR_FP))
+ if ( prev->thread.regs && (prev->thread.regs->msr & MSR_FP) )
giveup_fpu(prev);
-
+ /*
+ * If the previous thread 1) has some altivec regs it wants saved
+ * (has bits in vrsave set) and 2) used altivec in the last quantum
+ * (thus changing altivec regs) then save them.
+ *
+ * On SMP we always save/restore altivec regs just to avoid the
+ * complexity of changing processors.
+ * -- Cort
+ */
+ if ( (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)) &&
+ prev->thread.vrsave )
+ giveup_altivec(prev);
+ if ( (new->last_processor != NO_PROC_ID) &&
+ (new->last_processor != new->processor) && new->mm )
+ flush_tlb_mm(new->mm);
prev->last_processor = prev->processor;
current_set[smp_processor_id()] = new;
#endif /* __SMP__ */
+ /* Avoid the trap. On smp this this never happens since
+ * we don't set last_task_used_altivec -- Cort
+ */
+ if ( last_task_used_altivec == new )
+ new->thread.regs->msr |= MSR_VEC;
new_thread = &new->thread;
old_thread = &current->thread;
*last = _switch(old_thread, new_thread);
@@ -213,7 +235,8 @@ void show_regs(struct pt_regs * regs)
printk("TASK = %p[%d] '%s' ",
current, current->pid, current->comm);
printk("Last syscall: %ld ", current->thread.last_syscall);
- printk("\nlast math %p", last_task_used_math);
+ printk("\nlast math %p last altivec %p", last_task_used_math,
+ last_task_used_altivec);
#ifdef __SMP__
printk(" CPU: %d last CPU: %d", current->processor,current->last_processor);
@@ -243,12 +266,16 @@ void exit_thread(void)
{
if (last_task_used_math == current)
last_task_used_math = NULL;
+ if (last_task_used_altivec == current)
+ last_task_used_altivec = NULL;
}
void flush_thread(void)
{
if (last_task_used_math == current)
last_task_used_math = NULL;
+ if (last_task_used_altivec == current)
+ last_task_used_altivec = NULL;
}
void
@@ -305,11 +332,18 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
*/
if (regs->msr & MSR_FP)
giveup_fpu(current);
-
memcpy(&p->thread.fpr, &current->thread.fpr, sizeof(p->thread.fpr));
p->thread.fpscr = current->thread.fpscr;
childregs->msr &= ~MSR_FP;
+ if (regs->msr & MSR_VEC)
+ giveup_altivec(current);
+ if ( p->thread.vrsave )
+ memcpy(&p->thread.vrf, &current->thread.vrf, sizeof(p->thread.vrf));
+ p->thread.vscr = current->thread.vscr;
+ p->thread.vrsave = current->thread.vrsave;
+ childregs->msr &= ~MSR_VEC;
+
#ifdef __SMP__
p->last_processor = NO_PROC_ID;
#endif /* __SMP__ */
@@ -367,6 +401,8 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
shove_aux_table(sp);
if (last_task_used_math == current)
last_task_used_math = 0;
+ if (last_task_used_altivec == current)
+ last_task_used_altivec = 0;
current->thread.fpscr = 0;
}
@@ -543,3 +579,32 @@ void __init ll_puts(const char *s)
orig_y = y;
}
#endif
+
+/*
+ * These bracket the sleeping functions..
+ */
+extern void scheduling_functions_start_here(void);
+extern void scheduling_functions_end_here(void);
+#define first_sched ((unsigned long) scheduling_functions_start_here)
+#define last_sched ((unsigned long) scheduling_functions_end_here)
+
+unsigned long get_wchan(struct task_struct *p)
+{
+ unsigned long ip, sp;
+ unsigned long stack_page = (unsigned long) p;
+ int count = 0;
+ if (!p || p == current || p->state == TASK_RUNNING)
+ return 0;
+ sp = p->thread.ksp;
+ do {
+ sp = *(unsigned long *)sp;
+ if (sp < stack_page || sp >= stack_page + 8188)
+ return 0;
+ if (count > 0) {
+ ip = *(unsigned long *)(sp + 4);
+ if (ip < first_sched || ip >= last_sched)
+ return ip;
+ }
+ } while (count++ < 16);
+ return 0;
+}
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 8863a9940..2cf9ee714 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -245,6 +245,9 @@ int get_cpuinfo(char *buffer)
case 10:
len += sprintf(len+buffer, "604ev5 (MachV)\n");
break;
+ case 12:
+ len += sprintf(len+buffer, "7400 (G4)\n");
+ break;
case 50:
len += sprintf(len+buffer, "821\n");
case 80:
@@ -386,12 +389,10 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
if ( have_of )
{
-#ifdef CONFIG_MACH_SPECIFIC
/* prom_init has already been called from __start */
if (boot_infos)
relocate_nodes();
finish_device_tree();
-#endif /* CONFIG_MACH_SPECIFIC */
/*
* If we were booted via quik, r3 points to the physical
* address of the command-line parameters.
@@ -447,7 +448,7 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
int_control.int_cli = __no_use_cli;
int_control.int_save_flags = __no_use_save_flags;
int_control.int_restore_flags = __no_use_restore_flags;
-
+
switch (_machine)
{
case _MACH_Pmac:
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 99a9c2bce..07e45db6b 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -129,6 +129,42 @@ MachineCheckException(struct pt_regs *regs)
}
void
+AltiVecUnavailable(struct pt_regs *regs)
+{
+ /*
+ * This should be changed so we don't take a trap if coming
+ * back when last_task_used_altivec == current. We should also
+ * allow the kernel to use the altivec regs on UP to store tasks
+ * regs during switch
+ * -- Cort
+ */
+ if ( regs->msr & MSR_VEC )
+ {
+ show_regs(regs);
+ panic("AltiVec trap with Altivec enabled!\n");
+ }
+
+ if ( !user_mode(regs) )
+ {
+ show_regs(regs);
+ panic("Kernel Used Altivec with MSR_VEC off!\n");
+ }
+
+ if ( last_task_used_altivec != current )
+ {
+ if ( last_task_used_altivec )
+ giveup_altivec(current);
+ load_up_altivec(current);
+ /* on SMP we always save/restore on switch */
+#ifndef __SMP__
+ last_task_used_altivec = current;
+#endif
+ }
+ /* enable altivec for the task on return */
+ regs->msr |= MSR_VEC;
+}
+
+void
UnknownException(struct pt_regs *regs)
{
printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",