2013-04-25 23:28:28 +04:00
/*
* Performance counter support for POWER8 processors .
*
* Copyright 2009 Paul Mackerras , IBM Corporation .
* Copyright 2013 Michael Ellerman , IBM Corporation .
*
* 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 .
*/
2014-03-14 09:00:29 +04:00
# define pr_fmt(fmt) "power8-pmu: " fmt
2016-06-26 20:37:04 +03:00
# include "isa207-common.h"
2013-04-25 23:28:28 +04:00
/*
* Some power8 event codes .
*/
2016-01-12 01:55:26 +03:00
# define EVENT(_name, _code) _name = _code,
enum {
# include "power8-events-list.h"
} ;
2014-01-24 08:50:51 +04:00
2016-01-12 01:55:26 +03:00
# undef EVENT
2013-04-25 23:28:28 +04:00
2013-04-22 23:42:43 +04:00
/* MMCRA IFM bits - POWER8 */
# define POWER8_MMCRA_IFM1 0x0000000040000000UL
# define POWER8_MMCRA_IFM2 0x0000000080000000UL
# define POWER8_MMCRA_IFM3 0x00000000C0000000UL
2018-05-08 08:00:24 +03:00
/*
* Raw event encoding for PowerISA v2 .07 ( Power8 ) :
*
* 60 56 52 48 44 40 36 32
* | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - |
* | | [ ] [ thresh_cmp ] [ thresh_ctl ]
* | | | |
* | | * - IFM ( Linux ) thresh start / stop OR FAB match - *
* | * - BHRB ( Linux )
* * - EBB ( Linux )
*
* 28 24 20 16 12 8 4 0
* | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - |
* [ ] [ sample ] [ cache ] [ pmc ] [ unit ] c m [ pmcxsel ]
* | | | | |
* | | | | * - mark
* | | * - L1 / L2 / L3 cache_sel |
* | | |
* | * - sampling mode for marked events * - combine
* |
* * - thresh_sel
*
* Below uses IBM bit numbering .
*
* MMCR1 [ x : y ] = unit ( PMCxUNIT )
* MMCR1 [ x ] = combine ( PMCxCOMB )
*
* if pmc = = 3 and unit = = 0 and pmcxsel [ 0 : 6 ] = = 0 b0101011
* # PM_MRK_FAB_RSP_MATCH
* MMCR1 [ 20 : 27 ] = thresh_ctl ( FAB_CRESP_MATCH / FAB_TYPE_MATCH )
* else if pmc = = 4 and unit = = 0xf and pmcxsel [ 0 : 6 ] = = 0 b0101001
* # PM_MRK_FAB_RSP_MATCH_CYC
* MMCR1 [ 20 : 27 ] = thresh_ctl ( FAB_CRESP_MATCH / FAB_TYPE_MATCH )
* else
* MMCRA [ 48 : 55 ] = thresh_ctl ( THRESH START / END )
*
* if thresh_sel :
* MMCRA [ 45 : 47 ] = thresh_sel
*
* if thresh_cmp :
* MMCRA [ 22 : 24 ] = thresh_cmp [ 0 : 2 ]
* MMCRA [ 25 : 31 ] = thresh_cmp [ 3 : 9 ]
*
* if unit = = 6 or unit = = 7
* MMCRC [ 53 : 55 ] = cache_sel [ 1 : 3 ] ( L2EVENT_SEL )
* else if unit = = 8 or unit = = 9 :
* if cache_sel [ 0 ] = = 0 : # L3 bank
* MMCRC [ 47 : 49 ] = cache_sel [ 1 : 3 ] ( L3EVENT_SEL0 )
* else if cache_sel [ 0 ] = = 1 :
* MMCRC [ 50 : 51 ] = cache_sel [ 2 : 3 ] ( L3EVENT_SEL1 )
* else if cache_sel [ 1 ] : # L1 event
* MMCR1 [ 16 ] = cache_sel [ 2 ]
* MMCR1 [ 17 ] = cache_sel [ 3 ]
*
* if mark :
* MMCRA [ 63 ] = 1 ( SAMPLE_ENABLE )
* MMCRA [ 57 : 59 ] = sample [ 0 : 2 ] ( RAND_SAMP_ELIG )
* MMCRA [ 61 : 62 ] = sample [ 3 : 4 ] ( RAND_SAMP_MODE )
*
* if EBB and BHRB :
* MMCRA [ 32 : 33 ] = IFM
*
*/
2016-12-02 03:34:59 +03:00
/* PowerISA v2.07 format attribute structure*/
extern struct attribute_group isa207_pmu_format_group ;
2013-04-25 23:28:28 +04:00
/* Table of alternatives, sorted by column 0 */
static const unsigned int event_alternatives [ ] [ MAX_ALT ] = {
2016-04-21 13:16:34 +03:00
{ PM_MRK_ST_CMPL , PM_MRK_ST_CMPL_ALT } ,
{ PM_BR_MRK_2PATH , PM_BR_MRK_2PATH_ALT } ,
{ PM_L3_CO_MEPF , PM_L3_CO_MEPF_ALT } ,
{ PM_MRK_DATA_FROM_L2MISS , PM_MRK_DATA_FROM_L2MISS_ALT } ,
{ PM_CMPLU_STALL_ALT , PM_CMPLU_STALL } ,
{ PM_BR_2PATH , PM_BR_2PATH_ALT } ,
{ PM_INST_DISP , PM_INST_DISP_ALT } ,
{ PM_RUN_CYC_ALT , PM_RUN_CYC } ,
{ PM_MRK_FILT_MATCH , PM_MRK_FILT_MATCH_ALT } ,
{ PM_LD_MISS_L1 , PM_LD_MISS_L1_ALT } ,
{ PM_RUN_INST_CMPL_ALT , PM_RUN_INST_CMPL } ,
2013-04-25 23:28:28 +04:00
} ;
static int power8_get_alternatives ( u64 event , unsigned int flags , u64 alt [ ] )
{
2017-07-31 11:02:41 +03:00
int num_alt = 0 ;
2013-04-25 23:28:28 +04:00
2017-07-31 11:02:41 +03:00
num_alt = isa207_get_alternatives ( event , alt ,
ARRAY_SIZE ( event_alternatives ) , flags ,
event_alternatives ) ;
2013-04-25 23:28:28 +04:00
return num_alt ;
}
2016-01-12 01:55:26 +03:00
GENERIC_EVENT_ATTR ( cpu - cycles , PM_CYC ) ;
GENERIC_EVENT_ATTR ( stalled - cycles - frontend , PM_GCT_NOSLOT_CYC ) ;
GENERIC_EVENT_ATTR ( stalled - cycles - backend , PM_CMPLU_STALL ) ;
GENERIC_EVENT_ATTR ( instructions , PM_INST_CMPL ) ;
GENERIC_EVENT_ATTR ( branch - instructions , PM_BRU_FIN ) ;
GENERIC_EVENT_ATTR ( branch - misses , PM_BR_MPRED_CMPL ) ;
GENERIC_EVENT_ATTR ( cache - references , PM_LD_REF_L1 ) ;
GENERIC_EVENT_ATTR ( cache - misses , PM_LD_MISS_L1 ) ;
2017-04-11 04:51:10 +03:00
GENERIC_EVENT_ATTR ( mem_access , MEM_ACCESS ) ;
2016-01-12 01:55:26 +03:00
CACHE_EVENT_ATTR ( L1 - dcache - load - misses , PM_LD_MISS_L1 ) ;
CACHE_EVENT_ATTR ( L1 - dcache - loads , PM_LD_REF_L1 ) ;
CACHE_EVENT_ATTR ( L1 - dcache - prefetches , PM_L1_PREF ) ;
CACHE_EVENT_ATTR ( L1 - dcache - store - misses , PM_ST_MISS_L1 ) ;
CACHE_EVENT_ATTR ( L1 - icache - load - misses , PM_L1_ICACHE_MISS ) ;
CACHE_EVENT_ATTR ( L1 - icache - loads , PM_INST_FROM_L1 ) ;
CACHE_EVENT_ATTR ( L1 - icache - prefetches , PM_IC_PREF_WRITE ) ;
CACHE_EVENT_ATTR ( LLC - load - misses , PM_DATA_FROM_L3MISS ) ;
CACHE_EVENT_ATTR ( LLC - loads , PM_DATA_FROM_L3 ) ;
CACHE_EVENT_ATTR ( LLC - prefetches , PM_L3_PREF_ALL ) ;
CACHE_EVENT_ATTR ( LLC - store - misses , PM_L2_ST_MISS ) ;
CACHE_EVENT_ATTR ( LLC - stores , PM_L2_ST ) ;
CACHE_EVENT_ATTR ( branch - load - misses , PM_BR_MPRED_CMPL ) ;
CACHE_EVENT_ATTR ( branch - loads , PM_BRU_FIN ) ;
CACHE_EVENT_ATTR ( dTLB - load - misses , PM_DTLB_MISS ) ;
CACHE_EVENT_ATTR ( iTLB - load - misses , PM_ITLB_MISS ) ;
static struct attribute * power8_events_attr [ ] = {
GENERIC_EVENT_PTR ( PM_CYC ) ,
GENERIC_EVENT_PTR ( PM_GCT_NOSLOT_CYC ) ,
GENERIC_EVENT_PTR ( PM_CMPLU_STALL ) ,
GENERIC_EVENT_PTR ( PM_INST_CMPL ) ,
GENERIC_EVENT_PTR ( PM_BRU_FIN ) ,
GENERIC_EVENT_PTR ( PM_BR_MPRED_CMPL ) ,
GENERIC_EVENT_PTR ( PM_LD_REF_L1 ) ,
GENERIC_EVENT_PTR ( PM_LD_MISS_L1 ) ,
2017-04-11 04:51:10 +03:00
GENERIC_EVENT_PTR ( MEM_ACCESS ) ,
2016-01-12 01:55:26 +03:00
CACHE_EVENT_PTR ( PM_LD_MISS_L1 ) ,
CACHE_EVENT_PTR ( PM_LD_REF_L1 ) ,
CACHE_EVENT_PTR ( PM_L1_PREF ) ,
CACHE_EVENT_PTR ( PM_ST_MISS_L1 ) ,
CACHE_EVENT_PTR ( PM_L1_ICACHE_MISS ) ,
CACHE_EVENT_PTR ( PM_INST_FROM_L1 ) ,
CACHE_EVENT_PTR ( PM_IC_PREF_WRITE ) ,
CACHE_EVENT_PTR ( PM_DATA_FROM_L3MISS ) ,
CACHE_EVENT_PTR ( PM_DATA_FROM_L3 ) ,
CACHE_EVENT_PTR ( PM_L3_PREF_ALL ) ,
CACHE_EVENT_PTR ( PM_L2_ST_MISS ) ,
CACHE_EVENT_PTR ( PM_L2_ST ) ,
CACHE_EVENT_PTR ( PM_BR_MPRED_CMPL ) ,
CACHE_EVENT_PTR ( PM_BRU_FIN ) ,
CACHE_EVENT_PTR ( PM_DTLB_MISS ) ,
CACHE_EVENT_PTR ( PM_ITLB_MISS ) ,
NULL
} ;
static struct attribute_group power8_pmu_events_group = {
. name = " events " ,
. attrs = power8_events_attr ,
} ;
2013-04-25 23:28:28 +04:00
static const struct attribute_group * power8_pmu_attr_groups [ ] = {
2016-12-02 03:34:59 +03:00
& isa207_pmu_format_group ,
2016-01-12 01:55:26 +03:00
& power8_pmu_events_group ,
2013-04-25 23:28:28 +04:00
NULL ,
} ;
static int power8_generic_events [ ] = {
[ PERF_COUNT_HW_CPU_CYCLES ] = PM_CYC ,
[ PERF_COUNT_HW_STALLED_CYCLES_FRONTEND ] = PM_GCT_NOSLOT_CYC ,
[ PERF_COUNT_HW_STALLED_CYCLES_BACKEND ] = PM_CMPLU_STALL ,
[ PERF_COUNT_HW_INSTRUCTIONS ] = PM_INST_CMPL ,
[ PERF_COUNT_HW_BRANCH_INSTRUCTIONS ] = PM_BRU_FIN ,
[ PERF_COUNT_HW_BRANCH_MISSES ] = PM_BR_MPRED_CMPL ,
2014-01-24 08:50:51 +04:00
[ PERF_COUNT_HW_CACHE_REFERENCES ] = PM_LD_REF_L1 ,
[ PERF_COUNT_HW_CACHE_MISSES ] = PM_LD_MISS_L1 ,
2013-04-25 23:28:28 +04:00
} ;
2013-04-22 23:42:43 +04:00
static u64 power8_bhrb_filter_map ( u64 branch_sample_type )
{
u64 pmu_bhrb_filter = 0 ;
2013-06-10 09:53:28 +04:00
/* BHRB and regular PMU events share the same privilege state
2013-04-22 23:42:43 +04:00
* filter configuration . BHRB is always recorded along with a
2013-06-10 09:53:28 +04:00
* regular PMU event . As the privilege state filter is handled
* in the basic PMC configuration of the accompanying regular
* PMU event , we ignore any separate BHRB specific request .
2013-04-22 23:42:43 +04:00
*/
/* No branch filter requested */
if ( branch_sample_type & PERF_SAMPLE_BRANCH_ANY )
return pmu_bhrb_filter ;
/* Invalid branch filter options - HW does not support */
if ( branch_sample_type & PERF_SAMPLE_BRANCH_ANY_RETURN )
return - 1 ;
if ( branch_sample_type & PERF_SAMPLE_BRANCH_IND_CALL )
return - 1 ;
2015-10-13 10:09:10 +03:00
if ( branch_sample_type & PERF_SAMPLE_BRANCH_CALL )
return - 1 ;
2013-04-22 23:42:43 +04:00
if ( branch_sample_type & PERF_SAMPLE_BRANCH_ANY_CALL ) {
pmu_bhrb_filter | = POWER8_MMCRA_IFM1 ;
return pmu_bhrb_filter ;
}
/* Every thing else is unsupported */
return - 1 ;
}
static void power8_config_bhrb ( u64 pmu_bhrb_filter )
{
/* Enable BHRB filter in PMU */
mtspr ( SPRN_MMCRA , ( mfspr ( SPRN_MMCRA ) | pmu_bhrb_filter ) ) ;
}
2014-01-24 08:50:51 +04:00
# define C(x) PERF_COUNT_HW_CACHE_##x
/*
* Table of generalized cache - related events .
* 0 means not supported , - 1 means nonsensical , other values
* are event codes .
*/
static int power8_cache_events [ C ( MAX ) ] [ C ( OP_MAX ) ] [ C ( RESULT_MAX ) ] = {
[ C ( L1D ) ] = {
[ C ( OP_READ ) ] = {
[ C ( RESULT_ACCESS ) ] = PM_LD_REF_L1 ,
[ C ( RESULT_MISS ) ] = PM_LD_MISS_L1 ,
} ,
[ C ( OP_WRITE ) ] = {
[ C ( RESULT_ACCESS ) ] = 0 ,
[ C ( RESULT_MISS ) ] = PM_ST_MISS_L1 ,
} ,
[ C ( OP_PREFETCH ) ] = {
[ C ( RESULT_ACCESS ) ] = PM_L1_PREF ,
[ C ( RESULT_MISS ) ] = 0 ,
} ,
} ,
[ C ( L1I ) ] = {
[ C ( OP_READ ) ] = {
[ C ( RESULT_ACCESS ) ] = PM_INST_FROM_L1 ,
[ C ( RESULT_MISS ) ] = PM_L1_ICACHE_MISS ,
} ,
[ C ( OP_WRITE ) ] = {
[ C ( RESULT_ACCESS ) ] = PM_L1_DEMAND_WRITE ,
[ C ( RESULT_MISS ) ] = - 1 ,
} ,
[ C ( OP_PREFETCH ) ] = {
[ C ( RESULT_ACCESS ) ] = PM_IC_PREF_WRITE ,
[ C ( RESULT_MISS ) ] = 0 ,
} ,
} ,
[ C ( LL ) ] = {
[ C ( OP_READ ) ] = {
[ C ( RESULT_ACCESS ) ] = PM_DATA_FROM_L3 ,
[ C ( RESULT_MISS ) ] = PM_DATA_FROM_L3MISS ,
} ,
[ C ( OP_WRITE ) ] = {
[ C ( RESULT_ACCESS ) ] = PM_L2_ST ,
[ C ( RESULT_MISS ) ] = PM_L2_ST_MISS ,
} ,
[ C ( OP_PREFETCH ) ] = {
[ C ( RESULT_ACCESS ) ] = PM_L3_PREF_ALL ,
[ C ( RESULT_MISS ) ] = 0 ,
} ,
} ,
[ C ( DTLB ) ] = {
[ C ( OP_READ ) ] = {
[ C ( RESULT_ACCESS ) ] = 0 ,
[ C ( RESULT_MISS ) ] = PM_DTLB_MISS ,
} ,
[ C ( OP_WRITE ) ] = {
[ C ( RESULT_ACCESS ) ] = - 1 ,
[ C ( RESULT_MISS ) ] = - 1 ,
} ,
[ C ( OP_PREFETCH ) ] = {
[ C ( RESULT_ACCESS ) ] = - 1 ,
[ C ( RESULT_MISS ) ] = - 1 ,
} ,
} ,
[ C ( ITLB ) ] = {
[ C ( OP_READ ) ] = {
[ C ( RESULT_ACCESS ) ] = 0 ,
[ C ( RESULT_MISS ) ] = PM_ITLB_MISS ,
} ,
[ C ( OP_WRITE ) ] = {
[ C ( RESULT_ACCESS ) ] = - 1 ,
[ C ( RESULT_MISS ) ] = - 1 ,
} ,
[ C ( OP_PREFETCH ) ] = {
[ C ( RESULT_ACCESS ) ] = - 1 ,
[ C ( RESULT_MISS ) ] = - 1 ,
} ,
} ,
[ C ( BPU ) ] = {
[ C ( OP_READ ) ] = {
[ C ( RESULT_ACCESS ) ] = PM_BRU_FIN ,
[ C ( RESULT_MISS ) ] = PM_BR_MPRED_CMPL ,
} ,
[ C ( OP_WRITE ) ] = {
[ C ( RESULT_ACCESS ) ] = - 1 ,
[ C ( RESULT_MISS ) ] = - 1 ,
} ,
[ C ( OP_PREFETCH ) ] = {
[ C ( RESULT_ACCESS ) ] = - 1 ,
[ C ( RESULT_MISS ) ] = - 1 ,
} ,
} ,
[ C ( NODE ) ] = {
[ C ( OP_READ ) ] = {
[ C ( RESULT_ACCESS ) ] = - 1 ,
[ C ( RESULT_MISS ) ] = - 1 ,
} ,
[ C ( OP_WRITE ) ] = {
[ C ( RESULT_ACCESS ) ] = - 1 ,
[ C ( RESULT_MISS ) ] = - 1 ,
} ,
[ C ( OP_PREFETCH ) ] = {
[ C ( RESULT_ACCESS ) ] = - 1 ,
[ C ( RESULT_MISS ) ] = - 1 ,
} ,
} ,
} ;
# undef C
2013-04-25 23:28:28 +04:00
static struct power_pmu power8_pmu = {
. name = " POWER8 " ,
2016-06-26 20:37:04 +03:00
. n_counter = MAX_PMU_COUNTERS ,
2013-04-25 23:28:28 +04:00
. max_alternatives = MAX_ALT + 1 ,
2016-06-26 20:37:04 +03:00
. add_fields = ISA207_ADD_FIELDS ,
. test_adder = ISA207_TEST_ADDER ,
2016-06-26 20:37:05 +03:00
. compute_mmcr = isa207_compute_mmcr ,
2013-04-22 23:42:43 +04:00
. config_bhrb = power8_config_bhrb ,
. bhrb_filter_map = power8_bhrb_filter_map ,
2016-06-26 20:37:05 +03:00
. get_constraint = isa207_get_constraint ,
2013-04-25 23:28:28 +04:00
. get_alternatives = power8_get_alternatives ,
2017-04-11 04:51:08 +03:00
. get_mem_data_src = isa207_get_mem_data_src ,
. get_mem_weight = isa207_get_mem_weight ,
2016-06-26 20:37:05 +03:00
. disable_pmc = isa207_disable_pmc ,
2016-01-25 11:33:46 +03:00
. flags = PPMU_HAS_SIER | PPMU_ARCH_207S ,
2013-04-25 23:28:28 +04:00
. n_generic = ARRAY_SIZE ( power8_generic_events ) ,
. generic_events = power8_generic_events ,
2014-01-24 08:50:51 +04:00
. cache_events = & power8_cache_events ,
2013-04-25 23:28:28 +04:00
. attr_groups = power8_pmu_attr_groups ,
2013-04-22 23:42:43 +04:00
. bhrb_nr = 32 ,
2013-04-25 23:28:28 +04:00
} ;
static int __init init_power8_pmu ( void )
{
2013-07-13 06:53:40 +04:00
int rc ;
2013-04-25 23:28:28 +04:00
if ( ! cur_cpu_spec - > oprofile_cpu_type | |
strcmp ( cur_cpu_spec - > oprofile_cpu_type , " ppc64/power8 " ) )
return - ENODEV ;
2013-07-13 06:53:40 +04:00
rc = register_power_pmu ( & power8_pmu ) ;
if ( rc )
return rc ;
/* Tell userspace that EBB is supported */
cur_cpu_spec - > cpu_user_features2 | = PPC_FEATURE2_EBB ;
2014-03-14 09:00:29 +04:00
if ( cpu_has_feature ( CPU_FTR_PMAO_BUG ) )
pr_info ( " PMAO restore workaround active. \n " ) ;
2013-07-13 06:53:40 +04:00
return 0 ;
2013-04-25 23:28:28 +04:00
}
early_initcall ( init_power8_pmu ) ;