arm64/perf: Filter common events based on PMCEIDn_EL0
authorAshok Kumar <ashoks@broadcom.com>
Thu, 21 Apr 2016 12:58:44 +0000 (05:58 -0700)
committerWill Deacon <will.deacon@arm.com>
Mon, 25 Apr 2016 13:11:10 +0000 (14:11 +0100)
The complete common architectural and micro-architectural
event number structure is filtered based on PMCEIDn_EL0 and
exposed to /sys using is_visibile function pointer in events
attribute_group.
To filter the events in is_visible function, pmceid based bitmap
is stored in arm_pmu structure and the id field from
perf_pmu_events_attr is used to check against the bitmap.

The function which derives event bitmap from PMCEIDn_EL0 is
executed in the cpus, which has the pmu being initialized,
for heterogeneous pmu support.

Acked-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Ashok Kumar <ashoks@broadcom.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
arch/arm64/kernel/perf_event.c
include/linux/perf/arm_pmu.h

index 946ce4b..e6a0fdb 100644 (file)
@@ -326,10 +326,22 @@ static const unsigned armv8_thunder_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
        [C(BPU)][C(OP_WRITE)][C(RESULT_MISS)]   = ARMV8_PMUV3_PERFCTR_BR_MIS_PRED,
 };
 
+
+static ssize_t
+armv8pmu_events_sysfs_show(struct device *dev,
+                          struct device_attribute *attr, char *page)
+{
+       struct perf_pmu_events_attr *pmu_attr;
+
+       pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr);
+
+       return sprintf(page, "event=0x%03llx\n", pmu_attr->id);
+}
+
 #define ARMV8_EVENT_ATTR_RESOLVE(m) #m
 #define ARMV8_EVENT_ATTR(name, config) \
-       PMU_EVENT_ATTR_STRING(name, armv8_event_attr_##name, \
-                             "event=" ARMV8_EVENT_ATTR_RESOLVE(config))
+       PMU_EVENT_ATTR(name, armv8_event_attr_##name, \
+                      config, armv8pmu_events_sysfs_show)
 
 ARMV8_EVENT_ATTR(sw_incr, ARMV8_PMUV3_PERFCTR_SW_INCR);
 ARMV8_EVENT_ATTR(l1i_cache_refill, ARMV8_PMUV3_PERFCTR_L1I_CACHE_REFILL);
@@ -434,9 +446,27 @@ static struct attribute *armv8_pmuv3_event_attrs[] = {
        NULL,
 };
 
+static umode_t
+armv8pmu_event_attr_is_visible(struct kobject *kobj,
+                              struct attribute *attr, int unused)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct pmu *pmu = dev_get_drvdata(dev);
+       struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu);
+       struct perf_pmu_events_attr *pmu_attr;
+
+       pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr.attr);
+
+       if (test_bit(pmu_attr->id, cpu_pmu->pmceid_bitmap))
+               return attr->mode;
+
+       return 0;
+}
+
 static struct attribute_group armv8_pmuv3_events_attr_group = {
        .name = "events",
        .attrs = armv8_pmuv3_event_attrs,
+       .is_visible = armv8pmu_event_attr_is_visible,
 };
 
 PMU_FORMAT_ATTR(event, "config:0-9");
@@ -859,22 +889,31 @@ static int armv8_thunder_map_event(struct perf_event *event)
                                ARMV8_PMU_EVTYPE_EVENT);
 }
 
-static void armv8pmu_read_num_pmnc_events(void *info)
+static void __armv8pmu_probe_pmu(void *info)
 {
-       int *nb_cnt = info;
+       struct arm_pmu *cpu_pmu = info;
+       u32 pmceid[2];
 
        /* Read the nb of CNTx counters supported from PMNC */
-       *nb_cnt = (armv8pmu_pmcr_read() >> ARMV8_PMU_PMCR_N_SHIFT) & ARMV8_PMU_PMCR_N_MASK;
+       cpu_pmu->num_events = (armv8pmu_pmcr_read() >> ARMV8_PMU_PMCR_N_SHIFT)
+               & ARMV8_PMU_PMCR_N_MASK;
 
        /* Add the CPU cycles counter */
-       *nb_cnt += 1;
+       cpu_pmu->num_events += 1;
+
+       pmceid[0] = read_sysreg(pmceid0_el0);
+       pmceid[1] = read_sysreg(pmceid1_el0);
+
+       bitmap_from_u32array(cpu_pmu->pmceid_bitmap,
+                            ARMV8_PMUV3_MAX_COMMON_EVENTS, pmceid,
+                            ARRAY_SIZE(pmceid));
 }
 
-static int armv8pmu_probe_num_events(struct arm_pmu *arm_pmu)
+static int armv8pmu_probe_pmu(struct arm_pmu *cpu_pmu)
 {
-       return smp_call_function_any(&arm_pmu->supported_cpus,
-                                   armv8pmu_read_num_pmnc_events,
-                                   &arm_pmu->num_events, 1);
+       return smp_call_function_any(&cpu_pmu->supported_cpus,
+                                   __armv8pmu_probe_pmu,
+                                   cpu_pmu, 1);
 }
 
 static void armv8_pmu_init(struct arm_pmu *cpu_pmu)
@@ -897,7 +936,8 @@ 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);
+       cpu_pmu->pmu.attr_groups        = armv8_pmuv3_attr_groups;
+       return armv8pmu_probe_pmu(cpu_pmu);
 }
 
 static int armv8_a53_pmu_init(struct arm_pmu *cpu_pmu)
@@ -906,7 +946,7 @@ static int armv8_a53_pmu_init(struct arm_pmu *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 armv8pmu_probe_pmu(cpu_pmu);
 }
 
 static int armv8_a57_pmu_init(struct arm_pmu *cpu_pmu)
@@ -915,7 +955,7 @@ static int armv8_a57_pmu_init(struct arm_pmu *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 armv8pmu_probe_pmu(cpu_pmu);
 }
 
 static int armv8_a72_pmu_init(struct arm_pmu *cpu_pmu)
@@ -924,7 +964,7 @@ static int armv8_a72_pmu_init(struct arm_pmu *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 armv8pmu_probe_pmu(cpu_pmu);
 }
 
 static int armv8_thunder_pmu_init(struct arm_pmu *cpu_pmu)
@@ -933,7 +973,7 @@ static int armv8_thunder_pmu_init(struct arm_pmu *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 armv8pmu_probe_pmu(cpu_pmu);
 }
 
 static const struct of_device_id armv8_pmu_of_device_ids[] = {
index 4196c90..d28ac05 100644 (file)
@@ -105,6 +105,8 @@ struct arm_pmu {
        struct mutex    reserve_mutex;
        u64             max_period;
        bool            secure_access; /* 32-bit ARM only */
+#define ARMV8_PMUV3_MAX_COMMON_EVENTS 0x40
+       DECLARE_BITMAP(pmceid_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);
        struct platform_device  *plat_device;
        struct pmu_hw_events    __percpu *hw_events;
        struct notifier_block   hotplug_nb;