lkml.org 
[lkml]   [2023]   [Jan]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH v4 8/8] perf: arm_spe: Add support for SPEv1.2 inverted event filtering
    Arm SPEv1.2 (Arm v8.7/v9.2) adds a new feature called Inverted Event
    Filter which excludes samples matching the event filter. The feature
    mirrors the existing event filter in PMSEVFR_EL1 adding a new register,
    PMSNEVFR_EL1, which has the same event bit assignments.

    Tested-by: James Clark <james.clark@arm.com>
    Signed-off-by: Rob Herring <robh@kernel.org>
    ---
    v4:
    - Rebase on v6.2-rc1
    v3:
    - No change
    v2:
    - Update for auto generated register defines
    - Avoid accessing SYS_PMSNEVFR_EL1 on < v8.7
    ---
    drivers/perf/arm_spe_pmu.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
    1 file changed, 45 insertions(+)

    diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c
    index 82f67e941bc4..573db4211acd 100644
    --- a/drivers/perf/arm_spe_pmu.c
    +++ b/drivers/perf/arm_spe_pmu.c
    @@ -85,6 +85,7 @@ struct arm_spe_pmu {
    #define SPE_PMU_FEAT_ARCH_INST (1UL << 3)
    #define SPE_PMU_FEAT_LDS (1UL << 4)
    #define SPE_PMU_FEAT_ERND (1UL << 5)
    +#define SPE_PMU_FEAT_INV_FILT_EVT (1UL << 6)
    #define SPE_PMU_FEAT_DEV_PROBED (1UL << 63)
    u64 features;

    @@ -202,6 +203,10 @@ static const struct attribute_group arm_spe_pmu_cap_group = {
    #define ATTR_CFG_FLD_min_latency_LO 0
    #define ATTR_CFG_FLD_min_latency_HI 11

    +#define ATTR_CFG_FLD_inv_event_filter_CFG config3 /* PMSNEVFR_EL1 */
    +#define ATTR_CFG_FLD_inv_event_filter_LO 0
    +#define ATTR_CFG_FLD_inv_event_filter_HI 63
    +
    /* Why does everything I do descend into this? */
    #define __GEN_PMU_FORMAT_ATTR(cfg, lo, hi) \
    (lo) == (hi) ? #cfg ":" #lo "\n" : #cfg ":" #lo "-" #hi
    @@ -232,6 +237,7 @@ GEN_PMU_FORMAT_ATTR(branch_filter);
    GEN_PMU_FORMAT_ATTR(load_filter);
    GEN_PMU_FORMAT_ATTR(store_filter);
    GEN_PMU_FORMAT_ATTR(event_filter);
    +GEN_PMU_FORMAT_ATTR(inv_event_filter);
    GEN_PMU_FORMAT_ATTR(min_latency);

    static struct attribute *arm_spe_pmu_formats_attr[] = {
    @@ -243,12 +249,27 @@ static struct attribute *arm_spe_pmu_formats_attr[] = {
    &format_attr_load_filter.attr,
    &format_attr_store_filter.attr,
    &format_attr_event_filter.attr,
    + &format_attr_inv_event_filter.attr,
    &format_attr_min_latency.attr,
    NULL,
    };

    +static umode_t arm_spe_pmu_format_attr_is_visible(struct kobject *kobj,
    + struct attribute *attr,
    + int unused)
    + {
    + struct device *dev = kobj_to_dev(kobj);
    + struct arm_spe_pmu *spe_pmu = dev_get_drvdata(dev);
    +
    + if (attr == &format_attr_inv_event_filter.attr && !(spe_pmu->features & SPE_PMU_FEAT_INV_FILT_EVT))
    + return 0;
    +
    + return attr->mode;
    +}
    +
    static const struct attribute_group arm_spe_pmu_format_group = {
    .name = "format",
    + .is_visible = arm_spe_pmu_format_attr_is_visible,
    .attrs = arm_spe_pmu_formats_attr,
    };

    @@ -343,6 +364,9 @@ static u64 arm_spe_event_to_pmsfcr(struct perf_event *event)
    if (ATTR_CFG_GET_FLD(attr, event_filter))
    reg |= PMSFCR_EL1_FE;

    + if (ATTR_CFG_GET_FLD(attr, inv_event_filter))
    + reg |= PMSFCR_EL1_FnE;
    +
    if (ATTR_CFG_GET_FLD(attr, min_latency))
    reg |= PMSFCR_EL1_FL;

    @@ -355,6 +379,12 @@ static u64 arm_spe_event_to_pmsevfr(struct perf_event *event)
    return ATTR_CFG_GET_FLD(attr, event_filter);
    }

    +static u64 arm_spe_event_to_pmsnevfr(struct perf_event *event)
    +{
    + struct perf_event_attr *attr = &event->attr;
    + return ATTR_CFG_GET_FLD(attr, inv_event_filter);
    +}
    +
    static u64 arm_spe_event_to_pmslatfr(struct perf_event *event)
    {
    struct perf_event_attr *attr = &event->attr;
    @@ -703,6 +733,9 @@ static int arm_spe_pmu_event_init(struct perf_event *event)
    if (arm_spe_event_to_pmsevfr(event) & arm_spe_pmsevfr_res0(spe_pmu->pmsver))
    return -EOPNOTSUPP;

    + if (arm_spe_event_to_pmsnevfr(event) & arm_spe_pmsevfr_res0(spe_pmu->pmsver))
    + return -EOPNOTSUPP;
    +
    if (attr->exclude_idle)
    return -EOPNOTSUPP;

    @@ -721,6 +754,10 @@ static int arm_spe_pmu_event_init(struct perf_event *event)
    !(spe_pmu->features & SPE_PMU_FEAT_FILT_EVT))
    return -EOPNOTSUPP;

    + if ((FIELD_GET(PMSFCR_EL1_FnE, reg)) &&
    + !(spe_pmu->features & SPE_PMU_FEAT_INV_FILT_EVT))
    + return -EOPNOTSUPP;
    +
    if ((FIELD_GET(PMSFCR_EL1_FT, reg)) &&
    !(spe_pmu->features & SPE_PMU_FEAT_FILT_TYP))
    return -EOPNOTSUPP;
    @@ -756,6 +793,11 @@ static void arm_spe_pmu_start(struct perf_event *event, int flags)
    reg = arm_spe_event_to_pmsevfr(event);
    write_sysreg_s(reg, SYS_PMSEVFR_EL1);

    + if (spe_pmu->features & SPE_PMU_FEAT_INV_FILT_EVT) {
    + reg = arm_spe_event_to_pmsnevfr(event);
    + write_sysreg_s(reg, SYS_PMSNEVFR_EL1);
    + }
    +
    reg = arm_spe_event_to_pmslatfr(event);
    write_sysreg_s(reg, SYS_PMSLATFR_EL1);

    @@ -990,6 +1032,9 @@ static void __arm_spe_pmu_dev_probe(void *info)
    if (FIELD_GET(PMSIDR_EL1_FE, reg))
    spe_pmu->features |= SPE_PMU_FEAT_FILT_EVT;

    + if (FIELD_GET(PMSIDR_EL1_FnE, reg))
    + spe_pmu->features |= SPE_PMU_FEAT_INV_FILT_EVT;
    +
    if (FIELD_GET(PMSIDR_EL1_FT, reg))
    spe_pmu->features |= SPE_PMU_FEAT_FILT_TYP;

    --
    2.39.0

    \
     
     \ /
      Last update: 2023-03-26 23:33    [W:3.322 / U:0.012 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site