aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/bus/arm-ccn.c33
1 files changed, 21 insertions, 12 deletions
diff --git a/drivers/bus/arm-ccn.c b/drivers/bus/arm-ccn.c
index c826bb286054..12c1fd1bc398 100644
--- a/drivers/bus/arm-ccn.c
+++ b/drivers/bus/arm-ccn.c
@@ -940,15 +940,6 @@ static void arm_ccn_pmu_event_start(struct perf_event *event, int flags)
940 arm_ccn_pmu_read_counter(ccn, hw->idx)); 940 arm_ccn_pmu_read_counter(ccn, hw->idx));
941 hw->state = 0; 941 hw->state = 0;
942 942
943 /*
944 * Pin the timer, so that the overflows are handled by the chosen
945 * event->cpu (this is the same one as presented in "cpumask"
946 * attribute).
947 */
948 if (!ccn->irq)
949 hrtimer_start(&ccn->dt.hrtimer, arm_ccn_pmu_timer_period(),
950 HRTIMER_MODE_REL_PINNED);
951
952 /* Set the DT bus input, engaging the counter */ 943 /* Set the DT bus input, engaging the counter */
953 arm_ccn_pmu_xp_dt_config(event, 1); 944 arm_ccn_pmu_xp_dt_config(event, 1);
954} 945}
@@ -962,9 +953,6 @@ static void arm_ccn_pmu_event_stop(struct perf_event *event, int flags)
962 /* Disable counting, setting the DT bus to pass-through mode */ 953 /* Disable counting, setting the DT bus to pass-through mode */
963 arm_ccn_pmu_xp_dt_config(event, 0); 954 arm_ccn_pmu_xp_dt_config(event, 0);
964 955
965 if (!ccn->irq)
966 hrtimer_cancel(&ccn->dt.hrtimer);
967
968 /* Let the DT bus drain */ 956 /* Let the DT bus drain */
969 timeout = arm_ccn_pmu_read_counter(ccn, CCN_IDX_PMU_CYCLE_COUNTER) + 957 timeout = arm_ccn_pmu_read_counter(ccn, CCN_IDX_PMU_CYCLE_COUNTER) +
970 ccn->num_xps; 958 ccn->num_xps;
@@ -1122,15 +1110,31 @@ static void arm_ccn_pmu_event_config(struct perf_event *event)
1122 spin_unlock(&ccn->dt.config_lock); 1110 spin_unlock(&ccn->dt.config_lock);
1123} 1111}
1124 1112
1113static int arm_ccn_pmu_active_counters(struct arm_ccn *ccn)
1114{
1115 return bitmap_weight(ccn->dt.pmu_counters_mask,
1116 CCN_NUM_PMU_EVENT_COUNTERS + 1);
1117}
1118
1125static int arm_ccn_pmu_event_add(struct perf_event *event, int flags) 1119static int arm_ccn_pmu_event_add(struct perf_event *event, int flags)
1126{ 1120{
1127 int err; 1121 int err;
1128 struct hw_perf_event *hw = &event->hw; 1122 struct hw_perf_event *hw = &event->hw;
1123 struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu);
1129 1124
1130 err = arm_ccn_pmu_event_alloc(event); 1125 err = arm_ccn_pmu_event_alloc(event);
1131 if (err) 1126 if (err)
1132 return err; 1127 return err;
1133 1128
1129 /*
1130 * Pin the timer, so that the overflows are handled by the chosen
1131 * event->cpu (this is the same one as presented in "cpumask"
1132 * attribute).
1133 */
1134 if (!ccn->irq && arm_ccn_pmu_active_counters(ccn) == 1)
1135 hrtimer_start(&ccn->dt.hrtimer, arm_ccn_pmu_timer_period(),
1136 HRTIMER_MODE_REL_PINNED);
1137
1134 arm_ccn_pmu_event_config(event); 1138 arm_ccn_pmu_event_config(event);
1135 1139
1136 hw->state = PERF_HES_STOPPED; 1140 hw->state = PERF_HES_STOPPED;
@@ -1143,9 +1147,14 @@ static int arm_ccn_pmu_event_add(struct perf_event *event, int flags)
1143 1147
1144static void arm_ccn_pmu_event_del(struct perf_event *event, int flags) 1148static void arm_ccn_pmu_event_del(struct perf_event *event, int flags)
1145{ 1149{
1150 struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu);
1151
1146 arm_ccn_pmu_event_stop(event, PERF_EF_UPDATE); 1152 arm_ccn_pmu_event_stop(event, PERF_EF_UPDATE);
1147 1153
1148 arm_ccn_pmu_event_release(event); 1154 arm_ccn_pmu_event_release(event);
1155
1156 if (!ccn->irq && arm_ccn_pmu_active_counters(ccn) == 0)
1157 hrtimer_cancel(&ccn->dt.hrtimer);
1149} 1158}
1150 1159
1151static void arm_ccn_pmu_event_read(struct perf_event *event) 1160static void arm_ccn_pmu_event_read(struct perf_event *event)