Implement hwpmc(4) for Freescale e500 core.

This supports e500v1, e500v2, and e500mc. Tested only on e500v2, but the
performance counters are identical across all, with e500mc having some
additional events.

Relnotes:	Yes
This commit is contained in:
Justin Hibbits 2015-04-18 21:39:17 +00:00
parent 3d0045bb2b
commit a745246822
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=281713
14 changed files with 964 additions and 11 deletions

View File

@ -164,6 +164,7 @@ PMC_CLASSDEP_TABLE(octeon, OCTEON);
PMC_CLASSDEP_TABLE(ucf, UCF);
PMC_CLASSDEP_TABLE(ppc7450, PPC7450);
PMC_CLASSDEP_TABLE(ppc970, PPC970);
PMC_CLASSDEP_TABLE(e500, E500);
static struct pmc_event_descr soft_event_table[PMC_EV_DYN_COUNT];
@ -296,8 +297,9 @@ PMC_MDEP_TABLE(armv7, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7);
PMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K);
PMC_MDEP_TABLE(mips74k, MIPS74K, PMC_CLASS_SOFT, PMC_CLASS_MIPS74K);
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(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450, PMC_CLASS_TSC);
PMC_MDEP_TABLE(ppc970, PPC970, PMC_CLASS_SOFT, PMC_CLASS_PPC970, PMC_CLASS_TSC);
PMC_MDEP_TABLE(e500, E500, PMC_CLASS_SOFT, PMC_CLASS_E500, PMC_CLASS_TSC);
PMC_MDEP_TABLE(generic, SOFT, PMC_CLASS_SOFT);
static const struct pmc_event_descr tsc_event_table[] =
@ -368,6 +370,7 @@ PMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips);
#if defined(__powerpc__)
PMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, powerpc);
PMC_CLASS_TABLE_DESC(ppc970, PPC970, ppc970, powerpc);
PMC_CLASS_TABLE_DESC(e500, E500, e500, powerpc);
#endif
static struct pmc_class_descr soft_class_table_descr =
@ -2494,6 +2497,12 @@ static struct pmc_event_alias ppc970_aliases[] = {
EV_ALIAS(NULL, NULL)
};
static struct pmc_event_alias e500_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"
@ -2949,6 +2958,10 @@ pmc_event_names_of_class(enum pmc_class cl, const char ***eventnames,
ev = ppc970_event_table;
count = PMC_EVENT_TABLE_SIZE(ppc970);
break;
case PMC_CLASS_E500:
ev = e500_event_table;
count = PMC_EVENT_TABLE_SIZE(e500);
break;
case PMC_CLASS_SOFT:
ev = soft_event_table;
count = soft_event_info.pm_nevent;
@ -3245,6 +3258,10 @@ pmc_init(void)
PMC_MDEP_INIT(ppc970);
pmc_class_table[n] = &ppc970_class_table_descr;
break;
case PMC_CPU_PPC_E500:
PMC_MDEP_INIT(e500);
pmc_class_table[n] = &e500_class_table_descr;
break;
#endif
default:
/*
@ -3444,6 +3461,9 @@ _pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu)
} 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_E500_FIRST && pe <= PMC_EV_E500_LAST) {
ev = e500_event_table;
evfence = e500_event_table + PMC_EVENT_TABLE_SIZE(e500);
} else if (pe == PMC_EV_TSC_TSC) {
ev = tsc_event_table;
evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc);

View File

@ -31,8 +31,9 @@ dev/fb/fb.c optional sc
dev/fdt/fdt_powerpc.c optional fdt
# ofwbus depends on simplebus.
dev/fdt/simplebus.c optional aim | fdt
dev/hwpmc/hwpmc_powerpc.c optional hwpmc
dev/hwpmc/hwpmc_e500.c optional hwpmc
dev/hwpmc/hwpmc_mpc7xxx.c optional hwpmc
dev/hwpmc/hwpmc_powerpc.c optional hwpmc
dev/hwpmc/hwpmc_ppc970.c optional hwpmc
dev/iicbus/ad7417.c optional ad7417 powermac
dev/iicbus/adm1030.c optional powermac windtunnel | adm1030 powermac

660
sys/dev/hwpmc/hwpmc_e500.c Normal file
View File

@ -0,0 +1,660 @@
/*-
* Copyright (c) 2015 Justin Hibbits
* Copyright (c) 2005, Joseph Koshy
* 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/cpu.h>
#include <ddb/ddb.h>
#include "hwpmc_powerpc.h"
#define POWERPC_PMC_CAPS (PMC_CAP_INTERRUPT | PMC_CAP_USER | \
PMC_CAP_SYSTEM | PMC_CAP_EDGE | \
PMC_CAP_THRESHOLD | PMC_CAP_READ | \
PMC_CAP_WRITE | PMC_CAP_INVERT | \
PMC_CAP_QUALIFIER)
#define E500_PMC_HAS_OVERFLOWED(x) (e500_pmcn_read(x) & (0x1 << 31))
struct e500_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_cpu; /* e500 core (v1,v2,mc), mask */
};
#define E500_MAX_PMCS 4
#define PMC_PPC_MASK0 0
#define PMC_PPC_MASK1 1
#define PMC_PPC_MASK2 2
#define PMC_PPC_MASK3 3
#define PMC_PPC_MASK_ALL 0x0f
#define PMC_PPC_E500V1 1
#define PMC_PPC_E500V2 2
#define PMC_PPC_E500MC 4
#define PMC_PPC_E500_ANY 7
#define PMC_E500_EVENT(id, mask, number, core) \
[PMC_EV_E500_##id - PMC_EV_E500_FIRST] = \
{ .pe_ev = PMC_EV_E500_##id, .pe_counter_mask = mask, \
.pe_code = number, .pe_cpu = core }
#define PMC_E500MC_ONLY(id, number) \
PMC_E500_EVENT(id, PMC_PPC_MASK_ALL, number, PMC_PPC_E500MC)
#define PMC_E500_COMMON(id, number) \
PMC_E500_EVENT(id, PMC_PPC_MASK_ALL, number, PMC_PPC_E500_ANY)
static struct e500_event_code_map e500_event_codes[] = {
PMC_E500_COMMON(CYCLES, 1),
PMC_E500_COMMON(INSTR_COMPLETED, 2),
PMC_E500_COMMON(UOPS_COMPLETED, 3),
PMC_E500_COMMON(INSTR_FETCHED, 4),
PMC_E500_COMMON(UOPS_DECODED, 5),
PMC_E500_COMMON(PM_EVENT_TRANSITIONS, 6),
PMC_E500_COMMON(PM_EVENT_CYCLES, 7),
PMC_E500_COMMON(BRANCH_INSTRS_COMPLETED, 8),
PMC_E500_COMMON(LOAD_UOPS_COMPLETED, 9),
PMC_E500_COMMON(STORE_UOPS_COMPLETED, 10),
PMC_E500_COMMON(CQ_REDIRECTS, 11),
PMC_E500_COMMON(BRANCHES_FINISHED, 12),
PMC_E500_COMMON(TAKEN_BRANCHES_FINISHED, 13),
PMC_E500_COMMON(FINISHED_UNCOND_BRANCHES_MISS_BTB, 14),
PMC_E500_COMMON(BRANCH_MISPRED, 15),
PMC_E500_COMMON(BTB_BRANCH_MISPRED_FROM_DIRECTION, 16),
PMC_E500_COMMON(BTB_HITS_PSEUDO_HITS, 17),
PMC_E500_COMMON(CYCLES_DECODE_STALLED, 18),
PMC_E500_COMMON(CYCLES_ISSUE_STALLED, 19),
PMC_E500_COMMON(CYCLES_BRANCH_ISSUE_STALLED, 20),
PMC_E500_COMMON(CYCLES_SU1_SCHED_STALLED, 21),
PMC_E500_COMMON(CYCLES_SU2_SCHED_STALLED, 22),
PMC_E500_COMMON(CYCLES_MU_SCHED_STALLED, 23),
PMC_E500_COMMON(CYCLES_LRU_SCHED_STALLED, 24),
PMC_E500_COMMON(CYCLES_BU_SCHED_STALLED, 25),
PMC_E500_COMMON(TOTAL_TRANSLATED, 26),
PMC_E500_COMMON(LOADS_TRANSLATED, 27),
PMC_E500_COMMON(STORES_TRANSLATED, 28),
PMC_E500_COMMON(TOUCHES_TRANSLATED, 29),
PMC_E500_COMMON(CACHEOPS_TRANSLATED, 30),
PMC_E500_COMMON(CACHE_INHIBITED_ACCESS_TRANSLATED, 31),
PMC_E500_COMMON(GUARDED_LOADS_TRANSLATED, 32),
PMC_E500_COMMON(WRITE_THROUGH_STORES_TRANSLATED, 33),
PMC_E500_COMMON(MISALIGNED_LOAD_STORE_ACCESS_TRANSLATED, 34),
PMC_E500_COMMON(TOTAL_ALLOCATED_TO_DLFB, 35),
PMC_E500_COMMON(LOADS_TRANSLATED_ALLOCATED_TO_DLFB, 36),
PMC_E500_COMMON(STORES_COMPLETED_ALLOCATED_TO_DLFB, 37),
PMC_E500_COMMON(TOUCHES_TRANSLATED_ALLOCATED_TO_DLFB, 38),
PMC_E500_COMMON(STORES_COMPLETED, 39),
PMC_E500_COMMON(DATA_L1_CACHE_LOCKS, 40),
PMC_E500_COMMON(DATA_L1_CACHE_RELOADS, 41),
PMC_E500_COMMON(DATA_L1_CACHE_CASTOUTS, 42),
PMC_E500_COMMON(LOAD_MISS_DLFB_FULL, 43),
PMC_E500_COMMON(LOAD_MISS_LDQ_FULL, 44),
PMC_E500_COMMON(LOAD_GUARDED_MISS, 45),
PMC_E500_COMMON(STORE_TRANSLATE_WHEN_QUEUE_FULL, 46),
PMC_E500_COMMON(ADDRESS_COLLISION, 47),
PMC_E500_COMMON(DATA_MMU_MISS, 48),
PMC_E500_COMMON(DATA_MMU_BUSY, 49),
PMC_E500_COMMON(PART2_MISALIGNED_CACHE_ACCESS, 50),
PMC_E500_COMMON(LOAD_MISS_DLFB_FULL_CYCLES, 51),
PMC_E500_COMMON(LOAD_MISS_LDQ_FULL_CYCLES, 52),
PMC_E500_COMMON(LOAD_GUARDED_MISS_CYCLES, 53),
PMC_E500_COMMON(STORE_TRANSLATE_WHEN_QUEUE_FULL_CYCLES, 54),
PMC_E500_COMMON(ADDRESS_COLLISION_CYCLES, 55),
PMC_E500_COMMON(DATA_MMU_MISS_CYCLES, 56),
PMC_E500_COMMON(DATA_MMU_BUSY_CYCLES, 57),
PMC_E500_COMMON(PART2_MISALIGNED_CACHE_ACCESS_CYCLES, 58),
PMC_E500_COMMON(INSTR_L1_CACHE_LOCKS, 59),
PMC_E500_COMMON(INSTR_L1_CACHE_RELOADS, 60),
PMC_E500_COMMON(INSTR_L1_CACHE_FETCHES, 61),
PMC_E500_COMMON(INSTR_MMU_TLB4K_RELOADS, 62),
PMC_E500_COMMON(INSTR_MMU_VSP_RELOADS, 63),
PMC_E500_COMMON(DATA_MMU_TLB4K_RELOADS, 64),
PMC_E500_COMMON(DATA_MMU_VSP_RELOADS, 65),
PMC_E500_COMMON(L2MMU_MISSES, 66),
PMC_E500_COMMON(BIU_MASTER_REQUESTS, 67),
PMC_E500_COMMON(BIU_MASTER_INSTR_SIDE_REQUESTS, 68),
PMC_E500_COMMON(BIU_MASTER_DATA_SIDE_REQUESTS, 69),
PMC_E500_COMMON(BIU_MASTER_DATA_SIDE_CASTOUT_REQUESTS, 70),
PMC_E500_COMMON(BIU_MASTER_RETRIES, 71),
PMC_E500_COMMON(SNOOP_REQUESTS, 72),
PMC_E500_COMMON(SNOOP_HITS, 73),
PMC_E500_COMMON(SNOOP_PUSHES, 74),
PMC_E500_COMMON(SNOOP_RETRIES, 75),
PMC_E500_EVENT(DLFB_LOAD_MISS_CYCLES, PMC_PPC_MASK0|PMC_PPC_MASK1,
76, PMC_PPC_E500_ANY),
PMC_E500_EVENT(ILFB_FETCH_MISS_CYCLES, PMC_PPC_MASK0|PMC_PPC_MASK1,
77, PMC_PPC_E500_ANY),
PMC_E500_EVENT(EXT_INPU_INTR_LATENCY_CYCLES, PMC_PPC_MASK0|PMC_PPC_MASK1,
78, PMC_PPC_E500_ANY),
PMC_E500_EVENT(CRIT_INPUT_INTR_LATENCY_CYCLES, PMC_PPC_MASK0|PMC_PPC_MASK1,
79, PMC_PPC_E500_ANY),
PMC_E500_EVENT(EXT_INPUT_INTR_PENDING_LATENCY_CYCLES,
PMC_PPC_MASK0|PMC_PPC_MASK1, 80, PMC_PPC_E500_ANY),
PMC_E500_EVENT(CRIT_INPUT_INTR_PENDING_LATENCY_CYCLES,
PMC_PPC_MASK0|PMC_PPC_MASK1, 81, PMC_PPC_E500_ANY),
PMC_E500_COMMON(PMC0_OVERFLOW, 82),
PMC_E500_COMMON(PMC1_OVERFLOW, 83),
PMC_E500_COMMON(PMC2_OVERFLOW, 84),
PMC_E500_COMMON(PMC3_OVERFLOW, 85),
PMC_E500_COMMON(INTERRUPTS_TAKEN, 86),
PMC_E500_COMMON(EXT_INPUT_INTR_TAKEN, 87),
PMC_E500_COMMON(CRIT_INPUT_INTR_TAKEN, 88),
PMC_E500_COMMON(SYSCALL_TRAP_INTR, 89),
PMC_E500_EVENT(TLB_BIT_TRANSITIONS, PMC_PPC_MASK_ALL, 90,
PMC_PPC_E500V2 | PMC_PPC_E500MC),
PMC_E500MC_ONLY(L2_LINEFILL_BUFFER, 91),
PMC_E500MC_ONLY(LV2_VS, 92),
PMC_E500MC_ONLY(CASTOUTS_RELEASED, 93),
PMC_E500MC_ONLY(INTV_ALLOCATIONS, 94),
PMC_E500MC_ONLY(DLFB_RETRIES_TO_MBAR, 95),
PMC_E500MC_ONLY(STORE_RETRIES, 96),
PMC_E500MC_ONLY(STASH_L1_HITS, 97),
PMC_E500MC_ONLY(STASH_L2_HITS, 98),
PMC_E500MC_ONLY(STASH_BUSY_1, 99),
PMC_E500MC_ONLY(STASH_BUSY_2, 100),
PMC_E500MC_ONLY(STASH_BUSY_3, 101),
PMC_E500MC_ONLY(STASH_HITS, 102),
PMC_E500MC_ONLY(STASH_HIT_DLFB, 103),
PMC_E500MC_ONLY(STASH_REQUESTS, 106),
PMC_E500MC_ONLY(STASH_REQUESTS_L1, 107),
PMC_E500MC_ONLY(STASH_REQUESTS_L2, 108),
PMC_E500MC_ONLY(STALLS_NO_CAQ_OR_COB, 109),
PMC_E500MC_ONLY(L2_CACHE_ACCESSES, 110),
PMC_E500MC_ONLY(L2_HIT_CACHE_ACCESSES, 111),
PMC_E500MC_ONLY(L2_CACHE_DATA_ACCESSES, 112),
PMC_E500MC_ONLY(L2_CACHE_DATA_HITS, 113),
PMC_E500MC_ONLY(L2_CACHE_INSTR_ACCESSES, 114),
PMC_E500MC_ONLY(L2_CACHE_INSTR_HITS, 115),
PMC_E500MC_ONLY(L2_CACHE_ALLOCATIONS, 116),
PMC_E500MC_ONLY(L2_CACHE_DATA_ALLOCATIONS, 117),
PMC_E500MC_ONLY(L2_CACHE_DIRTY_DATA_ALLOCATIONS, 118),
PMC_E500MC_ONLY(L2_CACHE_INSTR_ALLOCATIONS, 119),
PMC_E500MC_ONLY(L2_CACHE_UPDATES, 120),
PMC_E500MC_ONLY(L2_CACHE_CLEAN_UPDATES, 121),
PMC_E500MC_ONLY(L2_CACHE_DIRTY_UPDATES, 122),
PMC_E500MC_ONLY(L2_CACHE_CLEAN_REDUNDANT_UPDATES, 123),
PMC_E500MC_ONLY(L2_CACHE_DIRTY_REDUNDANT_UPDATES, 124),
PMC_E500MC_ONLY(L2_CACHE_LOCKS, 125),
PMC_E500MC_ONLY(L2_CACHE_CASTOUTS, 126),
PMC_E500MC_ONLY(L2_CACHE_DATA_DIRTY_HITS, 127),
PMC_E500MC_ONLY(INSTR_LFB_WENT_HIGH_PRIORITY, 128),
PMC_E500MC_ONLY(SNOOP_THROTTLING_TURNED_ON, 129),
PMC_E500MC_ONLY(L2_CLEAN_LINE_INVALIDATIONS, 130),
PMC_E500MC_ONLY(L2_INCOHERENT_LINE_INVALIDATIONS, 131),
PMC_E500MC_ONLY(L2_COHERENT_LINE_INVALIDATIONS, 132),
PMC_E500MC_ONLY(COHERENT_LOOKUP_MISS_DUE_TO_VALID_BUT_INCOHERENT_MATCHES, 133),
PMC_E500MC_ONLY(IAC1S_DETECTED, 140),
PMC_E500MC_ONLY(IAC2S_DETECTED, 141),
PMC_E500MC_ONLY(DAC1S_DTECTED, 144),
PMC_E500MC_ONLY(DAC2S_DTECTED, 145),
PMC_E500MC_ONLY(DVT0_DETECTED, 148),
PMC_E500MC_ONLY(DVT1_DETECTED, 149),
PMC_E500MC_ONLY(DVT2_DETECTED, 150),
PMC_E500MC_ONLY(DVT3_DETECTED, 151),
PMC_E500MC_ONLY(DVT4_DETECTED, 152),
PMC_E500MC_ONLY(DVT5_DETECTED, 153),
PMC_E500MC_ONLY(DVT6_DETECTED, 154),
PMC_E500MC_ONLY(DVT7_DETECTED, 155),
PMC_E500MC_ONLY(CYCLES_COMPLETION_STALLED_NEXUS_FIFO_FULL, 156),
PMC_E500MC_ONLY(FPU_DOUBLE_PUMP, 160),
PMC_E500MC_ONLY(FPU_FINISH, 161),
PMC_E500MC_ONLY(FPU_DIVIDE_CYCLES, 162),
PMC_E500MC_ONLY(FPU_DENORM_INPUT_CYCLES, 163),
PMC_E500MC_ONLY(FPU_RESULT_STALL_CYCLES, 164),
PMC_E500MC_ONLY(FPU_FPSCR_FULL_STALL, 165),
PMC_E500MC_ONLY(FPU_PIPE_SYNC_STALLS, 166),
PMC_E500MC_ONLY(FPU_INPUT_DATA_STALLS, 167),
PMC_E500MC_ONLY(DECORATED_LOADS, 176),
PMC_E500MC_ONLY(DECORATED_STORES, 177),
PMC_E500MC_ONLY(LOAD_RETRIES, 178),
PMC_E500MC_ONLY(STWCX_SUCCESSES, 179),
PMC_E500MC_ONLY(STWCX_FAILURES, 180),
};
const size_t e500_event_codes_size =
sizeof(e500_event_codes) / sizeof(e500_event_codes[0]);
static pmc_value_t
e500_pmcn_read(unsigned int pmc)
{
switch (pmc) {
case 0:
return mfpmr(PMR_PMC0);
break;
case 1:
return mfpmr(PMR_PMC1);
break;
case 2:
return mfpmr(PMR_PMC2);
break;
case 3:
return mfpmr(PMR_PMC3);
break;
default:
panic("Invalid PMC number: %d\n", pmc);
}
}
static void
e500_pmcn_write(unsigned int pmc, uint32_t val)
{
switch (pmc) {
case 0:
mtpmr(PMR_PMC0, val);
break;
case 1:
mtpmr(PMR_PMC1, val);
break;
case 2:
mtpmr(PMR_PMC2, val);
break;
case 3:
mtpmr(PMR_PMC3, val);
break;
default:
panic("Invalid PMC number: %d\n", pmc);
}
}
static int
e500_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 < E500_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 = e500_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
e500_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 < E500_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);
e500_pmcn_write(ri, v);
return 0;
}
static int
e500_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 < E500_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
e500_start_pmc(int cpu, int ri)
{
uint32_t config;
struct pmc *pm;
struct pmc_hw *phw;
phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
pm = phw->phw_pmc;
config = pm->pm_md.pm_powerpc.pm_powerpc_evsel;
if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
config |= PMLCax_CE;
/* Enable the PMC. */
switch (ri) {
case 0:
mtpmr(PMR_PMLCa0, config);
break;
case 1:
mtpmr(PMR_PMLCa1, config);
break;
case 2:
mtpmr(PMR_PMLCa2, config);
break;
case 3:
mtpmr(PMR_PMLCa3, config);
break;
default:
break;
}
return 0;
}
static int
e500_stop_pmc(int cpu, int ri)
{
struct pmc *pm;
struct pmc_hw *phw;
register_t pmc_pmlc;
phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
pm = phw->phw_pmc;
/*
* Disable the PMCs.
*/
switch (ri) {
case 0:
pmc_pmlc = mfpmr(PMR_PMLCa0);
pmc_pmlc |= PMLCax_FC;
mtpmr(PMR_PMLCa0, pmc_pmlc);
break;
case 1:
pmc_pmlc = mfpmr(PMR_PMLCa1);
pmc_pmlc |= PMLCax_FC;
mtpmr(PMR_PMLCa1, pmc_pmlc);
break;
case 2:
pmc_pmlc = mfpmr(PMR_PMLCa2);
pmc_pmlc |= PMLCax_FC;
mtpmr(PMR_PMLCa2, pmc_pmlc);
break;
case 3:
pmc_pmlc = mfpmr(PMR_PMLCa3);
pmc_pmlc |= PMLCax_FC;
mtpmr(PMR_PMLCa3, pmc_pmlc);
break;
default:
break;
}
return 0;
}
static int
e500_pcpu_init(struct pmc_mdep *md, int cpu)
{
int first_ri, i;
struct pmc_cpu *pc;
struct powerpc_cpu *pac;
struct pmc_hw *phw;
KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
("[powerpc,%d] wrong cpu number %d", __LINE__, cpu));
PMCDBG(MDP,INI,1,"powerpc-init cpu=%d", cpu);
/* Freeze all counters. */
mtpmr(PMR_PMGC0, PMGC_FAC | PMGC_PMIE | PMGC_FCECE);
powerpc_pcpu[cpu] = pac = malloc(sizeof(struct powerpc_cpu), M_PMC,
M_WAITOK|M_ZERO);
pac->pc_ppcpmcs = malloc(sizeof(struct pmc_hw) * E500_MAX_PMCS,
M_PMC, M_WAITOK|M_ZERO);
pac->pc_class = PMC_CLASS_E500;
pc = pmc_pcpu[cpu];
first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC].pcd_ri;
KASSERT(pc != NULL, ("[powerpc,%d] NULL per-cpu pointer", __LINE__));
for (i = 0, phw = pac->pc_ppcpmcs; i < E500_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;
/* Initialize the PMC to stopped */
e500_stop_pmc(cpu, i);
}
/* Unfreeze global register. */
mtpmr(PMR_PMGC0, PMGC_PMIE | PMGC_FCECE);
return 0;
}
static int
e500_pcpu_fini(struct pmc_mdep *md, int cpu)
{
uint32_t pmgc0 = mfpmr(PMR_PMGC0);
pmgc0 |= PMGC_FAC;
mtpmr(PMR_PMGC0, pmgc0);
mtmsr(mfmsr() & ~PSL_PMM);
free(powerpc_pcpu[cpu]->pc_ppcpmcs, M_PMC);
free(powerpc_pcpu[cpu], M_PMC);
return 0;
}
static int
e500_allocate_pmc(int cpu, int ri, struct pmc *pm,
const struct pmc_op_pmcallocate *a)
{
enum pmc_event pe;
uint32_t caps, config, counter;
struct e500_event_code_map *ev;
uint16_t vers;
uint8_t pe_cpu_mask;
KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
KASSERT(ri >= 0 && ri < E500_MAX_PMCS,
("[powerpc,%d] illegal row index %d", __LINE__, ri));
caps = a->pm_caps;
pe = a->pm_ev;
config = PMLCax_FCS | PMLCax_FCU |
PMLCax_FCM1 | PMLCax_FCM1;
if (pe < PMC_EV_E500_FIRST || pe > PMC_EV_E500_LAST)
return (EINVAL);
ev = &e500_event_codes[pe-PMC_EV_E500_FIRST];
if (ev->pe_code == 0)
return (EINVAL);
vers = mfpvr() >> 16;
switch (vers) {
case FSL_E500v1:
pe_cpu_mask = ev->pe_code & PMC_PPC_E500V1;
break;
case FSL_E500v2:
pe_cpu_mask = ev->pe_code & PMC_PPC_E500V2;
break;
case FSL_E500mc:
pe_cpu_mask = ev->pe_code & PMC_PPC_E500MC;
break;
}
if (pe_cpu_mask == 0)
return (EINVAL);
config |= PMLCax_EVENT(ev->pe_code);
counter = ev->pe_counter_mask;
if ((counter & (1 << ri)) == 0)
return (EINVAL);
if (caps & PMC_CAP_SYSTEM)
config &= ~PMLCax_FCS;
if (caps & PMC_CAP_USER)
config &= ~PMLCax_FCU;
if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0)
config &= ~(PMLCax_FCS|PMLCax_FCU);
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
e500_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 < E500_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;
}
static int
e500_intr(int cpu, struct trapframe *tf)
{
int i, error, retval;
uint32_t config;
struct pmc *pm;
struct powerpc_cpu *pac;
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];
config = mfpmr(PMR_PMGC0) & ~PMGC_FAC;
/*
* 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.
*/
for (i = 0; i < E500_MAX_PMCS; i++) {
if ((pm = pac->pc_ppcpmcs[i].phw_pmc) == NULL ||
!PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) {
continue;
}
if (!E500_PMC_HAS_OVERFLOWED(i))
continue;
retval = 1; /* Found an interrupting PMC. */
if (pm->pm_state != PMC_STATE_RUNNING)
continue;
/* Stop the counter if logging fails. */
error = pmc_process_interrupt(cpu, PMC_HR, pm, tf,
TRAPF_USERMODE(tf));
if (error != 0)
e500_stop_pmc(cpu, i);
/* reload count. */
e500_write_pmc(cpu, i, pm->pm_sc.pm_reloadcount);
}
atomic_add_int(retval ? &pmc_stats.pm_intr_processed :
&pmc_stats.pm_intr_ignored, 1);
/* Re-enable PERF exceptions. */
if (retval)
mtpmr(PMR_PMGC0, config | PMGC_PMIE);
return (retval);
}
int
pmc_e500_initialize(struct pmc_mdep *pmc_mdep)
{
struct pmc_classdep *pcd;
pmc_mdep->pmd_cputype = PMC_CPU_PPC_E500;
pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC];
pcd->pcd_caps = POWERPC_PMC_CAPS;
pcd->pcd_class = PMC_CLASS_E500;
pcd->pcd_num = E500_MAX_PMCS;
pcd->pcd_ri = pmc_mdep->pmd_npmc;
pcd->pcd_width = 32;
pcd->pcd_allocate_pmc = e500_allocate_pmc;
pcd->pcd_config_pmc = e500_config_pmc;
pcd->pcd_pcpu_fini = e500_pcpu_fini;
pcd->pcd_pcpu_init = e500_pcpu_init;
pcd->pcd_describe = powerpc_describe;
pcd->pcd_get_config = powerpc_get_config;
pcd->pcd_read_pmc = e500_read_pmc;
pcd->pcd_release_pmc = e500_release_pmc;
pcd->pcd_start_pmc = e500_start_pmc;
pcd->pcd_stop_pmc = e500_stop_pmc;
pcd->pcd_write_pmc = e500_write_pmc;
pmc_mdep->pmd_npmc += E500_MAX_PMCS;
pmc_mdep->pmd_intr = e500_intr;
return (0);
}

View File

@ -567,7 +567,7 @@ mpc7xxx_pcpu_init(struct pmc_mdep *md, int cpu)
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;
first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC].pcd_ri;
KASSERT(pc != NULL, ("[powerpc,%d] NULL per-cpu pointer", __LINE__));
for (i = 0, phw = pac->pc_ppcpmcs; i < MPC7XXX_MAX_PMCS; i++, phw++) {
@ -729,7 +729,7 @@ pmc_mpc7xxx_initialize(struct pmc_mdep *pmc_mdep)
pmc_mdep->pmd_cputype = PMC_CPU_PPC_7450;
pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_PPC7450];
pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC];
pcd->pcd_caps = POWERPC_PMC_CAPS;
pcd->pcd_class = PMC_CLASS_PPC7450;
pcd->pcd_num = MPC7XXX_MAX_PMCS;

View File

@ -175,6 +175,11 @@ pmc_md_initialize()
case IBM970MP:
error = pmc_ppc970_initialize(pmc_mdep);
break;
case FSL_E500v1:
case FSL_E500v2:
case FSL_E500mc:
error = pmc_e500_initialize(pmc_mdep);
break;
default:
error = -1;
break;

View File

@ -51,6 +51,7 @@ struct powerpc_cpu {
extern struct powerpc_cpu **powerpc_pcpu;
extern int pmc_e500_initialize(struct pmc_mdep *pmc_mdep);
extern int pmc_mpc7xxx_initialize(struct pmc_mdep *pmc_mdep);
extern int pmc_ppc970_initialize(struct pmc_mdep *pmc_mdep);

View File

@ -555,7 +555,7 @@ ppc970_pcpu_init(struct pmc_mdep *md, int cpu)
pac->pc_class = PMC_CLASS_PPC970;
pc = pmc_pcpu[cpu];
first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_PPC970].pcd_ri;
first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC].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++) {
@ -661,7 +661,7 @@ pmc_ppc970_initialize(struct pmc_mdep *pmc_mdep)
pmc_mdep->pmd_cputype = PMC_CPU_PPC_970;
pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_PPC970];
pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC];
pcd->pcd_caps = POWERPC_PMC_CAPS;
pcd->pcd_class = PMC_CLASS_PPC970;
pcd->pcd_num = PPC970_MAX_PMCS;

View File

@ -5379,6 +5379,168 @@ __PMC_EV_ALIAS("IMPC_C0H_TRK_REQUEST.ALL", UCP_EVENT_84H_01H)
#define PMC_EV_PPC970_FIRST PMC_EV_PPC970_INSTR_COMPLETED
#define PMC_EV_PPC970_LAST PMC_EV_PPC970_ADDER
#define __PMC_EV_E500() \
__PMC_EV(E500, CYCLES) \
__PMC_EV(E500, INSTR_COMPLETED) \
__PMC_EV(E500, UOPS_COMPLETED) \
__PMC_EV(E500, INSTR_FETCHED) \
__PMC_EV(E500, UOPS_DECODED) \
__PMC_EV(E500, PM_EVENT_TRANSITIONS) \
__PMC_EV(E500, PM_EVENT_CYCLES) \
__PMC_EV(E500, BRANCH_INSTRS_COMPLETED) \
__PMC_EV(E500, LOAD_UOPS_COMPLETED) \
__PMC_EV(E500, STORE_UOPS_COMPLETED) \
__PMC_EV(E500, CQ_REDIRECTS) \
__PMC_EV(E500, BRANCHES_FINISHED) \
__PMC_EV(E500, TAKEN_BRANCHES_FINISHED) \
__PMC_EV(E500, FINISHED_UNCOND_BRANCHES_MISS_BTB) \
__PMC_EV(E500, BRANCH_MISPRED) \
__PMC_EV(E500, BTB_BRANCH_MISPRED_FROM_DIRECTION) \
__PMC_EV(E500, BTB_HITS_PSEUDO_HITS) \
__PMC_EV(E500, CYCLES_DECODE_STALLED) \
__PMC_EV(E500, CYCLES_ISSUE_STALLED) \
__PMC_EV(E500, CYCLES_BRANCH_ISSUE_STALLED) \
__PMC_EV(E500, CYCLES_SU1_SCHED_STALLED) \
__PMC_EV(E500, CYCLES_SU2_SCHED_STALLED) \
__PMC_EV(E500, CYCLES_MU_SCHED_STALLED) \
__PMC_EV(E500, CYCLES_LRU_SCHED_STALLED) \
__PMC_EV(E500, CYCLES_BU_SCHED_STALLED) \
__PMC_EV(E500, TOTAL_TRANSLATED) \
__PMC_EV(E500, LOADS_TRANSLATED) \
__PMC_EV(E500, STORES_TRANSLATED) \
__PMC_EV(E500, TOUCHES_TRANSLATED) \
__PMC_EV(E500, CACHEOPS_TRANSLATED) \
__PMC_EV(E500, CACHE_INHIBITED_ACCESS_TRANSLATED) \
__PMC_EV(E500, GUARDED_LOADS_TRANSLATED) \
__PMC_EV(E500, WRITE_THROUGH_STORES_TRANSLATED) \
__PMC_EV(E500, MISALIGNED_LOAD_STORE_ACCESS_TRANSLATED) \
__PMC_EV(E500, TOTAL_ALLOCATED_TO_DLFB) \
__PMC_EV(E500, LOADS_TRANSLATED_ALLOCATED_TO_DLFB) \
__PMC_EV(E500, STORES_COMPLETED_ALLOCATED_TO_DLFB) \
__PMC_EV(E500, TOUCHES_TRANSLATED_ALLOCATED_TO_DLFB) \
__PMC_EV(E500, STORES_COMPLETED) \
__PMC_EV(E500, DATA_L1_CACHE_LOCKS) \
__PMC_EV(E500, DATA_L1_CACHE_RELOADS) \
__PMC_EV(E500, DATA_L1_CACHE_CASTOUTS) \
__PMC_EV(E500, LOAD_MISS_DLFB_FULL) \
__PMC_EV(E500, LOAD_MISS_LDQ_FULL) \
__PMC_EV(E500, LOAD_GUARDED_MISS) \
__PMC_EV(E500, STORE_TRANSLATE_WHEN_QUEUE_FULL) \
__PMC_EV(E500, ADDRESS_COLLISION) \
__PMC_EV(E500, DATA_MMU_MISS) \
__PMC_EV(E500, DATA_MMU_BUSY) \
__PMC_EV(E500, PART2_MISALIGNED_CACHE_ACCESS) \
__PMC_EV(E500, LOAD_MISS_DLFB_FULL_CYCLES) \
__PMC_EV(E500, LOAD_MISS_LDQ_FULL_CYCLES) \
__PMC_EV(E500, LOAD_GUARDED_MISS_CYCLES) \
__PMC_EV(E500, STORE_TRANSLATE_WHEN_QUEUE_FULL_CYCLES) \
__PMC_EV(E500, ADDRESS_COLLISION_CYCLES) \
__PMC_EV(E500, DATA_MMU_MISS_CYCLES) \
__PMC_EV(E500, DATA_MMU_BUSY_CYCLES) \
__PMC_EV(E500, PART2_MISALIGNED_CACHE_ACCESS_CYCLES) \
__PMC_EV(E500, INSTR_L1_CACHE_LOCKS) \
__PMC_EV(E500, INSTR_L1_CACHE_RELOADS) \
__PMC_EV(E500, INSTR_L1_CACHE_FETCHES) \
__PMC_EV(E500, INSTR_MMU_TLB4K_RELOADS) \
__PMC_EV(E500, INSTR_MMU_VSP_RELOADS) \
__PMC_EV(E500, DATA_MMU_TLB4K_RELOADS) \
__PMC_EV(E500, DATA_MMU_VSP_RELOADS) \
__PMC_EV(E500, L2MMU_MISSES) \
__PMC_EV(E500, BIU_MASTER_REQUESTS) \
__PMC_EV(E500, BIU_MASTER_INSTR_SIDE_REQUESTS) \
__PMC_EV(E500, BIU_MASTER_DATA_SIDE_REQUESTS) \
__PMC_EV(E500, BIU_MASTER_DATA_SIDE_CASTOUT_REQUESTS) \
__PMC_EV(E500, BIU_MASTER_RETRIES) \
__PMC_EV(E500, SNOOP_REQUESTS) \
__PMC_EV(E500, SNOOP_HITS) \
__PMC_EV(E500, SNOOP_PUSHES) \
__PMC_EV(E500, SNOOP_RETRIES) \
__PMC_EV(E500, DLFB_LOAD_MISS_CYCLES) \
__PMC_EV(E500, ILFB_FETCH_MISS_CYCLES) \
__PMC_EV(E500, EXT_INPU_INTR_LATENCY_CYCLES) \
__PMC_EV(E500, CRIT_INPUT_INTR_LATENCY_CYCLES) \
__PMC_EV(E500, EXT_INPUT_INTR_PENDING_LATENCY_CYCLES) \
__PMC_EV(E500, CRIT_INPUT_INTR_PENDING_LATENCY_CYCLES) \
__PMC_EV(E500, PMC0_OVERFLOW) \
__PMC_EV(E500, PMC1_OVERFLOW) \
__PMC_EV(E500, PMC2_OVERFLOW) \
__PMC_EV(E500, PMC3_OVERFLOW) \
__PMC_EV(E500, INTERRUPTS_TAKEN) \
__PMC_EV(E500, EXT_INPUT_INTR_TAKEN) \
__PMC_EV(E500, CRIT_INPUT_INTR_TAKEN) \
__PMC_EV(E500, SYSCALL_TRAP_INTR) \
__PMC_EV(E500, TLB_BIT_TRANSITIONS) \
__PMC_EV(E500, L2_LINEFILL_BUFFER) \
__PMC_EV(E500, LV2_VS) \
__PMC_EV(E500, CASTOUTS_RELEASED) \
__PMC_EV(E500, INTV_ALLOCATIONS) \
__PMC_EV(E500, DLFB_RETRIES_TO_MBAR) \
__PMC_EV(E500, STORE_RETRIES) \
__PMC_EV(E500, STASH_L1_HITS) \
__PMC_EV(E500, STASH_L2_HITS) \
__PMC_EV(E500, STASH_BUSY_1) \
__PMC_EV(E500, STASH_BUSY_2) \
__PMC_EV(E500, STASH_BUSY_3) \
__PMC_EV(E500, STASH_HITS) \
__PMC_EV(E500, STASH_HIT_DLFB) \
__PMC_EV(E500, STASH_REQUESTS) \
__PMC_EV(E500, STASH_REQUESTS_L1) \
__PMC_EV(E500, STASH_REQUESTS_L2) \
__PMC_EV(E500, STALLS_NO_CAQ_OR_COB) \
__PMC_EV(E500, L2_CACHE_ACCESSES) \
__PMC_EV(E500, L2_HIT_CACHE_ACCESSES) \
__PMC_EV(E500, L2_CACHE_DATA_ACCESSES) \
__PMC_EV(E500, L2_CACHE_DATA_HITS) \
__PMC_EV(E500, L2_CACHE_INSTR_ACCESSES) \
__PMC_EV(E500, L2_CACHE_INSTR_HITS) \
__PMC_EV(E500, L2_CACHE_ALLOCATIONS) \
__PMC_EV(E500, L2_CACHE_DATA_ALLOCATIONS) \
__PMC_EV(E500, L2_CACHE_DIRTY_DATA_ALLOCATIONS) \
__PMC_EV(E500, L2_CACHE_INSTR_ALLOCATIONS) \
__PMC_EV(E500, L2_CACHE_UPDATES) \
__PMC_EV(E500, L2_CACHE_CLEAN_UPDATES) \
__PMC_EV(E500, L2_CACHE_DIRTY_UPDATES) \
__PMC_EV(E500, L2_CACHE_CLEAN_REDUNDANT_UPDATES) \
__PMC_EV(E500, L2_CACHE_DIRTY_REDUNDANT_UPDATES) \
__PMC_EV(E500, L2_CACHE_LOCKS) \
__PMC_EV(E500, L2_CACHE_CASTOUTS) \
__PMC_EV(E500, L2_CACHE_DATA_DIRTY_HITS) \
__PMC_EV(E500, INSTR_LFB_WENT_HIGH_PRIORITY) \
__PMC_EV(E500, SNOOP_THROTTLING_TURNED_ON) \
__PMC_EV(E500, L2_CLEAN_LINE_INVALIDATIONS) \
__PMC_EV(E500, L2_INCOHERENT_LINE_INVALIDATIONS) \
__PMC_EV(E500, L2_COHERENT_LINE_INVALIDATIONS) \
__PMC_EV(E500, COHERENT_LOOKUP_MISS_DUE_TO_VALID_BUT_INCOHERENT_MATCHES) \
__PMC_EV(E500, IAC1S_DETECTED) \
__PMC_EV(E500, IAC2S_DETECTED) \
__PMC_EV(E500, DAC1S_DTECTED) \
__PMC_EV(E500, DAC2S_DTECTED) \
__PMC_EV(E500, DVT0_DETECTED) \
__PMC_EV(E500, DVT1_DETECTED) \
__PMC_EV(E500, DVT2_DETECTED) \
__PMC_EV(E500, DVT3_DETECTED) \
__PMC_EV(E500, DVT4_DETECTED) \
__PMC_EV(E500, DVT5_DETECTED) \
__PMC_EV(E500, DVT6_DETECTED) \
__PMC_EV(E500, DVT7_DETECTED) \
__PMC_EV(E500, CYCLES_COMPLETION_STALLED_NEXUS_FIFO_FULL) \
__PMC_EV(E500, FPU_DOUBLE_PUMP) \
__PMC_EV(E500, FPU_FINISH) \
__PMC_EV(E500, FPU_DIVIDE_CYCLES) \
__PMC_EV(E500, FPU_DENORM_INPUT_CYCLES) \
__PMC_EV(E500, FPU_RESULT_STALL_CYCLES) \
__PMC_EV(E500, FPU_FPSCR_FULL_STALL) \
__PMC_EV(E500, FPU_PIPE_SYNC_STALLS) \
__PMC_EV(E500, FPU_INPUT_DATA_STALLS) \
__PMC_EV(E500, DECORATED_LOADS) \
__PMC_EV(E500, DECORATED_STORES) \
__PMC_EV(E500, LOAD_RETRIES) \
__PMC_EV(E500, STWCX_SUCCESSES) \
__PMC_EV(E500, STWCX_FAILURES) \
#define PMC_EV_E500_FIRST PMC_EV_E500_CYCLES
#define PMC_EV_E500_LAST PMC_EV_E500_STWCX_FAILURES
/*
* All known PMC events.
*
@ -5400,6 +5562,9 @@ __PMC_EV_ALIAS("IMPC_C0H_TRK_REQUEST.ALL", UCP_EVENT_84H_01H)
* 0x11300 0x00FF MIPS 24K events
* 0x11400 0x00FF Octeon events
* 0x11500 0x00FF MIPS 74K events
* 0x13000 0x00FF MPC7450 events
* 0x13100 0x00FF IBM PPC970 events
* 0x13300 0x00FF Freescale e500 events
* 0x14000 0x0100 ARMv7 events
* 0x20000 0x1000 Software events
*/
@ -5436,6 +5601,8 @@ __PMC_EV_ALIAS("IMPC_C0H_TRK_REQUEST.ALL", UCP_EVENT_84H_01H)
__PMC_EV_PPC7450() \
__PMC_EV_BLOCK(PPC970, 0x13100) \
__PMC_EV_PPC970() \
__PMC_EV_BLOCK(E500, 0x13300) \
__PMC_EV_E500() \
__PMC_EV_BLOCK(ARMV7, 0x14000) \
__PMC_EV_ARMV7() \

View File

@ -25,7 +25,7 @@ SRCS+= device_if.h bus_if.h
.endif
.if ${MACHINE_CPUARCH} == "powerpc"
SRCS+= hwpmc_powerpc.c hwpmc_mpc7xxx.c hwpmc_ppc970.c
SRCS+= hwpmc_powerpc.c hwpmc_e500.c hwpmc_mpc7xxx.c hwpmc_ppc970.c
.endif
.if ${MACHINE_CPUARCH} == "sparc64"

View File

@ -32,6 +32,8 @@
* Interrupts are dispatched to here from locore asm
*/
#include "opt_hwpmc_hooks.h"
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__FBSDID("$FreeBSD$");
@ -45,6 +47,9 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#ifdef HWPMC_HOOKS
#include <sys/pmckern.h>
#endif
#include <sys/proc.h>
#include <sys/smp.h>
#include <sys/unistd.h>
@ -67,6 +72,9 @@ void powerpc_decr_interrupt(struct trapframe *);
void powerpc_extr_interrupt(struct trapframe *);
void powerpc_crit_interrupt(struct trapframe *);
void powerpc_mchk_interrupt(struct trapframe *);
#ifdef HWPMC_HOOKS
void powerpc_pmc_interrupt(struct trapframe *framep);
#endif
static void dump_frame(struct trapframe *framep);
@ -142,3 +150,20 @@ powerpc_extr_interrupt(struct trapframe *framep)
critical_exit();
framep->srr1 &= ~PSL_WE;
}
#ifdef HWPMC_HOOKS
/*
* Performance Counter interrupt routine
*/
void
powerpc_pmc_interrupt(struct trapframe *framep)
{
critical_enter();
KASSERT(pmc_intr != NULL, ("Performance exception, but no handler!"));
(*pmc_intr)(PCPU_GET(cpuid), framep);
critical_exit();
if (pmc_hook && (PCPU_GET(curthread)->td_pflags & TDP_CALLCHAIN))
pmc_hook(PCPU_GET(curthread), PMC_FN_USER_CALLCHAIN, framep);
}
#endif

View File

@ -28,6 +28,8 @@
#include "assym.s"
#include "opt_hwpmc_hooks.h"
#include <machine/asm.h>
#include <machine/hid.h>
#include <machine/param.h>

View File

@ -83,6 +83,7 @@ __FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_ddb.h"
#include "opt_hwpmc_hooks.h"
#include "opt_kstack_pages.h"
#include "opt_platform.h"
@ -208,6 +209,9 @@ extern void *int_watchdog;
extern void *int_data_tlb_error;
extern void *int_inst_tlb_error;
extern void *int_debug;
#ifdef HWPMC_HOOKS
extern void *int_performance_counter;
#endif
#define SET_TRAP(ivor, handler) \
KASSERT(((uintptr_t)(&handler) & ~0xffffUL) == \
@ -235,6 +239,9 @@ ivor_setup(void)
SET_TRAP(SPR_IVOR13, int_data_tlb_error);
SET_TRAP(SPR_IVOR14, int_inst_tlb_error);
SET_TRAP(SPR_IVOR15, int_debug);
#ifdef HWPMC_HOOKS
SET_TRAP(SPR_IVOR35, int_performance_counter);
#endif
}
static void

View File

@ -497,6 +497,19 @@ INTERRUPT(int_watchdog)
b trap_common
#ifdef HWPMC_HOOKS
/*****************************************************************************
* PMC Interrupt
****************************************************************************/
INTERRUPT(int_performance_counter)
STANDARD_PROLOG(SPR_SPRG3, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
FRAME_SETUP(SPR_SPRG3, PC_TEMPSAVE, EXC_PERF)
addi %r3, %r1, 8
bl CNAME(powerpc_pmc_interrupt)
b trapexit
#endif
/*****************************************************************************
* Data TLB miss interrupt
*

View File

@ -7,9 +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
#define PMC_MDEP_CLASS_INDEX_POWERPC 1
union pmc_md_op_pmcallocate {
uint64_t __pad[4];
@ -19,6 +17,60 @@ union pmc_md_op_pmcallocate {
#define PMCLOG_READADDR PMCLOG_READ32
#define PMCLOG_EMITADDR PMCLOG_EMIT32
#define mtpmr(reg, val) \
__asm __volatile("mtpmr %0,%1" : : "K"(reg), "r"(val))
#define mfpmr(reg) \
( { register_t val; \
__asm __volatile("mfpmr %0,%1" : "=r"(val) : "K"(reg)); \
val; } )
#define PMR_PMC0 16
#define PMR_PMC1 17
#define PMR_PMC2 18
#define PMR_PMC3 19
#define PMR_PMLCa0 144
#define PMLCax_FC 0x80000000
#define PMLCax_FCS 0x40000000
#define PMLCax_FCU 0x20000000
#define PMLCax_FCM1 0x10000000
#define PMLCax_FCM0 0x08000000
#define PMLCax_CE 0x04000000
#define PMLCax_EVENT(x) ((x) << 16)
#define PMLCax_FCGS1 0x00000002
#define PMLCax_FCGS0 0x00000001
#define PMR_PMLCa1 145
#define PMR_PMLCa2 146
#define PMR_PMLCa3 147
#define PMR_PMLCb0 272
#define PMLCbx_TRIGONCTL(x) ((x) << 28)
#define PMLCbx_TRIGOFFCTL(x) ((x) << 24)
#define PMLCbx_PMCC 0x00800000
#define PMLCbx_PMP(x) ((x) << 13)
#define PMLCbx_TREHMUL(x) ((x) << 8)
#define PMLCbx_TRESHOLD(x) ((x) << 0)
#define PMR_PMLCb1 273
#define PMR_PMLCb2 274
#define PMR_PMLCb3 275
#define PMR_PMGC0 400
#define PMGC_FAC 0x80000000
#define PMGC_PMIE 0x40000000
#define PMGC_FCECE 0x20000000
#define PMGC_TBSEL(x) ((x) << 11)
#define PMGC_TBEE 0x00000100
#define PMR_UPMC0 0
#define PMR_UPMC1 1
#define PMR_UPMC2 2
#define PMR_UPMC3 3
#define PMR_UPMLCa0 128
#define PMR_UPMLCa1 129
#define PMR_UPMLCa2 130
#define PMR_UPMLCa3 131
#define PMR_UPMLCb0 256
#define PMR_UPMLCb1 257
#define PMR_UPMLCb2 258
#define PMR_UPMLCb3 259
#define PMR_UPMGC0 384
#if _KERNEL
struct pmc_md_powerpc_pmc {