[linux-yocto] [PATCH 62/70] ACP34xx: Add support for Performance Monitor (PMU)

Paul Butler butler.paul at gmail.com
Mon Jun 10 18:46:25 PDT 2013


From: David Mercado <david.mercado at windriver.com>

This patch adds PMU support for the LSI ACP34xx platform.

Signed-off-by: David Mercado <david.mercado at windriver.com>
---
 arch/powerpc/include/asm/Kbuild           |   1 +
 arch/powerpc/include/asm/cputable.h       |  16 +-
 arch/powerpc/include/asm/oprofile_impl.h  |   8 +-
 arch/powerpc/include/asm/perf_event.h     |   6 +-
 arch/powerpc/include/asm/perf_event_acp.h |  41 ++
 arch/powerpc/include/asm/reg_acp_pmu.h    | 118 ++++++
 arch/powerpc/include/asm/reg_acp_pmu_fn.h | 166 ++++++++
 arch/powerpc/kernel/cputable.c            | 330 ++++++++++------
 arch/powerpc/kernel/pmc.c                 |  14 +-
 arch/powerpc/oprofile/Makefile            |   1 +
 arch/powerpc/oprofile/common.c            |  62 +--
 arch/powerpc/oprofile/op_model_acp_pmu.c  | 280 ++++++++++++++
 arch/powerpc/perf/Makefile                |   3 +
 arch/powerpc/perf/core-lsi-acp.c          | 611 ++++++++++++++++++++++++++++++
 arch/powerpc/perf/ppc476-pmu.c            | 194 ++++++++++
 arch/powerpc/platforms/Kconfig.cputype    |  17 +
 16 files changed, 1700 insertions(+), 168 deletions(-)
 create mode 100644 arch/powerpc/include/asm/perf_event_acp.h
 create mode 100644 arch/powerpc/include/asm/reg_acp_pmu.h
 create mode 100644 arch/powerpc/include/asm/reg_acp_pmu_fn.h
 create mode 100644 arch/powerpc/oprofile/op_model_acp_pmu.c
 create mode 100644 arch/powerpc/perf/core-lsi-acp.c
 create mode 100644 arch/powerpc/perf/ppc476-pmu.c

diff --git a/arch/powerpc/include/asm/Kbuild b/arch/powerpc/include/asm/Kbuild
index 7e313f1..b308e90 100644
--- a/arch/powerpc/include/asm/Kbuild
+++ b/arch/powerpc/include/asm/Kbuild
@@ -34,5 +34,6 @@ header-y += termios.h
 header-y += types.h
 header-y += ucontext.h
 header-y += unistd.h
+header-y += reg_acp_pmu.h
 
 generic-y += rwsem.h
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index b9219e9..046c0eb 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -45,7 +45,7 @@
  */
 struct cpu_spec;
 
-typedef	void (*cpu_setup_t)(unsigned long offset, struct cpu_spec* spec);
+typedef	void (*cpu_setup_t)(unsigned long offset, struct cpu_spec *spec);
 typedef	void (*cpu_restore_t)(void);
 
 enum powerpc_oprofile_type {
@@ -56,6 +56,7 @@ enum powerpc_oprofile_type {
 	PPC_OPROFILE_FSL_EMB = 4,
 	PPC_OPROFILE_CELL = 5,
 	PPC_OPROFILE_PA6T = 6,
+	PPC_OPROFILE_ACP_PMU = 7,
 };
 
 enum powerpc_pmc_type {
@@ -207,7 +208,7 @@ extern const char *powerpc_base_platform;
 
 #define CPU_FTR_PPCAS_ARCH_V2	(CPU_FTR_NOEXECUTE | CPU_FTR_NODSISRALIGN)
 
-#define MMU_FTR_PPCAS_ARCH_V2 	(MMU_FTR_SLB | MMU_FTR_TLBIEL | \
+#define MMU_FTR_PPCAS_ARCH_V2	(MMU_FTR_SLB | MMU_FTR_TLBIEL | \
 				 MMU_FTR_16M_PAGE)
 
 /* We only set the altivec features if the kernel was compiled with altivec
@@ -368,11 +369,12 @@ extern const char *powerpc_base_platform;
 	    CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | \
 	    CPU_FTR_COMMON | CPU_FTR_FPU_UNAVAILABLE)
 #define CPU_FTRS_CLASSIC32	(CPU_FTR_COMMON | CPU_FTR_USE_TB)
-#define CPU_FTRS_8XX	(CPU_FTR_USE_TB)
-#define CPU_FTRS_40X	(CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE)
-#define CPU_FTRS_44X	(CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE)
-#define CPU_FTRS_440x6	(CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE | \
-	    CPU_FTR_INDEXED_DCR)
+#define CPU_FTRS_8XX (CPU_FTR_USE_TB)
+#define CPU_FTRS_40X (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE)
+#define CPU_FTRS_44X (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE)
+#define CPU_FTRS_440x6 \
+	(CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE | \
+	CPU_FTR_INDEXED_DCR)
 #define CPU_FTRS_47X	(CPU_FTRS_440x6)
 #define CPU_FTRS_E200	(CPU_FTR_USE_TB | CPU_FTR_SPE_COMP | \
 	    CPU_FTR_NODSISRALIGN | CPU_FTR_COHERENT_ICACHE | \
diff --git a/arch/powerpc/include/asm/oprofile_impl.h b/arch/powerpc/include/asm/oprofile_impl.h
index 639dc96..f77040a 100644
--- a/arch/powerpc/include/asm/oprofile_impl.h
+++ b/arch/powerpc/include/asm/oprofile_impl.h
@@ -66,12 +66,13 @@ extern struct op_powerpc_model op_model_power4;
 extern struct op_powerpc_model op_model_7450;
 extern struct op_powerpc_model op_model_cell;
 extern struct op_powerpc_model op_model_pa6t;
+extern struct op_powerpc_model op_model_acp_pmu;
 
 
 /* All the classic PPC parts use these */
 static inline unsigned int classic_ctr_read(unsigned int i)
 {
-	switch(i) {
+	switch (i) {
 	case 0:
 		return mfspr(SPRN_PMC1);
 	case 1:
@@ -99,7 +100,7 @@ static inline unsigned int classic_ctr_read(unsigned int i)
 
 static inline void classic_ctr_write(unsigned int i, unsigned int val)
 {
-	switch(i) {
+	switch (i) {
 	case 0:
 		mtspr(SPRN_PMC1, val);
 		break;
@@ -134,7 +135,8 @@ static inline void classic_ctr_write(unsigned int i, unsigned int val)
 }
 
 
-extern void op_powerpc_backtrace(struct pt_regs * const regs, unsigned int depth);
+extern void
+op_powerpc_backtrace(struct pt_regs * const regs, unsigned int depth);
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_OPROFILE_IMPL_H */
diff --git a/arch/powerpc/include/asm/perf_event.h b/arch/powerpc/include/asm/perf_event.h
index 5c16b89..e8e534c 100644
--- a/arch/powerpc/include/asm/perf_event.h
+++ b/arch/powerpc/include/asm/perf_event.h
@@ -22,8 +22,12 @@
 #include <asm/perf_event_fsl_emb.h>
 #endif
 
+#ifdef CONFIG_ACP_PMU_PERF_EVENT
+#include <asm/perf_event_acp.h>
+#endif
+
 #ifdef CONFIG_PERF_EVENTS
-#include <asm/ptrace.h>
+#include <linux/ptrace.h>
 #include <asm/reg.h>
 
 #define perf_arch_fetch_caller_regs(regs, __ip)			\
diff --git a/arch/powerpc/include/asm/perf_event_acp.h b/arch/powerpc/include/asm/perf_event_acp.h
new file mode 100644
index 0000000..356179b
--- /dev/null
+++ b/arch/powerpc/include/asm/perf_event_acp.h
@@ -0,0 +1,41 @@
+#ifndef PERF_EVENT_ACP_H
+#define PERF_EVENT_ACP_H
+
+/*
+ * Performance counter support for LSI Axxia3400
+ *
+ * Based on earlier code:
+ *
+ * perf_event_fsl_emb.h
+ *
+ * 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/types.h>
+#include <asm/hw_irq.h>
+
+#define MAX_HWEVENTS 8
+
+/* event flags */
+#define ACP_EVENT_VALID      1
+
+
+struct acp_pmu {
+	const char	*name;
+	int		n_counter; /* total number of counters */
+	/* Returns event flags */
+	u64		(*xlate_event)(u64 event_id);
+
+	int		n_generic;
+	int		*generic_events;
+	int		(*cache_events)[PERF_COUNT_HW_CACHE_MAX]
+			       [PERF_COUNT_HW_CACHE_OP_MAX]
+			       [PERF_COUNT_HW_CACHE_RESULT_MAX];
+};
+
+int register_acp_pmu(struct acp_pmu *);
+
+#endif
diff --git a/arch/powerpc/include/asm/reg_acp_pmu.h b/arch/powerpc/include/asm/reg_acp_pmu.h
new file mode 100644
index 0000000..8f2fe38
--- /dev/null
+++ b/arch/powerpc/include/asm/reg_acp_pmu.h
@@ -0,0 +1,118 @@
+/*
+ * Register definitions for the LSI Axxia3400 Embedded Performance
+ * Monitor.
+ *
+ * Portions derived from CPP platform legacy perf driver
+ *
+ * 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.
+ */
+#ifndef __ASM_POWERPC_REG_ACP_PMU_H__
+#define __ASM_POWERPC_REG_ACP_PMU_H__
+
+#define L2_LWARX_COMPLETE            (0x00)
+#define L2_STWCX_SUCCESS             (0x01)
+#define L2_MISS_EVICTION             (0x02)
+#define L2_MISS_D_FETCH              (0x03)
+#define L2_MISS_I_FETCH              (0x04)
+#define L2_MISS_STORE                (0x05)
+#define L2_HIT_D_FETCH               (0x06)
+#define L2_HIT_I_FETCH               (0x07)
+#define L2_HIT_STORE                 (0x08)
+#define L2_READ_AFTER_WRITE          (0x09)
+#define L2_WRITE_AFTER_WRITE         (0x0a)
+#define PLB_MASTER_COMMAND           (0x0b)
+#define PLB_MASTER_READ              (0x0c)
+#define PLB_MASTER_RWITM             (0x0d)
+#define PLB_MASTER_DCLAIM            (0x0e)
+#define PLB_MASTER_WRITE             (0x0f)
+#define PLB_READ_OCCUPANCY           (0x10)
+#define PLB_MASTER_INTVN_M           (0x11)
+#define PLB_MASTER_INTVN_S           (0x12)
+#define PLB_MASTER_MEM_DATA          (0x13)
+#define PLB_SNOOP_CMD                (0x14)
+#define PLB_SNOOP_L2_CMD             (0x15)
+#define PLB_SNOOP_HIT_INTVN          (0x16)
+#define PLB_SNOOP_HIT                (0x17)
+#define PLB_SNOOP_RETRY              (0x18)
+#define CPU_COMMITTED_INST           (0x19)
+#define CPU_DCACHE_HIT               (0x1a)
+#define CPU_DTLB_RELOAD              (0x1b)
+#define CPU_ICACHE_HIT               (0x1c)
+#define CPU_ITLB_RELOAD              (0x1d)
+#define L2_CYCLE_COUNT               (0x1e)
+#define CPU_CYCLE_COUNT              (0x1f)
+
+#ifdef __KERNEL__
+
+#include <asm/dcr-native.h>
+
+/* LSI ACP ppc476  Performance Monitor Registers */
+
+/* Address and Data Indirect Register */
+#define PMUDCRAI(core)               (0x80 + 0x300 + (core) * 0x100)
+#define PMUDCRDI(core)               (0x84 + 0x300 + (core) * 0x100)
+
+/* Global Control Registers */
+
+#define PMRN_PMUGS0     0x000 /* PMU Global Status Register */
+
+#define PMUGS_PMC_STATE(nr) (1<<(31-(nr))) /* Stop/Start state of PMUC(nr), */
+					   /* 1== start */
+#define PMUGS_CPUFAC    (1<<(31-29)) /* PMU_C476FAC signal input */
+#define PMUGS_CPUR      (1<<(31-30)) /* PMU_C476PR signal input */
+#define PMUGS_CPUMM     (1<<(31-31)) /* PMU_C476MM signal input */
+
+#define PMRN_PMUGC0     0x004 /* PMU Global Control Register */
+
+#define PMUGC0_PMCC      (1<<(31-15)) /* Returns all counters to zero */
+#define PMUGC0_LFAC      (1<<(31-30)) /* Freeze all counters */
+#define PMUGC0_FCEC      (1<<(31-31)) /* Freeze counters on enabled Condition*/
+
+#define PMRN_PMUIS0     0x010 /* PMU Global Interrupt Status Register */
+
+#define PMUIS_ISTAT(nr) (1<<(31-(nr))) /* Interrupt status of PMUC(nr), */
+				       /* 1== counter has an enable condition */
+
+#define PMRN_PMUIE0     0x014 /* PMU Global Interrupt Control Register */
+
+#define PMUIE_IE(nr) (1<<(31-(nr))) /* Interrupt enable of PMUC(nr), */
+				    /*  1== Interrupt enable for PMUC(nr) */
+
+#define PMRN_REVID      0xC00 /* PMU Revision ID register */
+
+/* Local Counter registers */
+
+#define PMRN_PMCA0	0x808	/* Performance Monitor Counter 0 */
+#define PMRN_PMCA1	0x818	/* Performance Monitor Counter 1 */
+#define PMRN_PMCA2	0x828	/* Performance Monitor Counter 2 */
+#define PMRN_PMCA3	0x838	/* Performance Monitor Counter 3 */
+#define PMRN_PMCA4	0x908	/* Performance Monitor Counter 4 */
+#define PMRN_PMCA5	0x918	/* Performance Monitor Counter 5 */
+#define PMRN_PMCA6	0x928	/* Performance Monitor Counter 6 */
+#define PMRN_PMCA7	0x938	/* Performance Monitor Counter 7 */
+#define PMRN_PMLCA0	0x800	/* PM Local Counter Control Register 0 */
+#define PMRN_PMLCA1	0x810	/* PM Local Counter Control Register 1 */
+#define PMRN_PMLCA2	0x820	/* PM Local Counter Control Register 2 */
+#define PMRN_PMLCA3	0x830	/* PM Local Counter Control Register 3 */
+#define PMRN_PMLCA4	0x900	/* PM Local Counter Control Register 4 */
+#define PMRN_PMLCA5	0x910	/* PM Local Counter Control Register 5 */
+#define PMRN_PMLCA6	0x920	/* PM Local Counter Control Register 6 */
+#define PMRN_PMLCA7	0x930	/* PM Local Counter Control Register 7 */
+
+
+#define PMLCA_FC	(1<<(31-10))	/* Freeze Counter */
+#define PMLCA_FCS	(1<<(31-11))	/* Freeze in Supervisor */
+#define PMLCA_FCU	(1<<(31-12))	/* Freeze in User */
+#define PMLCA_FCM1	(1<<(31-13))	/* Freeze Counter while Mark is Set */
+#define PMLCA_FCM0	(1<<(31-14))	/* Freeze Cntr while Mark is Cleared */
+#define PMLCA_CE	(1<<(31-15))	/* Condition Enable */
+
+#define PMLCA_EVENT_MASK 0x0000003f	/* Event field */
+#define PMLCA_EVENT_SHIFT 0
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_POWERPC_REG_ACP_PMU_H__ */
diff --git a/arch/powerpc/include/asm/reg_acp_pmu_fn.h b/arch/powerpc/include/asm/reg_acp_pmu_fn.h
new file mode 100644
index 0000000..8811b6b
--- /dev/null
+++ b/arch/powerpc/include/asm/reg_acp_pmu_fn.h
@@ -0,0 +1,166 @@
+/*
+ * Register read/write for the LSI Axxia3400 Embedded Performance
+ * Monitor.
+ *
+ * Portions derived from CPP platform legacy perf driver
+ *
+ * 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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_POWERPC_REG_ACP_PMU_FN_H__
+#define __ASM_POWERPC_REG_ACP_PMU_FN_H__
+
+#include <asm/reg_acp_pmu.h>
+
+/* LSI ACP ppc476  Performance Monitor Registers */
+
+/* common oprofile and perf event read/write pmu registers */
+
+/* Get local counter control register */
+
+static inline u32 get_pmlc(int core, int ctr)
+{
+	switch (ctr) {
+	case 0:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMLCA0);
+		break;
+	case 1:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMLCA1);
+		break;
+	case 2:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMLCA2);
+		break;
+	case 3:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMLCA3);
+		break;
+	case 4:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMLCA4);
+		break;
+	case 5:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMLCA5);
+		break;
+	case 6:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMLCA6);
+		break;
+	case 7:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMLCA7);
+		break;
+	default:
+		printk(KERN_ERR "oops trying to read PMC%d\n", ctr);
+		return 0;
+	}
+	return mfdcrx(PMUDCRDI(core));
+}
+
+/* Set local counter control register */
+
+static inline void set_pmlc(int core, int ctr, u32 pmlc)
+{
+	switch (ctr) {
+	case 0:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMLCA0);
+		break;
+	case 1:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMLCA1);
+		break;
+	case 2:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMLCA2);
+		break;
+	case 3:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMLCA3);
+		break;
+	case 4:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMLCA4);
+		break;
+	case 5:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMLCA5);
+		break;
+	case 6:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMLCA6);
+		break;
+	case 7:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMLCA7);
+		break;
+	default:
+		printk(KERN_ERR "oops trying to read PMC%d\n", ctr);
+		return;
+	}
+	mtdcrx(PMUDCRDI(core), pmlc);
+}
+
+/* Get local counter register */
+
+static inline unsigned int ctr_read(int core, unsigned int i)
+{
+	switch (i) {
+	case 0:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMCA0);
+		break;
+	case 1:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMCA1);
+		break;
+	case 2:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMCA2);
+		break;
+	case 3:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMCA3);
+		break;
+	case 4:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMCA4);
+		break;
+	case 5:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMCA5);
+		break;
+	case 6:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMCA6);
+		break;
+	case 7:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMCA7);
+		break;
+	default:
+		return 0;
+	}
+	return mfdcrx(PMUDCRDI(core));
+}
+
+/* Set local counter register */
+
+static inline void ctr_write(int core, unsigned int i, unsigned int val)
+{
+	switch (i) {
+	case 0:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMCA0);
+		break;
+	case 1:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMCA1);
+		break;
+	case 2:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMCA2);
+		break;
+	case 3:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMCA3);
+		break;
+	case 4:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMCA4);
+		break;
+	case 5:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMCA5);
+		break;
+	case 6:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMCA6);
+		break;
+	case 7:
+		mtdcrx(PMUDCRAI(core),  PMRN_PMCA7);
+		break;
+	default:
+		return;
+	}
+	mtdcrx(PMUDCRDI(core), val);
+}
+
+#endif /* __ASM_POWERPC_REG_ACP_PMU_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index dbd8354..28ccdda 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -22,7 +22,7 @@
 #include <asm/mmu.h>
 #include <asm/setup.h>
 
-struct cpu_spec* cur_cpu_spec = NULL;
+struct cpu_spec *cur_cpu_spec;
 EXPORT_SYMBOL(cur_cpu_spec);
 
 /* The platform string corresponding to the real PVR */
@@ -36,42 +36,42 @@ const char *powerpc_base_platform;
  * and ppc64
  */
 #ifdef CONFIG_PPC32
-extern void __setup_cpu_e200(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_e500v1(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_e500v2(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_e500mc(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_440ep(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_440epx(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_440gx(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_440grx(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_440spe(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_440x5(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_460ex(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_460gt(unsigned long offset, struct cpu_spec* spec);
+extern void __setup_cpu_e200(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_e500v1(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_e500v2(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_e500mc(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_440ep(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_440epx(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_440gx(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_440grx(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_440spe(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_440x5(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_460ex(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_460gt(unsigned long offset, struct cpu_spec *spec);
 extern void __setup_cpu_460sx(unsigned long offset, struct cpu_spec *spec);
 extern void __setup_cpu_apm821xx(unsigned long offset, struct cpu_spec *spec);
-extern void __setup_cpu_603(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_604(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_750(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_750cx(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_750fx(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_7400(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_7410(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_745x(unsigned long offset, struct cpu_spec* spec);
+extern void __setup_cpu_603(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_604(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_750(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_750cx(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_750fx(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_7400(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_7410(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_745x(unsigned long offset, struct cpu_spec *spec);
 #endif /* CONFIG_PPC32 */
 #ifdef CONFIG_PPC64
-extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_ppc970MP(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_pa6t(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_a2(unsigned long offset, struct cpu_spec* spec);
+extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_ppc970MP(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_pa6t(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_a2(unsigned long offset, struct cpu_spec *spec);
 extern void __restore_cpu_pa6t(void);
 extern void __restore_cpu_ppc970(void);
-extern void __setup_cpu_power7(unsigned long offset, struct cpu_spec* spec);
+extern void __setup_cpu_power7(unsigned long offset, struct cpu_spec *spec);
 extern void __restore_cpu_power7(void);
 extern void __restore_cpu_a2(void);
 #endif /* CONFIG_PPC64 */
 #if defined(CONFIG_E500)
-extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec);
+extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec *spec);
 extern void __restore_cpu_e5500(void);
 #endif /* CONFIG_E500 */
 
@@ -701,7 +701,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "750CL",
 		.cpu_features		= CPU_FTRS_750CL,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
-		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
+		.mmu_features		= MMU_FTR_HPTE_TABLE |
+					  MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -767,7 +768,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "750FX",
 		.cpu_features		= CPU_FTRS_750FX,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
-		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
+		.mmu_features		= MMU_FTR_HPTE_TABLE |
+					  MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -784,7 +786,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "750GX",
 		.cpu_features		= CPU_FTRS_750GX,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
-		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
+		.mmu_features		= MMU_FTR_HPTE_TABLE |
+					  MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -918,8 +921,10 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "7455",
 		.cpu_features		= CPU_FTRS_7455_1,
 		.cpu_user_features	= COMMON_USER |
-			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
-		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
+					  PPC_FEATURE_HAS_ALTIVEC_COMP |
+					  PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE |
+					  MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -936,8 +941,10 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "7455",
 		.cpu_features		= CPU_FTRS_7455_20,
 		.cpu_user_features	= COMMON_USER |
-			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
-		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
+					  PPC_FEATURE_HAS_ALTIVEC_COMP |
+					  PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE |
+					  MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -954,8 +961,10 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "7455",
 		.cpu_features		= CPU_FTRS_7455,
 		.cpu_user_features	= COMMON_USER |
-			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
-		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
+					  PPC_FEATURE_HAS_ALTIVEC_COMP |
+					  PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE |
+					  MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -972,8 +981,10 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "7447/7457",
 		.cpu_features		= CPU_FTRS_7447_10,
 		.cpu_user_features	= COMMON_USER |
-			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
-		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
+					  PPC_FEATURE_HAS_ALTIVEC_COMP |
+					  PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE |
+					  MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -990,8 +1001,10 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "7447/7457",
 		.cpu_features		= CPU_FTRS_7447_10,
 		.cpu_user_features	= COMMON_USER |
-			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
-		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
+					  PPC_FEATURE_HAS_ALTIVEC_COMP |
+					  PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE |
+					  MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -1007,8 +1020,11 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.pvr_value		= 0x80020000,
 		.cpu_name		= "7447/7457",
 		.cpu_features		= CPU_FTRS_7447,
-		.cpu_user_features	= COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
-		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
+		.cpu_user_features	= COMMON_USER |
+					  PPC_FEATURE_HAS_ALTIVEC_COMP |
+					  PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE |
+					  MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -1025,8 +1041,10 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "7447A",
 		.cpu_features		= CPU_FTRS_7447A,
 		.cpu_user_features	= COMMON_USER |
-			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
-		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
+					  PPC_FEATURE_HAS_ALTIVEC_COMP |
+					  PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE |
+					  MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -1043,8 +1061,10 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "7448",
 		.cpu_features		= CPU_FTRS_7448,
 		.cpu_user_features	= COMMON_USER |
-			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
-		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
+					  PPC_FEATURE_HAS_ALTIVEC_COMP |
+					  PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE |
+					  MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -1101,7 +1121,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_features		= CPU_FTRS_E300C2,
 		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
 		.mmu_features		= MMU_FTR_USE_HIGH_BATS |
-			MMU_FTR_NEED_DTLB_SW_LRU,
+					  MMU_FTR_NEED_DTLB_SW_LRU,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_603,
@@ -1115,7 +1135,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_features		= CPU_FTRS_E300,
 		.cpu_user_features	= COMMON_USER,
 		.mmu_features		= MMU_FTR_USE_HIGH_BATS |
-			MMU_FTR_NEED_DTLB_SW_LRU,
+					  MMU_FTR_NEED_DTLB_SW_LRU,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_603,
@@ -1131,7 +1151,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_features		= CPU_FTRS_E300,
 		.cpu_user_features	= COMMON_USER,
 		.mmu_features		= MMU_FTR_USE_HIGH_BATS |
-			MMU_FTR_NEED_DTLB_SW_LRU,
+					  MMU_FTR_NEED_DTLB_SW_LRU,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_603,
@@ -1188,7 +1208,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "403GCX",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-		 	PPC_FEATURE_HAS_MMU | PPC_FEATURE_NO_TB,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_NO_TB,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 16,
 		.dcache_bsize		= 16,
@@ -1213,7 +1234,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "405GP",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1226,7 +1248,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "STB03xxx",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1239,7 +1262,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "STB04xxx",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1252,7 +1276,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "NP405L",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1265,7 +1290,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "NP4GS3",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1278,7 +1304,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "NP405H",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1291,7 +1318,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "405GPr",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1304,7 +1332,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "STBx25xx",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1329,7 +1358,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "Virtex-II Pro",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1342,7 +1372,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "Virtex-4 FX",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1355,7 +1386,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "405EP",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1368,7 +1400,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "405EX Rev. A/B",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1381,7 +1414,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "405EX Rev. C",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1394,7 +1428,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "405EX Rev. C",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1407,7 +1442,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "405EX Rev. D",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1420,7 +1456,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "405EX Rev. D",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1433,7 +1470,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "405EXr Rev. A/B",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1446,7 +1484,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "405EXr Rev. C",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1459,7 +1498,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "405EXr Rev. C",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1472,7 +1512,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "405EXr Rev. D",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1485,7 +1526,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "405EXr Rev. D",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1499,7 +1541,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "405EZ",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1512,7 +1555,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "APM8018X",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1525,7 +1569,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "(generic 40x PPC)",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+					  PPC_FEATURE_HAS_MMU |
+					  PPC_FEATURE_HAS_4xxMAC,
 		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1552,7 +1597,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.pvr_value		= 0x40000858,
 		.cpu_name		= "440EP Rev. A",
 		.cpu_features		= CPU_FTRS_44X,
-		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+		.cpu_user_features	= COMMON_USER_BOOKE |
+					  PPC_FEATURE_HAS_FPU,
 		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1565,19 +1611,23 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.pvr_value		= 0x400008d3,
 		.cpu_name		= "440GR Rev. B",
 		.cpu_features		= CPU_FTRS_44X,
-		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+		.cpu_user_features	= COMMON_USER_BOOKE |
+					  PPC_FEATURE_HAS_FPU,
 		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
 		.platform		= "ppc440",
 	},
-	{ /* Matches both physical and logical PVR for 440EP (logical pvr = pvr | 0x8) */
+	{ /* Matches both physical and logical PVR for 440EP
+	   * (logical pvr = pvr | 0x8)
+	   */
 		.pvr_mask		= 0xf0000ff7,
 		.pvr_value		= 0x400008d4,
 		.cpu_name		= "440EP Rev. C",
 		.cpu_features		= CPU_FTRS_44X,
-		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+		.cpu_user_features	= COMMON_USER_BOOKE |
+					  PPC_FEATURE_HAS_FPU,
 		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1590,7 +1640,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.pvr_value		= 0x400008db,
 		.cpu_name		= "440EP Rev. B",
 		.cpu_features		= CPU_FTRS_44X,
-		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+		.cpu_user_features	= COMMON_USER_BOOKE |
+					  PPC_FEATURE_HAS_FPU,
 		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1616,7 +1667,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.pvr_value		= 0x200008D8,
 		.cpu_name		= "440EPX",
 		.cpu_features		= CPU_FTRS_44X,
-		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+		.cpu_user_features	= COMMON_USER_BOOKE |
+					  PPC_FEATURE_HAS_FPU,
 		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1756,7 +1808,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.pvr_value		= 0x13020002,
 		.cpu_name		= "460EX",
 		.cpu_features		= CPU_FTRS_440x6,
-		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+		.cpu_user_features	= COMMON_USER_BOOKE |
+					  PPC_FEATURE_HAS_FPU,
 		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1769,7 +1822,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.pvr_value		= 0x13020004,
 		.cpu_name		= "460EX Rev. B",
 		.cpu_features		= CPU_FTRS_440x6,
-		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+		.cpu_user_features	= COMMON_USER_BOOKE |
+					  PPC_FEATURE_HAS_FPU,
 		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1782,7 +1836,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.pvr_value		= 0x13020000,
 		.cpu_name		= "460GT",
 		.cpu_features		= CPU_FTRS_440x6,
-		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+		.cpu_user_features	= COMMON_USER_BOOKE |
+					  PPC_FEATURE_HAS_FPU,
 		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1795,7 +1850,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.pvr_value		= 0x13020005,
 		.cpu_name		= "460GT Rev. B",
 		.cpu_features		= CPU_FTRS_440x6,
-		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+		.cpu_user_features	= COMMON_USER_BOOKE |
+					  PPC_FEATURE_HAS_FPU,
 		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1822,7 +1878,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "APM821XX",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features	= COMMON_USER_BOOKE |
-			PPC_FEATURE_HAS_FPU,
+					  PPC_FEATURE_HAS_FPU,
 		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -1836,12 +1892,16 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "476, DD2",
 		.cpu_features		= CPU_FTRS_47X | CPU_FTR_476_DD2,
 		.cpu_user_features	= COMMON_USER_BOOKE |
-			PPC_FEATURE_HAS_FPU,
+					  PPC_FEATURE_HAS_FPU,
 		.mmu_features		= MMU_FTR_TYPE_47x |
-			MMU_FTR_USE_TLBIVAX_BCAST | MMU_FTR_LOCK_BCAST_INVAL,
+					  MMU_FTR_USE_TLBIVAX_BCAST |
+					  MMU_FTR_LOCK_BCAST_INVAL,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 128,
 		.machine_check		= machine_check_47x,
+		.num_pmcs		= 8,
+		.oprofile_cpu_type	= "ppc/476",
+		.oprofile_type		= PPC_OPROFILE_ACP_PMU,
 		.platform		= "ppc470",
 	},
 	{ /* X2 DD2 core */
@@ -1850,12 +1910,16 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "476, X2 DD2",
 		.cpu_features		= CPU_FTRS_47X | CPU_FTR_476_DD2,
 		.cpu_user_features	= COMMON_USER_BOOKE |
-			PPC_FEATURE_HAS_FPU,
+					  PPC_FEATURE_HAS_FPU,
 		.mmu_features		= MMU_FTR_TYPE_47x |
-			MMU_FTR_USE_TLBIVAX_BCAST | MMU_FTR_LOCK_BCAST_INVAL,
+					  MMU_FTR_USE_TLBIVAX_BCAST |
+					  MMU_FTR_LOCK_BCAST_INVAL,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 128,
 		.machine_check		= machine_check_47x,
+		.num_pmcs		= 8,
+		.oprofile_cpu_type	= "ppc/476",
+		.oprofile_type		= PPC_OPROFILE_ACP_PMU,
 		.platform		= "ppc470",
 	},
 	{ /* 476fpe */
@@ -1864,9 +1928,10 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "476fpe",
 		.cpu_features		= CPU_FTRS_47X | CPU_FTR_476_DD2,
 		.cpu_user_features	= COMMON_USER_BOOKE |
-			PPC_FEATURE_HAS_FPU,
+					  PPC_FEATURE_HAS_FPU,
 		.mmu_features		= MMU_FTR_TYPE_47x |
-			MMU_FTR_USE_TLBIVAX_BCAST | MMU_FTR_LOCK_BCAST_INVAL,
+					  MMU_FTR_USE_TLBIVAX_BCAST |
+					  MMU_FTR_LOCK_BCAST_INVAL,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 128,
 		.machine_check		= machine_check_47x,
@@ -1878,9 +1943,10 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name				= "476",
 		.cpu_features		= CPU_FTRS_47X | CPU_FTR_476_DD2,
 		.cpu_user_features	= COMMON_USER_BOOKE |
-			PPC_FEATURE_HAS_FPU,
+					  PPC_FEATURE_HAS_FPU,
 		.mmu_features		= MMU_FTR_TYPE_47x |
-			MMU_FTR_USE_TLBIVAX_BCAST | MMU_FTR_LOCK_BCAST_INVAL,
+					  MMU_FTR_USE_TLBIVAX_BCAST |
+					  MMU_FTR_LOCK_BCAST_INVAL,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 128,
 		.machine_check		= machine_check_47x,
@@ -1892,12 +1958,16 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "476, DD3",
 		.cpu_features		= CPU_FTRS_47X,
 		.cpu_user_features	= COMMON_USER_BOOKE |
-			PPC_FEATURE_HAS_FPU,
+					  PPC_FEATURE_HAS_FPU,
 		.mmu_features		= MMU_FTR_TYPE_47x |
-			MMU_FTR_USE_TLBIVAX_BCAST | MMU_FTR_LOCK_BCAST_INVAL,
+					  MMU_FTR_USE_TLBIVAX_BCAST |
+					  MMU_FTR_LOCK_BCAST_INVAL,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 128,
 		.machine_check		= machine_check_47x,
+		.num_pmcs		= 8,
+		.oprofile_cpu_type	= "ppc/476",
+		.oprofile_type		= PPC_OPROFILE_ACP_PMU,
 		.platform		= "ppc470",
 	},
 	{ /* 476 ACP25xx */
@@ -1906,12 +1976,16 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "476, ACP25xx",
 		.cpu_features		= CPU_FTRS_47X,
 		.cpu_user_features	= COMMON_USER_BOOKE |
-			PPC_FEATURE_HAS_FPU,
+					  PPC_FEATURE_HAS_FPU,
 		.mmu_features		= MMU_FTR_TYPE_47x |
-			MMU_FTR_USE_TLBIVAX_BCAST | MMU_FTR_LOCK_BCAST_INVAL,
+					  MMU_FTR_USE_TLBIVAX_BCAST |
+					  MMU_FTR_LOCK_BCAST_INVAL,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 128,
 		.machine_check		= machine_check_47x,
+		.num_pmcs		= 8,
+		.oprofile_cpu_type      = "ppc/476",
+		.oprofile_type          = PPC_OPROFILE_ACP_PMU,
 		.platform		= "ppc470",
 	},
 	{ /* 476 others */
@@ -1920,9 +1994,10 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "476, Other",
 		.cpu_features		= CPU_FTRS_47X,
 		.cpu_user_features	= COMMON_USER_BOOKE |
-			PPC_FEATURE_HAS_FPU,
+					  PPC_FEATURE_HAS_FPU,
 		.mmu_features		= MMU_FTR_TYPE_47x |
-			MMU_FTR_USE_TLBIVAX_BCAST | MMU_FTR_LOCK_BCAST_INVAL,
+					  MMU_FTR_USE_TLBIVAX_BCAST |
+					  MMU_FTR_LOCK_BCAST_INVAL,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 128,
 		.machine_check		= machine_check_47x,
@@ -1949,8 +2024,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		/* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
 		.cpu_features		= CPU_FTRS_E200,
 		.cpu_user_features	= COMMON_USER_BOOKE |
-			PPC_FEATURE_HAS_EFP_SINGLE |
-			PPC_FEATURE_UNIFIED_CACHE,
+					  PPC_FEATURE_HAS_EFP_SINGLE |
+					  PPC_FEATURE_UNIFIED_CACHE,
 		.mmu_features		= MMU_FTR_TYPE_FSL_E,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_e200,
@@ -1963,9 +2038,9 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		/* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
 		.cpu_features		= CPU_FTRS_E200,
 		.cpu_user_features	= COMMON_USER_BOOKE |
-			PPC_FEATURE_HAS_SPE_COMP |
-			PPC_FEATURE_HAS_EFP_SINGLE_COMP |
-			PPC_FEATURE_UNIFIED_CACHE,
+					  PPC_FEATURE_HAS_SPE_COMP |
+					  PPC_FEATURE_HAS_EFP_SINGLE_COMP |
+					  PPC_FEATURE_UNIFIED_CACHE,
 		.mmu_features		= MMU_FTR_TYPE_FSL_E,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_e200,
@@ -1977,8 +2052,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "(generic E200 PPC)",
 		.cpu_features		= CPU_FTRS_E200,
 		.cpu_user_features	= COMMON_USER_BOOKE |
-			PPC_FEATURE_HAS_EFP_SINGLE |
-			PPC_FEATURE_UNIFIED_CACHE,
+					  PPC_FEATURE_HAS_EFP_SINGLE |
+					  PPC_FEATURE_UNIFIED_CACHE,
 		.mmu_features		= MMU_FTR_TYPE_FSL_E,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_e200,
@@ -1995,8 +2070,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "e500",
 		.cpu_features		= CPU_FTRS_E500,
 		.cpu_user_features	= COMMON_USER_BOOKE |
-			PPC_FEATURE_HAS_SPE_COMP |
-			PPC_FEATURE_HAS_EFP_SINGLE_COMP,
+					  PPC_FEATURE_HAS_SPE_COMP |
+					  PPC_FEATURE_HAS_EFP_SINGLE_COMP,
 		.mmu_features		= MMU_FTR_TYPE_FSL_E,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -2013,9 +2088,9 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "e500v2",
 		.cpu_features		= CPU_FTRS_E500_2,
 		.cpu_user_features	= COMMON_USER_BOOKE |
-			PPC_FEATURE_HAS_SPE_COMP |
-			PPC_FEATURE_HAS_EFP_SINGLE_COMP |
-			PPC_FEATURE_HAS_EFP_DOUBLE_COMP,
+					  PPC_FEATURE_HAS_SPE_COMP |
+					  PPC_FEATURE_HAS_EFP_SINGLE_COMP |
+					  PPC_FEATURE_HAS_EFP_DOUBLE_COMP,
 		.mmu_features		= MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -2031,9 +2106,11 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.pvr_value		= 0x80230000,
 		.cpu_name		= "e500mc",
 		.cpu_features		= CPU_FTRS_E500MC,
-		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
-		.mmu_features		= MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS |
-			MMU_FTR_USE_TLBILX,
+		.cpu_user_features	= COMMON_USER_BOOKE |
+					  PPC_FEATURE_HAS_FPU,
+		.mmu_features		= MMU_FTR_TYPE_FSL_E |
+					  MMU_FTR_BIG_PHYS |
+					  MMU_FTR_USE_TLBILX,
 		.icache_bsize		= 64,
 		.dcache_bsize		= 64,
 		.num_pmcs		= 4,
@@ -2049,9 +2126,11 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.pvr_value		= 0x80240000,
 		.cpu_name		= "e5500",
 		.cpu_features		= CPU_FTRS_E5500,
-		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
-		.mmu_features		= MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS |
-			MMU_FTR_USE_TLBILX,
+		.cpu_user_features	= COMMON_USER_BOOKE |
+					  PPC_FEATURE_HAS_FPU,
+		.mmu_features		= MMU_FTR_TYPE_FSL_E |
+					  MMU_FTR_BIG_PHYS |
+					  MMU_FTR_USE_TLBILX,
 		.icache_bsize		= 64,
 		.dcache_bsize		= 64,
 		.num_pmcs		= 4,
@@ -2067,9 +2146,11 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.pvr_value		= 0x80400000,
 		.cpu_name		= "e6500",
 		.cpu_features		= CPU_FTRS_E6500,
-		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
-		.mmu_features		= MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS |
-			MMU_FTR_USE_TLBILX,
+		.cpu_user_features	= COMMON_USER_BOOKE |
+					  PPC_FEATURE_HAS_FPU,
+		.mmu_features		= MMU_FTR_TYPE_FSL_E |
+					  MMU_FTR_BIG_PHYS |
+					  MMU_FTR_USE_TLBILX,
 		.icache_bsize		= 64,
 		.dcache_bsize		= 64,
 		.num_pmcs		= 4,
@@ -2087,8 +2168,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_name		= "(generic E500 PPC)",
 		.cpu_features		= CPU_FTRS_E500,
 		.cpu_user_features	= COMMON_USER_BOOKE |
-			PPC_FEATURE_HAS_SPE_COMP |
-			PPC_FEATURE_HAS_EFP_SINGLE_COMP,
+					  PPC_FEATURE_HAS_SPE_COMP |
+					  PPC_FEATURE_HAS_EFP_SINGLE_COMP,
 		.mmu_features		= MMU_FTR_TYPE_FSL_E,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
@@ -2199,9 +2280,8 @@ static struct cpu_spec * __init setup_cpu_spec(unsigned long offset,
 	 * pointer on ppc64 and booke as we are running at 0 in real mode
 	 * on ppc64 and reloc_offset is always 0 on booke.
 	 */
-	if (t->cpu_setup) {
+	if (t->cpu_setup)
 		t->cpu_setup(offset, t);
-	}
 #endif /* CONFIG_PPC64 || CONFIG_BOOKE */
 
 	return t;
@@ -2214,7 +2294,7 @@ struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr)
 
 	s = PTRRELOC(s);
 
-	for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++) {
+	for (i = 0; i < ARRAY_SIZE(cpu_specs); i++, s++) {
 		if ((pvr & s->pvr_mask) == s->pvr_value)
 			return setup_cpu_spec(offset, s);
 	}
diff --git a/arch/powerpc/kernel/pmc.c b/arch/powerpc/kernel/pmc.c
index 58eaa3d..52cb8ec 100644
--- a/arch/powerpc/kernel/pmc.c
+++ b/arch/powerpc/kernel/pmc.c
@@ -20,6 +20,10 @@
 #include <asm/processor.h>
 #include <asm/cputable.h>
 #include <asm/pmc.h>
+#if defined(CONFIG_ACP_PMU_PERFMON)
+#include <linux/smp.h>
+#include <asm/reg_acp_pmu.h>
+#endif
 
 #ifndef MMCR0_PMAO
 #define MMCR0_PMAO	0
@@ -32,6 +36,11 @@ static void dummy_perf(struct pt_regs *regs)
 #elif defined(CONFIG_PPC64) || defined(CONFIG_6xx)
 	if (cur_cpu_spec->pmc_type == PPC_PMC_IBM)
 		mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~(MMCR0_PMXE|MMCR0_PMAO));
+#elif defined(CONFIG_ACP_PMU_PERFMON) && defined(CONFIG_SMP)
+	int core = raw_smp_processor_id();
+
+	mtdcrx(PMUDCRAI(core), PMRN_PMUIE0);
+	mtdcrx(PMUDCRDI(core), 0);
 #else
 	mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_PMXE);
 #endif
@@ -49,8 +58,7 @@ int reserve_pmc_hardware(perf_irq_t new_perf_irq)
 	raw_spin_lock(&pmc_owner_lock);
 
 	if (pmc_owner_caller) {
-		printk(KERN_WARNING "reserve_pmc_hardware: "
-		       "PMC hardware busy (reserved by caller %p)\n",
+		pr_warn("reserve_pmc_hardware: PMC hardware busy (reserved by caller %p)\n",
 		       pmc_owner_caller);
 		err = -EBUSY;
 		goto out;
@@ -69,7 +77,7 @@ void release_pmc_hardware(void)
 {
 	raw_spin_lock(&pmc_owner_lock);
 
-	WARN_ON(! pmc_owner_caller);
+	WARN_ON(!pmc_owner_caller);
 
 	pmc_owner_caller = NULL;
 	perf_irq = dummy_perf;
diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile
index 73456c4..576c32d 100644
--- a/arch/powerpc/oprofile/Makefile
+++ b/arch/powerpc/oprofile/Makefile
@@ -16,4 +16,5 @@ oprofile-$(CONFIG_OPROFILE_CELL) += op_model_cell.o \
 		cell/spu_task_sync.o
 oprofile-$(CONFIG_PPC_BOOK3S_64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o
 oprofile-$(CONFIG_FSL_EMB_PERFMON) += op_model_fsl_emb.o
+oprofile-$(CONFIG_ACP_PMU_PERFMON) += op_model_acp_pmu.o
 oprofile-$(CONFIG_6xx) += op_model_7450.o
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
index 4f51025..9ca513c 100644
--- a/arch/powerpc/oprofile/common.c
+++ b/arch/powerpc/oprofile/common.c
@@ -17,11 +17,11 @@
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <linux/errno.h>
-#include <asm/ptrace.h>
+#include <linux/ptrace.h>
 #include <asm/pmc.h>
 #include <asm/cputable.h>
 #include <asm/oprofile_impl.h>
-#include <asm/firmware.h>
+#include <linux/firmware.h>
 
 static struct op_powerpc_model *model;
 
@@ -115,8 +115,8 @@ static void op_powerpc_stop(void)
 {
 	if (model->stop)
 		on_each_cpu(op_powerpc_cpu_stop, NULL, 1);
-        if (model->global_stop)
-                model->global_stop();
+	if (model->global_stop)
+		model->global_stop();
 }
 
 static int op_powerpc_create_files(struct super_block *sb, struct dentry *root)
@@ -176,7 +176,8 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root)
 		oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
 		oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
 
-		oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
+		oprofilefs_create_ulong(sb, dir, "unit_mask",
+					&ctr[i].unit_mask);
 	}
 
 	oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel);
@@ -197,36 +198,39 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
 	switch (cur_cpu_spec->oprofile_type) {
 #ifdef CONFIG_PPC_BOOK3S_64
 #ifdef CONFIG_OPROFILE_CELL
-		case PPC_OPROFILE_CELL:
-			if (firmware_has_feature(FW_FEATURE_LPAR))
-				return -ENODEV;
-			model = &op_model_cell;
-			ops->sync_start = model->sync_start;
-			ops->sync_stop = model->sync_stop;
-			break;
+	case PPC_OPROFILE_CELL:
+		if (firmware_has_feature(FW_FEATURE_LPAR))
+			return -ENODEV;
+		model = &op_model_cell;
+		ops->sync_start = model->sync_start;
+		ops->sync_stop = model->sync_stop;
+		break;
 #endif
-		case PPC_OPROFILE_RS64:
-			model = &op_model_rs64;
-			break;
-		case PPC_OPROFILE_POWER4:
-			model = &op_model_power4;
-			break;
-		case PPC_OPROFILE_PA6T:
-			model = &op_model_pa6t;
-			break;
+	case PPC_OPROFILE_RS64:
+		model = &op_model_rs64;
+		break;
+	case PPC_OPROFILE_POWER4:
+		model = &op_model_power4;
+		break;
+	case PPC_OPROFILE_PA6T:
+		model = &op_model_pa6t;
+		break;
 #endif
+	case PPC_OPROFILE_ACP_PMU:
+		model = &op_model_acp_pmu;
+		break;
 #ifdef CONFIG_6xx
-		case PPC_OPROFILE_G4:
-			model = &op_model_7450;
-			break;
+	case PPC_OPROFILE_G4:
+		model = &op_model_7450;
+		break;
 #endif
 #if defined(CONFIG_FSL_EMB_PERFMON)
-		case PPC_OPROFILE_FSL_EMB:
-			model = &op_model_fsl_emb;
-			break;
+	case PPC_OPROFILE_FSL_EMB:
+		model = &op_model_fsl_emb;
+		break;
 #endif
-		default:
-			return -ENODEV;
+	default:
+		return -ENODEV;
 	}
 
 	model->num_counters = cur_cpu_spec->num_pmcs;
diff --git a/arch/powerpc/oprofile/op_model_acp_pmu.c b/arch/powerpc/oprofile/op_model_acp_pmu.c
new file mode 100644
index 0000000..e4b976a
--- /dev/null
+++ b/arch/powerpc/oprofile/op_model_acp_pmu.c
@@ -0,0 +1,280 @@
+/*
+ * Freescale Embedded oprofile support, based on ppc64 oprofile support
+ * Copyright (C) 2004 Anton Blanchard <anton at au.ibm.com>, IBM
+ *
+ * Copyright (c) 2004, 2010 Freescale Semiconductor, Inc
+ *
+ * Author: Andy Fleming
+ * Maintainer: Kumar Gala <galak at kernel.crashing.org>
+ *
+ * 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 <linux/ptrace.h>
+#include <asm/processor.h>
+#include <asm/cputable.h>
+#include <asm/reg_acp_pmu_fn.h>
+#include <asm/page.h>
+#include <asm/pmc.h>
+#include <asm/oprofile_impl.h>
+
+static unsigned long reset_value[OP_MAX_COUNTER];
+
+static int num_counters;
+static int oprofile_running;
+
+
+
+static void init_pmc_stop(int core, int ctr)
+{
+	u32 pmlc = (PMLCA_FC | PMLCA_FCS | PMLCA_FCU |
+		    PMLCA_FCM1 | PMLCA_FCM0);
+
+	set_pmlc(core, ctr, pmlc);
+}
+
+static void set_pmc_event(int core, int ctr, int event)
+{
+	u32 pmlc;
+
+	pmlc = get_pmlc(core, ctr);
+
+	pmlc = (pmlc & ~PMLCA_EVENT_MASK) |
+		((event << PMLCA_EVENT_SHIFT) &
+		 PMLCA_EVENT_MASK);
+
+	set_pmlc(core, ctr, pmlc);
+}
+
+static void set_pmc_user_kernel(int core, int ctr, int user, int kernel)
+{
+	u32 pmlc;
+
+	pmlc = get_pmlc(core, ctr);
+
+	if (user)
+		pmlc &= ~PMLCA_FCU;
+	else
+		pmlc |= PMLCA_FCU;
+
+	if (kernel)
+		pmlc &= ~PMLCA_FCS;
+	else
+		pmlc |= PMLCA_FCS;
+
+	set_pmlc(core, ctr, pmlc);
+}
+
+static void set_pmc_marked(int core, int ctr, int mark0, int mark1)
+{
+	u32 pmlc = get_pmlc(core, ctr);
+
+	if (mark0)
+		pmlc &= ~PMLCA_FCM0;
+	else
+		pmlc |= PMLCA_FCM0;
+
+	if (mark1)
+		pmlc &= ~PMLCA_FCM1;
+	else
+		pmlc |= PMLCA_FCM1;
+
+	set_pmlc(core, ctr, pmlc);
+}
+
+static void pmc_start_ctr(int core, int ctr, int enable)
+{
+	u32 pmlc = get_pmlc(core, ctr);
+
+	pmlc &= ~PMLCA_FC;
+
+	if (enable)
+		pmlc |= PMLCA_CE;
+	else
+		pmlc &= ~PMLCA_CE;
+
+	set_pmlc(core, ctr, pmlc);
+}
+
+static void pmc_start_ctrs(int core, int enable, u32 ie_mask)
+{
+	u32 pmgc0;
+
+	/* Enable interrupt on overflow condition for enabled counters */
+	mtdcrx(PMUDCRAI(core), PMRN_PMUIE0);
+	if (enable)
+		mtdcrx(PMUDCRDI(core), ie_mask);
+	else
+		mtdcrx(PMUDCRDI(core), 0);
+
+	/* Start counters */
+	mtdcrx(PMUDCRAI(core), PMRN_PMUGC0);
+	pmgc0 = mfdcrx(PMUDCRDI(core));
+	pmgc0 &= ~PMUGC0_LFAC; /* un-freeze all counters */
+	pmgc0 |= PMUGC0_FCEC; /* enable freeze all ctrs on of */
+
+	mtdcrx(PMUDCRDI(core), pmgc0);
+}
+
+static void pmc_stop_ctrs(int core)
+{
+	u32 pmgc0;
+
+	mtdcrx(PMUDCRAI(core), PMRN_PMUGC0);
+	pmgc0 = mfdcrx(PMUDCRDI(core));
+
+
+	pmgc0 |= (PMUGC0_LFAC|PMUGC0_PMCC);
+
+	pmgc0 &= ~PMUGC0_FCEC;
+	mtdcrx(PMUDCRDI(core), pmgc0);
+	mtdcrx(PMUDCRAI(core), PMRN_PMUIE0);
+	mtdcrx(PMUDCRDI(core), 0);
+
+}
+
+static int acp_pmu_cpu_setup(struct op_counter_config *ctr)
+{
+	int i;
+	int core = smp_processor_id();
+
+	/* freeze all counters */
+	pmc_stop_ctrs(core);
+
+	for (i = 0; i < num_counters; i++) {
+		init_pmc_stop(core, i);
+		set_pmc_event(core, i, ctr[i].event);
+		set_pmc_user_kernel(core, i, ctr[i].user, ctr[i].kernel);
+	}
+
+	return 0;
+}
+
+static int acp_pmu_reg_setup(struct op_counter_config *ctr,
+			     struct op_system_config *sys,
+			     int num_ctrs)
+{
+	int i;
+
+	num_counters = num_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;
+
+	return 0;
+}
+
+static int acp_pmu_start(struct op_counter_config *ctr)
+{
+	int i;
+	u32 ie_mask = 0;
+	int core = smp_processor_id();
+
+	/* Freeze counters during update */
+
+	mtmsr(mfmsr() | MSR_PMM);
+
+	for (i = 0; i < num_counters; ++i) {
+		if (ctr[i].enabled) {
+			ie_mask |= PMUIE_IE(i);
+
+			ctr_write(core, i, reset_value[i]);
+			/* Set each enabled counter to only
+			 * count when the Mark bit is *not* set */
+			set_pmc_marked(core, i, 1, 0);
+			pmc_start_ctr(core, i, 1);
+		} else {
+			ctr_write(core, i, 0);
+
+			/* Set the ctr to be stopped */
+			pmc_start_ctr(core, 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(core, 1, ie_mask);
+
+	oprofile_running = 1;
+#ifdef DEBUG
+	mtdcrx(PMUDCRAI(core), PMRN_PMUGC0);
+#endif
+	pr_debug("start on cpu %d, pmgc0 %x\n", core,
+		 mfdcrx(PMUDCRDI(core)));
+
+	return 0;
+}
+
+static void acp_pmu_stop(void)
+{
+	int core = smp_processor_id();
+
+	/* freeze counters */
+	pmc_stop_ctrs(core);
+
+	oprofile_running = 0;
+
+	mtdcrx(PMUDCRAI(core), PMRN_PMUGC0);
+	pr_debug("stop on cpu %d, pmgc0 %x\n", smp_processor_id(),
+		 mfdcrx(PMUDCRDI(core)));
+
+	mb();
+}
+
+
+static void acp_pmu_handle_interrupt(struct pt_regs *regs,
+				    struct op_counter_config *ctr)
+{
+	int core = smp_processor_id();
+	u32 ie_mask = 0;
+	unsigned long pc;
+	int is_kernel;
+	int val;
+	int i;
+
+	pc = regs->nip;
+	is_kernel = is_kernel_addr(pc);
+
+	for (i = 0; i < num_counters; ++i) {
+		val = ctr_read(core, i);
+		if (val < 0) {
+			if (oprofile_running && ctr[i].enabled) {
+				ie_mask |= PMUIE_IE(i);
+				oprofile_add_ext_sample(pc, regs, i, is_kernel);
+				ctr_write(core, i, reset_value[i]);
+			} else {
+				ctr_write(core, 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.  The PMM bit should not be set until after the interrupt
+	 * is cleared to avoid it getting lost in some hypervisor
+	 * environments.
+	 */
+	mtmsr(mfmsr() | MSR_PMM);
+	pmc_start_ctrs(core, 1, ie_mask);
+}
+
+struct op_powerpc_model op_model_acp_pmu = {
+	.reg_setup		= acp_pmu_reg_setup,
+	.cpu_setup		= acp_pmu_cpu_setup,
+	.start			= acp_pmu_start,
+	.stop			= acp_pmu_stop,
+	.handle_interrupt	= acp_pmu_handle_interrupt,
+};
diff --git a/arch/powerpc/perf/Makefile b/arch/powerpc/perf/Makefile
index af3fac2..e4906ad 100644
--- a/arch/powerpc/perf/Makefile
+++ b/arch/powerpc/perf/Makefile
@@ -7,6 +7,9 @@ obj64-$(CONFIG_PPC_PERF_CTRS)	+= power4-pmu.o ppc970-pmu.o power5-pmu.o \
 				   power5+-pmu.o power6-pmu.o power7-pmu.o
 obj32-$(CONFIG_PPC_PERF_CTRS)	+= mpc7450-pmu.o
 
+obj-$(CONFIG_ACP_PMU_PERF_EVENT) += core-lsi-acp.o
+obj-$(CONFIG_ACP_PMU_PERF_EVENT_PPC476) += ppc476-pmu.o
+
 obj-$(CONFIG_FSL_EMB_PERF_EVENT) += core-fsl-emb.o
 obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o
 
diff --git a/arch/powerpc/perf/core-lsi-acp.c b/arch/powerpc/perf/core-lsi-acp.c
new file mode 100644
index 0000000..9e8986d
--- /dev/null
+++ b/arch/powerpc/perf/core-lsi-acp.c
@@ -0,0 +1,611 @@
+/*
+ * Performance event support - LSI ACP Embedded Performance Monitor
+ *
+ * Based on earlier code:
+ *
+ * perf_event_fsl_emb.c
+ *
+ * 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/perf_event.h>
+#include <linux/percpu.h>
+#include <linux/hardirq.h>
+#include <asm/reg_acp_pmu_fn.h>
+#include <asm/pmc.h>
+#include <asm/machdep.h>
+#include <linux/firmware.h>
+#include <linux/ptrace.h>
+
+
+struct cpu_hw_events {
+	int n_events;
+	int disabled;
+	u8  pmcs_enabled;
+	struct perf_event *event[MAX_HWEVENTS];
+};
+static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
+
+static struct acp_pmu *ppmu;
+
+/* Number of perf_events counting hardware events */
+static atomic_t num_events;
+/* Used to avoid races in calling reserve/release_pmc_hardware */
+static DEFINE_MUTEX(pmc_reserve_mutex);
+
+/*
+ * If interrupts were soft-disabled when a PMU interrupt occurs, treat
+ * it as an NMI.
+ */
+static inline int perf_intr_is_nmi(struct pt_regs *regs)
+{
+#ifdef __powerpc64__
+	return !regs->softe;
+#else
+	return 0;
+#endif
+}
+
+static void perf_event_interrupt(struct pt_regs *regs);
+
+
+static void acp_pmu_read(struct perf_event *event)
+{
+	int core = smp_processor_id();
+	s64 val, delta, prev;
+
+	if (event->hw.state & PERF_HES_STOPPED)
+		return;
+
+	/*
+	 * Performance monitor interrupts come even when interrupts
+	 * are soft-disabled, as long as interrupts are hard-enabled.
+	 * Therefore we treat them like NMIs.
+	 */
+	do {
+		prev = local64_read(&event->hw.prev_count);
+		barrier();
+		val = ctr_read(core, event->hw.idx);
+	} while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev);
+
+	/* The counters are only 32 bits wide */
+	delta = (val - prev) & 0xfffffffful;
+	local64_add(delta, &event->count);
+	local64_sub(delta, &event->hw.period_left);
+}
+
+/*
+ * Disable all events to prevent PMU interrupts and to allow
+ * events to be added or removed.
+ */
+static void acp_pmu_disable(struct pmu *pmu)
+{
+	int core = smp_processor_id();
+	struct cpu_hw_events *cpuhw;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	cpuhw = &__get_cpu_var(cpu_hw_events);
+
+	if (!cpuhw->disabled) {
+		cpuhw->disabled = 1;
+
+		/*
+		 * Check if we ever enabled the PMU on this cpu.
+		 */
+		if (!cpuhw->pmcs_enabled) {
+			ppc_enable_pmcs();
+			cpuhw->pmcs_enabled = 1;
+		}
+
+		if (atomic_read(&num_events)) {
+			u32 pmgc0;
+			/*
+			 * Set the 'freeze all counters' bit, and disable
+			 * interrupts.  The barrier is to make sure the
+			 * mtpmr has been executed and the PMU has frozen
+			 * the events before we return.
+			 */
+			mtdcrx(PMUDCRAI(core), PMRN_PMUGC0);
+			pmgc0 = mfdcrx(PMUDCRDI(core));
+			pmgc0 |= PMUGC0_LFAC;
+			pmgc0 &= ~PMUGC0_FCEC;
+			mtdcrx(PMUDCRDI(core), pmgc0);
+			mtdcrx(PMUDCRAI(core), PMRN_PMUIE0);
+			mtdcrx(PMUDCRDI(core), 0);
+
+			isync();
+		}
+	}
+	local_irq_restore(flags);
+}
+
+/*
+ * Re-enable all events if disable == 0.
+ * If we were previously disabled and events were added, then
+ * put the new config on the PMU.
+ */
+static void acp_pmu_enable(struct pmu *pmu)
+{
+	int core = smp_processor_id();
+	struct cpu_hw_events *cpuhw;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	cpuhw = &__get_cpu_var(cpu_hw_events);
+	if (!cpuhw->disabled)
+		goto out;
+
+	cpuhw->disabled = 0;
+	ppc_set_pmu_inuse(cpuhw->n_events != 0);
+
+	if (cpuhw->n_events > 0) {
+		u32 pmgc0;
+		u32 pmuie0 = 0;
+		int i;
+		int num_counters = ppmu->n_counter;
+		for (i = 0; i < num_counters; i++) {
+			if (cpuhw->event[i])
+				pmuie0 |= PMUIE_IE(i);
+		}
+		mtdcrx(PMUDCRAI(core), PMRN_PMUIE0);
+		mtdcrx(PMUDCRDI(core), pmuie0);
+
+		mtdcrx(PMUDCRAI(core), PMRN_PMUGC0);
+		pmgc0 = mfdcrx(PMUDCRDI(core));
+		pmgc0 &= ~PMUGC0_LFAC; /* un-freeze all counters */
+		pmgc0 |= PMUGC0_FCEC; /* enable freeze all ctrs on of */
+		mtdcrx(PMUDCRDI(core), pmgc0);
+
+		isync();
+	}
+
+out:
+	local_irq_restore(flags);
+}
+
+static int collect_events(struct perf_event *group, int max_count,
+			  struct perf_event *ctrs[])
+{
+	int n = 0;
+	struct perf_event *event;
+
+	if (!is_software_event(group)) {
+		if (n >= max_count)
+			return -1;
+		ctrs[n] = group;
+		n++;
+	}
+	list_for_each_entry(event, &group->sibling_list, group_entry) {
+		if (!is_software_event(event) &&
+		    event->state != PERF_EVENT_STATE_OFF) {
+			if (n >= max_count)
+				return -1;
+			ctrs[n] = event;
+			n++;
+		}
+	}
+	return n;
+}
+
+/* context locked on entry */
+static int acp_pmu_add(struct perf_event *event, int flags)
+{
+	struct cpu_hw_events *cpuhw;
+	int core = smp_processor_id();
+	int ret = -EAGAIN;
+	int num_counters = ppmu->n_counter;
+	u64 val;
+	int i;
+	u32 pmuie0;
+
+	perf_pmu_disable(event->pmu);
+	cpuhw = &get_cpu_var(cpu_hw_events);
+
+	/* Allocate counters */
+	for (i = 0; i < num_counters; i++) {
+		if (cpuhw->event[i])
+			continue;
+
+		break;
+	}
+
+	if (i < 0)
+		goto out;
+
+	event->hw.idx = i;
+	cpuhw->event[i] = event;
+	++cpuhw->n_events;
+
+	val = 0;
+	if (event->hw.sample_period) {
+		s64 left = local64_read(&event->hw.period_left);
+		if (left < 0x80000000L)
+			val = 0x80000000L - left;
+	}
+	local64_set(&event->hw.prev_count, val);
+
+	if (!(flags & PERF_EF_START)) {
+		event->hw.state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+		val = 0;
+	}
+
+	ctr_write(core, i, val);
+	perf_event_update_userpage(event);
+
+	set_pmlc(core, i, event->hw.config_base);
+
+	/* Enable counter interrupt on overflow condition */
+	mtdcrx(PMUDCRAI(core), PMRN_PMUIE0);
+	pmuie0 = mfdcrx(PMUDCRDI(core));
+	pmuie0 |= PMUIE_IE(i);
+	mtdcrx(PMUDCRDI(core), pmuie0);
+
+	ret = 0;
+out:
+	put_cpu_var(cpu_hw_events);
+	perf_pmu_enable(event->pmu);
+	return ret;
+}
+
+/* context locked on entry */
+static void acp_pmu_del(struct perf_event *event, int flags)
+{
+	int core = smp_processor_id();
+	struct cpu_hw_events *cpuhw;
+	int i = event->hw.idx;
+
+	perf_pmu_disable(event->pmu);
+	if (i < 0)
+		goto out;
+
+	acp_pmu_read(event);
+
+	cpuhw = &get_cpu_var(cpu_hw_events);
+
+	WARN_ON(event != cpuhw->event[event->hw.idx]);
+
+	set_pmlc(core, i, 0);
+	ctr_write(core, i, 0);
+
+	cpuhw->event[i] = NULL;
+	event->hw.idx = -1;
+
+out:
+	perf_pmu_enable(event->pmu);
+	put_cpu_var(cpu_hw_events);
+}
+
+static void acp_pmu_start(struct perf_event *event, int ef_flags)
+{
+	int core = smp_processor_id();
+	unsigned long flags;
+	s64 left;
+
+	if (event->hw.idx < 0 || !event->hw.sample_period)
+		return;
+
+	if (!(event->hw.state & PERF_HES_STOPPED))
+		return;
+
+	if (ef_flags & PERF_EF_RELOAD)
+		WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+
+	local_irq_save(flags);
+	perf_pmu_disable(event->pmu);
+
+	event->hw.state = 0;
+	left = local64_read(&event->hw.period_left);
+	ctr_write(core, event->hw.idx, left);
+
+	perf_event_update_userpage(event);
+	perf_pmu_enable(event->pmu);
+	local_irq_restore(flags);
+}
+
+static void acp_pmu_stop(struct perf_event *event, int ef_flags)
+{
+	unsigned long flags;
+	int core = smp_processor_id();
+
+	if (event->hw.idx < 0 || !event->hw.sample_period)
+		return;
+
+	if (event->hw.state & PERF_HES_STOPPED)
+		return;
+
+	local_irq_save(flags);
+	perf_pmu_disable(event->pmu);
+
+	acp_pmu_read(event);
+	event->hw.state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+	ctr_write(core, event->hw.idx, 0);
+
+	perf_event_update_userpage(event);
+	perf_pmu_enable(event->pmu);
+	local_irq_restore(flags);
+}
+
+/*
+ * Release the PMU if this is the last perf_event.
+ */
+static void hw_perf_event_destroy(struct perf_event *event)
+{
+	if (!atomic_add_unless(&num_events, -1, 1)) {
+		mutex_lock(&pmc_reserve_mutex);
+		if (atomic_dec_return(&num_events) == 0)
+			release_pmc_hardware();
+		mutex_unlock(&pmc_reserve_mutex);
+	}
+}
+
+/*
+ * Translate a generic cache event_id config to a raw event_id code.
+ */
+static int hw_perf_cache_event(u64 config, u64 *eventp)
+{
+	unsigned long type, op, result;
+	int ev;
+
+	if (!ppmu->cache_events)
+		return -EINVAL;
+
+	/* unpack config */
+	type = config & 0xff;
+	op = (config >> 8) & 0xff;
+	result = (config >> 16) & 0xff;
+
+	if (type >= PERF_COUNT_HW_CACHE_MAX ||
+	    op >= PERF_COUNT_HW_CACHE_OP_MAX ||
+	    result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+		return -EINVAL;
+
+	ev = (*ppmu->cache_events)[type][op][result];
+	if (ev == 0)
+		return -EOPNOTSUPP;
+	if (ev == -1)
+		return -EINVAL;
+	*eventp = ev;
+	return 0;
+}
+
+static int acp_pmu_event_init(struct perf_event *event)
+{
+	u64 ev;
+	struct perf_event *events[MAX_HWEVENTS];
+	int n;
+	int err;
+
+	switch (event->attr.type) {
+	case PERF_TYPE_HARDWARE:
+		ev = event->attr.config;
+		if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0)
+			return -EOPNOTSUPP;
+		ev = ppmu->generic_events[ev];
+		break;
+
+	case PERF_TYPE_HW_CACHE:
+		err = hw_perf_cache_event(event->attr.config, &ev);
+		if (err)
+			return err;
+		break;
+
+	case PERF_TYPE_RAW:
+		ev = event->attr.config;
+		break;
+
+	default:
+		return -ENOENT;
+	}
+
+	event->hw.config = ppmu->xlate_event(ev);
+	if (!(event->hw.config & ACP_EVENT_VALID))
+		return -EINVAL;
+
+	/*
+	 * If this is in a group, check if it can go on with all the
+	 * other hardware events in the group.  We assume the event
+	 * hasn't been linked into its leader's sibling list at this point.
+	 */
+	n = 0;
+	if (event->group_leader != event) {
+		n = collect_events(event->group_leader,
+				   ppmu->n_counter - 1, events);
+		if (n < 0)
+			return -EINVAL;
+	}
+	event->hw.idx = -1;
+
+	event->hw.config_base = PMLCA_CE | PMLCA_FCM1 |
+				(u32)((ev) & PMLCA_EVENT_MASK);
+
+	if (event->attr.exclude_user)
+		event->hw.config_base |= PMLCA_FCU;
+	if (event->attr.exclude_kernel)
+		event->hw.config_base |= PMLCA_FCS;
+	if (event->attr.exclude_idle)
+		return -ENOTSUPP;
+
+	event->hw.last_period = event->hw.sample_period;
+	local64_set(&event->hw.period_left, event->hw.last_period);
+
+	/*
+	 * See if we need to reserve the PMU.
+	 * If no events are currently in use, then we have to take a
+	 * mutex to ensure that we don't race with another task doing
+	 * reserve_pmc_hardware or release_pmc_hardware.
+	 */
+	err = 0;
+	if (!atomic_inc_not_zero(&num_events)) {
+
+		mutex_lock(&pmc_reserve_mutex);
+		if (atomic_read(&num_events) == 0 &&
+		    reserve_pmc_hardware(perf_event_interrupt))
+			err = -EBUSY;
+		else
+			atomic_inc(&num_events);
+		mutex_unlock(&pmc_reserve_mutex);
+		isync();
+	}
+	event->destroy = hw_perf_event_destroy;
+
+	return err;
+}
+
+static struct pmu acp_pmu = {
+	.pmu_enable	= acp_pmu_enable,
+	.pmu_disable	= acp_pmu_disable,
+	.event_init	= acp_pmu_event_init,
+	.add		= acp_pmu_add,
+	.del		= acp_pmu_del,
+	.start		= acp_pmu_start,
+	.stop		= acp_pmu_stop,
+	.read		= acp_pmu_read,
+};
+
+/*
+ * A counter has overflowed; update its count and record
+ * things if requested.  Note that interrupts are hard-disabled
+ * here so there is no possibility of being interrupted.
+ */
+static void record_and_restart(int core, struct perf_event *event,
+			       unsigned long val, struct pt_regs *regs)
+{
+	u64 period = event->hw.sample_period;
+	s64 prev, delta, left;
+	int record = 0;
+
+	if (event->hw.state & PERF_HES_STOPPED) {
+		ctr_write(core, event->hw.idx, 0);
+		return;
+	}
+
+	/* we don't have to worry about interrupts here */
+	prev = local64_read(&event->hw.prev_count);
+	delta = (val - prev) & 0xfffffffful;
+	local64_add(delta, &event->count);
+
+	/*
+	 * See if the total period for this event has expired,
+	 * and update for the next period.
+	 */
+	val = 0;
+	left = local64_read(&event->hw.period_left) - delta;
+	if (period) {
+		if (left <= 0) {
+			left += period;
+			if (left <= 0)
+				left = period;
+			record = 1;
+			event->hw.last_period = event->hw.sample_period;
+		}
+		if (left < 0x80000000LL)
+			val = 0x80000000LL - left;
+	}
+
+	ctr_write(core, event->hw.idx, val);
+	local64_set(&event->hw.prev_count, val);
+	local64_set(&event->hw.period_left, left);
+	perf_event_update_userpage(event);
+
+	/*
+	 * Finally record data if requested.
+	 */
+	if (record) {
+		struct perf_sample_data data;
+
+		perf_sample_data_init(&data, 0);
+		data.period = event->hw.last_period;
+
+		if (perf_event_overflow(event, &data, regs))
+			acp_pmu_stop(event, 0);
+	}
+}
+
+static void perf_event_interrupt(struct pt_regs *regs)
+{
+	int i;
+	int core = smp_processor_id();
+	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+	struct perf_event *event;
+	unsigned long val;
+	int found = 0;
+	int nmi;
+	u32 pmgc0;
+
+	nmi = perf_intr_is_nmi(regs);
+	if (nmi)
+		nmi_enter();
+	else
+		irq_enter();
+
+	for (i = 0; i < ppmu->n_counter; ++i) {
+		event = cpuhw->event[i];
+		val = ctr_read(core, i);
+		if ((int)val < 0) {
+			if (event) {
+				/* event has overflowed */
+				found = 1;
+				record_and_restart(core, event, val, regs);
+			} else {
+				/*
+				 * Disabled counter is negative,
+				 * reset it just in case.
+				 */
+				ctr_write(core, i, 0);
+			}
+		}
+	}
+
+	/* PMM will keep counters frozen until we return from the interrupt. */
+	mtmsr(mfmsr() | MSR_PMM);
+
+	mtdcrx(PMUDCRAI(core), PMRN_PMUGC0);
+	pmgc0 = mfdcrx(PMUDCRDI(core));
+	pmgc0 &= ~PMUGC0_LFAC; /* un-freeze all counters */
+	pmgc0 |= PMUGC0_FCEC; /* enable freeze all ctrs on of */
+	mtdcrx(PMUDCRDI(core), pmgc0);
+
+	isync();
+
+	if (nmi)
+		nmi_exit();
+	else
+		irq_exit();
+}
+
+int register_acp_pmu(struct acp_pmu *pmu)
+{
+	int core;
+
+	if (ppmu)
+		return -EBUSY;		/* something's already registered */
+
+	/*
+	 * ACP PMU is enabled and may fire after reset
+	 * disable until someone is listening
+	 */
+
+	for_each_possible_cpu(core) {
+		u32 pmgc0;
+
+		mtdcrx(PMUDCRAI(core), PMRN_PMUGC0);
+		pmgc0 = mfdcrx(PMUDCRDI(core));
+		pmgc0 |= (PMUGC0_LFAC|PMUGC0_PMCC);
+		pmgc0 &= ~PMUGC0_FCEC;
+		mtdcrx(PMUDCRDI(core), pmgc0);
+	}
+
+	ppmu = pmu;
+	pr_info("%s performance monitor hardware support registered\n",
+		pmu->name);
+
+	perf_pmu_register(&acp_pmu, "cpu", PERF_TYPE_RAW);
+
+	return 0;
+}
diff --git a/arch/powerpc/perf/ppc476-pmu.c b/arch/powerpc/perf/ppc476-pmu.c
new file mode 100644
index 0000000..9bd9060
--- /dev/null
+++ b/arch/powerpc/perf/ppc476-pmu.c
@@ -0,0 +1,194 @@
+/*
+ * Performance counter support for LSI Axxia3400
+ *
+ * Based on earlier code:
+ *
+ * e500mc-pmu.c
+ *
+ * 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/interrupt.h>
+#include <linux/string.h>
+#include <linux/perf_event.h>
+#include <asm/pmc.h>
+#include <asm/reg.h>
+#include <asm/cputable.h>
+#include <asm/perf_event_acp.h>
+#include <asm/reg_acp_pmu.h>
+
+/* PMU IRQ handler */
+static irqreturn_t acp_pmu_isr(int irq, void *dev_id)
+{
+	__get_cpu_var(irq_stat).pmu_irqs++;
+	perf_irq(get_irq_regs());
+	return IRQ_HANDLED;
+}
+
+/*
+ * Map of generic hardware event types to hardware events
+ * Zero if unsupported
+ */
+static int ppc476_generic_events[] = {
+	[PERF_COUNT_HW_CPU_CYCLES]              = CPU_CYCLE_COUNT,
+	[PERF_COUNT_HW_INSTRUCTIONS]            = CPU_COMMITTED_INST,
+	[PERF_COUNT_HW_CACHE_REFERENCES]        = CPU_DCACHE_HIT,
+	[PERF_COUNT_HW_CACHE_MISSES]            = CPU_DTLB_RELOAD,
+
+};
+
+/*
+ * Table of generalized cache-related events.
+ *
+ * 0 means not supported, -1 means nonsensical, other values
+ * are event codes.
+ */
+
+#define C(x)	PERF_COUNT_HW_CACHE_##x
+
+static int ppc476_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+
+	/*
+	 * The PPC476 PMU does have a few cache events but they don't
+	 * fit directly into this model. Therefore, we need to combine
+	 * several PM events to get the numbers that perf is looking for.
+	 *
+	 */
+
+	[C(L1D)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+		[C(OP_READ)] = {        CPU_DCACHE_HIT, CPU_DTLB_RELOAD  },
+		[C(OP_WRITE)] = {       CPU_DCACHE_HIT, CPU_DTLB_RELOAD  },
+		[C(OP_PREFETCH)] = {    0,              0                },
+	},
+	[C(L1I)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+		[C(OP_READ)] = {        CPU_ICACHE_HIT, CPU_ITLB_RELOAD  },
+		[C(OP_WRITE)] = {       CPU_ICACHE_HIT, CPU_ITLB_RELOAD  },
+		[C(OP_PREFETCH)] = {    0,              0                },
+	},
+	[C(LL)] = {             /*      RESULT_ACCESS   RESULT_MISS */
+		[C(OP_READ)] = {        0,              0       },
+		[C(OP_WRITE)] = {       0,              0       },
+		[C(OP_PREFETCH)] = {    0,              0       },
+	},
+
+	/*
+	 * There are data/instruction MMU misses, but that's a miss on
+	 * the chip's internal level-one TLB which is probably not
+	 * what the user wants.  Instead, unified level-two TLB misses
+	 * are reported here.
+	 */
+
+	[C(DTLB)] = {		/*	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0,	        0	},
+		[C(OP_WRITE)] = {       0,		0	},
+		[C(OP_PREFETCH)] = {    0,		0	},
+	},
+	[C(ITLB)] = {		/*	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0,	        0	},
+		[C(OP_WRITE)] = {	0,		0	},
+		[C(OP_PREFETCH)] = {	0,		0	},
+	},
+	[C(BPU)] = {		/*	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	-1,		-1	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	-1,		-1	},
+	},
+	[C(NODE)] = {		/*	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	-1,		-1	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	-1,		-1	},
+	},
+};
+
+static int num_events = 32;
+
+
+static u64 ppc476_xlate_event(u64 event_id)
+{
+	u32 event_low = (u32)event_id;
+	u64 ret;
+
+	if (event_low >= num_events)
+		return 0;
+
+	ret = ACP_EVENT_VALID;
+
+	return ret;
+}
+
+static struct acp_pmu ppc476_pmu = {
+	.name			= "ppc476 family",
+	.n_counter		= 8,
+	.xlate_event		= ppc476_xlate_event,
+	.n_generic		= ARRAY_SIZE(ppc476_generic_events),
+	.generic_events		= ppc476_generic_events,
+	.cache_events		= &ppc476_cache_events,
+};
+
+static int init_ppc476_pmu(void)
+{
+	unsigned int irq;
+	int intNum, core;
+	static const char * const irqname[] = { "pmu-core0",
+						"pmu-core1",
+						"pmu-core2",
+						"pmu-core3" };
+
+	if (!cur_cpu_spec->oprofile_cpu_type)
+		return -ENODEV;
+
+	if (!strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/476"))
+		num_events = 32;
+	else
+		return -ENODEV;
+
+	/*
+	 * Install the PMU interrupt handlers:
+	 *
+	 * NOTE: On the LSI ACP platform, the PMU interrupts are
+	 * hard-wired as inputs to the MPIC. The irq numbers are
+	 * fixed as follows:
+	 *
+	 *   Core 0 PMU: IRQ 95
+	 *   Core 1 PMU: IRQ 94
+	 *   Core 2 PMU: IRQ 93
+	 *   Core 3 PMU: IRQ 92
+	 *
+	 * The IRQ assignment should probably be done in the DTB,
+	 * like ARM does, but no other PowerPC platform does this.
+	 * So for now, we hard-code the numbers here.
+	 */
+	for_each_possible_cpu(core) {
+		if (core == 0)
+			intNum = 95;
+		else if (core == 1)
+			intNum = 94;
+		else if (core == 2)
+			intNum = 93;
+		else if (core == 3)
+			intNum = 92;
+		else
+			break;
+
+		irq = irq_create_mapping(NULL, intNum);
+		if (irq == NO_IRQ) {
+			pr_err("PMU irq_create_mapping() failed\n");
+			break;
+		}
+		if (irq_set_affinity(irq, get_cpu_mask(core))) {
+			pr_warning("PMU IRQ affinity failed (irq=%d, cpu=%d)\n",
+				   irq, core);
+			continue;
+		}
+		if (request_irq(irq, acp_pmu_isr,
+				IRQF_DISABLED | IRQF_NOBALANCING,
+				irqname[core], NULL))
+			pr_err("PMU reqeust for IRQ%d failed\n", irq);
+	}
+
+	return register_acp_pmu(&ppc476_pmu);
+}
+
+early_initcall(init_ppc476_pmu);
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 425db18..05ff28c 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -163,9 +163,26 @@ config FSL_EMB_PERF_EVENT_E500
 
 config 4xx
 	bool
+	select ACP_PMU_PERFMON
 	depends on 40x || 44x
 	default y
 
+config ACP_PMU_PERFMON
+       bool "LSI Embedded Perfmon"
+       depends on 44x && ACP
+       help
+         This is the Performance Monitor support found on the Axxia3400 ppc476 chip
+
+config ACP_PMU_PERF_EVENT
+       bool
+       depends on ACP_PMU_PERFMON && PERF_EVENTS && !PPC_PERF_CTRS
+       default y
+
+config ACP_PMU_PERF_EVENT_PPC476
+       bool
+       depends on ACP_PMU_PERFMON && PERF_EVENTS && !PPC_PERF_CTRS
+       default y
+
 config BOOKE
 	bool
 	depends on E200 || E500 || 44x || PPC_BOOK3E
-- 
1.8.3




More information about the linux-yocto mailing list