|
@@ -940,15 +940,6 @@ static void arm_ccn_pmu_event_start(struct perf_event *event, int flags)
|
|
|
arm_ccn_pmu_read_counter(ccn, hw->idx));
|
|
|
hw->state = 0;
|
|
|
|
|
|
- /*
|
|
|
- * Pin the timer, so that the overflows are handled by the chosen
|
|
|
- * event->cpu (this is the same one as presented in "cpumask"
|
|
|
- * attribute).
|
|
|
- */
|
|
|
- if (!ccn->irq)
|
|
|
- hrtimer_start(&ccn->dt.hrtimer, arm_ccn_pmu_timer_period(),
|
|
|
- HRTIMER_MODE_REL_PINNED);
|
|
|
-
|
|
|
/* Set the DT bus input, engaging the counter */
|
|
|
arm_ccn_pmu_xp_dt_config(event, 1);
|
|
|
}
|
|
@@ -962,9 +953,6 @@ static void arm_ccn_pmu_event_stop(struct perf_event *event, int flags)
|
|
|
/* Disable counting, setting the DT bus to pass-through mode */
|
|
|
arm_ccn_pmu_xp_dt_config(event, 0);
|
|
|
|
|
|
- if (!ccn->irq)
|
|
|
- hrtimer_cancel(&ccn->dt.hrtimer);
|
|
|
-
|
|
|
/* Let the DT bus drain */
|
|
|
timeout = arm_ccn_pmu_read_counter(ccn, CCN_IDX_PMU_CYCLE_COUNTER) +
|
|
|
ccn->num_xps;
|
|
@@ -1122,15 +1110,31 @@ static void arm_ccn_pmu_event_config(struct perf_event *event)
|
|
|
spin_unlock(&ccn->dt.config_lock);
|
|
|
}
|
|
|
|
|
|
+static int arm_ccn_pmu_active_counters(struct arm_ccn *ccn)
|
|
|
+{
|
|
|
+ return bitmap_weight(ccn->dt.pmu_counters_mask,
|
|
|
+ CCN_NUM_PMU_EVENT_COUNTERS + 1);
|
|
|
+}
|
|
|
+
|
|
|
static int arm_ccn_pmu_event_add(struct perf_event *event, int flags)
|
|
|
{
|
|
|
int err;
|
|
|
struct hw_perf_event *hw = &event->hw;
|
|
|
+ struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu);
|
|
|
|
|
|
err = arm_ccn_pmu_event_alloc(event);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
|
+ /*
|
|
|
+ * Pin the timer, so that the overflows are handled by the chosen
|
|
|
+ * event->cpu (this is the same one as presented in "cpumask"
|
|
|
+ * attribute).
|
|
|
+ */
|
|
|
+ if (!ccn->irq && arm_ccn_pmu_active_counters(ccn) == 1)
|
|
|
+ hrtimer_start(&ccn->dt.hrtimer, arm_ccn_pmu_timer_period(),
|
|
|
+ HRTIMER_MODE_REL_PINNED);
|
|
|
+
|
|
|
arm_ccn_pmu_event_config(event);
|
|
|
|
|
|
hw->state = PERF_HES_STOPPED;
|
|
@@ -1143,9 +1147,14 @@ static int arm_ccn_pmu_event_add(struct perf_event *event, int flags)
|
|
|
|
|
|
static void arm_ccn_pmu_event_del(struct perf_event *event, int flags)
|
|
|
{
|
|
|
+ struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu);
|
|
|
+
|
|
|
arm_ccn_pmu_event_stop(event, PERF_EF_UPDATE);
|
|
|
|
|
|
arm_ccn_pmu_event_release(event);
|
|
|
+
|
|
|
+ if (!ccn->irq && arm_ccn_pmu_active_counters(ccn) == 0)
|
|
|
+ hrtimer_cancel(&ccn->dt.hrtimer);
|
|
|
}
|
|
|
|
|
|
static void arm_ccn_pmu_event_read(struct perf_event *event)
|