From f969d69ba9f952e5bdd38278e25e26a3e4a61a70 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sat, 29 Jan 2000 01:41:54 +0000 Subject: Merge with 2.3.27. --- arch/ppc/kernel/Makefile | 8 +- arch/ppc/kernel/apus_setup.c | 244 +++++++++++++++++++++++------------------ arch/ppc/kernel/chrp_setup.c | 26 ++--- arch/ppc/kernel/entry.S | 2 +- arch/ppc/kernel/head.S | 157 ++++++++++++++++++++++++-- arch/ppc/kernel/irq.c | 38 ++++--- arch/ppc/kernel/mk_defs.c | 3 + arch/ppc/kernel/pmac_setup.c | 6 +- arch/ppc/kernel/pmac_support.c | 4 + arch/ppc/kernel/ppc_ksyms.c | 3 + arch/ppc/kernel/prep_setup.c | 2 +- arch/ppc/kernel/process.c | 117 +++++++++++++++----- arch/ppc/kernel/setup.c | 7 +- arch/ppc/kernel/traps.c | 36 ++++++ 14 files changed, 465 insertions(+), 188 deletions(-) (limited to 'arch/ppc/kernel') 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 #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 #include #undef ide_free_irq @@ -59,6 +61,7 @@ #include #include #include +#include #include #include #include @@ -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 -#include #include #include #include @@ -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. @@ -806,6 +803,73 @@ KernelFP: 86: .string "floating point used in kernel (task=%p, pc=%x)\n" .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, @@ -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< #include #include -#include #include #include #include @@ -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, ¤t->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, ¤t->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 = ¤t->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, ¤t->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, ¤t->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 @@ -128,6 +128,42 @@ MachineCheckException(struct pt_regs *regs) _exception(SIGSEGV, 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) { -- cgit v1.2.3