summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libpmc/libpmc.c42
-rw-r--r--sys/conf/files.powerpc1
-rw-r--r--sys/dev/hwpmc/hwpmc_mpc7xxx.c29
-rw-r--r--sys/dev/hwpmc/hwpmc_powerpc.c11
-rw-r--r--sys/dev/hwpmc/hwpmc_powerpc.h2
-rw-r--r--sys/dev/hwpmc/hwpmc_ppc970.c689
-rw-r--r--sys/dev/hwpmc/pmc_events.h57
-rw-r--r--sys/powerpc/include/pmc_mdep.h1
-rw-r--r--sys/powerpc/include/spr.h36
-rw-r--r--sys/sys/pmc.h2
10 files changed, 828 insertions, 42 deletions
diff --git a/lib/libpmc/libpmc.c b/lib/libpmc/libpmc.c
index 74956a9..209ae56 100644
--- a/lib/libpmc/libpmc.c
+++ b/lib/libpmc/libpmc.c
@@ -28,6 +28,7 @@
__FBSDID("$FreeBSD$");
#include <sys/types.h>
+#include <sys/param.h>
#include <sys/module.h>
#include <sys/pmc.h>
#include <sys/syscall.h>
@@ -85,7 +86,7 @@ static int soft_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
struct pmc_op_pmcallocate *_pmc_config);
#if defined(__powerpc__)
-static int ppc7450_allocate_pmc(enum pmc_event _pe, char* ctrspec,
+static int powerpc_allocate_pmc(enum pmc_event _pe, char* ctrspec,
struct pmc_op_pmcallocate *_pmc_config);
#endif /* __powerpc__ */
@@ -156,6 +157,7 @@ PMC_CLASSDEP_TABLE(mips24k, MIPS24K);
PMC_CLASSDEP_TABLE(octeon, OCTEON);
PMC_CLASSDEP_TABLE(ucf, UCF);
PMC_CLASSDEP_TABLE(ppc7450, PPC7450);
+PMC_CLASSDEP_TABLE(ppc970, PPC970);
static struct pmc_event_descr soft_event_table[PMC_EV_DYN_COUNT];
@@ -262,6 +264,7 @@ PMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE);
PMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K);
PMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON);
PMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450);
+PMC_MDEP_TABLE(ppc970, PPC970, PMC_CLASS_SOFT, PMC_CLASS_PPC970);
PMC_MDEP_TABLE(generic, SOFT, PMC_CLASS_SOFT);
static const struct pmc_event_descr tsc_event_table[] =
@@ -322,7 +325,8 @@ PMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips);
PMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips);
#endif /* __mips__ */
#if defined(__powerpc__)
-PMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, ppc7450);
+PMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, powerpc);
+PMC_CLASS_TABLE_DESC(ppc970, PPC970, ppc970, powerpc);
#endif
static struct pmc_class_descr soft_class_table_descr =
@@ -2404,13 +2408,19 @@ static struct pmc_event_alias ppc7450_aliases[] = {
EV_ALIAS(NULL, NULL)
};
-#define PPC7450_KW_OS "os"
-#define PPC7450_KW_USR "usr"
-#define PPC7450_KW_ANYTHREAD "anythread"
+static struct pmc_event_alias ppc970_aliases[] = {
+ EV_ALIAS("instructions", "INSTR_COMPLETED"),
+ EV_ALIAS("cycles", "CYCLES"),
+ EV_ALIAS(NULL, NULL)
+};
+
+#define POWERPC_KW_OS "os"
+#define POWERPC_KW_USR "usr"
+#define POWERPC_KW_ANYTHREAD "anythread"
static int
-ppc7450_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
- struct pmc_op_pmcallocate *pmc_config __unused)
+powerpc_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
+ struct pmc_op_pmcallocate *pmc_config __unused)
{
char *p;
@@ -2419,11 +2429,11 @@ ppc7450_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
while ((p = strsep(&ctrspec, ",")) != NULL) {
- if (KWMATCH(p, PPC7450_KW_OS))
+ if (KWMATCH(p, POWERPC_KW_OS))
pmc_config->pm_caps |= PMC_CAP_SYSTEM;
- else if (KWMATCH(p, PPC7450_KW_USR))
+ else if (KWMATCH(p, POWERPC_KW_USR))
pmc_config->pm_caps |= PMC_CAP_USER;
- else if (KWMATCH(p, PPC7450_KW_ANYTHREAD))
+ else if (KWMATCH(p, POWERPC_KW_ANYTHREAD))
pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM);
else
return (-1);
@@ -2431,6 +2441,7 @@ ppc7450_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
return (0);
}
+
#endif /* __powerpc__ */
@@ -2830,6 +2841,10 @@ pmc_event_names_of_class(enum pmc_class cl, const char ***eventnames,
ev = ppc7450_event_table;
count = PMC_EVENT_TABLE_SIZE(ppc7450);
break;
+ case PMC_CLASS_PPC970:
+ ev = ppc970_event_table;
+ count = PMC_EVENT_TABLE_SIZE(ppc970);
+ break;
case PMC_CLASS_SOFT:
ev = soft_event_table;
count = soft_event_info.pm_nevent;
@@ -3100,6 +3115,10 @@ pmc_init(void)
PMC_MDEP_INIT(ppc7450);
pmc_class_table[n] = &ppc7450_class_table_descr;
break;
+ case PMC_CPU_PPC_970:
+ PMC_MDEP_INIT(ppc970);
+ pmc_class_table[n] = &ppc970_class_table_descr;
+ break;
#endif
default:
/*
@@ -3270,6 +3289,9 @@ _pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu)
} else if (pe >= PMC_EV_PPC7450_FIRST && pe <= PMC_EV_PPC7450_LAST) {
ev = ppc7450_event_table;
evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450);
+ } else if (pe >= PMC_EV_PPC970_FIRST && pe <= PMC_EV_PPC970_LAST) {
+ ev = ppc970_event_table;
+ evfence = ppc970_event_table + PMC_EVENT_TABLE_SIZE(ppc970);
} else if (pe == PMC_EV_TSC_TSC) {
ev = tsc_event_table;
evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc);
diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc
index 2f63ff9..6a823de 100644
--- a/sys/conf/files.powerpc
+++ b/sys/conf/files.powerpc
@@ -31,6 +31,7 @@ dev/fb/fb.c optional sc
dev/fdt/fdt_powerpc.c optional fdt
dev/hwpmc/hwpmc_powerpc.c optional hwpmc
dev/hwpmc/hwpmc_mpc7xxx.c optional hwpmc
+dev/hwpmc/hwpmc_ppc970.c optional hwpmc
dev/iicbus/ad7417.c optional ad7417 powermac
dev/iicbus/ds1631.c optional ds1631 powermac
dev/iicbus/ds1775.c optional ds1775 powermac
diff --git a/sys/dev/hwpmc/hwpmc_mpc7xxx.c b/sys/dev/hwpmc/hwpmc_mpc7xxx.c
index 93b5c74..8394e12 100644
--- a/sys/dev/hwpmc/hwpmc_mpc7xxx.c
+++ b/sys/dev/hwpmc/hwpmc_mpc7xxx.c
@@ -69,10 +69,10 @@ __FBSDID("$FreeBSD$");
* specifically).
*/
-struct powerpc_event_code_map {
+struct mpc7xxx_event_code_map {
enum pmc_event pe_ev; /* enum value */
uint8_t pe_counter_mask; /* Which counter this can be counted in. */
- uint8_t pe_code; /* numeric code */
+ uint8_t pe_code; /* numeric code */
};
#define PPC_PMC_MASK1 0
@@ -85,7 +85,7 @@ struct powerpc_event_code_map {
#define PMC_POWERPC_EVENT(id, mask, number) \
{ .pe_ev = PMC_EV_PPC7450_##id, .pe_counter_mask = mask, .pe_code = number }
-static struct powerpc_event_code_map powerpc_event_codes[] = {
+static struct mpc7xxx_event_code_map mpc7xxx_event_codes[] = {
PMC_POWERPC_EVENT(CYCLE,PPC_PMC_MASK_ALL, 1),
PMC_POWERPC_EVENT(INSTR_COMPLETED, 0x0f, 2),
PMC_POWERPC_EVENT(TLB_BIT_TRANSITIONS, 0x0f, 3),
@@ -311,8 +311,8 @@ static struct powerpc_event_code_map powerpc_event_codes[] = {
PMC_POWERPC_EVENT(PREFETCH_ENGINE_FULL, 0x20, 57)
};
-const size_t powerpc_event_codes_size =
- sizeof(powerpc_event_codes) / sizeof(powerpc_event_codes[0]);
+const size_t mpc7xxx_event_codes_size =
+ sizeof(mpc7xxx_event_codes) / sizeof(mpc7xxx_event_codes[0]);
static pmc_value_t
mpc7xxx_pmcn_read(unsigned int pmc)
@@ -565,6 +565,7 @@ mpc7xxx_pcpu_init(struct pmc_mdep *md, int cpu)
M_WAITOK|M_ZERO);
pac->pc_ppcpmcs = malloc(sizeof(struct pmc_hw) * MPC7XXX_MAX_PMCS,
M_PMC, M_WAITOK|M_ZERO);
+ pac->pc_class = PMC_CLASS_PPC7450;
pc = pmc_pcpu[cpu];
first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_PPC7450].pcd_ri;
KASSERT(pc != NULL, ("[powerpc,%d] NULL per-cpu pointer", __LINE__));
@@ -611,14 +612,14 @@ mpc7xxx_allocate_pmc(int cpu, int ri, struct pmc *pm,
caps = a->pm_caps;
pe = a->pm_ev;
- for (i = 0; i < powerpc_event_codes_size; i++) {
- if (powerpc_event_codes[i].pe_ev == pe) {
- config = powerpc_event_codes[i].pe_code;
- counter = powerpc_event_codes[i].pe_counter_mask;
+ for (i = 0; i < mpc7xxx_event_codes_size; i++) {
+ if (mpc7xxx_event_codes[i].pe_ev == pe) {
+ config = mpc7xxx_event_codes[i].pe_code;
+ counter = mpc7xxx_event_codes[i].pe_counter_mask;
break;
}
}
- if (i == powerpc_event_codes_size)
+ if (i == mpc7xxx_event_codes_size)
return (EINVAL);
if ((counter & (1 << ri)) == 0)
@@ -724,6 +725,8 @@ pmc_mpc7xxx_initialize(struct pmc_mdep *pmc_mdep)
{
struct pmc_classdep *pcd;
+ pmc_mdep->pmd_cputype = PMC_CPU_PPC_7450;
+
pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_PPC7450];
pcd->pcd_caps = POWERPC_PMC_CAPS;
pcd->pcd_class = PMC_CLASS_PPC7450;
@@ -735,6 +738,8 @@ pmc_mpc7xxx_initialize(struct pmc_mdep *pmc_mdep)
pcd->pcd_config_pmc = mpc7xxx_config_pmc;
pcd->pcd_pcpu_fini = mpc7xxx_pcpu_fini;
pcd->pcd_pcpu_init = mpc7xxx_pcpu_init;
+ pcd->pcd_describe = powerpc_describe;
+ pcd->pcd_get_config = powerpc_get_config;
pcd->pcd_read_pmc = mpc7xxx_read_pmc;
pcd->pcd_release_pmc = mpc7xxx_release_pmc;
pcd->pcd_start_pmc = mpc7xxx_start_pmc;
@@ -742,7 +747,7 @@ pmc_mpc7xxx_initialize(struct pmc_mdep *pmc_mdep)
pcd->pcd_write_pmc = mpc7xxx_write_pmc;
pmc_mdep->pmd_npmc += MPC7XXX_MAX_PMCS;
- pmc_mdep->pmd_intr = mpc7xxx_intr;
+ pmc_mdep->pmd_intr = mpc7xxx_intr;
- return 0;
+ return (0);
}
diff --git a/sys/dev/hwpmc/hwpmc_powerpc.c b/sys/dev/hwpmc/hwpmc_powerpc.c
index 8da54c2..0efae5e 100644
--- a/sys/dev/hwpmc/hwpmc_powerpc.c
+++ b/sys/dev/hwpmc/hwpmc_powerpc.c
@@ -96,7 +96,7 @@ powerpc_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc)
if ((error = copystr(powerpc_name, pi->pm_name, PMC_NAME_MAX,
NULL)) != 0)
return error;
- pi->pm_class = PMC_CLASS_PPC7450;
+ pi->pm_class = powerpc_pcpu[cpu]->pc_class;
if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
pi->pm_enabled = TRUE;
*ppmc = phw->phw_pmc;
@@ -133,8 +133,6 @@ pmc_md_initialize()
/* Just one class */
pmc_mdep = pmc_mdep_alloc(1);
- pmc_mdep->pmd_cputype = PMC_CPU_PPC_7450;
-
vers = mfpvr() >> 16;
pmc_mdep->pmd_switch_in = powerpc_switch_in;
@@ -151,6 +149,8 @@ pmc_md_initialize()
case IBM970:
case IBM970FX:
case IBM970MP:
+ error = pmc_ppc970_initialize(pmc_mdep);
+ break;
default:
error = -1;
break;
@@ -159,7 +159,6 @@ pmc_md_initialize()
if (error != 0) {
pmc_mdep_free(pmc_mdep);
pmc_mdep = NULL;
- return NULL;
}
return (pmc_mdep);
@@ -168,7 +167,9 @@ pmc_md_initialize()
void
pmc_md_finalize(struct pmc_mdep *md)
{
- free(md, M_PMC);
+
+ free(powerpc_pcpu, M_PMC);
+ powerpc_pcpu = NULL;
}
int
diff --git a/sys/dev/hwpmc/hwpmc_powerpc.h b/sys/dev/hwpmc/hwpmc_powerpc.h
index a9b54f4..8f0b8ce 100644
--- a/sys/dev/hwpmc/hwpmc_powerpc.h
+++ b/sys/dev/hwpmc/hwpmc_powerpc.h
@@ -46,11 +46,13 @@
struct powerpc_cpu {
struct pmc_hw *pc_ppcpmcs;
+ enum pmc_class pc_class;
};
extern struct powerpc_cpu **powerpc_pcpu;
extern int pmc_mpc7xxx_initialize(struct pmc_mdep *pmc_mdep);
+extern int pmc_ppc970_initialize(struct pmc_mdep *pmc_mdep);
extern int powerpc_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc);
extern int powerpc_get_config(int cpu, int ri, struct pmc **ppm);
diff --git a/sys/dev/hwpmc/hwpmc_ppc970.c b/sys/dev/hwpmc/hwpmc_ppc970.c
new file mode 100644
index 0000000..0d73508
--- /dev/null
+++ b/sys/dev/hwpmc/hwpmc_ppc970.c
@@ -0,0 +1,689 @@
+/*-
+ * Copyright (c) 2013 Justin Hibbits
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/pmc.h>
+#include <sys/pmckern.h>
+#include <sys/systm.h>
+
+#include <machine/pmc_mdep.h>
+#include <machine/spr.h>
+#include <machine/cpu.h>
+
+#include "hwpmc_powerpc.h"
+
+#define PPC970_MAX_PMCS 8
+
+/* MMCR0, PMC1 is 8 bytes in, PMC2 is 1 byte in. */
+#define PPC970_SET_MMCR0_PMCSEL(r, x, i) \
+ ((r & ~(0x1f << (7 * (1 - i) + 1))) | (x << (7 * (1 - i) + 1)))
+/* MMCR1 has 6 PMC*SEL items (PMC3->PMC8), in sequence. */
+#define PPC970_SET_MMCR1_PMCSEL(r, x, i) \
+ ((r & ~(0x1f << (5 * (7 - i) + 2))) | (x << (5 * (7 - i) + 2)))
+
+#define PPC970_PMC_HAS_OVERFLOWED(x) (ppc970_pmcn_read(x) & (0x1 << 31))
+
+/* How PMC works on PPC970:
+ *
+ * Any PMC can count a direct event. Indirect events are handled specially.
+ * Direct events: As published.
+ *
+ * Encoding 00 000 -- Add byte lane bit counters
+ * MMCR1[24:31] -- select bit matching PMC being an adder.
+ * Bus events:
+ * PMCxSEL: 1x -- select from byte lane: 10 == lower lane (0/1), 11 == upper
+ * lane (2/3).
+ * PMCxSEL[2:4] -- bit in the byte lane selected.
+ *
+ * PMC[1,2,5,6] == lane 0/lane 2
+ * PMC[3,4,7,8] == lane 1,3
+ *
+ *
+ * Lanes:
+ * Lane 0 -- TTM0(FPU,ISU,IFU,VPU)
+ * TTM1(IDU,ISU,STS)
+ * LSU0 byte 0
+ * LSU1 byte 0
+ * Lane 1 -- TTM0
+ * TTM1
+ * LSU0 byte 1
+ * LSU1 byte 1
+ * Lane 2 -- TTM0
+ * TTM1
+ * LSU0 byte 2
+ * LSU1 byte 2 or byte 6
+ * Lane 3 -- TTM0
+ * TTM1
+ * LSU0 byte 3
+ * LSU1 byte 3 or byte 7
+ *
+ * Adders:
+ * Add byte lane for PMC (above), bit 0+4, 1+5, 2+6, 3+7
+ */
+
+struct pmc_ppc970_event {
+ enum pmc_event pe_event;
+ uint32_t pe_flags;
+#define PMC_PPC970_FLAG_PMCS 0x000000ff
+#define PMC_PPC970_FLAG_PMC1 0x01
+#define PMC_PPC970_FLAG_PMC2 0x02
+#define PMC_PPC970_FLAG_PMC3 0x04
+#define PMC_PPC970_FLAG_PMC4 0x08
+#define PMC_PPC970_FLAG_PMC5 0x10
+#define PMC_PPC970_FLAG_PMC6 0x20
+#define PMC_PPC970_FLAG_PMC7 0x40
+#define PMC_PPC970_FLAG_PMC8 0x80
+ uint32_t pe_code;
+};
+
+static struct pmc_ppc970_event ppc970_event_codes[] = {
+ {PMC_EV_PPC970_INSTR_COMPLETED,
+ .pe_flags = PMC_PPC970_FLAG_PMCS,
+ .pe_code = 0x09
+ },
+ {PMC_EV_PPC970_MARKED_GROUP_DISPATCH,
+ .pe_flags = PMC_PPC970_FLAG_PMC1,
+ .pe_code = 0x2
+ },
+ {PMC_EV_PPC970_MARKED_STORE_COMPLETED,
+ .pe_flags = PMC_PPC970_FLAG_PMC1,
+ .pe_code = 0x03
+ },
+ {PMC_EV_PPC970_GCT_EMPTY,
+ .pe_flags = PMC_PPC970_FLAG_PMC1,
+ .pe_code = 0x04
+ },
+ {PMC_EV_PPC970_RUN_CYCLES,
+ .pe_flags = PMC_PPC970_FLAG_PMC1,
+ .pe_code = 0x05
+ },
+ {PMC_EV_PPC970_OVERFLOW,
+ .pe_flags = PMC_PPC970_FLAG_PMCS,
+ .pe_code = 0x0a
+ },
+ {PMC_EV_PPC970_CYCLES,
+ .pe_flags = PMC_PPC970_FLAG_PMCS,
+ .pe_code = 0x0f
+ },
+ {PMC_EV_PPC970_THRESHOLD_TIMEOUT,
+ .pe_flags = PMC_PPC970_FLAG_PMC2,
+ .pe_code = 0x3
+ },
+ {PMC_EV_PPC970_GROUP_DISPATCH,
+ .pe_flags = PMC_PPC970_FLAG_PMC2,
+ .pe_code = 0x4
+ },
+ {PMC_EV_PPC970_BR_MARKED_INSTR_FINISH,
+ .pe_flags = PMC_PPC970_FLAG_PMC2,
+ .pe_code = 0x5
+ },
+ {PMC_EV_PPC970_GCT_EMPTY_BY_SRQ_FULL,
+ .pe_flags = PMC_PPC970_FLAG_PMC2,
+ .pe_code = 0xb
+ },
+ {PMC_EV_PPC970_STOP_COMPLETION,
+ .pe_flags = PMC_PPC970_FLAG_PMC3,
+ .pe_code = 0x1
+ },
+ {PMC_EV_PPC970_LSU_EMPTY,
+ .pe_flags = PMC_PPC970_FLAG_PMC3,
+ .pe_code = 0x2
+ },
+ {PMC_EV_PPC970_MARKED_STORE_WITH_INTR,
+ .pe_flags = PMC_PPC970_FLAG_PMC3,
+ .pe_code = 0x3
+ },
+ {PMC_EV_PPC970_CYCLES_IN_SUPER,
+ .pe_flags = PMC_PPC970_FLAG_PMC3,
+ .pe_code = 0x4
+ },
+ {PMC_EV_PPC970_VPU_MARKED_INSTR_COMPLETED,
+ .pe_flags = PMC_PPC970_FLAG_PMC3,
+ .pe_code = 0x5
+ },
+ {PMC_EV_PPC970_FXU0_IDLE_FXU1_BUSY,
+ .pe_flags = PMC_PPC970_FLAG_PMC4,
+ .pe_code = 0x2
+ },
+ {PMC_EV_PPC970_SRQ_EMPTY,
+ .pe_flags = PMC_PPC970_FLAG_PMC4,
+ .pe_code = 0x3
+ },
+ {PMC_EV_PPC970_MARKED_GROUP_COMPLETED,
+ .pe_flags = PMC_PPC970_FLAG_PMC4,
+ .pe_code = 0x4
+ },
+ {PMC_EV_PPC970_CR_MARKED_INSTR_FINISH,
+ .pe_flags = PMC_PPC970_FLAG_PMC4,
+ .pe_code = 0x5
+ },
+ {PMC_EV_PPC970_DISPATCH_SUCCESS,
+ .pe_flags = PMC_PPC970_FLAG_PMC5,
+ .pe_code = 0x1
+ },
+ {PMC_EV_PPC970_FXU0_IDLE_FXU1_IDLE,
+ .pe_flags = PMC_PPC970_FLAG_PMC5,
+ .pe_code = 0x2
+ },
+ {PMC_EV_PPC970_ONE_PLUS_INSTR_COMPLETED,
+ .pe_flags = PMC_PPC970_FLAG_PMC5,
+ .pe_code = 0x3
+ },
+ {PMC_EV_PPC970_GROUP_MARKED_IDU,
+ .pe_flags = PMC_PPC970_FLAG_PMC5,
+ .pe_code = 0x4
+ },
+ {PMC_EV_PPC970_MARKED_GROUP_COMPLETE_TIMEOUT,
+ .pe_flags = PMC_PPC970_FLAG_PMC5,
+ .pe_code = 0x5
+ },
+ {PMC_EV_PPC970_FXU0_BUSY_FXU1_BUSY,
+ .pe_flags = PMC_PPC970_FLAG_PMC6,
+ .pe_code = 0x2
+ },
+ {PMC_EV_PPC970_MARKED_STORE_SENT_TO_STS,
+ .pe_flags = PMC_PPC970_FLAG_PMC6,
+ .pe_code = 0x3
+ },
+ {PMC_EV_PPC970_FXU_MARKED_INSTR_FINISHED,
+ .pe_flags = PMC_PPC970_FLAG_PMC6,
+ .pe_code = 0x4
+ },
+ {PMC_EV_PPC970_MARKED_GROUP_ISSUED,
+ .pe_flags = PMC_PPC970_FLAG_PMC6,
+ .pe_code = 0x5
+ },
+ {PMC_EV_PPC970_FXU0_BUSY_FXU1_IDLE,
+ .pe_flags = PMC_PPC970_FLAG_PMC7,
+ .pe_code = 0x2
+ },
+ {PMC_EV_PPC970_GROUP_COMPLETED,
+ .pe_flags = PMC_PPC970_FLAG_PMC7,
+ .pe_code = 0x3
+ },
+ {PMC_EV_PPC970_FPU_MARKED_INSTR_COMPLETED,
+ .pe_flags = PMC_PPC970_FLAG_PMC7,
+ .pe_code = 0x4
+ },
+ {PMC_EV_PPC970_MARKED_INSTR_FINISH_ANY_UNIT,
+ .pe_flags = PMC_PPC970_FLAG_PMC7,
+ .pe_code = 0x5
+ },
+ {PMC_EV_PPC970_EXTERNAL_INTERRUPT,
+ .pe_flags = PMC_PPC970_FLAG_PMC8,
+ .pe_code = 0x2
+ },
+ {PMC_EV_PPC970_GROUP_DISPATCH_REJECT,
+ .pe_flags = PMC_PPC970_FLAG_PMC8,
+ .pe_code = 0x3
+ },
+ {PMC_EV_PPC970_LSU_MARKED_INSTR_FINISH,
+ .pe_flags = PMC_PPC970_FLAG_PMC8,
+ .pe_code = 0x4
+ },
+ {PMC_EV_PPC970_TIMEBASE_EVENT,
+ .pe_flags = PMC_PPC970_FLAG_PMC8,
+ .pe_code = 0x5
+ },
+#if 0
+ {PMC_EV_PPC970_LSU_COMPLETION_STALL, },
+ {PMC_EV_PPC970_FXU_COMPLETION_STALL, },
+ {PMC_EV_PPC970_DCACHE_MISS_COMPLETION_STALL, },
+ {PMC_EV_PPC970_FPU_COMPLETION_STALL, },
+ {PMC_EV_PPC970_FXU_LONG_INSTR_COMPLETION_STALL, },
+ {PMC_EV_PPC970_REJECT_COMPLETION_STALL, },
+ {PMC_EV_PPC970_FPU_LONG_INSTR_COMPLETION_STALL, },
+ {PMC_EV_PPC970_GCT_EMPTY_BY_ICACHE_MISS, },
+ {PMC_EV_PPC970_REJECT_COMPLETION_STALL_ERAT_MISS, },
+ {PMC_EV_PPC970_GCT_EMPTY_BY_BRANCH_MISS_PREDICT, },
+#endif
+};
+static size_t ppc970_event_codes_size = nitems(ppc970_event_codes);
+
+static pmc_value_t
+ppc970_pmcn_read(unsigned int pmc)
+{
+ pmc_value_t val;
+
+ switch (pmc) {
+ case 0:
+ val = mfspr(SPR_970PMC1);
+ break;
+ case 1:
+ val = mfspr(SPR_970PMC2);
+ break;
+ case 2:
+ val = mfspr(SPR_970PMC3);
+ break;
+ case 3:
+ val = mfspr(SPR_970PMC4);
+ break;
+ case 4:
+ val = mfspr(SPR_970PMC5);
+ break;
+ case 5:
+ val = mfspr(SPR_970PMC6);
+ break;
+ case 6:
+ val = mfspr(SPR_970PMC7);
+ break;
+ case 7:
+ val = mfspr(SPR_970PMC8);
+ break;
+ default:
+ panic("Invalid PMC number: %d\n", pmc);
+ }
+
+ return (val);
+}
+
+static void
+ppc970_pmcn_write(unsigned int pmc, uint32_t val)
+{
+ switch (pmc) {
+ case 0:
+ mtspr(SPR_970PMC1, val);
+ break;
+ case 1:
+ mtspr(SPR_970PMC2, val);
+ break;
+ case 2:
+ mtspr(SPR_970PMC3, val);
+ break;
+ case 3:
+ mtspr(SPR_970PMC4, val);
+ break;
+ case 4:
+ mtspr(SPR_970PMC5, val);
+ break;
+ case 5:
+ mtspr(SPR_970PMC6, val);
+ break;
+ case 6:
+ mtspr(SPR_970PMC7, val);
+ break;
+ case 7:
+ mtspr(SPR_970PMC8, val);
+ break;
+ default:
+ panic("Invalid PMC number: %d\n", pmc);
+ }
+}
+
+static int
+ppc970_config_pmc(int cpu, int ri, struct pmc *pm)
+{
+ struct pmc_hw *phw;
+
+ PMCDBG(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm);
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri >= 0 && ri < PPC970_MAX_PMCS,
+ ("[powerpc,%d] illegal row-index %d", __LINE__, ri));
+
+ phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
+
+ KASSERT(pm == NULL || phw->phw_pmc == NULL,
+ ("[powerpc,%d] pm=%p phw->pm=%p hwpmc not unconfigured",
+ __LINE__, pm, phw->phw_pmc));
+
+ phw->phw_pmc = pm;
+
+ return 0;
+}
+
+static int
+ppc970_set_pmc(int cpu, int ri, int config)
+{
+ struct pmc *pm;
+ struct pmc_hw *phw;
+ register_t pmc_mmcr;
+
+ phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
+ pm = phw->phw_pmc;
+
+ /*
+ * Disable the PMCs.
+ */
+ switch (ri) {
+ case 0:
+ case 1:
+ pmc_mmcr = mfspr(SPR_970MMCR0);
+ pmc_mmcr = PPC970_SET_MMCR0_PMCSEL(pmc_mmcr, config, ri);
+ mtspr(SPR_970MMCR0, pmc_mmcr);
+ break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ pmc_mmcr = mfspr(SPR_970MMCR1);
+ pmc_mmcr = PPC970_SET_MMCR1_PMCSEL(pmc_mmcr, config, ri);
+ mtspr(SPR_970MMCR1, pmc_mmcr);
+ break;
+ }
+ return 0;
+}
+
+static int
+ppc970_start_pmc(int cpu, int ri)
+{
+ struct pmc *pm;
+ struct pmc_hw *phw;
+ register_t pmc_mmcr;
+ uint32_t config;
+ int error;
+
+ phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
+ pm = phw->phw_pmc;
+ config = pm->pm_md.pm_powerpc.pm_powerpc_evsel & ~POWERPC_PMC_ENABLE;
+
+ error = ppc970_set_pmc(cpu, ri, config);
+
+ /* The mask is inverted (enable is 1) compared to the flags in MMCR0, which
+ * are Freeze flags.
+ */
+ config = ~pm->pm_md.pm_powerpc.pm_powerpc_evsel & POWERPC_PMC_ENABLE;
+
+ pmc_mmcr = mfspr(SPR_970MMCR0);
+ pmc_mmcr &= ~SPR_MMCR0_FC;
+ pmc_mmcr |= config;
+ mtspr(SPR_970MMCR0, pmc_mmcr);
+
+ return 0;
+}
+
+static int
+ppc970_stop_pmc(int cpu, int ri)
+{
+ return ppc970_set_pmc(cpu, ri, PMC970N_NONE);
+}
+
+static int
+ppc970_read_pmc(int cpu, int ri, pmc_value_t *v)
+{
+ struct pmc *pm;
+ pmc_value_t tmp;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri >= 0 && ri < PPC970_MAX_PMCS,
+ ("[powerpc,%d] illegal row index %d", __LINE__, ri));
+
+ pm = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc;
+ KASSERT(pm,
+ ("[core,%d] cpu %d ri %d pmc not configured", __LINE__, cpu,
+ ri));
+
+ tmp = ppc970_pmcn_read(ri);
+ PMCDBG(MDP,REA,2,"ppc-read id=%d -> %jd", ri, tmp);
+ if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
+ *v = POWERPC_PERFCTR_VALUE_TO_RELOAD_COUNT(tmp);
+ else
+ *v = tmp;
+
+ return 0;
+}
+
+static int
+ppc970_write_pmc(int cpu, int ri, pmc_value_t v)
+{
+ struct pmc *pm;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri >= 0 && ri < PPC970_MAX_PMCS,
+ ("[powerpc,%d] illegal row-index %d", __LINE__, ri));
+
+ pm = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc;
+
+ if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
+ v = POWERPC_RELOAD_COUNT_TO_PERFCTR_VALUE(v);
+
+ PMCDBG(MDP,WRI,1,"powerpc-write cpu=%d ri=%d v=%jx", cpu, ri, v);
+
+ ppc970_pmcn_write(ri, v);
+
+ return 0;
+}
+
+static int
+ppc970_intr(int cpu, struct trapframe *tf)
+{
+ struct pmc *pm;
+ struct powerpc_cpu *pac;
+ pmc_value_t v;
+ uint32_t config;
+ int i, error, retval;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[powerpc,%d] out of range CPU %d", __LINE__, cpu));
+
+ PMCDBG(MDP,INT,1, "cpu=%d tf=%p um=%d", cpu, (void *) tf,
+ TRAPF_USERMODE(tf));
+
+ retval = 0;
+
+ pac = powerpc_pcpu[cpu];
+
+ /*
+ * look for all PMCs that have interrupted:
+ * - look for a running, sampling PMC which has overflowed
+ * and which has a valid 'struct pmc' association
+ *
+ * If found, we call a helper to process the interrupt.
+ */
+
+ config = mfspr(SPR_970MMCR0);
+ mtspr(SPR_970MMCR0, config | SPR_MMCR0_FC);
+ for (i = 0; i < PPC970_MAX_PMCS; i++) {
+ if ((pm = pac->pc_ppcpmcs[i].phw_pmc) == NULL ||
+ !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) {
+ continue;
+ }
+
+ if (!PPC970_PMC_HAS_OVERFLOWED(i))
+ continue;
+
+ retval = 1; /* Found an interrupting PMC. */
+
+ if (pm->pm_state != PMC_STATE_RUNNING)
+ continue;
+
+ /* Stop the PMC, reload count. */
+ v = pm->pm_sc.pm_reloadcount;
+
+ ppc970_pmcn_write(i, v);
+
+ /* Restart the counter if logging succeeded. */
+ error = pmc_process_interrupt(cpu, PMC_HR, pm, tf,
+ TRAPF_USERMODE(tf));
+ mtspr(SPR_970MMCR0, config);
+ if (error != 0)
+ ppc970_stop_pmc(cpu, i);
+ atomic_add_int(retval ? &pmc_stats.pm_intr_processed :
+ &pmc_stats.pm_intr_ignored, 1);
+
+ }
+
+ /* Re-enable PERF exceptions. */
+ mtspr(SPR_970MMCR0, mfspr(SPR_970MMCR0) | SPR_MMCR0_PMXE);
+
+ return (retval);
+}
+
+static int
+ppc970_pcpu_init(struct pmc_mdep *md, int cpu)
+{
+ struct pmc_cpu *pc;
+ struct powerpc_cpu *pac;
+ struct pmc_hw *phw;
+ int first_ri, i;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[powerpc,%d] wrong cpu number %d", __LINE__, cpu));
+ PMCDBG(MDP,INI,1,"powerpc-init cpu=%d", cpu);
+
+ powerpc_pcpu[cpu] = pac = malloc(sizeof(struct powerpc_cpu), M_PMC,
+ M_WAITOK|M_ZERO);
+ pac->pc_ppcpmcs = malloc(sizeof(struct pmc_hw) * PPC970_MAX_PMCS,
+ M_PMC, M_WAITOK|M_ZERO);
+ pac->pc_class = PMC_CLASS_PPC970;
+
+ pc = pmc_pcpu[cpu];
+ first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_PPC970].pcd_ri;
+ KASSERT(pc != NULL, ("[powerpc,%d] NULL per-cpu pointer", __LINE__));
+
+ for (i = 0, phw = pac->pc_ppcpmcs; i < PPC970_MAX_PMCS; i++, phw++) {
+ phw->phw_state = PMC_PHW_FLAG_IS_ENABLED |
+ PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(i);
+ phw->phw_pmc = NULL;
+ pc->pc_hwpmcs[i + first_ri] = phw;
+ }
+
+ /* Clear the MMCRs, and set FC, to disable all PMCs. */
+ /* 970 PMC is not counted when set to 0x08 */
+ mtspr(SPR_970MMCR0, SPR_MMCR0_FC | SPR_MMCR0_PMXE | SPR_MMCR0_PMC1CE |
+ SPR_MMCR0_PMCNCE | SPR_970MMCR0_PMC1SEL(0x8) | SPR_970MMCR0_PMC2SEL(0x8));
+ mtspr(SPR_970MMCR1, 0x4218420);
+
+ return 0;
+}
+
+static int
+ppc970_pcpu_fini(struct pmc_mdep *md, int cpu)
+{
+ register_t mmcr0 = mfspr(SPR_MMCR0);
+
+ mmcr0 |= SPR_MMCR0_FC;
+ mmcr0 &= ~SPR_MMCR0_PMXE;
+ mtspr(SPR_MMCR0, mmcr0);
+ free(powerpc_pcpu[cpu]->pc_ppcpmcs, M_PMC);
+ free(powerpc_pcpu[cpu], M_PMC);
+ return 0;
+}
+
+static int
+ppc970_allocate_pmc(int cpu, int ri, struct pmc *pm,
+ const struct pmc_op_pmcallocate *a)
+{
+ enum pmc_event pe;
+ uint32_t caps, config = 0, counter = 0;
+ int i;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri >= 0 && ri < PPC970_MAX_PMCS,
+ ("[powerpc,%d] illegal row index %d", __LINE__, ri));
+
+ caps = a->pm_caps;
+
+ pe = a->pm_ev;
+
+ if (pe < PMC_EV_PPC970_FIRST || pe > PMC_EV_PPC970_LAST)
+ return (EINVAL);
+
+ for (i = 0; i < ppc970_event_codes_size; i++) {
+ if (ppc970_event_codes[i].pe_event == pe) {
+ config = ppc970_event_codes[i].pe_code;
+ counter = ppc970_event_codes[i].pe_flags;
+ break;
+ }
+ }
+ if (i == ppc970_event_codes_size)
+ return (EINVAL);
+
+ if ((counter & (1 << ri)) == 0)
+ return (EINVAL);
+
+ if (caps & PMC_CAP_SYSTEM)
+ config |= POWERPC_PMC_KERNEL_ENABLE;
+ if (caps & PMC_CAP_USER)
+ config |= POWERPC_PMC_USER_ENABLE;
+ if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0)
+ config |= POWERPC_PMC_ENABLE;
+
+ pm->pm_md.pm_powerpc.pm_powerpc_evsel = config;
+
+ PMCDBG(MDP,ALL,2,"powerpc-allocate ri=%d -> config=0x%x", ri, config);
+
+ return 0;
+}
+
+static int
+ppc970_release_pmc(int cpu, int ri, struct pmc *pmc)
+{
+ struct pmc_hw *phw;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri >= 0 && ri < PPC970_MAX_PMCS,
+ ("[powerpc,%d] illegal row-index %d", __LINE__, ri));
+
+ phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
+ KASSERT(phw->phw_pmc == NULL,
+ ("[powerpc,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc));
+
+ return 0;
+}
+
+int
+pmc_ppc970_initialize(struct pmc_mdep *pmc_mdep)
+{
+ struct pmc_classdep *pcd;
+
+ pmc_mdep->pmd_cputype = PMC_CPU_PPC_970;
+
+ pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_PPC970];
+ pcd->pcd_caps = POWERPC_PMC_CAPS;
+ pcd->pcd_class = PMC_CLASS_PPC970;
+ pcd->pcd_num = PPC970_MAX_PMCS;
+ pcd->pcd_ri = pmc_mdep->pmd_npmc;
+ pcd->pcd_width = 32;
+
+ pcd->pcd_allocate_pmc = ppc970_allocate_pmc;
+ pcd->pcd_config_pmc = ppc970_config_pmc;
+ pcd->pcd_pcpu_fini = ppc970_pcpu_fini;
+ pcd->pcd_pcpu_init = ppc970_pcpu_init;
+ pcd->pcd_describe = powerpc_describe;
+ pcd->pcd_get_config = powerpc_get_config;
+ pcd->pcd_read_pmc = ppc970_read_pmc;
+ pcd->pcd_release_pmc = ppc970_release_pmc;
+ pcd->pcd_start_pmc = ppc970_start_pmc;
+ pcd->pcd_stop_pmc = ppc970_stop_pmc;
+ pcd->pcd_write_pmc = ppc970_write_pmc;
+
+ pmc_mdep->pmd_npmc += PPC970_MAX_PMCS;
+ pmc_mdep->pmd_intr = ppc970_intr;
+
+ return (0);
+}
diff --git a/sys/dev/hwpmc/pmc_events.h b/sys/dev/hwpmc/pmc_events.h
index ac933fe..a17b132 100644
--- a/sys/dev/hwpmc/pmc_events.h
+++ b/sys/dev/hwpmc/pmc_events.h
@@ -4749,6 +4749,61 @@ __PMC_EV_ALIAS("IMPC_C0H_TRK_REQUEST.ALL", UCP_EVENT_84H_01H)
#define PMC_EV_PPC7450_FIRST PMC_EV_PPC7450_CYCLE
#define PMC_EV_PPC7450_LAST PMC_EV_PPC7450_PREFETCH_ENGINE_FULL
+#define __PMC_EV_PPC970() \
+ __PMC_EV(PPC970, INSTR_COMPLETED) \
+ __PMC_EV(PPC970, MARKED_GROUP_DISPATCH) \
+ __PMC_EV(PPC970, MARKED_STORE_COMPLETED) \
+ __PMC_EV(PPC970, GCT_EMPTY) \
+ __PMC_EV(PPC970, RUN_CYCLES) \
+ __PMC_EV(PPC970, OVERFLOW) \
+ __PMC_EV(PPC970, CYCLES) \
+ __PMC_EV(PPC970, THRESHOLD_TIMEOUT) \
+ __PMC_EV(PPC970, GROUP_DISPATCH) \
+ __PMC_EV(PPC970, BR_MARKED_INSTR_FINISH) \
+ __PMC_EV(PPC970, GCT_EMPTY_BY_SRQ_FULL) \
+ __PMC_EV(PPC970, STOP_COMPLETION) \
+ __PMC_EV(PPC970, LSU_EMPTY) \
+ __PMC_EV(PPC970, MARKED_STORE_WITH_INTR) \
+ __PMC_EV(PPC970, CYCLES_IN_SUPER) \
+ __PMC_EV(PPC970, VPU_MARKED_INSTR_COMPLETED) \
+ __PMC_EV(PPC970, FXU0_IDLE_FXU1_BUSY) \
+ __PMC_EV(PPC970, SRQ_EMPTY) \
+ __PMC_EV(PPC970, MARKED_GROUP_COMPLETED) \
+ __PMC_EV(PPC970, CR_MARKED_INSTR_FINISH) \
+ __PMC_EV(PPC970, DISPATCH_SUCCESS) \
+ __PMC_EV(PPC970, FXU0_IDLE_FXU1_IDLE) \
+ __PMC_EV(PPC970, ONE_PLUS_INSTR_COMPLETED) \
+ __PMC_EV(PPC970, GROUP_MARKED_IDU) \
+ __PMC_EV(PPC970, MARKED_GROUP_COMPLETE_TIMEOUT) \
+ __PMC_EV(PPC970, FXU0_BUSY_FXU1_BUSY) \
+ __PMC_EV(PPC970, MARKED_STORE_SENT_TO_STS) \
+ __PMC_EV(PPC970, FXU_MARKED_INSTR_FINISHED) \
+ __PMC_EV(PPC970, MARKED_GROUP_ISSUED) \
+ __PMC_EV(PPC970, FXU0_BUSY_FXU1_IDLE) \
+ __PMC_EV(PPC970, GROUP_COMPLETED) \
+ __PMC_EV(PPC970, FPU_MARKED_INSTR_COMPLETED) \
+ __PMC_EV(PPC970, MARKED_INSTR_FINISH_ANY_UNIT) \
+ __PMC_EV(PPC970, EXTERNAL_INTERRUPT) \
+ __PMC_EV(PPC970, GROUP_DISPATCH_REJECT) \
+ __PMC_EV(PPC970, LSU_MARKED_INSTR_FINISH) \
+ __PMC_EV(PPC970, TIMEBASE_EVENT) \
+ __PMC_EV(PPC970, LSU_COMPLETION_STALL) \
+ __PMC_EV(PPC970, FXU_COMPLETION_STALL) \
+ __PMC_EV(PPC970, DCACHE_MISS_COMPLETION_STALL) \
+ __PMC_EV(PPC970, FPU_COMPLETION_STALL) \
+ __PMC_EV(PPC970, FXU_LONG_INSTR_COMPLETION_STALL) \
+ __PMC_EV(PPC970, REJECT_COMPLETION_STALL) \
+ __PMC_EV(PPC970, FPU_LONG_INSTR_COMPLETION_STALL) \
+ __PMC_EV(PPC970, GCT_EMPTY_BY_ICACHE_MISS) \
+ __PMC_EV(PPC970, REJECT_COMPLETION_STALL_ERAT_MISS) \
+ __PMC_EV(PPC970, GCT_EMPTY_BY_BRANCH_MISS_PREDICT) \
+ __PMC_EV(PPC970, BUS_HIGH) \
+ __PMC_EV(PPC970, BUS_LOW) \
+ __PMC_EV(PPC970, ADDER)
+
+
+#define PMC_EV_PPC970_FIRST PMC_EV_PPC970_INSTR_COMPLETED
+#define PMC_EV_PPC970_LAST PMC_EV_PPC970_ADDER
/*
* All known PMC events.
*
@@ -4799,6 +4854,8 @@ __PMC_EV_ALIAS("IMPC_C0H_TRK_REQUEST.ALL", UCP_EVENT_84H_01H)
__PMC_EV_UCP() \
__PMC_EV_BLOCK(PPC7450, 0x13000) \
__PMC_EV_PPC7450() \
+ __PMC_EV_BLOCK(PPC970, 0x13100) \
+ __PMC_EV_PPC970() \
#define PMC_EVENT_FIRST PMC_EV_TSC_TSC
#define PMC_EVENT_LAST PMC_EV_SOFT_LAST
diff --git a/sys/powerpc/include/pmc_mdep.h b/sys/powerpc/include/pmc_mdep.h
index a0f2062..87dc76c 100644
--- a/sys/powerpc/include/pmc_mdep.h
+++ b/sys/powerpc/include/pmc_mdep.h
@@ -7,6 +7,7 @@
#ifndef _MACHINE_PMC_MDEP_H_
#define _MACHINE_PMC_MDEP_H_
+#define PMC_MDEP_CLASS_INDEX_CPU 1
#define PMC_MDEP_CLASS_INDEX_PPC7450 1
#define PMC_MDEP_CLASS_INDEX_PPC970 1
diff --git a/sys/powerpc/include/spr.h b/sys/powerpc/include/spr.h
index f275069..b9fb3c1 100644
--- a/sys/powerpc/include/spr.h
+++ b/sys/powerpc/include/spr.h
@@ -294,6 +294,27 @@
#define M_CASID 0x0000000f /* Current AS Id */
#define SPR_MD_AP 0x31a /* ..8 DMMU access protection */
#define SPR_MD_EPN 0x31b /* ..8 DMMU effective number */
+
+#define SPR_970MMCR0 0x31b /* ... Monitor Mode Control Register 0 (PPC 970) */
+#define SPR_970MMCR0_PMC1SEL(x) ((x) << 8) /* PMC1 selector (970) */
+#define SPR_970MMCR0_PMC2SEL(x) ((x) << 1) /* PMC2 selector (970) */
+#define SPR_970MMCR1 0x31e /* ... Monitor Mode Control Register 1 (PPC 970) */
+#define SPR_970MMCR1_PMC3SEL(x) (((x) & 0x1f) << 27) /* PMC 3 selector */
+#define SPR_970MMCR1_PMC4SEL(x) (((x) & 0x1f) << 22) /* PMC 4 selector */
+#define SPR_970MMCR1_PMC5SEL(x) (((x) & 0x1f) << 17) /* PMC 5 selector */
+#define SPR_970MMCR1_PMC6SEL(x) (((x) & 0x1f) << 12) /* PMC 6 selector */
+#define SPR_970MMCR1_PMC7SEL(x) (((x) & 0x1f) << 7) /* PMC 7 selector */
+#define SPR_970MMCR1_PMC8SEL(x) (((x) & 0x1f) << 2) /* PMC 8 selector */
+#define SPR_970MMCRA 0x312 /* ... Monitor Mode Control Register 2 (PPC 970) */
+#define SPR_970PMC1 0x313 /* ... PMC 1 */
+#define SPR_970PMC2 0x314 /* ... PMC 2 */
+#define SPR_970PMC3 0x315 /* ... PMC 3 */
+#define SPR_970PMC4 0x316 /* ... PMC 4 */
+#define SPR_970PMC5 0x317 /* ... PMC 5 */
+#define SPR_970PMC6 0x318 /* ... PMC 6 */
+#define SPR_970PMC7 0x319 /* ... PMC 7 */
+#define SPR_970PMC8 0x31a /* ... PMC 8 */
+
#define SPR_M_TWB 0x31c /* ..8 MMU tablewalk base */
#define M_TWB_L1TB 0xfffff000 /* level-1 translation base */
#define M_TWB_L1INDX 0x00000ffc /* level-1 index */
@@ -323,19 +344,6 @@
#define SPR_DVC1 0x3b6 /* 4.. Data Value Compare 1 */
#define SPR_DVC2 0x3b7 /* 4.. Data Value Compare 2 */
#define SPR_MMCR0 0x3b8 /* .6. Monitor Mode Control Register 0 */
-
-#define SPR_970MMCR0 0x31b /* ... Monitor Mode Control Register 0 (PPC 970) */
-#define SPR_970MMCR1 0x31e /* ... Monitor Mode Control Register 1 (PPC 970) */
-#define SPR_970MMCRA 0x312 /* ... Monitor Mode Control Register 2 (PPC 970) */
-#define SPR_970PMC1 0x313 /* ... PMC 1 */
-#define SPR_970PMC2 0x314 /* ... PMC 2 */
-#define SPR_970PMC3 0x315 /* ... PMC 3 */
-#define SPR_970PMC4 0x316 /* ... PMC 4 */
-#define SPR_970PMC5 0x317 /* ... PMC 5 */
-#define SPR_970PMC6 0x318 /* ... PMC 6 */
-#define SPR_970PMC7 0x319 /* ... PMC 7 */
-#define SPR_970PMC8 0x31a /* ... PMC 8 */
-
#define SPR_MMCR0_FC 0x80000000 /* Freeze counters */
#define SPR_MMCR0_FCS 0x40000000 /* Freeze counters in supervisor mode */
#define SPR_MMCR0_FCP 0x20000000 /* Freeze counters in user mode */
@@ -354,8 +362,6 @@
#define SPR_MMCR0_TRIGGER 0x00002000 /* Trigger */
#define SPR_MMCR0_PMC1SEL(x) (((x) & 0x3f) << 6) /* PMC1 selector */
#define SPR_MMCR0_PMC2SEL(x) (((x) & 0x3f) << 0) /* PMC2 selector */
-#define SPR_970MMCR0_PMC1SEL(x) ((x) << 8) /* PMC1 selector (970) */
-#define SPR_970MMCR0_PMC2SEL(x) ((x) << 1) /* PMC2 selector (970) */
#define SPR_SGR 0x3b9 /* 4.. Storage Guarded Register */
#define SPR_PMC1 0x3b9 /* .6. Performance Counter Register 1 */
#define SPR_DCWR 0x3ba /* 4.. Data Cache Write-through Register */
diff --git a/sys/sys/pmc.h b/sys/sys/pmc.h
index e5a9c45..de397c8 100644
--- a/sys/sys/pmc.h
+++ b/sys/sys/pmc.h
@@ -95,6 +95,7 @@
__PMC_CPU(MIPS_24K, 0x200, "MIPS 24K") \
__PMC_CPU(MIPS_OCTEON, 0x201, "Cavium Octeon") \
__PMC_CPU(PPC_7450, 0x300, "PowerPC MPC7450") \
+ __PMC_CPU(PPC_970, 0x380, "IBM PowerPC 970") \
__PMC_CPU(GENERIC, 0x400, "Generic")
enum pmc_cputype {
@@ -125,6 +126,7 @@ enum pmc_cputype {
__PMC_CLASS(MIPS24K) /* MIPS 24K */ \
__PMC_CLASS(OCTEON) /* Cavium Octeon */ \
__PMC_CLASS(PPC7450) /* Motorola MPC7450 class */ \
+ __PMC_CLASS(PPC970) /* IBM PowerPC 970 class */ \
__PMC_CLASS(SOFT) /* Software events */
enum pmc_class {
OpenPOWER on IntegriCloud