--- linux-source-2.6.14/arch/ppc/kernel/Makefile 2005-10-28 16:41:17.000000000 +0900 +++ oprofile/linux-source-2.6.14-ptrace-getregs-oprofile/arch/ppc/kernel/Makefile 2005-12-28 00:44:33.000000000 +0900 @@ -17,7 +17,7 @@ obj-y := traps.o irq.o idle.o time.o process.o signal.o ptrace.o align.o \ semaphore.o syscalls.o setup.o \ cputable.o ppc_htab.o perfmon.o -obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o +obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o perfmon_6xx.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o obj-$(CONFIG_POWER4) += cpu_setup_power4.o obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o diff -x debian -uprN -X oprofile/linux-source-2.6.14-ptrace-getregs-oprofile/Documentation/dontdiff linux-source-2.6.14/arch/ppc/kernel/head.S oprofile/linux-source-2.6.14-ptrace-getregs-oprofile/arch/ppc/kernel/head.S --- linux-source-2.6.14/arch/ppc/kernel/head.S 2005-10-28 16:41:17.000000000 +0900 +++ oprofile/linux-source-2.6.14-ptrace-getregs-oprofile/arch/ppc/kernel/head.S 2005-12-31 18:36:41.000000000 +0900 @@ -540,7 +540,7 @@ SystemCall: Trap_0f: EXCEPTION_PROLOG addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE(0xf00, UnknownException) + EXC_XFER_EE(0xf00, PerformanceMonitorException) /* * Handle TLB miss for instruction on 603/603e. diff -x debian -uprN -X oprofile/linux-source-2.6.14-ptrace-getregs-oprofile/Documentation/dontdiff linux-source-2.6.14/arch/ppc/kernel/perfmon_6xx.c oprofile/linux-source-2.6.14-ptrace-getregs-oprofile/arch/ppc/kernel/perfmon_6xx.c --- linux-source-2.6.14/arch/ppc/kernel/perfmon_6xx.c 1970-01-01 09:00:00.000000000 +0900 +++ oprofile/linux-source-2.6.14-ptrace-getregs-oprofile/arch/ppc/kernel/perfmon_6xx.c 2005-12-31 18:51:12.000000000 +0900 @@ -0,1 +1,172 @@ +/* kernel/perfmon_6xx.c + * 7447A Performance Monitor code. + * Copyright (c) 2005 Junichi Uekawa + * + * Derived from bookE performance monitoring code + * Author: Andy Fleming + * Copyright (c) 2004 Freescale Semiconductor, Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* called from 6xx_reg_setup, initial stopping. + */ +void set_pmc_event(int ctr, unsigned int event) +{ + unsigned int mmcr0 = mfspr(SPRN_MMCR0); + unsigned int mmcr1 = mfspr(SPRN_MMCR1); + + printk("set_pmc_event ctr:%i event:%i\n", ctr, event); + + switch (ctr) { + case 0: + /* 1 1111 1100 0000 */ + mmcr0 &= ~(127 << 6); + mmcr0 |= (event << 6); + mtspr(SPRN_MMCR0, mmcr0); + break; + case 1: + /* 11 1111 */ + mmcr0 &= ~63; + mmcr0 |= (event); + mtspr(SPRN_MMCR0, mmcr0); + break; + case 2: + /* 1111 1000 0000 0000 0000 0000 0000 0000 */ + mmcr1 &= ~(31 << 27); + mmcr1 |= (event << 27); + mtspr(SPRN_MMCR1, mmcr1); + break; + case 3: + /* 0000 0111 1100 0000 0000 0000 0000 0000 */ + mmcr1 &= ~(31 << 22); + mmcr1 |= (event << 22); + mtspr(SPRN_MMCR1, mmcr1); + break; + case 4: + /* 0000 0000 0011 1110 0000 0000 0000 0000 */ + mmcr1 &= ~(31 << 17); + mmcr1 |= (event << 17); + mtspr(SPRN_MMCR1, mmcr1); + break; + case 5: + /* 0000 0000 0000 0001 1111 1000 0000 0000 */ + mmcr1 &= ~(63 << 11); + mmcr1 |= (event << 11); + mtspr(SPRN_MMCR1, mmcr1); + break; + default: + panic("Bad ctr number!\n"); + } + + printk("set_pmc_event mmcr0:%x mmcr1:%x\n", mmcr0, mmcr1); +} + +void init_pmc_stop(int ctr) +{ + printk("init_pmc_stop %i\n", ctr); + set_pmc_event(ctr, 0); +} + +void set_pmc_user_kernel(int user, int kernel) +{ + unsigned int mmcr0; + + printk("set_pmc_user_kernel %i %i\n", user, kernel); + + mmcr0=mfspr(SPRN_MMCR0); + if(user) + mmcr0 &= ~MMCR0_FCP; + else + mmcr0 |= MMCR0_FCP; + + if(kernel) + mmcr0 &= ~MMCR0_FCS; + else + mmcr0 |= MMCR0_FCS; + mtspr(SPRN_MMCR0, mmcr0); +} + +void set_pmc_marked(int mark0, int mark1) +{ + unsigned int mmcr0; + + printk("set_pmc_marked %i %i\n", mark0, mark1); + + mmcr0=mfspr(SPRN_MMCR0); + if(mark0) + mmcr0 &= ~MMCR0_FCM0; + else + mmcr0 |= MMCR0_FCM0; + + if(mark1) + mmcr0 &= ~MMCR0_FCM1; + else + mmcr0 |= MMCR0_FCM1; + mtspr(SPRN_MMCR0, mmcr0); +} + +void pmc_start_ctrs(int enable) +{ + unsigned int mmcr0 = mfspr(SPRN_MMCR0); + + //printk("pmc_start_ctrs %i\n", enable); + + mmcr0 &= ~MMCR0_FC; + mmcr0 |= MMCR0_FCECE; + if (enable) + mmcr0 |= ( MMCR0_PMXE | MMCR0_PM1CE | MMCR0_PMnCE ); + else + mmcr0 &= ~( MMCR0_PMXE | MMCR0_PM1CE | MMCR0_PMnCE ); + mtspr(SPRN_MMCR0, mmcr0); + mb(); + + //printk("pmc_start_ctrs final mmcr0: %x\n", mmcr0); +} + +void pmc_stop_ctrs(void) +{ + unsigned int mmcr0 = mfspr(SPRN_MMCR0); + + //printk("pmc_stop_ctrs\n"); + + mmcr0 |= MMCR0_FC; + + mmcr0 &= ~(MMCR0_FCECE | MMCR0_PMXE ); + mtspr(SPRN_MMCR0, mmcr0); +} + +EXPORT_SYMBOL(init_pmc_stop); +EXPORT_SYMBOL(set_pmc_event); +EXPORT_SYMBOL(set_pmc_user_kernel); +EXPORT_SYMBOL(set_pmc_marked); +EXPORT_SYMBOL(pmc_start_ctrs); +EXPORT_SYMBOL(pmc_stop_ctrs); --- linux-source-2.6.14/arch/ppc/kernel/traps.c 2005-10-28 09:02:08.000000000 +0900 +++ oprofile/linux-source-2.6.14-ptrace-getregs-oprofile/arch/ppc/kernel/traps.c 2005-12-31 18:13:56.000000000 +0900 @@ -871,7 +871,8 @@ void AltivecAssistException(struct pt_re } #endif /* CONFIG_ALTIVEC */ -#ifdef CONFIG_E500 +#if defined(CONFIG_E500) || defined(CONFIG_6xx) +/* try to share the same code with E500. */ void PerformanceMonitorException(struct pt_regs *regs) { perf_irq(regs); diff -x debian -uprN -X oprofile/linux-source-2.6.14-ptrace-getregs-oprofile/Documentation/dontdiff linux-source-2.6.14/arch/ppc/oprofile/Makefile oprofile/linux-source-2.6.14-ptrace-getregs-oprofile/arch/ppc/oprofile/Makefile --- linux-source-2.6.14/arch/ppc/oprofile/Makefile 2005-10-28 09:02:08.000000000 +0900 +++ oprofile/linux-source-2.6.14-ptrace-getregs-oprofile/arch/ppc/oprofile/Makefile 2005-12-27 14:35:47.000000000 +0900 @@ -11,5 +11,7 @@ oprofile-y := $(DRIVER_OBJS) common.o ifeq ($(CONFIG_FSL_BOOKE),y) oprofile-y += op_model_fsl_booke.o endif - +ifeq ($(CONFIG_6xx),y) + oprofile-y += op_model_6xx.o +endif --- linux-source-2.6.14/arch/ppc/oprofile/common.c 2005-10-28 09:02:08.000000000 +0900 +++ oprofile/linux-source-2.6.14-ptrace-getregs-oprofile/arch/ppc/oprofile/common.c 2005-12-27 14:34:27.000000000 +0900 @@ -129,9 +129,11 @@ int __init oprofile_arch_init(struct opr char *name; int cpu_id = smp_processor_id(); -#ifdef CONFIG_FSL_BOOKE +#if defined CONFIG_FSL_BOOKE model = &op_model_fsl_booke; -#else +#elif defined CONFIG_6xx + model = &op_model_6xx; +#else return -ENODEV; #endif diff -x debian -uprN -X oprofile/linux-source-2.6.14-ptrace-getregs-oprofile/Documentation/dontdiff linux-source-2.6.14/arch/ppc/oprofile/op_model_6xx.c oprofile/linux-source-2.6.14-ptrace-getregs-oprofile/arch/ppc/oprofile/op_model_6xx.c --- linux-source-2.6.14/arch/ppc/oprofile/op_model_6xx.c 1970-01-01 09:00:00.000000000 +0900 +++ oprofile/linux-source-2.6.14-ptrace-getregs-oprofile/arch/ppc/oprofile/op_model_6xx.c 2005-12-31 18:51:34.000000000 +0900 @@ -0,1 +1,211 @@ +/* + * oprofile/op_model_6xx.c + * + * PPC 7447A oprofile support, based on Book-E oprofile support + * Copyright (C) 2005 Junichi Uekawa + * + * Freescale Book-E oprofile support, based on ppc64 oprofile support + * Copyright (C) 2004 Anton Blanchard , IBM + * + * Copyright (c) 2004 Freescale Semiconductor, Inc + * + * Author: Andy Fleming + * Maintainer: Kumar Gala + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "op_impl.h" + +static unsigned long reset_value[OP_MAX_COUNTER]; + +static int num_counters; +static int oprofile_running; + +/* from include/asm-ppc64/oprofile_impl.h */ +static inline unsigned int ctr_read(unsigned int i) +{ + //printk("ctr_read %x\n", i); + switch(i) { + case 0: + return mfspr(SPRN_PMC1); + case 1: + return mfspr(SPRN_PMC2); + case 2: + return mfspr(SPRN_PMC3); + case 3: + return mfspr(SPRN_PMC4); + case 4: + return mfspr(SPRN_PMC5); + case 5: + return mfspr(SPRN_PMC6); + default: + return 0; + } +} + +/* from include/asm-ppc64/oprofile_impl.h */ +static inline void ctr_write(unsigned int i, unsigned int val) +{ + //printk("ctr_write %i %x\n", i, val); + switch(i) { + case 0: + mtspr(SPRN_PMC1, val); + break; + case 1: + mtspr(SPRN_PMC2, val); + break; + case 2: + mtspr(SPRN_PMC3, val); + break; + case 3: + mtspr(SPRN_PMC4, val); + break; + case 4: + mtspr(SPRN_PMC5, val); + break; + case 5: + mtspr(SPRN_PMC6, val); + break; + default: + break; + } +} + +static void model_6xx_reg_setup(struct op_counter_config *ctr, + struct op_system_config *sys, + int num_ctrs) +{ + int i; + + num_counters = num_ctrs; + + /* freeze all counters */ + pmc_stop_ctrs(); + + /* Our counters count up, and "count" refers to + * how much before the next interrupt, and we interrupt + * on overflow. So we calculate the starting value + * which will give us "count" until overflow. + * Then we set the events on the enabled counters */ + for (i = 0; i < num_counters; ++i) { + reset_value[i] = 0x80000000UL - ctr[i].count; + + init_pmc_stop(i); + + set_pmc_event(i, ctr[i].event); + + } + + /* 7450: we only have system-wide stuff, so + we will just use counter 0's values. +2 */ + set_pmc_user_kernel(ctr[0].user, ctr[0].kernel); +} + +static void model_6xx_start(struct op_counter_config *ctr) +{ + int i; + + printk("model_6xx_start: MSR PMM: %x\n", mfmsr() & MSR_PMM ); + + /* mark */ + mtmsr(mfmsr() | MSR_PMM); + + /* Set Each enabled counters to only + * count when the Mark bit is not set ... */ + set_pmc_marked(1, 0); + + for (i = 0; i < num_counters; ++i) { + if (ctr[i].enabled) { + ctr_write(i, reset_value[i]); + //pmc_start_ctr(i, 1); + set_pmc_event(i,ctr[i].event); + } else { + ctr_write(i, 0); + /* Set the ctr to be stopped */ + set_pmc_event(i,0); + } + } + + /* Clear the freeze bit, and enable the interrupt. + * The counters won't actually start until the rfi clears + * the PMM bit */ + pmc_start_ctrs(1); + + oprofile_running = 1; + + pr_debug("start on cpu %d, SIAR %x\n", smp_processor_id(), + mfspr(SPRN_SIA)); +} + +static void model_6xx_stop(void) +{ + /* freeze counters */ + pmc_stop_ctrs(); + + oprofile_running = 0; + + pr_debug("stop on cpu %d, siar %x\n", smp_processor_id(), + mfspr(SPRN_SIA)); + + mb(); +} + + +static void model_6xx_handle_interrupt(struct pt_regs *regs, + struct op_counter_config *ctr) +{ + unsigned long pc; + int is_kernel; + int val; + int i; + + //printk("model_6xx_handle_interrupt\n"); + + /* set the PMM bit (see comment below) */ + mtmsr(mfmsr() | MSR_PMM); + + pc = mfspr(SPRN_SIA); + is_kernel = (pc >= KERNELBASE); + + for (i = 0; i < num_counters; ++i) { + val = ctr_read(i); + if (val < 0) { + if (oprofile_running && ctr[i].enabled) { + oprofile_add_pc(pc, is_kernel, i); + ctr_write(i, reset_value[i]); + } else { + ctr_write(i, 0); + } + } + } + + /* The freeze bit was set by the interrupt. */ + /* Clear the freeze bit, and reenable the interrupt. + * The counters won't actually start until the rfi clears + * the PMM bit */ + /* Would rfi clear the PMM bit? */ + pmc_start_ctrs(1); +} + +struct op_ppc32_model op_model_6xx = { + .reg_setup = model_6xx_reg_setup, + .start = model_6xx_start, + .stop = model_6xx_stop, + .handle_interrupt = model_6xx_handle_interrupt, +}; --- linux-source-2.6.14/include/asm-ppc/perfmon.h 2005-10-28 09:02:08.000000000 +0900 +++ oprofile/linux-source-2.6.14-ptrace-getregs-oprofile/include/asm-ppc/perfmon.h 2005-12-30 07:24:56.000000000 +0900 @@ -6,7 +6,18 @@ extern void (*perf_irq)(struct pt_regs * int request_perfmon_irq(void (*handler)(struct pt_regs *)); void free_perfmon_irq(void); +#ifdef CONFIG_6xx +void init_pmc_stop(int ctr); +void set_pmc_event(int ctr, unsigned int event); +void set_pmc_user_kernel(int user, int kernel); +void set_pmc_marked(int mark0, int mark1); +void pmc_start_ctrs(int enable); +void pmc_stop_ctrs(void); +//void dump_pmcs(void); +extern struct op_ppc32_model op_model_6xx; +#endif + #ifdef CONFIG_FSL_BOOKE void init_pmc_stop(int ctr); void set_pmc_event(int ctr, int event); --- linux-source-2.6.14/include/asm-ppc/reg.h 2005-10-28 09:02:08.000000000 +0900 +++ oprofile/linux-source-2.6.14-ptrace-getregs-oprofile/include/asm-ppc/reg.h 2005-12-31 11:57:46.000000000 +0900 @@ -42,6 +42,9 @@ #define MSR_PX (1<<2) /* Protection Exclusive Mode */ #define MSR_RI (1<<1) /* Recoverable Exception */ #define MSR_LE (1<<0) /* Little Endian */ +#ifndef MSR_PMM +#define MSR_PMM (1<<2) /* 7450: Performance monitor mark bit */ +#endif /* Default MSR for kernel mode. */ #ifdef CONFIG_APUS_FAST_EXCEPT @@ -277,6 +280,8 @@ #define SPRN_LR 0x008 /* Link Register */ #define SPRN_MMCR0 0x3B8 /* Monitor Mode Control Register 0 */ #define SPRN_MMCR1 0x3BC /* Monitor Mode Control Register 1 */ +#define SPRN_MMCR2 0x3B0 /* 7450: Monitor Mode Control Register 2 */ +#define SPRN_BAMR 0x3B7 /* 7450: Breakpoint Address Mask Register */ #ifndef SPRN_PIR #define SPRN_PIR 0x3FF /* Processor Identification Register */ #endif @@ -284,13 +289,17 @@ #define SPRN_PMC2 0x3BA /* Performance Counter Register 2 */ #define SPRN_PMC3 0x3BD /* Performance Counter Register 3 */ #define SPRN_PMC4 0x3BE /* Performance Counter Register 4 */ +#define SPRN_PMC5 0x3B1 /* 7450: Performance Counter Register 5 */ +#define SPRN_PMC6 0x3B2 /* 7450: Performance Counter Register 6 */ #define SPRN_PTEHI 0x3D5 /* 981 7450 PTE HI word (S/W TLB load) */ #define SPRN_PTELO 0x3D6 /* 982 7450 PTE LO word (S/W TLB load) */ #define SPRN_PVR 0x11F /* Processor Version Register */ #define SPRN_RPA 0x3D6 /* Required Physical Address Register */ #define SPRN_SDA 0x3BF /* Sampled Data Address Register */ #define SPRN_SDR1 0x019 /* MMU Hash Base Register */ -#define SPRN_SIA 0x3BB /* Sampled Instruction Address Register */ +#define SPRN_SIA 0x3BB /* Sampled Instruction Address Register + 7450 manual calls this register "SIAR" + */ #define SPRN_SPRG0 0x110 /* Special Purpose Register General 0 */ #define SPRN_SPRG1 0x111 /* Special Purpose Register General 1 */ #define SPRN_SPRG2 0x112 /* Special Purpose Register General 2 */ @@ -318,12 +327,17 @@ #define THRM3_E (1<<0) #define SPRN_TLBMISS 0x3D4 /* 980 7450 TLB Miss Register */ #define SPRN_UMMCR0 0x3A8 /* User Monitor Mode Control Register 0 */ -#define SPRN_UMMCR1 0x3AC /* User Monitor Mode Control Register 0 */ +#define SPRN_UMMCR1 0x3AC /* User Monitor Mode Control Register 1 */ +#define SPRN_UMMCR2 0x3A0 /* User Monitor Mode Control Register 2 */ #define SPRN_UPMC1 0x3A9 /* User Performance Counter Register 1 */ #define SPRN_UPMC2 0x3AA /* User Performance Counter Register 2 */ #define SPRN_UPMC3 0x3AD /* User Performance Counter Register 3 */ #define SPRN_UPMC4 0x3AE /* User Performance Counter Register 4 */ -#define SPRN_USIA 0x3AB /* User Sampled Instruction Address Register */ +#define SPRN_UPMC5 0x3A1 /* 7450: User Performance Counter Register 5 */ +#define SPRN_UPMC6 0x3A2 /* 7450: User Performance Counter Register 6 */ +#define SPRN_USIA 0x3AB /* User Sampled Instruction Address Register + 7450 manual calls it USIAR + */ #define SPRN_VRSAVE 0x100 /* Vector Register Save Register */ #define SPRN_XER 0x001 /* Fixed Point Exception Register */ @@ -336,6 +350,14 @@ #define MMCR0_PMC2_ITLB 0x7 #define MMCR0_PMC2_LOADMISSTIME 0x5 #define MMCR0_PMXE (1 << 26) +#define MMCR0_PM1CE (1 << 15) /* 7450: PM1 Counter enable */ +#define MMCR0_PMnCE (1 << 14) /* 7450: PMn(n>1) Counter enable */ +#define MMCR0_FCS (1 << 30) /* 7450: Supervisor mode 1=freeze pmc*/ +#define MMCR0_FCP (1 << 29) /* 7450: User mode 1=freeze pmc */ +#define MMCR0_FCM1 (1 << 28) /* 7450: mode1 1=freeze pmc */ +#define MMCR0_FCM0 (1 << 27) /* 7450: mode0 1=freeze pmc */ +#define MMCR0_FC (1 << 31) /* 7450: freeze pmc*/ +#define MMCR0_FCECE (1 << 25) /* 7450: freeze counters on exception */ /* Processor Version Register */