[PATCH v2 3/6] arm64/perf: Filter common events based on PMCEIDn_EL0
Ashok Kumar
ashoks at broadcom.com
Thu Mar 24 05:52:37 PDT 2016
The complete common architectural and micro-architectural
event number structure is filtered based on PMCEIDn_EL0 and
copied to a new structure which is exposed to /sys
The function which derives event bitmap from PMCEIDn_EL0 is
executed in the cpus, which has the pmu being initialized,
for heterogeneous pmu support.
Enforced armv8_pmuv3_event_attrs array for event number
ordering as this is indexed with event number now.
Signed-off-by: Ashok Kumar <ashoks at broadcom.com>
---
arch/arm64/kernel/perf_event.c | 281 ++++++++++++++++++++++++++++-------------
1 file changed, 195 insertions(+), 86 deletions(-)
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 5358587..a025ec2 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -378,62 +378,106 @@ ARMV8_EVENT_ATTR(l2i_tlb_refill, ARMV8_PMUV3_PERFCTR_L2I_TLB_REFILL);
ARMV8_EVENT_ATTR(l2d_tlb, ARMV8_PMUV3_PERFCTR_L2D_TLB);
ARMV8_EVENT_ATTR(l2i_tlb, ARMV8_PMUV3_PERFCTR_L2I_TLB);
-static struct attribute *armv8_pmuv3_event_attrs[] = {
- &armv8_event_attr_sw_incr.attr.attr,
- &armv8_event_attr_l1i_cache_refill.attr.attr,
- &armv8_event_attr_l1i_tlb_refill.attr.attr,
- &armv8_event_attr_l1d_cache_refill.attr.attr,
- &armv8_event_attr_l1d_cache.attr.attr,
- &armv8_event_attr_l1d_tlb_refill.attr.attr,
- &armv8_event_attr_ld_retired.attr.attr,
- &armv8_event_attr_st_retired.attr.attr,
- &armv8_event_attr_inst_retired.attr.attr,
- &armv8_event_attr_exc_taken.attr.attr,
- &armv8_event_attr_exc_return.attr.attr,
- &armv8_event_attr_cid_write_retired.attr.attr,
- &armv8_event_attr_pc_write_retired.attr.attr,
- &armv8_event_attr_br_immed_retired.attr.attr,
- &armv8_event_attr_br_return_retired.attr.attr,
- &armv8_event_attr_unaligned_ldst_retired.attr.attr,
- &armv8_event_attr_br_mis_pred.attr.attr,
- &armv8_event_attr_cpu_cycles.attr.attr,
- &armv8_event_attr_br_pred.attr.attr,
- &armv8_event_attr_mem_access.attr.attr,
- &armv8_event_attr_l1i_cache.attr.attr,
- &armv8_event_attr_l1d_cache_wb.attr.attr,
- &armv8_event_attr_l2d_cache.attr.attr,
- &armv8_event_attr_l2d_cache_refill.attr.attr,
- &armv8_event_attr_l2d_cache_wb.attr.attr,
- &armv8_event_attr_bus_access.attr.attr,
- &armv8_event_attr_memory_error.attr.attr,
- &armv8_event_attr_inst_spec.attr.attr,
- &armv8_event_attr_ttbr_write_retired.attr.attr,
- &armv8_event_attr_bus_cycles.attr.attr,
- &armv8_event_attr_chain.attr.attr,
- &armv8_event_attr_l1d_cache_allocate.attr.attr,
- &armv8_event_attr_l2d_cache_allocate.attr.attr,
- &armv8_event_attr_br_retired.attr.attr,
- &armv8_event_attr_br_mis_pred_retired.attr.attr,
- &armv8_event_attr_stall_frontend.attr.attr,
- &armv8_event_attr_stall_backend.attr.attr,
- &armv8_event_attr_l1d_tlb.attr.attr,
- &armv8_event_attr_l1i_tlb.attr.attr,
- &armv8_event_attr_l2i_cache.attr.attr,
- &armv8_event_attr_l2i_cache_refill.attr.attr,
- &armv8_event_attr_l3d_cache_allocate.attr.attr,
- &armv8_event_attr_l3d_cache_refill.attr.attr,
- &armv8_event_attr_l3d_cache.attr.attr,
- &armv8_event_attr_l3d_cache_wb.attr.attr,
- &armv8_event_attr_l2d_tlb_refill.attr.attr,
- &armv8_event_attr_l2i_tlb_refill.attr.attr,
- &armv8_event_attr_l2d_tlb.attr.attr,
- &armv8_event_attr_l2i_tlb.attr.attr,
- NULL,
-};
-
-static struct attribute_group armv8_pmuv3_events_attr_group = {
- .name = "events",
- .attrs = armv8_pmuv3_event_attrs,
+#define ARMV8_PMUV3_MAX_COMMON_EVENTS 0x40
+static struct attribute *armv8_pmuv3_event_attrs[ARMV8_PMUV3_MAX_COMMON_EVENTS] = {
+ [ARMV8_PMUV3_PERFCTR_SW_INCR] =
+ &armv8_event_attr_sw_incr.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L1I_CACHE_REFILL] =
+ &armv8_event_attr_l1i_cache_refill.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L1I_TLB_REFILL] =
+ &armv8_event_attr_l1i_tlb_refill.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL] =
+ &armv8_event_attr_l1d_cache_refill.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L1D_CACHE] =
+ &armv8_event_attr_l1d_cache.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L1D_TLB_REFILL] =
+ &armv8_event_attr_l1d_tlb_refill.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_LD_RETIRED] =
+ &armv8_event_attr_ld_retired.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_ST_RETIRED] =
+ &armv8_event_attr_st_retired.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_INST_RETIRED] =
+ &armv8_event_attr_inst_retired.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_EXC_TAKEN] =
+ &armv8_event_attr_exc_taken.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_EXC_RETURN] =
+ &armv8_event_attr_exc_return.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_CID_WRITE_RETIRED] =
+ &armv8_event_attr_cid_write_retired.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_PC_WRITE_RETIRED] =
+ &armv8_event_attr_pc_write_retired.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_BR_IMMED_RETIRED] =
+ &armv8_event_attr_br_immed_retired.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_BR_RETURN_RETIRED] =
+ &armv8_event_attr_br_return_retired.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_UNALIGNED_LDST_RETIRED] =
+ &armv8_event_attr_unaligned_ldst_retired.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_BR_MIS_PRED] =
+ &armv8_event_attr_br_mis_pred.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_CPU_CYCLES] =
+ &armv8_event_attr_cpu_cycles.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_BR_PRED] =
+ &armv8_event_attr_br_pred.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_MEM_ACCESS] =
+ &armv8_event_attr_mem_access.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L1I_CACHE] =
+ &armv8_event_attr_l1i_cache.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L1D_CACHE_WB] =
+ &armv8_event_attr_l1d_cache_wb.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L2D_CACHE] =
+ &armv8_event_attr_l2d_cache.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L2D_CACHE_REFILL] =
+ &armv8_event_attr_l2d_cache_refill.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L2D_CACHE_WB] =
+ &armv8_event_attr_l2d_cache_wb.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_BUS_ACCESS] =
+ &armv8_event_attr_bus_access.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_MEMORY_ERROR] =
+ &armv8_event_attr_memory_error.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_INST_SPEC] =
+ &armv8_event_attr_inst_spec.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_TTBR_WRITE_RETIRED] =
+ &armv8_event_attr_ttbr_write_retired.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_BUS_CYCLES] =
+ &armv8_event_attr_bus_cycles.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_CHAIN] =
+ &armv8_event_attr_chain.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L1D_CACHE_ALLOCATE] =
+ &armv8_event_attr_l1d_cache_allocate.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L2D_CACHE_ALLOCATE] =
+ &armv8_event_attr_l2d_cache_allocate.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_BR_RETIRED] =
+ &armv8_event_attr_br_retired.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_BR_MIS_PRED_RETIRED] =
+ &armv8_event_attr_br_mis_pred_retired.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_STALL_FRONTEND] =
+ &armv8_event_attr_stall_frontend.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_STALL_BACKEND] =
+ &armv8_event_attr_stall_backend.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L1D_TLB] =
+ &armv8_event_attr_l1d_tlb.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L1I_TLB] =
+ &armv8_event_attr_l1i_tlb.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L2I_CACHE] =
+ &armv8_event_attr_l2i_cache.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L2I_CACHE_REFILL] =
+ &armv8_event_attr_l2i_cache_refill.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L3D_CACHE_ALLOCATE] =
+ &armv8_event_attr_l3d_cache_allocate.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L3D_CACHE_REFILL] =
+ &armv8_event_attr_l3d_cache_refill.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L3D_CACHE] =
+ &armv8_event_attr_l3d_cache.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L3D_CACHE_WB] =
+ &armv8_event_attr_l3d_cache_wb.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L2D_TLB_REFILL] =
+ &armv8_event_attr_l2d_tlb_refill.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L2I_TLB_REFILL] =
+ &armv8_event_attr_l2i_tlb_refill.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L2D_TLB] =
+ &armv8_event_attr_l2d_tlb.attr.attr,
+ [ARMV8_PMUV3_PERFCTR_L2I_TLB] =
+ &armv8_event_attr_l2i_tlb.attr.attr,
};
PMU_FORMAT_ATTR(event, "config:0-9");
@@ -448,12 +492,6 @@ static struct attribute_group armv8_pmuv3_format_attr_group = {
.attrs = armv8_pmuv3_format_attrs,
};
-static const struct attribute_group *armv8_pmuv3_attr_groups[] = {
- &armv8_pmuv3_events_attr_group,
- &armv8_pmuv3_format_attr_group,
- NULL,
-};
-
/*
* Perf Events' indices
*/
@@ -522,6 +560,18 @@ static inline void armv8pmu_pmcr_write(u32 val)
asm volatile("msr pmcr_el0, %0" :: "r" (val));
}
+static inline u32 armv8pmu_pmceidn_read(int reg)
+{
+ u32 val = 0;
+
+ if (reg == 0)
+ asm volatile("mrs %0, pmceid0_el0" : "=r" (val));
+ else if (reg == 1)
+ asm volatile("mrs %0, pmceid1_el0" : "=r" (val));
+
+ return val;
+}
+
static inline int armv8pmu_has_overflowed(u32 pmovsr)
{
return pmovsr & ARMV8_OVERFLOWED_MASK;
@@ -890,26 +940,53 @@ static int armv8_thunder_map_event(struct perf_event *event)
ARMV8_EVTYPE_EVENT);
}
-static void armv8pmu_read_num_pmnc_events(void *info)
+static unsigned int armv8pmu_read_num_pmnc_events(void)
{
- int *nb_cnt = info;
-
+ unsigned int nb_cnt;
/* Read the nb of CNTx counters supported from PMNC */
- *nb_cnt = (armv8pmu_pmcr_read() >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK;
+ nb_cnt = (armv8pmu_pmcr_read() >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK;
/* Add the CPU cycles counter */
- *nb_cnt += 1;
+ nb_cnt += 1;
+
+ return nb_cnt;
+}
+
+static void armv8pmu_read_common_events_bitmap(unsigned long *bmp)
+{
+ u32 reg[2];
+
+ reg[0] = armv8pmu_pmceidn_read(0);
+ reg[1] = armv8pmu_pmceidn_read(1);
+
+ bitmap_from_u32array(bmp, ARMV8_PMUV3_MAX_COMMON_EVENTS,
+ reg, ARRAY_SIZE(reg));
+ return;
}
-static int armv8pmu_probe_num_events(struct arm_pmu *arm_pmu)
+struct armv8pmu_probe_pmu_data {
+ int num_evt_cntrs;
+ DECLARE_BITMAP(events_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);
+};
+
+static void armv8pmu_probe_pmu(void *info)
{
- return smp_call_function_any(&arm_pmu->supported_cpus,
- armv8pmu_read_num_pmnc_events,
- &arm_pmu->num_events, 1);
+ struct armv8pmu_probe_pmu_data *data = info;
+
+ data->num_evt_cntrs = armv8pmu_read_num_pmnc_events();
+ armv8pmu_read_common_events_bitmap(data->events_bitmap);
}
-static void armv8_pmu_init(struct arm_pmu *cpu_pmu)
+static int armv8_pmu_init(struct arm_pmu *cpu_pmu)
{
+ u32 evt, idx = 0;
+ struct attribute **event_attrs;
+ struct attribute_group *events_attr_group;
+ const struct attribute_group **attr_groups;
+ struct device *dev = &cpu_pmu->plat_device->dev;
+ struct armv8pmu_probe_pmu_data pmu_data;
+ int error;
+
cpu_pmu->handle_irq = armv8pmu_handle_irq,
cpu_pmu->enable = armv8pmu_enable_event,
cpu_pmu->disable = armv8pmu_disable_event,
@@ -921,50 +998,82 @@ static void armv8_pmu_init(struct arm_pmu *cpu_pmu)
cpu_pmu->reset = armv8pmu_reset,
cpu_pmu->max_period = (1LLU << 32) - 1,
cpu_pmu->set_event_filter = armv8pmu_set_event_filter;
+
+ error = smp_call_function_any(&cpu_pmu->supported_cpus,
+ armv8pmu_probe_pmu,
+ &pmu_data, 1);
+ if (error)
+ goto out;
+
+ cpu_pmu->num_events = pmu_data.num_evt_cntrs;
+
+ event_attrs = devm_kcalloc(dev, bitmap_weight(pmu_data.events_bitmap,
+ ARMV8_PMUV3_MAX_COMMON_EVENTS) + 1,
+ sizeof(*event_attrs), GFP_KERNEL);
+ if (!event_attrs)
+ goto mem_out;
+
+ events_attr_group = devm_kzalloc(dev, sizeof(*events_attr_group),
+ GFP_KERNEL);
+ if (!events_attr_group)
+ goto mem_out;
+
+ attr_groups = devm_kcalloc(dev, 3, sizeof(*attr_groups), GFP_KERNEL);
+ if (!attr_groups)
+ goto mem_out;
+
+ for_each_set_bit(evt, pmu_data.events_bitmap,
+ ARMV8_PMUV3_MAX_COMMON_EVENTS)
+ event_attrs[idx++] = armv8_pmuv3_event_attrs[evt];
+
+ events_attr_group->name = "events";
+ events_attr_group->attrs = event_attrs;
+
+ attr_groups[0] = events_attr_group;
+ attr_groups[1] = &armv8_pmuv3_format_attr_group;
+
+ cpu_pmu->pmu.attr_groups = attr_groups;
+
+ return 0;
+mem_out:
+ error = -ENOMEM;
+out:
+ return error;
}
static int armv8_pmuv3_init(struct arm_pmu *cpu_pmu)
{
- armv8_pmu_init(cpu_pmu);
cpu_pmu->name = "armv8_pmuv3";
cpu_pmu->map_event = armv8_pmuv3_map_event;
- return armv8pmu_probe_num_events(cpu_pmu);
+ return armv8_pmu_init(cpu_pmu);
}
static int armv8_a53_pmu_init(struct arm_pmu *cpu_pmu)
{
- armv8_pmu_init(cpu_pmu);
cpu_pmu->name = "armv8_cortex_a53";
cpu_pmu->map_event = armv8_a53_map_event;
- cpu_pmu->pmu.attr_groups = armv8_pmuv3_attr_groups;
- return armv8pmu_probe_num_events(cpu_pmu);
+ return armv8_pmu_init(cpu_pmu);
}
static int armv8_a57_pmu_init(struct arm_pmu *cpu_pmu)
{
- armv8_pmu_init(cpu_pmu);
cpu_pmu->name = "armv8_cortex_a57";
cpu_pmu->map_event = armv8_a57_map_event;
- cpu_pmu->pmu.attr_groups = armv8_pmuv3_attr_groups;
- return armv8pmu_probe_num_events(cpu_pmu);
+ return armv8_pmu_init(cpu_pmu);
}
static int armv8_a72_pmu_init(struct arm_pmu *cpu_pmu)
{
- armv8_pmu_init(cpu_pmu);
cpu_pmu->name = "armv8_cortex_a72";
cpu_pmu->map_event = armv8_a57_map_event;
- cpu_pmu->pmu.attr_groups = armv8_pmuv3_attr_groups;
- return armv8pmu_probe_num_events(cpu_pmu);
+ return armv8_pmu_init(cpu_pmu);
}
static int armv8_thunder_pmu_init(struct arm_pmu *cpu_pmu)
{
- armv8_pmu_init(cpu_pmu);
cpu_pmu->name = "armv8_cavium_thunder";
cpu_pmu->map_event = armv8_thunder_map_event;
- cpu_pmu->pmu.attr_groups = armv8_pmuv3_attr_groups;
- return armv8pmu_probe_num_events(cpu_pmu);
+ return armv8_pmu_init(cpu_pmu);
}
static const struct of_device_id armv8_pmu_of_device_ids[] = {
--
2.1.0
More information about the linux-arm-kernel
mailing list