[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