diff --git a/arch/alpha/kernel/perf_event.c b/arch/alpha/kernel/perf_event.c index a3eaab094ece02..4de1802d249fba 100644 --- a/arch/alpha/kernel/perf_event.c +++ b/arch/alpha/kernel/perf_event.c @@ -352,7 +352,7 @@ static int collect_events(struct perf_event *group, int max_count, current_idx[n++] = PMC_NO_INDEX; } for_each_sibling_event(pe, group) { - if (!is_software_event(pe) && pe->state != PERF_EVENT_STATE_OFF) { + if (!is_software_event(pe)) { if (n >= max_count) return -1; event[n] = pe; @@ -761,7 +761,8 @@ static struct pmu pmu = { .start = alpha_pmu_start, .stop = alpha_pmu_stop, .read = alpha_pmu_read, - .capabilities = PERF_PMU_CAP_NO_EXCLUDE, + .capabilities = PERF_PMU_CAP_SAMPLING | + PERF_PMU_CAP_NO_EXCLUDE, }; diff --git a/arch/arc/kernel/perf_event.c b/arch/arc/kernel/perf_event.c index ed6d4f0cd62162..7e154f6f0abd13 100644 --- a/arch/arc/kernel/perf_event.c +++ b/arch/arc/kernel/perf_event.c @@ -816,8 +816,8 @@ static int arc_pmu_device_probe(struct platform_device *pdev) } - if (irq == -1) - arc_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; + if (irq != -1) + arc_pmu->pmu.capabilities |= PERF_PMU_CAP_SAMPLING; /* * perf parser doesn't really like '-' symbol in events name, so let's diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c index 94e4f4a2f73fc3..9e3734e249a278 100644 --- a/arch/arm/mach-imx/mmdc.c +++ b/arch/arm/mach-imx/mmdc.c @@ -238,11 +238,8 @@ static bool mmdc_pmu_group_event_is_valid(struct perf_event *event, { int cfg = event->attr.config; - if (is_software_event(event)) - return true; - if (event->pmu != pmu) - return false; + return true; return !test_and_set_bit(cfg, used_counters); } @@ -260,12 +257,12 @@ static bool mmdc_pmu_group_is_valid(struct perf_event *event) struct perf_event *sibling; unsigned long counter_mask = 0; - set_bit(leader->attr.config, &counter_mask); + if (event == leader) + return true; - if (event != leader) { - if (!mmdc_pmu_group_event_is_valid(event, pmu, &counter_mask)) - return false; - } + set_bit(event->attr.config, &counter_mask); + if (!mmdc_pmu_group_event_is_valid(leader, pmu, &counter_mask)) + return false; for_each_sibling_event(sibling, leader) { if (!mmdc_pmu_group_event_is_valid(sibling, pmu, &counter_mask)) @@ -280,20 +277,6 @@ static int mmdc_pmu_event_init(struct perf_event *event) struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu); int cfg = event->attr.config; - if (event->attr.type != event->pmu->type) - return -ENOENT; - - if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) - return -EOPNOTSUPP; - - if (event->cpu < 0) { - dev_warn(pmu_mmdc->dev, "Can't provide per-task data!\n"); - return -EOPNOTSUPP; - } - - if (event->attr.sample_period) - return -EINVAL; - if (cfg < 0 || cfg >= MMDC_NUM_COUNTERS) return -EINVAL; diff --git a/arch/arm/mm/cache-l2x0-pmu.c b/arch/arm/mm/cache-l2x0-pmu.c index 93ef0502b7ff22..b8753463c1c4b7 100644 --- a/arch/arm/mm/cache-l2x0-pmu.c +++ b/arch/arm/mm/cache-l2x0-pmu.c @@ -274,18 +274,17 @@ static bool l2x0_pmu_group_is_valid(struct perf_event *event) struct pmu *pmu = event->pmu; struct perf_event *leader = event->group_leader; struct perf_event *sibling; - int num_hw = 0; + int num_hw = 1; + + if (leader == event) + return true; if (leader->pmu == pmu) num_hw++; - else if (!is_software_event(leader)) - return false; for_each_sibling_event(sibling, leader) { if (sibling->pmu == pmu) num_hw++; - else if (!is_software_event(sibling)) - return false; } return num_hw <= PMU_NR_COUNTERS; @@ -295,16 +294,6 @@ static int l2x0_pmu_event_init(struct perf_event *event) { struct hw_perf_event *hw = &event->hw; - if (event->attr.type != l2x0_pmu->type) - return -ENOENT; - - if (is_sampling_event(event) || - event->attach_state & PERF_ATTACH_TASK) - return -EINVAL; - - if (event->cpu < 0) - return -EINVAL; - if (event->attr.config & ~L2X0_EVENT_CNT_CFG_SRC_MASK) return -EINVAL; diff --git a/arch/csky/kernel/perf_event.c b/arch/csky/kernel/perf_event.c index e0a36acd265b38..ecf4b2863f78ec 100644 --- a/arch/csky/kernel/perf_event.c +++ b/arch/csky/kernel/perf_event.c @@ -1204,6 +1204,7 @@ int init_hw_perf_events(void) } csky_pmu.pmu = (struct pmu) { + .capabilities = PERF_PMU_CAP_SAMPLING, .pmu_enable = csky_pmu_enable, .pmu_disable = csky_pmu_disable, .event_init = csky_pmu_event_init, @@ -1314,7 +1315,7 @@ int csky_pmu_device_probe(struct platform_device *pdev, ret = csky_pmu_request_irq(csky_pmu_handle_irq); if (ret) { - csky_pmu.pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; + csky_pmu.pmu.capabilities &= ~PERF_PMU_CAP_SAMPLING; pr_notice("[perf] PMU request irq fail!\n"); } diff --git a/arch/loongarch/kernel/perf_event.c b/arch/loongarch/kernel/perf_event.c index 8ad09870348893..341b17bedd0e62 100644 --- a/arch/loongarch/kernel/perf_event.c +++ b/arch/loongarch/kernel/perf_event.c @@ -571,6 +571,7 @@ static int loongarch_pmu_event_init(struct perf_event *event) } static struct pmu pmu = { + .capabilities = PERF_PMU_CAP_SAMPLING, .pmu_enable = loongarch_pmu_enable, .pmu_disable = loongarch_pmu_disable, .event_init = loongarch_pmu_event_init, diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c index 196a070349b093..4c5d64d1158ed3 100644 --- a/arch/mips/kernel/perf_event_mipsxx.c +++ b/arch/mips/kernel/perf_event_mipsxx.c @@ -687,6 +687,7 @@ static int mipspmu_event_init(struct perf_event *event) } static struct pmu pmu = { + .capabilities = PERF_PMU_CAP_SAMPLING, .pmu_enable = mipspmu_enable, .pmu_disable = mipspmu_disable, .event_init = mipspmu_event_init, diff --git a/arch/powerpc/perf/8xx-pmu.c b/arch/powerpc/perf/8xx-pmu.c index 1d2972229e3a7e..71c35bd72eaeaf 100644 --- a/arch/powerpc/perf/8xx-pmu.c +++ b/arch/powerpc/perf/8xx-pmu.c @@ -181,8 +181,7 @@ static struct pmu mpc8xx_pmu = { .add = mpc8xx_pmu_add, .del = mpc8xx_pmu_del, .read = mpc8xx_pmu_read, - .capabilities = PERF_PMU_CAP_NO_INTERRUPT | - PERF_PMU_CAP_NO_NMI, + .capabilities = PERF_PMU_CAP_NO_NMI, }; static int init_mpc8xx_pmu(void) diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 8b0081441f85d1..cfe7d3c120e158 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -1602,8 +1602,7 @@ static int collect_events(struct perf_event *group, int max_count, events[n++] = group->hw.config; } for_each_sibling_event(event, group) { - if (event->pmu->task_ctx_nr == perf_hw_context && - event->state != PERF_EVENT_STATE_OFF) { + if (event->pmu->task_ctx_nr == perf_hw_context) { if (n >= max_count) return -1; ctrs[n] = event; @@ -2208,6 +2207,7 @@ ssize_t power_events_sysfs_show(struct device *dev, } static struct pmu power_pmu = { + .capabilities = PERF_PMU_CAP_SAMPLING, .pmu_enable = power_pmu_enable, .pmu_disable = power_pmu_disable, .event_init = power_pmu_event_init, diff --git a/arch/powerpc/perf/core-fsl-emb.c b/arch/powerpc/perf/core-fsl-emb.c index 7120ab20cbfecb..62038ff3663fc0 100644 --- a/arch/powerpc/perf/core-fsl-emb.c +++ b/arch/powerpc/perf/core-fsl-emb.c @@ -261,8 +261,7 @@ static int collect_events(struct perf_event *group, int max_count, n++; } for_each_sibling_event(event, group) { - if (!is_software_event(event) && - event->state != PERF_EVENT_STATE_OFF) { + if (!is_software_event(event)) { if (n >= max_count) return -1; ctrs[n] = event; @@ -571,6 +570,7 @@ static int fsl_emb_pmu_event_init(struct perf_event *event) } static struct pmu fsl_emb_pmu = { + .capabilities = PERF_PMU_CAP_SAMPLING, .pmu_enable = fsl_emb_pmu_enable, .pmu_disable = fsl_emb_pmu_disable, .event_init = fsl_emb_pmu_event_init, diff --git a/arch/powerpc/perf/hv-24x7.c b/arch/powerpc/perf/hv-24x7.c index e42677cc254a9a..5b03d6b3499933 100644 --- a/arch/powerpc/perf/hv-24x7.c +++ b/arch/powerpc/perf/hv-24x7.c @@ -1379,10 +1379,6 @@ static int h_24x7_event_init(struct perf_event *event) unsigned long hret; u64 ct; - /* Not our event */ - if (event->attr.type != event->pmu->type) - return -ENOENT; - /* Unused areas must be 0 */ if (event_get_reserved1(event) || event_get_reserved2(event) || @@ -1397,10 +1393,6 @@ static int h_24x7_event_init(struct perf_event *event) return -EINVAL; } - /* no branch sampling */ - if (has_branch_stack(event)) - return -EOPNOTSUPP; - /* offset must be 8 byte aligned */ if (event_get_offset(event) % 8) { pr_devel("bad alignment\n"); @@ -1726,9 +1718,6 @@ static int hv_24x7_init(void) if (!hv_page_cache) return -ENOMEM; - /* sampling not supported */ - h_24x7_pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; - r = create_events_from_catalog(&event_group.attrs, &event_desc_group.attrs, &event_long_desc_group.attrs); diff --git a/arch/powerpc/perf/hv-gpci.c b/arch/powerpc/perf/hv-gpci.c index 241551d1282f80..9663aa18bc457d 100644 --- a/arch/powerpc/perf/hv-gpci.c +++ b/arch/powerpc/perf/hv-gpci.c @@ -775,20 +775,12 @@ static int h_gpci_event_init(struct perf_event *event) u8 length; unsigned long ret; - /* Not our event */ - if (event->attr.type != event->pmu->type) - return -ENOENT; - /* config2 is unused */ if (event->attr.config2) { pr_devel("config2 set when reserved\n"); return -EINVAL; } - /* no branch sampling */ - if (has_branch_stack(event)) - return -EOPNOTSUPP; - length = event_get_length(event); if (length < 1 || length > 8) { pr_devel("length invalid\n"); @@ -1008,9 +1000,6 @@ static int hv_gpci_init(void) if (r) return r; - /* sampling not supported */ - h_gpci_pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; - arg = (void *)get_cpu_var(hv_gpci_reqb); memset(arg, 0, HGPCI_REQ_BUFFER_SIZE); diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c index 8664a7d297ad81..cee6390986dc79 100644 --- a/arch/powerpc/perf/imc-pmu.c +++ b/arch/powerpc/perf/imc-pmu.c @@ -517,16 +517,6 @@ static int nest_imc_event_init(struct perf_event *event) struct imc_pmu_ref *ref; bool flag = false; - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* Sampling not supported */ - if (event->hw.sample_period) - return -EINVAL; - - if (event->cpu < 0) - return -EINVAL; - pmu = imc_event_to_pmu(event); /* Sanity check for config (event offset) */ @@ -819,16 +809,6 @@ static int core_imc_event_init(struct perf_event *event) struct imc_pmu *pmu; struct imc_pmu_ref *ref; - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* Sampling not supported */ - if (event->hw.sample_period) - return -EINVAL; - - if (event->cpu < 0) - return -EINVAL; - event->hw.idx = -1; pmu = imc_event_to_pmu(event); @@ -983,16 +963,9 @@ static int thread_imc_event_init(struct perf_event *event) struct task_struct *target; struct imc_pmu *pmu; - if (event->attr.type != event->pmu->type) - return -ENOENT; - if (!perfmon_capable()) return -EACCES; - /* Sampling not supported */ - if (event->hw.sample_period) - return -EINVAL; - event->hw.idx = -1; pmu = imc_event_to_pmu(event); @@ -1436,9 +1409,6 @@ static void trace_imc_event_del(struct perf_event *event, int flags) static int trace_imc_event_init(struct perf_event *event) { - if (event->attr.type != event->pmu->type) - return -ENOENT; - if (!perfmon_capable()) return -EACCES; @@ -1507,6 +1477,7 @@ static int update_pmu_ops(struct imc_pmu *pmu) pmu->pmu.commit_txn = thread_imc_pmu_commit_txn; break; case IMC_DOMAIN_TRACE: + pmu->pmu.capabilities |= PERF_PMU_CAP_SAMPLING; pmu->pmu.event_init = trace_imc_event_init; pmu->pmu.add = trace_imc_event_add; pmu->pmu.del = trace_imc_event_del; diff --git a/arch/powerpc/perf/kvm-hv-pmu.c b/arch/powerpc/perf/kvm-hv-pmu.c index ae264c9080ef69..513f5b172ba60a 100644 --- a/arch/powerpc/perf/kvm-hv-pmu.c +++ b/arch/powerpc/perf/kvm-hv-pmu.c @@ -180,9 +180,6 @@ static int kvmppc_pmu_event_init(struct perf_event *event) __func__, event, event->id, event->cpu, event->oncpu, config); - if (event->attr.type != event->pmu->type) - return -ENOENT; - if (config >= KVMPPC_EVENT_MAX) return -EINVAL; @@ -391,7 +388,7 @@ static struct pmu kvmppc_pmu = { .attr_groups = kvmppc_pmu_attr_groups, .type = -1, .scope = PERF_PMU_SCOPE_SYS_WIDE, - .capabilities = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_NO_INTERRUPT, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, }; static int __init kvmppc_register_pmu(void) diff --git a/arch/powerpc/perf/vpa-pmu.c b/arch/powerpc/perf/vpa-pmu.c index 8407334689596a..35883a071360dd 100644 --- a/arch/powerpc/perf/vpa-pmu.c +++ b/arch/powerpc/perf/vpa-pmu.c @@ -72,17 +72,6 @@ static const struct attribute_group *vpa_pmu_attr_groups[] = { static int vpa_pmu_event_init(struct perf_event *event) { - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* it does not support event sampling mode */ - if (is_sampling_event(event)) - return -EOPNOTSUPP; - - /* no branch sampling */ - if (has_branch_stack(event)) - return -EOPNOTSUPP; - /* Invalid event code */ if ((event->attr.config <= 0) || (event->attr.config > 3)) return -EINVAL; @@ -164,7 +153,7 @@ static struct pmu vpa_pmu = { .del = vpa_pmu_del, .read = vpa_pmu_read, .attr_groups = vpa_pmu_attr_groups, - .capabilities = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_NO_INTERRUPT, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, }; static int __init pseries_vpa_pmu_init(void) diff --git a/arch/powerpc/platforms/pseries/papr_scm.c b/arch/powerpc/platforms/pseries/papr_scm.c index f7c9271bda5843..e6474ee0c140b3 100644 --- a/arch/powerpc/platforms/pseries/papr_scm.c +++ b/arch/powerpc/platforms/pseries/papr_scm.c @@ -372,21 +372,6 @@ static int papr_scm_pmu_event_init(struct perf_event *event) struct nvdimm_pmu *nd_pmu = to_nvdimm_pmu(event->pmu); struct papr_scm_priv *p; - if (!nd_pmu) - return -EINVAL; - - /* test the event attr type for PMU enumeration */ - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* it does not support event sampling mode */ - if (is_sampling_event(event)) - return -EOPNOTSUPP; - - /* no branch sampling */ - if (has_branch_stack(event)) - return -EOPNOTSUPP; - p = (struct papr_scm_priv *)nd_pmu->dev->driver_data; if (!p) return -EINVAL; @@ -463,8 +448,7 @@ static void papr_scm_pmu_register(struct papr_scm_priv *p) nd_pmu->pmu.add = papr_scm_pmu_add; nd_pmu->pmu.del = papr_scm_pmu_del; - nd_pmu->pmu.capabilities = PERF_PMU_CAP_NO_INTERRUPT | - PERF_PMU_CAP_NO_EXCLUDE; + nd_pmu->pmu.capabilities = PERF_PMU_CAP_NO_EXCLUDE; /*updating the cpumask variable */ nodeid = numa_map_to_online_node(dev_to_node(&p->pdev->dev)); diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c index 4d09954ebf49e8..fa732e94f6e409 100644 --- a/arch/s390/kernel/perf_cpum_cf.c +++ b/arch/s390/kernel/perf_cpum_cf.c @@ -760,8 +760,6 @@ static int __hw_perf_event_init(struct perf_event *event, unsigned int type) break; case PERF_TYPE_HARDWARE: - if (is_sampling_event(event)) /* No sampling support */ - return -ENOENT; ev = attr->config; if (!attr->exclude_user && attr->exclude_kernel) { /* @@ -1056,7 +1054,7 @@ static void cpumf_pmu_del(struct perf_event *event, int flags) /* Performance monitoring unit for s390x */ static struct pmu cpumf_pmu = { .task_ctx_nr = perf_sw_context, - .capabilities = PERF_PMU_CAP_NO_INTERRUPT, + .capabilities = PERF_PMU_CAP_RAW_EVENTS, .pmu_enable = cpumf_pmu_enable, .pmu_disable = cpumf_pmu_disable, .event_init = cpumf_pmu_event_init, @@ -1790,8 +1788,7 @@ static int cfdiag_event_init(struct perf_event *event) struct perf_event_attr *attr = &event->attr; int err = -ENOENT; - if (event->attr.config != PERF_EVENT_CPUM_CF_DIAG || - event->attr.type != event->pmu->type) + if (event->attr.config != PERF_EVENT_CPUM_CF_DIAG) goto out; /* Raw events are used to access counters directly, @@ -1861,6 +1858,7 @@ static const struct attribute_group *cfdiag_attr_groups[] = { */ static struct pmu cf_diag = { .task_ctx_nr = perf_sw_context, + .capabilities = PERF_PMU_CAP_SAMPLING, .event_init = cfdiag_event_init, .pmu_enable = cpumf_pmu_enable, .pmu_disable = cpumf_pmu_disable, diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c index f432869f89213d..3d2c400f0aaab0 100644 --- a/arch/s390/kernel/perf_cpum_sf.c +++ b/arch/s390/kernel/perf_cpum_sf.c @@ -1892,6 +1892,8 @@ static const struct attribute_group *cpumsf_pmu_attr_groups[] = { }; static struct pmu cpumf_sampling = { + .capabilities = PERF_PMU_CAP_SAMPLING, + .pmu_enable = cpumsf_pmu_enable, .pmu_disable = cpumsf_pmu_disable, diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index f373a1009c456e..b5b6d8b5d943f7 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -569,6 +569,7 @@ static const struct attribute_group *paicrypt_attr_groups[] = { /* Performance monitoring unit for mapped counters */ static struct pmu paicrypt = { .task_ctx_nr = perf_hw_context, + .capabilities = PERF_PMU_CAP_SAMPLING | PERF_PMU_CAP_RAW_EVENTS, .event_init = paicrypt_event_init, .add = paicrypt_add, .del = paicrypt_del, diff --git a/arch/s390/kernel/perf_pai_ext.c b/arch/s390/kernel/perf_pai_ext.c index d827473e7f87f8..bcd28c38da70dc 100644 --- a/arch/s390/kernel/perf_pai_ext.c +++ b/arch/s390/kernel/perf_pai_ext.c @@ -595,6 +595,7 @@ static const struct attribute_group *paiext_attr_groups[] = { /* Performance monitoring unit for mapped counters */ static struct pmu paiext = { .task_ctx_nr = perf_hw_context, + .capabilities = PERF_PMU_CAP_SAMPLING | PERF_PMU_CAP_RAW_EVENTS, .event_init = paiext_event_init, .add = paiext_add, .del = paiext_del, diff --git a/arch/sh/kernel/perf_event.c b/arch/sh/kernel/perf_event.c index 1d2507f2243723..d1b53453852496 100644 --- a/arch/sh/kernel/perf_event.c +++ b/arch/sh/kernel/perf_event.c @@ -352,7 +352,6 @@ int register_sh_pmu(struct sh_pmu *_pmu) * no interrupts, and are therefore unable to do sampling without * further work and timer assistance. */ - pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; WARN_ON(_pmu->num_events > MAX_HWEVENTS); diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index cae4d33002a54e..6ecea8e7b592a4 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -1357,8 +1357,7 @@ static int collect_events(struct perf_event *group, int max_count, current_idx[n++] = PIC_NO_INDEX; } for_each_sibling_event(event, group) { - if (!is_software_event(event) && - event->state != PERF_EVENT_STATE_OFF) { + if (!is_software_event(event)) { if (n >= max_count) return -1; evts[n] = event; @@ -1574,6 +1573,7 @@ static int sparc_pmu_commit_txn(struct pmu *pmu) } static struct pmu pmu = { + .capabilities = PERF_PMU_CAP_SAMPLING, .pmu_enable = sparc_pmu_enable, .pmu_disable = sparc_pmu_disable, .event_init = sparc_pmu_event_init, diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c index 112f43b23ebf84..ed07d80b6fe0eb 100644 --- a/arch/x86/events/amd/ibs.c +++ b/arch/x86/events/amd/ibs.c @@ -248,27 +248,6 @@ int forward_event_to_ibs(struct perf_event *event) return -ENOENT; } -/* - * Grouping of IBS events is not possible since IBS can have only - * one event active at any point in time. - */ -static int validate_group(struct perf_event *event) -{ - struct perf_event *sibling; - - if (event->group_leader == event) - return 0; - - if (event->group_leader->pmu == event->pmu) - return -EINVAL; - - for_each_sibling_event(sibling, event->group_leader) { - if (sibling->pmu == event->pmu) - return -EINVAL; - } - return 0; -} - static bool perf_ibs_ldlat_event(struct perf_ibs *perf_ibs, struct perf_event *event) { @@ -309,9 +288,12 @@ static int perf_ibs_init(struct perf_event *event) event->attr.exclude_hv)) return -EINVAL; - ret = validate_group(event); - if (ret) - return ret; + /* + * Grouping of IBS events is not possible since IBS can have only + * one event active at any point in time. + */ + if (in_hardware_group(event)) + return -EINVAL; if (hwc->sample_period) { if (config & perf_ibs->cnt_mask) @@ -786,6 +768,7 @@ static struct perf_ibs perf_ibs_fetch = { .pmu = { .task_ctx_nr = perf_hw_context, + .capabilities = PERF_PMU_CAP_SAMPLING, .event_init = perf_ibs_init, .add = perf_ibs_add, .del = perf_ibs_del, @@ -811,6 +794,7 @@ static struct perf_ibs perf_ibs_op = { .pmu = { .task_ctx_nr = perf_hw_context, + .capabilities = PERF_PMU_CAP_SAMPLING, .event_init = perf_ibs_init, .add = perf_ibs_add, .del = perf_ibs_del, diff --git a/arch/x86/events/amd/iommu.c b/arch/x86/events/amd/iommu.c index a721da9987ddd2..8053bec14dec43 100644 --- a/arch/x86/events/amd/iommu.c +++ b/arch/x86/events/amd/iommu.c @@ -209,21 +209,6 @@ static int perf_iommu_event_init(struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; - /* test the event attr type check for PMU enumeration */ - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* - * IOMMU counters are shared across all cores. - * Therefore, it does not support per-process mode. - * Also, it does not support event sampling mode. - */ - if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) - return -EINVAL; - - if (event->cpu < 0) - return -EINVAL; - /* update the hw_perf_event struct with the iommu config data */ hwc->conf = event->attr.config; hwc->conf1 = event->attr.config1; diff --git a/arch/x86/events/amd/power.c b/arch/x86/events/amd/power.c index dad42790cf7d56..a5e42ee2464aa5 100644 --- a/arch/x86/events/amd/power.c +++ b/arch/x86/events/amd/power.c @@ -125,14 +125,7 @@ static int pmu_event_init(struct perf_event *event) { u64 cfg = event->attr.config & AMD_POWER_EVENT_MASK; - /* Only look at AMD power events. */ - if (event->attr.type != pmu_class.type) - return -ENOENT; - /* Unsupported modes and filters. */ - if (event->attr.sample_period) - return -EINVAL; - if (cfg != AMD_POWER_EVENTSEL_PKG) return -EINVAL; diff --git a/arch/x86/events/amd/uncore.c b/arch/x86/events/amd/uncore.c index e8b6af199c738e..76f58c7b4c1931 100644 --- a/arch/x86/events/amd/uncore.c +++ b/arch/x86/events/amd/uncore.c @@ -270,12 +270,6 @@ static int amd_uncore_event_init(struct perf_event *event) struct amd_uncore_ctx *ctx; struct hw_perf_event *hwc = &event->hw; - if (event->attr.type != event->pmu->type) - return -ENOENT; - - if (event->cpu < 0) - return -EINVAL; - pmu = event_to_amd_uncore_pmu(event); ctx = *per_cpu_ptr(pmu->ctx, event->cpu); if (!ctx) @@ -767,7 +761,7 @@ int amd_uncore_df_ctx_init(struct amd_uncore *uncore, unsigned int cpu) .start = amd_uncore_start, .stop = amd_uncore_stop, .read = amd_uncore_read, - .capabilities = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_NO_INTERRUPT, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, .module = THIS_MODULE, }; @@ -903,7 +897,7 @@ int amd_uncore_l3_ctx_init(struct amd_uncore *uncore, unsigned int cpu) .start = amd_uncore_start, .stop = amd_uncore_stop, .read = amd_uncore_read, - .capabilities = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_NO_INTERRUPT, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, .module = THIS_MODULE, }; @@ -1068,7 +1062,7 @@ int amd_uncore_umc_ctx_init(struct amd_uncore *uncore, unsigned int cpu) .start = amd_uncore_umc_start, .stop = amd_uncore_stop, .read = amd_uncore_umc_read, - .capabilities = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_NO_INTERRUPT, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, .module = THIS_MODULE, }; diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 7610f26dfbd90c..764728bb80aed2 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -1211,7 +1211,7 @@ static int collect_events(struct cpu_hw_events *cpuc, struct perf_event *leader, return n; for_each_sibling_event(event, leader) { - if (!is_x86_event(event) || event->state <= PERF_EVENT_STATE_OFF) + if (!is_x86_event(event)) continue; if (collect_event(cpuc, event, max_count, n)) @@ -1836,8 +1836,7 @@ static void __init pmu_check_apic(void) * events (user-space has to fall back and * sample via a hrtimer based software event): */ - pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; - + pmu.capabilities &= ~PERF_PMU_CAP_SAMPLING; } static struct attribute_group x86_pmu_format_group __ro_after_init = { @@ -2698,6 +2697,8 @@ static bool x86_pmu_filter(struct pmu *pmu, int cpu) } static struct pmu pmu = { + .capabilities = PERF_PMU_CAP_SAMPLING | PERF_PMU_CAP_RAW_EVENTS, + .pmu_enable = x86_pmu_enable, .pmu_disable = x86_pmu_disable, diff --git a/arch/x86/events/intel/bts.c b/arch/x86/events/intel/bts.c index 61da6b8a3d519f..27e23153ba6fb0 100644 --- a/arch/x86/events/intel/bts.c +++ b/arch/x86/events/intel/bts.c @@ -565,9 +565,6 @@ static int bts_event_init(struct perf_event *event) { int ret; - if (event->attr.type != bts_pmu.type) - return -ENOENT; - /* * BTS leaks kernel addresses even when CPL0 tracing is * disabled, so disallow intel_bts driver for unprivileged diff --git a/arch/x86/events/intel/cstate.c b/arch/x86/events/intel/cstate.c index ec753e39b00778..90a884d7786454 100644 --- a/arch/x86/events/intel/cstate.c +++ b/arch/x86/events/intel/cstate.c @@ -277,16 +277,6 @@ static int cstate_pmu_event_init(struct perf_event *event) { u64 cfg = event->attr.config; - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* unsupported modes and filters */ - if (event->attr.sample_period) /* no sampling */ - return -EINVAL; - - if (event->cpu < 0) - return -EINVAL; - if (event->pmu == &cstate_core_pmu) { if (cfg >= PERF_CSTATE_CORE_EVENT_MAX) return -EINVAL; @@ -397,7 +387,7 @@ static struct pmu cstate_core_pmu = { .start = cstate_pmu_event_start, .stop = cstate_pmu_event_stop, .read = cstate_pmu_event_update, - .capabilities = PERF_PMU_CAP_NO_INTERRUPT | PERF_PMU_CAP_NO_EXCLUDE, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, .scope = PERF_PMU_SCOPE_CORE, .module = THIS_MODULE, }; @@ -413,7 +403,7 @@ static struct pmu cstate_pkg_pmu = { .start = cstate_pmu_event_start, .stop = cstate_pmu_event_stop, .read = cstate_pmu_event_update, - .capabilities = PERF_PMU_CAP_NO_INTERRUPT | PERF_PMU_CAP_NO_EXCLUDE, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, .scope = PERF_PMU_SCOPE_PKG, .module = THIS_MODULE, }; @@ -429,7 +419,7 @@ static struct pmu cstate_module_pmu = { .start = cstate_pmu_event_start, .stop = cstate_pmu_event_stop, .read = cstate_pmu_event_update, - .capabilities = PERF_PMU_CAP_NO_INTERRUPT | PERF_PMU_CAP_NO_EXCLUDE, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, .scope = PERF_PMU_SCOPE_CLUSTER, .module = THIS_MODULE, }; diff --git a/arch/x86/events/intel/pt.c b/arch/x86/events/intel/pt.c index e8cf29d2b10c96..a5004dd7632bd2 100644 --- a/arch/x86/events/intel/pt.c +++ b/arch/x86/events/intel/pt.c @@ -1795,9 +1795,6 @@ static void pt_event_destroy(struct perf_event *event) static int pt_event_init(struct perf_event *event) { - if (event->attr.type != pt_pmu.pmu.type) - return -ENOENT; - if (!pt_event_valid(event)) return -EINVAL; diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c index a762f7f5b16165..98ffab403bb45b 100644 --- a/arch/x86/events/intel/uncore.c +++ b/arch/x86/events/intel/uncore.c @@ -406,8 +406,7 @@ uncore_collect_events(struct intel_uncore_box *box, struct perf_event *leader, return n; for_each_sibling_event(event, leader) { - if (!is_box_event(box, event) || - event->state <= PERF_EVENT_STATE_OFF) + if (!is_box_event(box, event)) continue; if (n >= max_count) @@ -732,24 +731,11 @@ static int uncore_pmu_event_init(struct perf_event *event) struct hw_perf_event *hwc = &event->hw; int ret; - if (event->attr.type != event->pmu->type) - return -ENOENT; - pmu = uncore_event_to_pmu(event); /* no device found for this pmu */ if (!pmu->registered) return -ENOENT; - /* Sampling not supported yet */ - if (hwc->sample_period) - return -EINVAL; - - /* - * Place all uncore events for a particular physical package - * onto a single cpu - */ - if (event->cpu < 0) - return -EINVAL; box = uncore_pmu_to_box(pmu, event->cpu); if (!box || box->cpu < 0) return -EINVAL; diff --git a/arch/x86/events/intel/uncore_snb.c b/arch/x86/events/intel/uncore_snb.c index 807e582b8f17dc..8537f61bb0934f 100644 --- a/arch/x86/events/intel/uncore_snb.c +++ b/arch/x86/events/intel/uncore_snb.c @@ -906,29 +906,11 @@ static int snb_uncore_imc_event_init(struct perf_event *event) u64 cfg = event->attr.config & SNB_UNCORE_PCI_IMC_EVENT_MASK; int idx, base; - if (event->attr.type != event->pmu->type) - return -ENOENT; - pmu = uncore_event_to_pmu(event); /* no device found for this pmu */ if (!pmu->registered) return -ENOENT; - /* Sampling not supported yet */ - if (hwc->sample_period) - return -EINVAL; - - /* unsupported modes and filters */ - if (event->attr.sample_period) /* no sampling */ - return -EINVAL; - - /* - * Place all uncore events for a particular physical package - * onto a single cpu - */ - if (event->cpu < 0) - return -EINVAL; - /* check only supported bits are set */ if (event->attr.config & ~SNB_UNCORE_PCI_IMC_EVENT_MASK) return -EINVAL; diff --git a/arch/x86/events/msr.c b/arch/x86/events/msr.c index 7f5007a4752a17..cf6214849a2537 100644 --- a/arch/x86/events/msr.c +++ b/arch/x86/events/msr.c @@ -206,13 +206,7 @@ static int msr_event_init(struct perf_event *event) { u64 cfg = event->attr.config; - if (event->attr.type != event->pmu->type) - return -ENOENT; - /* unsupported modes and filters */ - if (event->attr.sample_period) /* no sampling */ - return -EINVAL; - if (cfg >= PERF_MSR_EVENT_MAX) return -EINVAL; @@ -298,7 +292,7 @@ static struct pmu pmu_msr = { .start = msr_event_start, .stop = msr_event_stop, .read = msr_event_update, - .capabilities = PERF_PMU_CAP_NO_INTERRUPT | PERF_PMU_CAP_NO_EXCLUDE, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, .attr_update = attr_update, }; diff --git a/arch/x86/events/rapl.c b/arch/x86/events/rapl.c index defd86137f123f..5d298e371b282c 100644 --- a/arch/x86/events/rapl.c +++ b/arch/x86/events/rapl.c @@ -370,21 +370,10 @@ static int rapl_pmu_event_init(struct perf_event *event) unsigned int rapl_pmu_idx; struct rapl_pmus *rapl_pmus; - /* only look at RAPL events */ - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* unsupported modes and filters */ - if (event->attr.sample_period) /* no sampling */ - return -EINVAL; - /* check only supported bits are set */ if (event->attr.config & ~RAPL_EVENT_MASK) return -EINVAL; - if (event->cpu < 0) - return -EINVAL; - rapl_pmus = container_of(event->pmu, struct rapl_pmus, pmu); if (!rapl_pmus) return -EINVAL; diff --git a/arch/xtensa/kernel/perf_event.c b/arch/xtensa/kernel/perf_event.c index 223f1d4523109d..b03a2feb0f928e 100644 --- a/arch/xtensa/kernel/perf_event.c +++ b/arch/xtensa/kernel/perf_event.c @@ -397,6 +397,7 @@ irqreturn_t xtensa_pmu_irq_handler(int irq, void *dev_id) } static struct pmu xtensa_pmu = { + .capabilities = PERF_PMU_CAP_SAMPLING, .pmu_enable = xtensa_pmu_enable, .pmu_disable = xtensa_pmu_disable, .event_init = xtensa_pmu_event_init, diff --git a/drivers/devfreq/event/rockchip-dfi.c b/drivers/devfreq/event/rockchip-dfi.c index 0470d7c175f4f6..87ec7bc965bd09 100644 --- a/drivers/devfreq/event/rockchip-dfi.c +++ b/drivers/devfreq/event/rockchip-dfi.c @@ -401,19 +401,10 @@ static const struct attribute_group *attr_groups[] = { static int rockchip_ddr_perf_event_init(struct perf_event *event) { - struct rockchip_dfi *dfi = container_of(event->pmu, struct rockchip_dfi, pmu); - - if (event->attr.type != event->pmu->type) - return -ENOENT; - - if (event->attach_state & PERF_ATTACH_TASK) + /* Disallow groups since we can't start/stop/read multiple counters at once */ + if (in_hardware_group(event)) return -EINVAL; - if (event->cpu < 0) { - dev_warn(dfi->dev, "Can't provide per-task data!\n"); - return -EINVAL; - } - return 0; } diff --git a/drivers/dma/idxd/perfmon.c b/drivers/dma/idxd/perfmon.c index 4b6af2f15d8ab9..4d6f1fc4768582 100644 --- a/drivers/dma/idxd/perfmon.c +++ b/drivers/dma/idxd/perfmon.c @@ -75,8 +75,7 @@ static int perfmon_collect_events(struct idxd_pmu *idxd_pmu, return n; for_each_sibling_event(event, leader) { - if (!is_idxd_event(idxd_pmu, event) || - event->state <= PERF_EVENT_STATE_OFF) + if (!is_idxd_event(idxd_pmu, event)) continue; if (n >= max_count) @@ -172,20 +171,6 @@ static int perfmon_pmu_event_init(struct perf_event *event) idxd = event_to_idxd(event); event->hw.idx = -1; - - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* sampling not supported */ - if (event->attr.sample_period) - return -EINVAL; - - if (event->cpu < 0) - return -EINVAL; - - if (event->pmu != &idxd->idxd_pmu->pmu) - return -EINVAL; - event->hw.event_base = ioread64(PERFMON_TABLE_OFFSET(idxd)); event->hw.config = event->attr.config; diff --git a/drivers/fpga/dfl-fme-perf.c b/drivers/fpga/dfl-fme-perf.c index 7422d2bc6f3742..0cc9538e0898ad 100644 --- a/drivers/fpga/dfl-fme-perf.c +++ b/drivers/fpga/dfl-fme-perf.c @@ -799,21 +799,6 @@ static int fme_perf_event_init(struct perf_event *event) struct fme_perf_event_ops *ops; u32 eventid, evtype, portid; - /* test the event attr type check for PMU enumeration */ - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* - * fme counters are shared across all cores. - * Therefore, it does not support per-process mode. - * Also, it does not support event sampling mode. - */ - if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) - return -EINVAL; - - if (event->cpu < 0) - return -EINVAL; - if (event->cpu != priv->cpu) return -EINVAL; @@ -921,8 +906,7 @@ static int fme_perf_pmu_register(struct platform_device *pdev, pmu->start = fme_perf_event_start; pmu->stop = fme_perf_event_stop; pmu->read = fme_perf_event_read; - pmu->capabilities = PERF_PMU_CAP_NO_INTERRUPT | - PERF_PMU_CAP_NO_EXCLUDE; + pmu->capabilities = PERF_PMU_CAP_NO_EXCLUDE; name = devm_kasprintf(priv->dev, GFP_KERNEL, "dfl_fme%d", pdev->id); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pmu.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pmu.c index 6e91ea1de5aafa..294a7aea9aaa09 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pmu.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pmu.c @@ -210,10 +210,6 @@ static int amdgpu_perf_event_init(struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; - /* test the event attr type check for PMU enumeration */ - if (event->attr.type != event->pmu->type) - return -ENOENT; - /* update the hw_perf_event struct with config data */ hwc->config = event->attr.config; hwc->config_base = AMDGPU_PMU_PERF_TYPE_NONE; diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 5bc696bfbb0fea..193e96976782d1 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -626,19 +626,6 @@ static int i915_pmu_event_init(struct perf_event *event) if (!pmu->registered) return -ENODEV; - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* unsupported modes and filters */ - if (event->attr.sample_period) /* no sampling */ - return -EINVAL; - - if (has_branch_stack(event)) - return -EOPNOTSUPP; - - if (event->cpu < 0) - return -EINVAL; - if (is_engine_event(event)) ret = engine_event_init(event); else diff --git a/drivers/gpu/drm/xe/xe_pmu.c b/drivers/gpu/drm/xe/xe_pmu.c index cab51d826345d0..084e26728c3560 100644 --- a/drivers/gpu/drm/xe/xe_pmu.c +++ b/drivers/gpu/drm/xe/xe_pmu.c @@ -238,24 +238,11 @@ static int xe_pmu_event_init(struct perf_event *event) if (!pmu->registered) return -ENODEV; - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* unsupported modes and filters */ - if (event->attr.sample_period) /* no sampling */ - return -EINVAL; - - if (event->cpu < 0) - return -EINVAL; - gt = config_to_gt_id(event->attr.config); id = config_to_event_id(event->attr.config); if (!event_supported(pmu, gt, id)) return -ENOENT; - if (has_branch_stack(event)) - return -EOPNOTSUPP; - if (!event_param_valid(event)) return -ENOENT; diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index f1551c08ecb20e..fd98eb6a194287 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -178,11 +178,6 @@ static int etm_event_init(struct perf_event *event) { int ret = 0; - if (event->attr.type != etm_pmu.type) { - ret = -ENOENT; - goto out; - } - ret = etm_addr_filters_alloc(event); if (ret) goto out; diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c index 3090479a297988..470226defa14d4 100644 --- a/drivers/hwtracing/ptt/hisi_ptt.c +++ b/drivers/hwtracing/ptt/hisi_ptt.c @@ -998,14 +998,6 @@ static int hisi_ptt_pmu_event_init(struct perf_event *event) int ret; u32 val; - if (event->attr.type != hisi_ptt->hisi_ptt_pmu.type) - return -ENOENT; - - if (event->cpu < 0) { - dev_dbg(event->pmu->dev, "Per-task mode not supported\n"); - return -EOPNOTSUPP; - } - if (event->attach_state & PERF_ATTACH_TASK) return -EOPNOTSUPP; diff --git a/drivers/iommu/intel/perfmon.c b/drivers/iommu/intel/perfmon.c index 75f493bcb353ed..2b9bb89e1fd3a3 100644 --- a/drivers/iommu/intel/perfmon.c +++ b/drivers/iommu/intel/perfmon.c @@ -258,21 +258,25 @@ static int iommu_pmu_validate_group(struct perf_event *event) { struct iommu_pmu *iommu_pmu = iommu_event_to_pmu(event); struct perf_event *sibling; - int nr = 0; + int nr = 1; + if (event == event->group_leader) + return 0; /* * All events in a group must be scheduled simultaneously. * Check whether there is enough counters for all the events. */ - for_each_sibling_event(sibling, event->group_leader) { - if (!is_iommu_pmu_event(iommu_pmu, sibling) || - sibling->state <= PERF_EVENT_STATE_OFF) - continue; + if (is_iommu_pmu_event(iommu_pmu, event->group_leader)) + ++nr; - if (++nr > iommu_pmu->num_cntr) - return -EINVAL; + for_each_sibling_event(sibling, event->group_leader) { + if (is_iommu_pmu_event(iommu_pmu, sibling)) + ++nr; } + if (nr > iommu_pmu->num_cntr) + return -EINVAL; + return 0; } @@ -280,16 +284,6 @@ static int iommu_pmu_event_init(struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* sampling not supported */ - if (event->attr.sample_period) - return -EINVAL; - - if (event->cpu < 0) - return -EINVAL; - if (iommu_pmu_validate_event(event)) return -EINVAL; diff --git a/drivers/perf/alibaba_uncore_drw_pmu.c b/drivers/perf/alibaba_uncore_drw_pmu.c index 99a0ef9817e05f..2404333ff902fc 100644 --- a/drivers/perf/alibaba_uncore_drw_pmu.c +++ b/drivers/perf/alibaba_uncore_drw_pmu.c @@ -526,41 +526,15 @@ static int ali_drw_pmu_event_init(struct perf_event *event) { struct ali_drw_pmu *drw_pmu = to_ali_drw_pmu(event->pmu); struct hw_perf_event *hwc = &event->hw; - struct perf_event *sibling; struct device *dev = drw_pmu->pmu.dev; - if (event->attr.type != event->pmu->type) - return -ENOENT; - - if (is_sampling_event(event)) { - dev_err(dev, "Sampling not supported!\n"); - return -EOPNOTSUPP; - } - - if (event->attach_state & PERF_ATTACH_TASK) { - dev_err(dev, "Per-task counter cannot allocate!\n"); - return -EOPNOTSUPP; - } - event->cpu = drw_pmu->cpu; - if (event->cpu < 0) { - dev_err(dev, "Per-task mode not supported!\n"); - return -EOPNOTSUPP; - } - if (event->group_leader != event && - !is_software_event(event->group_leader)) { + if (in_hardware_group(event)) { dev_err(dev, "driveway only allow one event!\n"); return -EINVAL; } - for_each_sibling_event(sibling, event->group_leader) { - if (sibling != event && !is_software_event(sibling)) { - dev_err(dev, "driveway event not allowed!\n"); - return -EINVAL; - } - } - /* reset all the pmu counters */ writel(ALI_DRW_PMU_CNT_RST, drw_pmu->cfg_base + ALI_DRW_PMU_CNT_CTRL); diff --git a/drivers/perf/amlogic/meson_ddr_pmu_core.c b/drivers/perf/amlogic/meson_ddr_pmu_core.c index c1e755c356a333..8f46cf835fb513 100644 --- a/drivers/perf/amlogic/meson_ddr_pmu_core.c +++ b/drivers/perf/amlogic/meson_ddr_pmu_core.c @@ -121,15 +121,6 @@ static int meson_ddr_perf_event_init(struct perf_event *event) u64 config1 = event->attr.config1; u64 config2 = event->attr.config2; - if (event->attr.type != event->pmu->type) - return -ENOENT; - - if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) - return -EOPNOTSUPP; - - if (event->cpu < 0) - return -EOPNOTSUPP; - /* check if the number of parameters is too much */ if (event->attr.config != ALL_CHAN_COUNTER_ID && hweight64(config1) + hweight64(config2) > MAX_AXI_PORTS_OF_CHANNEL) diff --git a/drivers/perf/arm-cci.c b/drivers/perf/arm-cci.c index 1cc3214d6b6da0..84ba97389c6585 100644 --- a/drivers/perf/arm-cci.c +++ b/drivers/perf/arm-cci.c @@ -333,7 +333,7 @@ static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_ev int if_type; if (hw_event & ~CCI400_PMU_EVENT_MASK) - return -ENOENT; + return -EINVAL; if (hw_event == CCI400_PMU_CYCLES) return hw_event; @@ -354,14 +354,14 @@ static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_ev if_type = CCI_IF_MASTER; break; default: - return -ENOENT; + return -EINVAL; } if (ev_code >= cci_pmu->model->event_ranges[if_type].min && ev_code <= cci_pmu->model->event_ranges[if_type].max) return hw_event; - return -ENOENT; + return -EINVAL; } static int probe_cci400_revision(struct cci_pmu *cci_pmu) @@ -541,7 +541,7 @@ static int cci500_validate_hw_event(struct cci_pmu *cci_pmu, int if_type; if (hw_event & ~CCI5xx_PMU_EVENT_MASK) - return -ENOENT; + return -EINVAL; switch (ev_source) { case CCI5xx_PORT_S0: @@ -565,14 +565,14 @@ static int cci500_validate_hw_event(struct cci_pmu *cci_pmu, if_type = CCI_IF_GLOBAL; break; default: - return -ENOENT; + return -EINVAL; } if (ev_code >= cci_pmu->model->event_ranges[if_type].min && ev_code <= cci_pmu->model->event_ranges[if_type].max) return hw_event; - return -ENOENT; + return -EINVAL; } /* @@ -592,7 +592,7 @@ static int cci550_validate_hw_event(struct cci_pmu *cci_pmu, int if_type; if (hw_event & ~CCI5xx_PMU_EVENT_MASK) - return -ENOENT; + return -EINVAL; switch (ev_source) { case CCI5xx_PORT_S0: @@ -617,14 +617,14 @@ static int cci550_validate_hw_event(struct cci_pmu *cci_pmu, if_type = CCI_IF_GLOBAL; break; default: - return -ENOENT; + return -EINVAL; } if (ev_code >= cci_pmu->model->event_ranges[if_type].min && ev_code <= cci_pmu->model->event_ranges[if_type].max) return hw_event; - return -ENOENT; + return -EINVAL; } #endif /* CONFIG_ARM_CCI5xx_PMU */ @@ -801,17 +801,6 @@ static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *ev return -EAGAIN; } -static int pmu_map_event(struct perf_event *event) -{ - struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu); - - if (event->attr.type < PERF_TYPE_MAX || - !cci_pmu->model->validate_hw_event) - return -ENOENT; - - return cci_pmu->model->validate_hw_event(cci_pmu, event->attr.config); -} - static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler) { int i; @@ -1216,21 +1205,8 @@ static int validate_event(struct pmu *cci_pmu, struct cci_pmu_hw_events *hw_events, struct perf_event *event) { - if (is_software_event(event)) - return 1; - - /* - * Reject groups spanning multiple HW PMUs (e.g. CPU + CCI). The - * core perf code won't check that the pmu->ctx == leader->ctx - * until after pmu->event_init(event). - */ + /* Ignore grouped events that aren't ours */ if (event->pmu != cci_pmu) - return 0; - - if (event->state < PERF_EVENT_STATE_OFF) - return 1; - - if (event->state == PERF_EVENT_STATE_OFF && !event->attr.enable_on_exec) return 1; return pmu_get_event_idx(hw_events, event) >= 0; @@ -1266,10 +1242,11 @@ static int validate_group(struct perf_event *event) static int __hw_perf_event_init(struct perf_event *event) { + struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu); struct hw_perf_event *hwc = &event->hw; int mapping; - mapping = pmu_map_event(event); + mapping = cci_pmu->model->validate_hw_event(cci_pmu, event->attr.config); if (mapping < 0) { pr_debug("event %x:%llx not supported\n", event->attr.type, @@ -1306,13 +1283,6 @@ static int cci_pmu_event_init(struct perf_event *event) atomic_t *active_events = &cci_pmu->active_events; int err = 0; - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* Shared by all CPUs, no meaningful state to sample */ - if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) - return -EOPNOTSUPP; - /* * Following the example set by other "uncore" PMUs, we accept any CPU * and rewrite its affinity dynamically rather than having perf core @@ -1322,8 +1292,6 @@ static int cci_pmu_event_init(struct perf_event *event) * the event being installed into its context, so the PMU's CPU can't * change under our feet. */ - if (event->cpu < 0) - return -EINVAL; event->cpu = cci_pmu->cpu; event->destroy = hw_perf_event_destroy; diff --git a/drivers/perf/arm-ccn.c b/drivers/perf/arm-ccn.c index 1a0d0e1a226334..6ec4cb9417e7dc 100644 --- a/drivers/perf/arm-ccn.c +++ b/drivers/perf/arm-ccn.c @@ -704,31 +704,12 @@ static void arm_ccn_pmu_event_release(struct perf_event *event) static int arm_ccn_pmu_event_init(struct perf_event *event) { struct arm_ccn *ccn; - struct hw_perf_event *hw = &event->hw; u32 node_xp, type, event_id; int valid; int i; - struct perf_event *sibling; - - if (event->attr.type != event->pmu->type) - return -ENOENT; ccn = pmu_to_arm_ccn(event->pmu); - if (hw->sample_period) { - dev_dbg(ccn->dev, "Sampling not supported!\n"); - return -EOPNOTSUPP; - } - - if (has_branch_stack(event)) { - dev_dbg(ccn->dev, "Can't exclude execution levels!\n"); - return -EINVAL; - } - - if (event->cpu < 0) { - dev_dbg(ccn->dev, "Can't provide per-task data!\n"); - return -EOPNOTSUPP; - } /* * Many perf core operations (eg. events rotation) operate on a * single CPU context. This is obvious for CPU PMUs, where one @@ -814,21 +795,6 @@ static int arm_ccn_pmu_event_init(struct perf_event *event) node_xp, type, port); } - /* - * We must NOT create groups containing mixed PMUs, although software - * events are acceptable (for example to create a CCN group - * periodically read when a hrtimer aka cpu-clock leader triggers). - */ - if (event->group_leader->pmu != event->pmu && - !is_software_event(event->group_leader)) - return -EINVAL; - - for_each_sibling_event(sibling, event->group_leader) { - if (sibling->pmu != event->pmu && - !is_software_event(sibling)) - return -EINVAL; - } - return 0; } diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c index 11fb2234b10fcf..0f65d28c1b7ad1 100644 --- a/drivers/perf/arm-cmn.c +++ b/drivers/perf/arm-cmn.c @@ -1652,7 +1652,7 @@ static void arm_cmn_val_add_event(struct arm_cmn *cmn, struct arm_cmn_val *val, enum cmn_node_type type; int i; - if (is_software_event(event)) + if (event->pmu != &cmn->pmu) return; type = CMN_EVENT_TYPE(event); @@ -1693,9 +1693,6 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event) if (leader == event) return 0; - if (event->pmu != leader->pmu && !is_software_event(leader)) - return -EINVAL; - val = kzalloc(sizeof(*val), GFP_KERNEL); if (!val) return -ENOMEM; @@ -1768,16 +1765,6 @@ static int arm_cmn_event_init(struct perf_event *event) bool bynodeid; u16 nodeid, eventid; - if (event->attr.type != event->pmu->type) - return -ENOENT; - - if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) - return -EINVAL; - - event->cpu = cmn->cpu; - if (event->cpu < 0) - return -EINVAL; - type = CMN_EVENT_TYPE(event); /* DTC events (i.e. cycles) already have everything they need */ if (type == CMN_TYPE_DTC) diff --git a/drivers/perf/arm-ni.c b/drivers/perf/arm-ni.c index 1615a05640319b..c48c820974121d 100644 --- a/drivers/perf/arm-ni.c +++ b/drivers/perf/arm-ni.c @@ -271,40 +271,37 @@ static void arm_ni_pmu_disable(struct pmu *pmu) } struct arm_ni_val { + const struct pmu *pmu; unsigned int evcnt; unsigned int ccnt; }; -static bool arm_ni_val_count_event(struct perf_event *evt, struct arm_ni_val *val) +static void arm_ni_val_count_event(struct perf_event *evt, struct arm_ni_val *val) { - if (is_software_event(evt)) - return true; - - if (NI_EVENT_TYPE(evt) == NI_PMU) { - val->ccnt++; - return val->ccnt <= 1; + if (evt->pmu == val->pmu) { + if (NI_EVENT_TYPE(evt) == NI_PMU) + val->ccnt++; + else + val->evcnt++; } - - val->evcnt++; - return val->evcnt <= NI_NUM_COUNTERS; } static int arm_ni_validate_group(struct perf_event *event) { struct perf_event *sibling, *leader = event->group_leader; - struct arm_ni_val val = { 0 }; + struct arm_ni_val val = { .pmu = event->pmu }; if (leader == event) return 0; arm_ni_val_count_event(event, &val); - if (!arm_ni_val_count_event(leader, &val)) + arm_ni_val_count_event(leader, &val); + for_each_sibling_event(sibling, leader) + arm_ni_val_count_event(sibling, &val); + + if (val.evcnt > NI_NUM_COUNTERS || val.ccnt > 1) return -EINVAL; - for_each_sibling_event(sibling, leader) { - if (!arm_ni_val_count_event(sibling, &val)) - return -EINVAL; - } return 0; } @@ -312,12 +309,6 @@ static int arm_ni_event_init(struct perf_event *event) { struct arm_ni_cd *cd = pmu_to_cd(event->pmu); - if (event->attr.type != event->pmu->type) - return -ENOENT; - - if (is_sampling_event(event)) - return -EINVAL; - event->cpu = cd_to_ni(cd)->cpu; if (NI_EVENT_TYPE(event) == NI_PMU) return arm_ni_validate_group(event); diff --git a/drivers/perf/arm_cspmu/arm_cspmu.c b/drivers/perf/arm_cspmu/arm_cspmu.c index efa9b229e7012e..47d207a97bfcbb 100644 --- a/drivers/perf/arm_cspmu/arm_cspmu.c +++ b/drivers/perf/arm_cspmu/arm_cspmu.c @@ -561,12 +561,9 @@ static bool arm_cspmu_validate_event(struct pmu *pmu, struct arm_cspmu_hw_events *hw_events, struct perf_event *event) { - if (is_software_event(event)) - return true; - - /* Reject groups spanning multiple HW PMUs. */ + /* Ignore grouped events that aren't ours */ if (event->pmu != pmu) - return false; + return true; return (arm_cspmu_get_event_idx(hw_events, event) >= 0); } @@ -604,25 +601,6 @@ static int arm_cspmu_event_init(struct perf_event *event) cspmu = to_arm_cspmu(event->pmu); - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* - * Following other "uncore" PMUs, we do not support sampling mode or - * attach to a task (per-process mode). - */ - if (is_sampling_event(event)) { - dev_dbg(cspmu->pmu.dev, - "Can't support sampling events\n"); - return -EOPNOTSUPP; - } - - if (event->cpu < 0 || event->attach_state & PERF_ATTACH_TASK) { - dev_dbg(cspmu->pmu.dev, - "Can't support per-task counters\n"); - return -EINVAL; - } - /* * Make sure the CPU assignment is on one of the CPUs associated with * this PMU. @@ -1131,7 +1109,7 @@ static int arm_cspmu_get_cpus(struct arm_cspmu *cspmu) static int arm_cspmu_register_pmu(struct arm_cspmu *cspmu) { - int ret, capabilities; + int ret; ret = arm_cspmu_alloc_attr_groups(cspmu); if (ret) @@ -1142,10 +1120,6 @@ static int arm_cspmu_register_pmu(struct arm_cspmu *cspmu) if (ret) return ret; - capabilities = PERF_PMU_CAP_NO_EXCLUDE; - if (cspmu->irq == 0) - capabilities |= PERF_PMU_CAP_NO_INTERRUPT; - cspmu->pmu = (struct pmu){ .task_ctx_nr = perf_invalid_context, .module = cspmu->impl.module, @@ -1159,7 +1133,7 @@ static int arm_cspmu_register_pmu(struct arm_cspmu *cspmu) .stop = arm_cspmu_stop, .read = arm_cspmu_read, .attr_groups = cspmu->attr_groups, - .capabilities = capabilities, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, }; /* Hardware counter init */ diff --git a/drivers/perf/arm_dmc620_pmu.c b/drivers/perf/arm_dmc620_pmu.c index 619cf937602fb5..751a06ba531981 100644 --- a/drivers/perf/arm_dmc620_pmu.c +++ b/drivers/perf/arm_dmc620_pmu.c @@ -513,21 +513,6 @@ static int dmc620_pmu_event_init(struct perf_event *event) { struct dmc620_pmu *dmc620_pmu = to_dmc620_pmu(event->pmu); struct hw_perf_event *hwc = &event->hw; - struct perf_event *sibling; - - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* - * DMC 620 PMUs are shared across all cpus and cannot - * support task bound and sampling events. - */ - if (is_sampling_event(event) || - event->attach_state & PERF_ATTACH_TASK) { - dev_dbg(dmc620_pmu->pmu.dev, - "Can't support per-task counters\n"); - return -EOPNOTSUPP; - } /* * Many perf core operations (eg. events rotation) operate on a @@ -539,27 +524,16 @@ static int dmc620_pmu_event_init(struct perf_event *event) * processor. */ event->cpu = dmc620_pmu->irq->cpu; - if (event->cpu < 0) - return -EINVAL; hwc->idx = -1; - if (event->group_leader == event) - return 0; - /* * We can't atomically disable all HW counters so only one event allowed, * although software events are acceptable. */ - if (!is_software_event(event->group_leader)) + if (in_hardware_group(event)) return -EINVAL; - for_each_sibling_event(sibling, event->group_leader) { - if (sibling != event && - !is_software_event(sibling)) - return -EINVAL; - } - return 0; } diff --git a/drivers/perf/arm_dsu_pmu.c b/drivers/perf/arm_dsu_pmu.c index cb4fb59fe04bb9..eacbe1864794d6 100644 --- a/drivers/perf/arm_dsu_pmu.c +++ b/drivers/perf/arm_dsu_pmu.c @@ -492,11 +492,9 @@ static bool dsu_pmu_validate_event(struct pmu *pmu, struct dsu_hw_events *hw_events, struct perf_event *event) { - if (is_software_event(event)) - return true; - /* Reject groups spanning multiple HW PMUs. */ + /* Ignore grouped events that aren't ours */ if (event->pmu != pmu) - return false; + return true; return dsu_pmu_get_event_idx(hw_events, event) >= 0; } @@ -526,26 +524,6 @@ static int dsu_pmu_event_init(struct perf_event *event) { struct dsu_pmu *dsu_pmu = to_dsu_pmu(event->pmu); - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* We don't support sampling */ - if (is_sampling_event(event)) { - dev_dbg(dsu_pmu->pmu.dev, "Can't support sampling events\n"); - return -EOPNOTSUPP; - } - - /* We cannot support task bound events */ - if (event->cpu < 0 || event->attach_state & PERF_ATTACH_TASK) { - dev_dbg(dsu_pmu->pmu.dev, "Can't support per-task counters\n"); - return -EINVAL; - } - - if (has_branch_stack(event)) { - dev_dbg(dsu_pmu->pmu.dev, "Can't support filtering\n"); - return -EINVAL; - } - if (!cpumask_test_cpu(event->cpu, &dsu_pmu->associated_cpus)) { dev_dbg(dsu_pmu->pmu.dev, "Requested cpu is not associated with the DSU\n"); diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 5c310e803dd783..bc772a3bf41186 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -375,21 +375,8 @@ validate_event(struct pmu *pmu, struct pmu_hw_events *hw_events, { struct arm_pmu *armpmu; - if (is_software_event(event)) - return 1; - - /* - * Reject groups spanning multiple HW PMUs (e.g. CPU + CCI). The - * core perf code won't check that the pmu->ctx == leader->ctx - * until after pmu->event_init(event). - */ + /* Ignore grouped events that aren't ours */ if (event->pmu != pmu) - return 0; - - if (event->state < PERF_EVENT_STATE_OFF) - return 1; - - if (event->state == PERF_EVENT_STATE_OFF && !event->attr.enable_on_exec) return 1; armpmu = to_arm_pmu(event->pmu); @@ -889,7 +876,9 @@ struct arm_pmu *armpmu_alloc(void) * PERF_TYPE_HARDWARE and PERF_TYPE_HW_CACHE events on a * specific PMU. */ - .capabilities = PERF_PMU_CAP_EXTENDED_REGS | + .capabilities = PERF_PMU_CAP_SAMPLING | + PERF_PMU_CAP_RAW_EVENTS | + PERF_PMU_CAP_EXTENDED_REGS | PERF_PMU_CAP_EXTENDED_HW_TYPE, }; diff --git a/drivers/perf/arm_pmu_platform.c b/drivers/perf/arm_pmu_platform.c index 118170a5cedefa..754dba9e45288e 100644 --- a/drivers/perf/arm_pmu_platform.c +++ b/drivers/perf/arm_pmu_platform.c @@ -109,7 +109,7 @@ static int pmu_parse_irqs(struct arm_pmu *pmu) */ if (num_irqs == 0) { dev_warn(dev, "no irqs for PMU, sampling events not supported\n"); - pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; + pmu->pmu.capabilities &= ~PERF_PMU_CAP_SAMPLING; cpumask_setall(&pmu->supported_cpus); return 0; } diff --git a/drivers/perf/arm_smmuv3_pmu.c b/drivers/perf/arm_smmuv3_pmu.c index 621f02a7f43be3..d534a4eb457a1a 100644 --- a/drivers/perf/arm_smmuv3_pmu.c +++ b/drivers/perf/arm_smmuv3_pmu.c @@ -377,9 +377,6 @@ static int smmu_pmu_get_event_idx(struct smmu_pmu *smmu_pmu, static bool smmu_pmu_events_compatible(struct perf_event *curr, struct perf_event *new) { - if (new->pmu != curr->pmu) - return false; - if (to_smmu_pmu(new->pmu)->global_filter && !smmu_pmu_check_global_filter(curr, new)) return false; @@ -401,19 +398,6 @@ static int smmu_pmu_event_init(struct perf_event *event) int group_num_events = 1; u16 event_id; - if (event->attr.type != event->pmu->type) - return -ENOENT; - - if (hwc->sample_period) { - dev_dbg(dev, "Sampling not supported\n"); - return -EOPNOTSUPP; - } - - if (event->cpu < 0) { - dev_dbg(dev, "Per-task mode not supported\n"); - return -EOPNOTSUPP; - } - /* Verify specified event is supported on this PMU */ event_id = get_event(event); if (event_id < SMMU_PMCG_ARCH_MAX_EVENTS && @@ -422,15 +406,6 @@ static int smmu_pmu_event_init(struct perf_event *event) return -EINVAL; } - /* Don't allow groups with mixed PMUs, except for s/w events */ - if (!is_software_event(event->group_leader)) { - if (!smmu_pmu_events_compatible(event->group_leader, event)) - return -EINVAL; - - if (++group_num_events > smmu_pmu->num_counters) - return -EINVAL; - } - /* * Ensure all events are on the same cpu so all events are in the * same cpu context, to avoid races on pmu_enable etc. @@ -442,8 +417,16 @@ static int smmu_pmu_event_init(struct perf_event *event) if (event->group_leader == event) return 0; + if (event->group_leader->pmu == event->pmu) { + if (!smmu_pmu_events_compatible(event->group_leader, event)) + return -EINVAL; + + if (++group_num_events > smmu_pmu->num_counters) + return -EINVAL; + } + for_each_sibling_event(sibling, event->group_leader) { - if (is_software_event(sibling)) + if (sibling->pmu != event->pmu) continue; if (!smmu_pmu_events_compatible(sibling, event)) diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c index 369e77ad5f13ff..89001d2ceabfec 100644 --- a/drivers/perf/arm_spe_pmu.c +++ b/drivers/perf/arm_spe_pmu.c @@ -718,10 +718,6 @@ static int arm_spe_pmu_event_init(struct perf_event *event) struct perf_event_attr *attr = &event->attr; struct arm_spe_pmu *spe_pmu = to_spe_pmu(event->pmu); - /* This is, of course, deeply driver-specific */ - if (attr->type != event->pmu->type) - return -ENOENT; - if (event->cpu >= 0 && !cpumask_test_cpu(event->cpu, &spe_pmu->supported_cpus)) return -ENOENT; @@ -955,7 +951,8 @@ static int arm_spe_pmu_perf_init(struct arm_spe_pmu *spe_pmu) spe_pmu->pmu = (struct pmu) { .module = THIS_MODULE, .parent = &spe_pmu->pdev->dev, - .capabilities = PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_ITRACE, + .capabilities = PERF_PMU_CAP_SAMPLING | + PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_ITRACE, .attr_groups = arm_spe_pmu_attr_groups, /* * We hitch a ride on the software context here, so that diff --git a/drivers/perf/cxl_pmu.c b/drivers/perf/cxl_pmu.c index d094030220bf25..c4f8d5ae45a17a 100644 --- a/drivers/perf/cxl_pmu.c +++ b/drivers/perf/cxl_pmu.c @@ -563,12 +563,6 @@ static int cxl_pmu_event_init(struct perf_event *event) struct cxl_pmu_info *info = pmu_to_cxl_pmu_info(event->pmu); int rc; - /* Top level type sanity check - is this a Hardware Event being requested */ - if (event->attr.type != event->pmu->type) - return -ENOENT; - - if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) - return -EOPNOTSUPP; /* TODO: Validation of any filter */ /* diff --git a/drivers/perf/dwc_pcie_pmu.c b/drivers/perf/dwc_pcie_pmu.c index 146ff57813fb16..a0eb72c38fdb7d 100644 --- a/drivers/perf/dwc_pcie_pmu.c +++ b/drivers/perf/dwc_pcie_pmu.c @@ -353,29 +353,12 @@ static int dwc_pcie_pmu_event_init(struct perf_event *event) { struct dwc_pcie_pmu *pcie_pmu = to_dwc_pcie_pmu(event->pmu); enum dwc_pcie_event_type type = DWC_PCIE_EVENT_TYPE(event); - struct perf_event *sibling; u32 lane; - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* We don't support sampling */ - if (is_sampling_event(event)) - return -EINVAL; - - /* We cannot support task bound events */ - if (event->cpu < 0 || event->attach_state & PERF_ATTACH_TASK) - return -EINVAL; - - if (event->group_leader != event && - !is_software_event(event->group_leader)) + /* Disallow groups since we can't start/stop/read multiple counters at once */ + if (in_hardware_group(event)) return -EINVAL; - for_each_sibling_event(sibling, event->group_leader) { - if (sibling->pmu != event->pmu && !is_software_event(sibling)) - return -EINVAL; - } - if (type < 0 || type >= DWC_PCIE_EVENT_TYPE_MAX) return -EINVAL; diff --git a/drivers/perf/fsl_imx8_ddr_perf.c b/drivers/perf/fsl_imx8_ddr_perf.c index b989ffa95d692f..d63d5d4d90848c 100644 --- a/drivers/perf/fsl_imx8_ddr_perf.c +++ b/drivers/perf/fsl_imx8_ddr_perf.c @@ -331,6 +331,9 @@ static u32 ddr_perf_filter_val(struct perf_event *event) static bool ddr_perf_filters_compatible(struct perf_event *a, struct perf_event *b) { + /* Ignore grouped events that aren't ours */ + if (a->pmu != b->pmu) + return true; if (!ddr_perf_is_filtered(a)) return true; if (!ddr_perf_is_filtered(b)) @@ -398,27 +401,8 @@ static int ddr_perf_event_init(struct perf_event *event) struct hw_perf_event *hwc = &event->hw; struct perf_event *sibling; - if (event->attr.type != event->pmu->type) - return -ENOENT; - - if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) - return -EOPNOTSUPP; - - if (event->cpu < 0) { - dev_warn(pmu->dev, "Can't provide per-task data!\n"); - return -EOPNOTSUPP; - } - - /* - * We must NOT create groups containing mixed PMUs, although software - * events are acceptable (for example to create a CCN group - * periodically read when a hrtimer aka cpu-clock leader triggers). - */ - if (event->group_leader->pmu != event->pmu && - !is_software_event(event->group_leader)) - return -EINVAL; - - if (pmu->devtype_data->quirks & DDR_CAP_AXI_ID_FILTER) { + if (event != event->group_leader && + pmu->devtype_data->quirks & DDR_CAP_AXI_ID_FILTER) { if (!ddr_perf_filters_compatible(event, event->group_leader)) return -EINVAL; for_each_sibling_event(sibling, event->group_leader) { @@ -427,12 +411,6 @@ static int ddr_perf_event_init(struct perf_event *event) } } - for_each_sibling_event(sibling, event->group_leader) { - if (sibling->pmu != event->pmu && - !is_software_event(sibling)) - return -EINVAL; - } - event->cpu = pmu->cpu; hwc->idx = -1; diff --git a/drivers/perf/fsl_imx9_ddr_perf.c b/drivers/perf/fsl_imx9_ddr_perf.c index 267754fdf58146..9e0b2a96948164 100644 --- a/drivers/perf/fsl_imx9_ddr_perf.c +++ b/drivers/perf/fsl_imx9_ddr_perf.c @@ -552,33 +552,6 @@ static int ddr_perf_event_init(struct perf_event *event) { struct ddr_pmu *pmu = to_ddr_pmu(event->pmu); struct hw_perf_event *hwc = &event->hw; - struct perf_event *sibling; - - if (event->attr.type != event->pmu->type) - return -ENOENT; - - if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) - return -EOPNOTSUPP; - - if (event->cpu < 0) { - dev_warn(pmu->dev, "Can't provide per-task data!\n"); - return -EOPNOTSUPP; - } - - /* - * We must NOT create groups containing mixed PMUs, although software - * events are acceptable (for example to create a CCN group - * periodically read when a hrtimer aka cpu-clock leader triggers). - */ - if (event->group_leader->pmu != event->pmu && - !is_software_event(event->group_leader)) - return -EINVAL; - - for_each_sibling_event(sibling, event->group_leader) { - if (sibling->pmu != event->pmu && - !is_software_event(sibling)) - return -EINVAL; - } event->cpu = pmu->cpu; hwc->idx = -1; diff --git a/drivers/perf/hisilicon/hisi_pcie_pmu.c b/drivers/perf/hisilicon/hisi_pcie_pmu.c index c5394d007b61be..b0b736af82e3f2 100644 --- a/drivers/perf/hisilicon/hisi_pcie_pmu.c +++ b/drivers/perf/hisilicon/hisi_pcie_pmu.c @@ -338,21 +338,16 @@ static bool hisi_pcie_pmu_validate_event_group(struct perf_event *event) int counters = 1; int num; - event_group[0] = leader; - if (!is_software_event(leader)) { - if (leader->pmu != event->pmu) - return false; + if (leader == event) + return true; - if (leader != event && !hisi_pcie_pmu_cmp_event(leader, event)) - event_group[counters++] = event; - } + event_group[0] = event; + if (leader->pmu == event->pmu && !hisi_pcie_pmu_cmp_event(leader, event)) + event_group[counters++] = leader; for_each_sibling_event(sibling, event->group_leader) { - if (is_software_event(sibling)) - continue; - if (sibling->pmu != event->pmu) - return false; + continue; for (num = 0; num < counters; num++) { /* @@ -383,19 +378,11 @@ static int hisi_pcie_pmu_event_init(struct perf_event *event) struct hisi_pcie_pmu *pcie_pmu = to_pcie_pmu(event->pmu); struct hw_perf_event *hwc = &event->hw; - /* Check the type first before going on, otherwise it's not our event */ - if (event->attr.type != event->pmu->type) - return -ENOENT; - if (EXT_COUNTER_IS_USED(hisi_pcie_get_event(event))) hwc->event_base = HISI_PCIE_EXT_CNT; else hwc->event_base = HISI_PCIE_CNT; - /* Sampling is not supported. */ - if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) - return -EOPNOTSUPP; - if (!hisi_pcie_pmu_valid_filter(event, pcie_pmu)) return -EINVAL; diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c index a449651f79c9f6..67d64d664b4f26 100644 --- a/drivers/perf/hisilicon/hisi_uncore_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c @@ -101,26 +101,17 @@ static bool hisi_validate_event_group(struct perf_event *event) /* Include count for the event */ int counters = 1; - if (!is_software_event(leader)) { - /* - * We must NOT create groups containing mixed PMUs, although - * software events are acceptable - */ - if (leader->pmu != event->pmu) - return false; - - /* Increment counter for the leader */ - if (leader != event) - counters++; - } + if (leader == event) + return true; + + /* Increment counter for the leader */ + if (leader->pmu == event->pmu) + counters++; for_each_sibling_event(sibling, event->group_leader) { - if (is_software_event(sibling)) - continue; - if (sibling->pmu != event->pmu) - return false; /* Increment counter for each sibling */ - counters++; + if (sibling->pmu == event->pmu) + counters++; } /* The group can not count events more than the counters in the HW */ @@ -208,24 +199,6 @@ int hisi_uncore_pmu_event_init(struct perf_event *event) struct hw_perf_event *hwc = &event->hw; struct hisi_pmu *hisi_pmu; - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* - * We do not support sampling as the counters are all - * shared by all CPU cores in a CPU die(SCCL). Also we - * do not support attach to a task(per-process mode) - */ - if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) - return -EOPNOTSUPP; - - /* - * The uncore counters not specific to any CPU, so cannot - * support per-task - */ - if (event->cpu < 0) - return -EINVAL; - /* * Validate if the events in group does not exceed the * available counters in hardware. diff --git a/drivers/perf/hisilicon/hns3_pmu.c b/drivers/perf/hisilicon/hns3_pmu.c index c157f3572cae57..f6996eafea5a7b 100644 --- a/drivers/perf/hisilicon/hns3_pmu.c +++ b/drivers/perf/hisilicon/hns3_pmu.c @@ -1058,21 +1058,16 @@ static bool hns3_pmu_validate_event_group(struct perf_event *event) int counters = 1; int num; - event_group[0] = leader; - if (!is_software_event(leader)) { - if (leader->pmu != event->pmu) - return false; + if (leader == event) + return true; - if (leader != event && !hns3_pmu_cmp_event(leader, event)) - event_group[counters++] = event; - } + event_group[0] = event; + if (leader->pmu == event->pmu && !hns3_pmu_cmp_event(leader, event)) + event_group[counters++] = leader; for_each_sibling_event(sibling, event->group_leader) { - if (is_software_event(sibling)) - continue; - if (sibling->pmu != event->pmu) - return false; + continue; for (num = 0; num < counters; num++) { /* @@ -1238,13 +1233,6 @@ static int hns3_pmu_event_init(struct perf_event *event) int idx; int ret; - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* Sampling is not supported */ - if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) - return -EOPNOTSUPP; - event->cpu = hns3_pmu->on_cpu; idx = hns3_pmu_get_event_idx(hns3_pmu); diff --git a/drivers/perf/marvell_cn10k_ddr_pmu.c b/drivers/perf/marvell_cn10k_ddr_pmu.c index 72ac17efd846a6..26ad83cdb735e9 100644 --- a/drivers/perf/marvell_cn10k_ddr_pmu.c +++ b/drivers/perf/marvell_cn10k_ddr_pmu.c @@ -474,24 +474,6 @@ static int cn10k_ddr_perf_event_init(struct perf_event *event) struct cn10k_ddr_pmu *pmu = to_cn10k_ddr_pmu(event->pmu); struct hw_perf_event *hwc = &event->hw; - if (event->attr.type != event->pmu->type) - return -ENOENT; - - if (is_sampling_event(event)) { - dev_info(pmu->dev, "Sampling not supported!\n"); - return -EOPNOTSUPP; - } - - if (event->cpu < 0) { - dev_warn(pmu->dev, "Can't provide per-task data!\n"); - return -EOPNOTSUPP; - } - - /* We must NOT create groups containing mixed PMUs */ - if (event->group_leader->pmu != event->pmu && - !is_software_event(event->group_leader)) - return -EINVAL; - /* Set ownership of event to one CPU, same event can not be observed * on multiple cpus at same time. */ diff --git a/drivers/perf/marvell_cn10k_tad_pmu.c b/drivers/perf/marvell_cn10k_tad_pmu.c index 51ccb0befa05df..6ed30a649ed3f6 100644 --- a/drivers/perf/marvell_cn10k_tad_pmu.c +++ b/drivers/perf/marvell_cn10k_tad_pmu.c @@ -149,13 +149,8 @@ static int tad_pmu_event_init(struct perf_event *event) { struct tad_pmu *tad_pmu = to_tad_pmu(event->pmu); - if (event->attr.type != event->pmu->type) - return -ENOENT; - - if (!event->attr.disabled) - return -EINVAL; - - if (event->state != PERF_EVENT_STATE_OFF) + /* Disallow groups since we can't start/stop/read multiple counters at once */ + if (in_hardware_group(event)) return -EINVAL; event->cpu = tad_pmu->cpu; @@ -362,8 +357,7 @@ static int tad_pmu_probe(struct platform_device *pdev) tad_pmu->pmu = (struct pmu) { .module = THIS_MODULE, - .capabilities = PERF_PMU_CAP_NO_EXCLUDE | - PERF_PMU_CAP_NO_INTERRUPT, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, .task_ctx_nr = perf_invalid_context, .event_init = tad_pmu_event_init, diff --git a/drivers/perf/marvell_pem_pmu.c b/drivers/perf/marvell_pem_pmu.c index 29fbcd1848e445..5c7abae77c1223 100644 --- a/drivers/perf/marvell_pem_pmu.c +++ b/drivers/perf/marvell_pem_pmu.c @@ -190,32 +190,14 @@ static int pem_perf_event_init(struct perf_event *event) { struct pem_pmu *pmu = to_pem_pmu(event->pmu); struct hw_perf_event *hwc = &event->hw; - struct perf_event *sibling; - - if (event->attr.type != event->pmu->type) - return -ENOENT; if (event->attr.config >= PEM_EVENTIDS_MAX) return -EINVAL; - if (is_sampling_event(event) || - event->attach_state & PERF_ATTACH_TASK) { - return -EOPNOTSUPP; - } - - if (event->cpu < 0) - return -EOPNOTSUPP; - - /* We must NOT create groups containing mixed PMUs */ - if (event->group_leader->pmu != event->pmu && - !is_software_event(event->group_leader)) + /* Disallow groups since we can't start/stop/read multiple counters at once */ + if (in_hardware_group(event)) return -EINVAL; - for_each_sibling_event(sibling, event->group_leader) { - if (sibling->pmu != event->pmu && - !is_software_event(sibling)) - return -EINVAL; - } /* * Set ownership of event to one CPU, same event can not be observed * on multiple cpus at same time. diff --git a/drivers/perf/qcom_l2_pmu.c b/drivers/perf/qcom_l2_pmu.c index ea8c857299373d..eba9a7e4029363 100644 --- a/drivers/perf/qcom_l2_pmu.c +++ b/drivers/perf/qcom_l2_pmu.c @@ -442,23 +442,8 @@ static int l2_cache_event_init(struct perf_event *event) struct perf_event *sibling; struct l2cache_pmu *l2cache_pmu; - if (event->attr.type != event->pmu->type) - return -ENOENT; - l2cache_pmu = to_l2cache_pmu(event->pmu); - if (hwc->sample_period) { - dev_dbg_ratelimited(&l2cache_pmu->pdev->dev, - "Sampling not supported\n"); - return -EOPNOTSUPP; - } - - if (event->cpu < 0) { - dev_dbg_ratelimited(&l2cache_pmu->pdev->dev, - "Per-task mode not supported\n"); - return -EOPNOTSUPP; - } - if (((L2_EVT_GROUP(event->attr.config) > L2_EVT_GROUP_MAX) || ((event->attr.config & ~L2_EVT_MASK) != 0)) && (event->attr.config != L2CYCLE_CTR_RAW_CODE)) { @@ -468,23 +453,6 @@ static int l2_cache_event_init(struct perf_event *event) return -EINVAL; } - /* Don't allow groups with mixed PMUs, except for s/w events */ - if (event->group_leader->pmu != event->pmu && - !is_software_event(event->group_leader)) { - dev_dbg_ratelimited(&l2cache_pmu->pdev->dev, - "Can't create mixed PMU group\n"); - return -EINVAL; - } - - for_each_sibling_event(sibling, event->group_leader) { - if (sibling->pmu != event->pmu && - !is_software_event(sibling)) { - dev_dbg_ratelimited(&l2cache_pmu->pdev->dev, - "Can't create mixed PMU group\n"); - return -EINVAL; - } - } - cluster = get_cluster_pmu(l2cache_pmu, event->cpu); if (!cluster) { /* CPU has not been initialised */ @@ -493,17 +461,25 @@ static int l2_cache_event_init(struct perf_event *event) return -EINVAL; } - /* Ensure all events in a group are on the same cpu */ - if ((event->group_leader != event) && - (cluster->on_cpu != event->group_leader->cpu)) { + hwc->idx = -1; + hwc->config_base = event->attr.config; + + /* + * Ensure all events are on the same cpu so all events are in the + * same cpu context, to avoid races on pmu_enable etc. + */ + event->cpu = cluster->on_cpu; + if (event->cpu != event->group_leader->cpu) { dev_dbg_ratelimited(&l2cache_pmu->pdev->dev, "Can't create group on CPUs %d and %d", event->cpu, event->group_leader->cpu); return -EINVAL; } - if ((event != event->group_leader) && - !is_software_event(event->group_leader) && + if (event == event->group_leader) + return 0; + + if ((event->group_leader->pmu == event->pmu) && (L2_EVT_GROUP(event->group_leader->attr.config) == L2_EVT_GROUP(event->attr.config))) { dev_dbg_ratelimited(&l2cache_pmu->pdev->dev, @@ -514,8 +490,7 @@ static int l2_cache_event_init(struct perf_event *event) } for_each_sibling_event(sibling, event->group_leader) { - if ((sibling != event) && - !is_software_event(sibling) && + if ((sibling->pmu == event->pmu) && (L2_EVT_GROUP(sibling->attr.config) == L2_EVT_GROUP(event->attr.config))) { dev_dbg_ratelimited(&l2cache_pmu->pdev->dev, @@ -526,15 +501,6 @@ static int l2_cache_event_init(struct perf_event *event) } } - hwc->idx = -1; - hwc->config_base = event->attr.config; - - /* - * Ensure all events are on the same cpu so all events are in the - * same cpu context, to avoid races on pmu_enable etc. - */ - event->cpu = cluster->on_cpu; - return 0; } diff --git a/drivers/perf/qcom_l3_pmu.c b/drivers/perf/qcom_l3_pmu.c index 66e6cabd6fff1d..af0ced386fb15f 100644 --- a/drivers/perf/qcom_l3_pmu.c +++ b/drivers/perf/qcom_l3_pmu.c @@ -454,18 +454,16 @@ static bool qcom_l3_cache__validate_event_group(struct perf_event *event) struct perf_event *sibling; int counters = 0; - if (leader->pmu != event->pmu && !is_software_event(leader)) - return false; + if (leader == event) + return true; counters = event_num_counters(event); - counters += event_num_counters(leader); + if (leader->pmu == event->pmu) + counters += event_num_counters(leader); for_each_sibling_event(sibling, leader) { - if (is_software_event(sibling)) - continue; - if (sibling->pmu != event->pmu) - return false; - counters += event_num_counters(sibling); + if (sibling->pmu == event->pmu) + counters += event_num_counters(sibling); } /* @@ -480,25 +478,6 @@ static int qcom_l3_cache__event_init(struct perf_event *event) struct l3cache_pmu *l3pmu = to_l3cache_pmu(event->pmu); struct hw_perf_event *hwc = &event->hw; - /* - * Is the event for this PMU? - */ - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* - * Sampling not supported since these events are not core-attributable. - */ - if (hwc->sample_period) - return -EINVAL; - - /* - * Task mode not available, we run the counters as socket counters, - * not attributable to any CPU and therefore cannot attribute per-task. - */ - if (event->cpu < 0) - return -EINVAL; - /* Validate the group */ if (!qcom_l3_cache__validate_event_group(event)) return -EINVAL; diff --git a/drivers/perf/riscv_pmu_legacy.c b/drivers/perf/riscv_pmu_legacy.c index 93c8e0fdb58985..40140e4574548d 100644 --- a/drivers/perf/riscv_pmu_legacy.c +++ b/drivers/perf/riscv_pmu_legacy.c @@ -123,7 +123,6 @@ static void pmu_legacy_init(struct riscv_pmu *pmu) pmu->event_mapped = pmu_legacy_event_mapped; pmu->event_unmapped = pmu_legacy_event_unmapped; pmu->csr_index = pmu_legacy_csr_index; - pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; pmu->pmu.capabilities |= PERF_PMU_CAP_NO_EXCLUDE; perf_pmu_register(&pmu->pmu, "cpu", PERF_TYPE_RAW); diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c index 698de8ddf895ba..4fb1aab0b54763 100644 --- a/drivers/perf/riscv_pmu_sbi.c +++ b/drivers/perf/riscv_pmu_sbi.c @@ -1359,8 +1359,9 @@ static int pmu_sbi_device_probe(struct platform_device *pdev) ret = pmu_sbi_setup_irqs(pmu, pdev); if (ret < 0) { pr_info("Perf sampling/filtering is not supported as sscof extension is not available\n"); - pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; pmu->pmu.capabilities |= PERF_PMU_CAP_NO_EXCLUDE; + } else { + pmu->pmu.capabilities |= PERF_PMU_CAP_SAMPLING; } pmu->pmu.attr_groups = riscv_pmu_attr_groups; diff --git a/drivers/perf/starfive_starlink_pmu.c b/drivers/perf/starfive_starlink_pmu.c index 5e5a672b42294e..ee52164034179b 100644 --- a/drivers/perf/starfive_starlink_pmu.c +++ b/drivers/perf/starfive_starlink_pmu.c @@ -347,19 +347,15 @@ static bool starlink_pmu_validate_event_group(struct perf_event *event) struct perf_event *sibling; int counter = 1; - /* - * Ensure hardware events in the group are on the same PMU, - * software events are acceptable. - */ - if (event->group_leader->pmu != event->pmu && - !is_software_event(event->group_leader)) - return false; - - for_each_sibling_event(sibling, leader) { - if (sibling->pmu != event->pmu && !is_software_event(sibling)) - return false; + if (leader == event) + return true; + if (leader->pmu == event->pmu) counter++; + + for_each_sibling_event(sibling, leader) { + if (sibling->pmu == event->pmu) + counter++; } return counter <= STARLINK_PMU_NUM_COUNTERS; @@ -370,20 +366,6 @@ static int starlink_pmu_event_init(struct perf_event *event) struct starlink_pmu *starlink_pmu = to_starlink_pmu(event->pmu); struct hw_perf_event *hwc = &event->hw; - /* - * Sampling is not supported, as counters are shared - * by all CPU. - */ - if (hwc->sample_period) - return -EOPNOTSUPP; - - /* - * Per-task and attach to a task are not supported, - * as uncore events are not specific to any CPU. - */ - if (event->cpu < 0 || event->attach_state & PERF_ATTACH_TASK) - return -EOPNOTSUPP; - if (!starlink_pmu_validate_event_group(event)) return -EINVAL; diff --git a/drivers/perf/thunderx2_pmu.c b/drivers/perf/thunderx2_pmu.c index 6ed4707bd6bb5d..0ef85cb722891e 100644 --- a/drivers/perf/thunderx2_pmu.c +++ b/drivers/perf/thunderx2_pmu.c @@ -519,19 +519,6 @@ static enum tx2_uncore_type get_tx2_pmu_type(struct acpi_device *adev) return (enum tx2_uncore_type)id->driver_data; } -static bool tx2_uncore_validate_event(struct pmu *pmu, - struct perf_event *event, int *counters) -{ - if (is_software_event(event)) - return true; - /* Reject groups spanning multiple HW PMUs. */ - if (event->pmu != pmu) - return false; - - *counters = *counters + 1; - return true; -} - /* * Make sure the group of events can be scheduled at once * on the PMU. @@ -539,23 +526,20 @@ static bool tx2_uncore_validate_event(struct pmu *pmu, static bool tx2_uncore_validate_event_group(struct perf_event *event, int max_counters) { - struct perf_event *sibling, *leader = event->group_leader; - int counters = 0; + struct perf_event *sibling; + int counters = 1; if (event->group_leader == event) return true; - if (!tx2_uncore_validate_event(event->pmu, leader, &counters)) - return false; + if (event->group_leader->pmu == event->pmu) + ++counters; - for_each_sibling_event(sibling, leader) { - if (!tx2_uncore_validate_event(event->pmu, sibling, &counters)) - return false; + for_each_sibling_event(sibling, event->group_leader) { + if (sibling->pmu == event->pmu) + ++counters; } - if (!tx2_uncore_validate_event(event->pmu, event, &counters)) - return false; - /* * If the group requires more counters than the HW has, * it cannot ever be scheduled. @@ -569,21 +553,6 @@ static int tx2_uncore_event_init(struct perf_event *event) struct hw_perf_event *hwc = &event->hw; struct tx2_uncore_pmu *tx2_pmu; - /* Test the event attr type check for PMU enumeration */ - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* - * SOC PMU counters are shared across all cores. - * Therefore, it does not support per-process mode. - * Also, it does not support event sampling mode. - */ - if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) - return -EINVAL; - - if (event->cpu < 0) - return -EINVAL; - tx2_pmu = pmu_to_tx2_pmu(event->pmu); if (tx2_pmu->cpu >= nr_cpu_ids) return -EINVAL; diff --git a/drivers/perf/xgene_pmu.c b/drivers/perf/xgene_pmu.c index 33b5497bdc06e4..408e69533e7a06 100644 --- a/drivers/perf/xgene_pmu.c +++ b/drivers/perf/xgene_pmu.c @@ -877,22 +877,7 @@ static int xgene_perf_event_init(struct perf_event *event) { struct xgene_pmu_dev *pmu_dev = to_pmu_dev(event->pmu); struct hw_perf_event *hw = &event->hw; - struct perf_event *sibling; - /* Test the event attr type check for PMU enumeration */ - if (event->attr.type != event->pmu->type) - return -ENOENT; - - /* - * SOC PMU counters are shared across all cores. - * Therefore, it does not support per-process mode. - * Also, it does not support event sampling mode. - */ - if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) - return -EINVAL; - - if (event->cpu < 0) - return -EINVAL; /* * Many perf core operations (eg. events rotation) operate on a * single CPU context. This is obvious for CPU PMUs, where one @@ -913,20 +898,6 @@ static int xgene_perf_event_init(struct perf_event *event) */ hw->config_base = event->attr.config1; - /* - * We must NOT create groups containing mixed PMUs, although software - * events are acceptable - */ - if (event->group_leader->pmu != event->pmu && - !is_software_event(event->group_leader)) - return -EINVAL; - - for_each_sibling_event(sibling, event->group_leader) { - if (sibling->pmu != event->pmu && - !is_software_event(sibling)) - return -EINVAL; - } - return 0; } diff --git a/drivers/powercap/intel_rapl_common.c b/drivers/powercap/intel_rapl_common.c index c7e7f9bf531371..eff369b0277373 100644 --- a/drivers/powercap/intel_rapl_common.c +++ b/drivers/powercap/intel_rapl_common.c @@ -1791,17 +1791,10 @@ static int rapl_pmu_event_init(struct perf_event *event) u64 cfg = event->attr.config & RAPL_EVENT_MASK; int domain, idx; - /* Only look at RAPL events */ - if (event->attr.type != event->pmu->type) - return -ENOENT; - /* Check for supported events only */ if (!cfg || cfg >= PERF_RAPL_MAX) return -EINVAL; - if (event->cpu < 0) - return -EINVAL; - /* Find out which Package the event belongs to */ list_for_each_entry(pos, &rapl_packages, plist) { if (is_rp_pmu_cpu(pos, event->cpu)) { @@ -2014,7 +2007,7 @@ static int rapl_pmu_update(struct rapl_package *rp) rapl_pmu.pmu.stop = rapl_pmu_event_stop; rapl_pmu.pmu.read = rapl_pmu_event_read; rapl_pmu.pmu.module = THIS_MODULE; - rapl_pmu.pmu.capabilities = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_NO_INTERRUPT; + rapl_pmu.pmu.capabilities = PERF_PMU_CAP_NO_EXCLUDE; ret = perf_pmu_register(&rapl_pmu.pmu, "power", -1); if (ret) { pr_info("Failed to register PMU\n"); diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index ec9d9602568395..c6ad036c003792 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -294,7 +294,7 @@ struct perf_event_pmu_context; /** * pmu::capabilities flags */ -#define PERF_PMU_CAP_NO_INTERRUPT 0x0001 +#define PERF_PMU_CAP_SAMPLING 0x0001 #define PERF_PMU_CAP_NO_NMI 0x0002 #define PERF_PMU_CAP_AUX_NO_SG 0x0004 #define PERF_PMU_CAP_EXTENDED_REGS 0x0008 @@ -305,6 +305,7 @@ struct perf_event_pmu_context; #define PERF_PMU_CAP_EXTENDED_HW_TYPE 0x0100 #define PERF_PMU_CAP_AUX_PAUSE 0x0200 #define PERF_PMU_CAP_AUX_PREFER_LARGE 0x0400 +#define PERF_PMU_CAP_RAW_EVENTS 0x0800 /** * pmu::scope @@ -1556,6 +1557,13 @@ static inline int in_software_context(struct perf_event *event) return event->pmu_ctx->pmu->task_ctx_nr == perf_sw_context; } +/* True if the event has (or would have) any non-software siblings */ +static inline bool in_hardware_group(const struct perf_event *event) +{ + return event != event->group_leader && + !in_software_context(event->group_leader); +} + static inline int is_exclusive_pmu(struct pmu *pmu) { return pmu->capabilities & PERF_PMU_CAP_EXCLUSIVE; diff --git a/kernel/events/core.c b/kernel/events/core.c index 8060c2857bb2b3..2ecee76d2ae2a1 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -4359,7 +4359,7 @@ perf_adjust_freq_unthr_context(struct perf_event_context *ctx, bool unthrottle) continue; if (!perf_pmu_ctx_is_active(pmu_ctx)) continue; - if (pmu_ctx->pmu->capabilities & PERF_PMU_CAP_NO_INTERRUPT) + if (!(pmu_ctx->pmu->capabilities & PERF_PMU_CAP_SAMPLING)) continue; perf_pmu_disable(pmu_ctx->pmu); @@ -10819,7 +10819,7 @@ static int perf_swevent_init(struct perf_event *event) static struct pmu perf_swevent = { .task_ctx_nr = perf_sw_context, - .capabilities = PERF_PMU_CAP_NO_NMI, + .capabilities = PERF_PMU_CAP_SAMPLING | PERF_PMU_CAP_NO_NMI, .event_init = perf_swevent_init, .add = perf_swevent_add, @@ -10861,6 +10861,7 @@ static int perf_tp_event_init(struct perf_event *event) static struct pmu perf_tracepoint = { .task_ctx_nr = perf_sw_context, + .capabilities = PERF_PMU_CAP_SAMPLING, .event_init = perf_tp_event_init, .add = perf_trace_add, .del = perf_trace_del, @@ -11066,6 +11067,7 @@ static struct pmu perf_kprobe = { .stop = perf_swevent_stop, .read = perf_swevent_read, .attr_groups = kprobe_attr_groups, + .capabilities = PERF_PMU_CAP_SAMPLING, }; static int perf_kprobe_event_init(struct perf_event *event) @@ -11125,6 +11127,7 @@ static struct pmu perf_uprobe = { .stop = perf_swevent_stop, .read = perf_swevent_read, .attr_groups = uprobe_attr_groups, + .capabilities = PERF_PMU_CAP_SAMPLING, }; static int perf_uprobe_event_init(struct perf_event *event) @@ -11899,7 +11902,7 @@ static int cpu_clock_event_init(struct perf_event *event) static struct pmu perf_cpu_clock = { .task_ctx_nr = perf_sw_context, - .capabilities = PERF_PMU_CAP_NO_NMI, + .capabilities = PERF_PMU_CAP_SAMPLING | PERF_PMU_CAP_NO_NMI, .dev = PMU_NULL_DEV, .event_init = cpu_clock_event_init, @@ -11982,7 +11985,7 @@ static int task_clock_event_init(struct perf_event *event) static struct pmu perf_task_clock = { .task_ctx_nr = perf_sw_context, - .capabilities = PERF_PMU_CAP_NO_NMI, + .capabilities = PERF_PMU_CAP_SAMPLING | PERF_PMU_CAP_NO_NMI, .dev = PMU_NULL_DEV, .event_init = task_clock_event_init, @@ -12553,11 +12556,26 @@ static inline bool has_extended_regs(struct perf_event *event) (event->attr.sample_regs_intr & PERF_REG_EXTENDED_MASK); } +static bool is_raw_pmu(const struct pmu *pmu) +{ + return pmu->type == PERF_TYPE_RAW || + pmu->capabilities & PERF_PMU_CAP_RAW_EVENTS; +} + static int perf_try_init_event(struct pmu *pmu, struct perf_event *event) { struct perf_event_context *ctx = NULL; int ret; + /* + * Before touching anything, we can safely skip: + * - any event for a specific PMU which is not this one + * - any common event if this PMU doesn't support them + */ + if (event->attr.type != pmu->type && + (event->attr.type >= PERF_TYPE_MAX || is_raw_pmu(pmu))) + return -ENOENT; + if (!try_module_get(pmu->module)) return -ENODEV; @@ -13476,11 +13494,10 @@ SYSCALL_DEFINE5(perf_event_open, goto err_task; } - if (is_sampling_event(event)) { - if (event->pmu->capabilities & PERF_PMU_CAP_NO_INTERRUPT) { - err = -EOPNOTSUPP; - goto err_alloc; - } + if (is_sampling_event(event) && + !(event->pmu->capabilities & PERF_PMU_CAP_SAMPLING)) { + err = -EOPNOTSUPP; + goto err_alloc; } /* diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c index 8ec2cb68890389..604be7d7aecfaf 100644 --- a/kernel/events/hw_breakpoint.c +++ b/kernel/events/hw_breakpoint.c @@ -996,6 +996,7 @@ static void hw_breakpoint_stop(struct perf_event *bp, int flags) static struct pmu perf_breakpoint = { .task_ctx_nr = perf_sw_context, /* could eventually get its own */ + .capabilities = PERF_PMU_CAP_SAMPLING, .event_init = hw_breakpoint_event_init, .add = hw_breakpoint_add, .del = hw_breakpoint_del,