--- 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 <dancer@debian.org>
+ *
+ * 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 <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/prctl.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/reg.h>
+#include <asm/xmon.h>
+#include <asm/perfmon.h>
+
+/* 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 <dancer@debian.org>
+ *
+ * Freescale Book-E oprofile support, based on ppc64 oprofile support
+ * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc
+ *
+ * Author: Andy Fleming
+ * Maintainer: Kumar Gala <Kumar.Gala@freescale.com>
+ *
+ * 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 <linux/oprofile.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/cputable.h>
+#include <asm/page.h>
+#include <asm/perfmon.h>
+
+#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 */
 

