aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bus/arm-ccn.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/bus/arm-ccn.c')
-rw-r--r--drivers/bus/arm-ccn.c57
1 files changed, 28 insertions, 29 deletions
diff --git a/drivers/bus/arm-ccn.c b/drivers/bus/arm-ccn.c
index acc3eb542c74..97a9185af433 100644
--- a/drivers/bus/arm-ccn.c
+++ b/drivers/bus/arm-ccn.c
@@ -167,7 +167,7 @@ struct arm_ccn_dt {
167 struct hrtimer hrtimer; 167 struct hrtimer hrtimer;
168 168
169 cpumask_t cpu; 169 cpumask_t cpu;
170 struct notifier_block cpu_nb; 170 struct list_head entry;
171 171
172 struct pmu pmu; 172 struct pmu pmu;
173}; 173};
@@ -189,6 +189,8 @@ struct arm_ccn {
189 struct arm_ccn_dt dt; 189 struct arm_ccn_dt dt;
190}; 190};
191 191
192static DEFINE_MUTEX(arm_ccn_mutex);
193static LIST_HEAD(arm_ccn_list);
192 194
193static int arm_ccn_node_to_xp(int node) 195static int arm_ccn_node_to_xp(int node)
194{ 196{
@@ -1171,30 +1173,27 @@ static enum hrtimer_restart arm_ccn_pmu_timer_handler(struct hrtimer *hrtimer)
1171} 1173}
1172 1174
1173 1175
1174static int arm_ccn_pmu_cpu_notifier(struct notifier_block *nb, 1176static int arm_ccn_pmu_offline_cpu(unsigned int cpu)
1175 unsigned long action, void *hcpu)
1176{ 1177{
1177 struct arm_ccn_dt *dt = container_of(nb, struct arm_ccn_dt, cpu_nb); 1178 struct arm_ccn_dt *dt;
1178 struct arm_ccn *ccn = container_of(dt, struct arm_ccn, dt);
1179 unsigned int cpu = (long)hcpu; /* for (long) see kernel/cpu.c */
1180 unsigned int target; 1179 unsigned int target;
1181 1180
1182 switch (action & ~CPU_TASKS_FROZEN) { 1181 mutex_lock(&arm_ccn_mutex);
1183 case CPU_DOWN_PREPARE: 1182 list_for_each_entry(dt, &arm_ccn_list, entry) {
1183 struct arm_ccn *ccn = container_of(dt, struct arm_ccn, dt);
1184
1184 if (!cpumask_test_and_clear_cpu(cpu, &dt->cpu)) 1185 if (!cpumask_test_and_clear_cpu(cpu, &dt->cpu))
1185 break; 1186 continue;
1186 target = cpumask_any_but(cpu_online_mask, cpu); 1187 target = cpumask_any_but(cpu_online_mask, cpu);
1187 if (target >= nr_cpu_ids) 1188 if (target >= nr_cpu_ids)
1188 break; 1189 continue;
1189 perf_pmu_migrate_context(&dt->pmu, cpu, target); 1190 perf_pmu_migrate_context(&dt->pmu, cpu, target);
1190 cpumask_set_cpu(target, &dt->cpu); 1191 cpumask_set_cpu(target, &dt->cpu);
1191 if (ccn->irq) 1192 if (ccn->irq)
1192 WARN_ON(irq_set_affinity_hint(ccn->irq, &dt->cpu) != 0); 1193 WARN_ON(irq_set_affinity_hint(ccn->irq, &dt->cpu) != 0);
1193 default:
1194 break;
1195 } 1194 }
1196 1195 mutex_unlock(&arm_ccn_mutex);
1197 return NOTIFY_OK; 1196 return 0;
1198} 1197}
1199 1198
1200 1199
@@ -1266,16 +1265,6 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn)
1266 /* Pick one CPU which we will use to collect data from CCN... */ 1265 /* Pick one CPU which we will use to collect data from CCN... */
1267 cpumask_set_cpu(smp_processor_id(), &ccn->dt.cpu); 1266 cpumask_set_cpu(smp_processor_id(), &ccn->dt.cpu);
1268 1267
1269 /*
1270 * ... and change the selection when it goes offline. Priority is
1271 * picked to have a chance to migrate events before perf is notified.
1272 */
1273 ccn->dt.cpu_nb.notifier_call = arm_ccn_pmu_cpu_notifier;
1274 ccn->dt.cpu_nb.priority = CPU_PRI_PERF + 1,
1275 err = register_cpu_notifier(&ccn->dt.cpu_nb);
1276 if (err)
1277 goto error_cpu_notifier;
1278
1279 /* Also make sure that the overflow interrupt is handled by this CPU */ 1268 /* Also make sure that the overflow interrupt is handled by this CPU */
1280 if (ccn->irq) { 1269 if (ccn->irq) {
1281 err = irq_set_affinity_hint(ccn->irq, &ccn->dt.cpu); 1270 err = irq_set_affinity_hint(ccn->irq, &ccn->dt.cpu);
@@ -1289,12 +1278,13 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn)
1289 if (err) 1278 if (err)
1290 goto error_pmu_register; 1279 goto error_pmu_register;
1291 1280
1281 mutex_lock(&arm_ccn_mutex);
1282 list_add(&ccn->dt.entry, &arm_ccn_list);
1283 mutex_unlock(&arm_ccn_mutex);
1292 return 0; 1284 return 0;
1293 1285
1294error_pmu_register: 1286error_pmu_register:
1295error_set_affinity: 1287error_set_affinity:
1296 unregister_cpu_notifier(&ccn->dt.cpu_nb);
1297error_cpu_notifier:
1298 ida_simple_remove(&arm_ccn_pmu_ida, ccn->dt.id); 1288 ida_simple_remove(&arm_ccn_pmu_ida, ccn->dt.id);
1299 for (i = 0; i < ccn->num_xps; i++) 1289 for (i = 0; i < ccn->num_xps; i++)
1300 writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL); 1290 writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL);
@@ -1306,9 +1296,12 @@ static void arm_ccn_pmu_cleanup(struct arm_ccn *ccn)
1306{ 1296{
1307 int i; 1297 int i;
1308 1298
1299 mutex_lock(&arm_ccn_mutex);
1300 list_del(&ccn->dt.entry);
1301 mutex_unlock(&arm_ccn_mutex);
1302
1309 if (ccn->irq) 1303 if (ccn->irq)
1310 irq_set_affinity_hint(ccn->irq, NULL); 1304 irq_set_affinity_hint(ccn->irq, NULL);
1311 unregister_cpu_notifier(&ccn->dt.cpu_nb);
1312 for (i = 0; i < ccn->num_xps; i++) 1305 for (i = 0; i < ccn->num_xps; i++)
1313 writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL); 1306 writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL);
1314 writel(0, ccn->dt.base + CCN_DT_PMCR); 1307 writel(0, ccn->dt.base + CCN_DT_PMCR);
@@ -1316,7 +1309,6 @@ static void arm_ccn_pmu_cleanup(struct arm_ccn *ccn)
1316 ida_simple_remove(&arm_ccn_pmu_ida, ccn->dt.id); 1309 ida_simple_remove(&arm_ccn_pmu_ida, ccn->dt.id);
1317} 1310}
1318 1311
1319
1320static int arm_ccn_for_each_valid_region(struct arm_ccn *ccn, 1312static int arm_ccn_for_each_valid_region(struct arm_ccn *ccn,
1321 int (*callback)(struct arm_ccn *ccn, int region, 1313 int (*callback)(struct arm_ccn *ccn, int region,
1322 void __iomem *base, u32 type, u32 id)) 1314 void __iomem *base, u32 type, u32 id))
@@ -1533,7 +1525,13 @@ static struct platform_driver arm_ccn_driver = {
1533 1525
1534static int __init arm_ccn_init(void) 1526static int __init arm_ccn_init(void)
1535{ 1527{
1536 int i; 1528 int i, ret;
1529
1530 ret = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ARM_CCN_ONLINE,
1531 "AP_PERF_ARM_CCN_ONLINE", NULL,
1532 arm_ccn_pmu_offline_cpu);
1533 if (ret)
1534 return ret;
1537 1535
1538 for (i = 0; i < ARRAY_SIZE(arm_ccn_pmu_events); i++) 1536 for (i = 0; i < ARRAY_SIZE(arm_ccn_pmu_events); i++)
1539 arm_ccn_pmu_events_attrs[i] = &arm_ccn_pmu_events[i].attr.attr; 1537 arm_ccn_pmu_events_attrs[i] = &arm_ccn_pmu_events[i].attr.attr;
@@ -1543,6 +1541,7 @@ static int __init arm_ccn_init(void)
1543 1541
1544static void __exit arm_ccn_exit(void) 1542static void __exit arm_ccn_exit(void)
1545{ 1543{
1544 cpuhp_remove_state_nocalls(CPUHP_AP_PERF_ARM_CCN_ONLINE);
1546 platform_driver_unregister(&arm_ccn_driver); 1545 platform_driver_unregister(&arm_ccn_driver);
1547} 1546}
1548 1547