aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDave Martin <dave.martin@linaro.org>2012-12-12 18:13:44 +0000
committerAndrey Konovalov <andrey.konovalov@linaro.org>2013-05-25 13:21:21 +0400
commite7a123aeb0117cc41f5dfde53d3554308a1d592e (patch)
tree0e772cebf90fff374802c79893a8fb5f95d34248 /drivers
parentb52a4b4ba21d5d27ac49a2ff2f40f621b23db8f9 (diff)
ARM: perf: Allow multiple CPU PMUs per CPU
In a system where Linux logical CPUs can migrate between different physical CPUs, multiple CPU PMUs can logically count events for each logical CPU, as logical CPUs migrate from one cluster to another. This patch allows multiple PMUs to be registered against each CPU. The pairing of a PMU and a CPU is reperesented by a struct arm_cpu_pmu, with existing per-CPU state used by perf moving into this structure. arm_cpu_pmus are per-cpu-allocated, and hang off the relevant arm_pmu structure. This arrangement allows us to find all the CPU-PMU pairings for a given PMU, but not for a given CPU. Do do the latter, a list of all registered CPU PMUs is maintained, and we iterate over that when we need to find all of a CPU's CPU PMUs. This is not elegent, but it shouldn't be a heavy cost since the number of different CPU PMUs across the system is currently expected to be low (i.e., 2 or fewer). This could be improved later. As a side-effect, the get_hw_events() method no longer has enough context to provide an answer, because there may be multiple candidate PMUs for a CPU. This patch adds the struct arm_pmu * for the relevant PMU to this interface to resolve this problem, resulting in trivial changes to various ARM PMU implementations. Signed-off-by: Dave Martin <dave.martin@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bus/arm-cci.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index b110645bc56..eee1c5722fd 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -156,7 +156,8 @@ static u32 cci_pmu_get_max_counters(void)
return n_cnts + 1;
}
-static struct pmu_hw_events *cci_pmu_get_hw_events(void)
+static struct pmu_hw_events *cci_pmu_get_hw_events(
+ struct arm_pmu *__always_unused pmu)
{
return &cci_hw_events;
}
@@ -233,7 +234,7 @@ static int cci_pmu_request_irq(struct arm_pmu *cci_pmu, irq_handler_t handler)
static irqreturn_t cci_pmu_handle_irq(int irq_num, void *dev)
{
struct arm_pmu *cci_pmu = (struct arm_pmu *)dev;
- struct pmu_hw_events *events = cci_pmu->get_hw_events();
+ struct pmu_hw_events *events = cci_pmu->get_hw_events(cci_pmu);
struct perf_sample_data data;
struct pt_regs *regs;
int idx;
@@ -285,7 +286,7 @@ static void cci_pmu_enable_event(struct perf_event *event)
{
unsigned long flags;
struct arm_pmu *cci_pmu = to_arm_pmu(event->pmu);
- struct pmu_hw_events *events = cci_pmu->get_hw_events();
+ struct pmu_hw_events *events = cci_pmu->get_hw_events(cci_pmu);
struct hw_perf_event *hw_counter = &event->hw;
int idx = hw_counter->idx;
@@ -309,7 +310,7 @@ static void cci_pmu_disable_event(struct perf_event *event)
{
unsigned long flags;
struct arm_pmu *cci_pmu = to_arm_pmu(event->pmu);
- struct pmu_hw_events *events = cci_pmu->get_hw_events();
+ struct pmu_hw_events *events = cci_pmu->get_hw_events(cci_pmu);
struct hw_perf_event *hw_counter = &event->hw;
int idx = hw_counter->idx;
@@ -330,7 +331,7 @@ static void cci_pmu_start(struct arm_pmu *cci_pmu)
u32 val;
unsigned long flags;
struct cci_drvdata *info = platform_get_drvdata(cci_pmu->plat_device);
- struct pmu_hw_events *events = cci_pmu->get_hw_events();
+ struct pmu_hw_events *events = cci_pmu->get_hw_events(cci_pmu);
raw_spin_lock_irqsave(&events->pmu_lock, flags);
@@ -346,7 +347,7 @@ static void cci_pmu_stop(struct arm_pmu *cci_pmu)
u32 val;
unsigned long flags;
struct cci_drvdata *info = platform_get_drvdata(cci_pmu->plat_device);
- struct pmu_hw_events *events = cci_pmu->get_hw_events();
+ struct pmu_hw_events *events = cci_pmu->get_hw_events(cci_pmu);
raw_spin_lock_irqsave(&events->pmu_lock, flags);