aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bus
diff options
context:
space:
mode:
authorSuzuki K. Poulose <suzuki.poulose@arm.com>2015-03-17 14:15:00 -0400
committerWill Deacon <will.deacon@arm.com>2015-03-27 09:44:11 -0400
commitb1862199be6098855b598b69f5098d2fb4cecfcb (patch)
treec91684b61d6b94c74e77359175a2726e1d0262b1 /drivers/bus
parent06e5801b8cb3fc057d88cb4dc03c0b64b2744cda (diff)
drivers: cci: reject groups spanning multiple HW PMUs
The perf core implicitly rejects events spanning multiple HW PMUs, as in these cases the event->ctx will differ. However this validation is performed after pmu::event_init() is called in perf_init_event(), and thus pmu::event_init() may be called with a group leader from a different HW PMU. The CCI PMU driver does not take this fact into account, and assumes that the any other hardware event belongs to the CCI. There are two issues with it : 1) It is wrong and we should reject such groups. 2) Validation allocates an temporary idx for this non-cci event, which leads to wrong calculation of the counter availability, and eventually lesser number of events in the group. This patch updates the CCI PMU driver to first test for and reject events from other PMUs, which is the right thing to do. Cc: Will Deacon <will.deacon@arm.com> Acked-by: Mark Rutland <mark.rutland@arm.com> Acked-by: Peter Ziljstra (Intel) <peterz@infradead.org> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'drivers/bus')
-rw-r--r--drivers/bus/arm-cci.c19
1 files changed, 14 insertions, 5 deletions
diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 84fd66057dad..68ef6f2aa24d 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -660,12 +660,21 @@ static void cci_pmu_del(struct perf_event *event, int flags)
660} 660}
661 661
662static int 662static int
663validate_event(struct cci_pmu_hw_events *hw_events, 663validate_event(struct pmu *cci_pmu,
664 struct perf_event *event) 664 struct cci_pmu_hw_events *hw_events,
665 struct perf_event *event)
665{ 666{
666 if (is_software_event(event)) 667 if (is_software_event(event))
667 return 1; 668 return 1;
668 669
670 /*
671 * Reject groups spanning multiple HW PMUs (e.g. CPU + CCI). The
672 * core perf code won't check that the pmu->ctx == leader->ctx
673 * until after pmu->event_init(event).
674 */
675 if (event->pmu != cci_pmu)
676 return 0;
677
669 if (event->state < PERF_EVENT_STATE_OFF) 678 if (event->state < PERF_EVENT_STATE_OFF)
670 return 1; 679 return 1;
671 680
@@ -687,15 +696,15 @@ validate_group(struct perf_event *event)
687 .used_mask = CPU_BITS_NONE, 696 .used_mask = CPU_BITS_NONE,
688 }; 697 };
689 698
690 if (!validate_event(&fake_pmu, leader)) 699 if (!validate_event(event->pmu, &fake_pmu, leader))
691 return -EINVAL; 700 return -EINVAL;
692 701
693 list_for_each_entry(sibling, &leader->sibling_list, group_entry) { 702 list_for_each_entry(sibling, &leader->sibling_list, group_entry) {
694 if (!validate_event(&fake_pmu, sibling)) 703 if (!validate_event(event->pmu, &fake_pmu, sibling))
695 return -EINVAL; 704 return -EINVAL;
696 } 705 }
697 706
698 if (!validate_event(&fake_pmu, event)) 707 if (!validate_event(event->pmu, &fake_pmu, event))
699 return -EINVAL; 708 return -EINVAL;
700 709
701 return 0; 710 return 0;