diff options
Diffstat (limited to 'drivers/bus/arm-ccn.c')
-rw-r--r-- | drivers/bus/arm-ccn.c | 57 |
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 | ||
192 | static DEFINE_MUTEX(arm_ccn_mutex); | ||
193 | static LIST_HEAD(arm_ccn_list); | ||
192 | 194 | ||
193 | static int arm_ccn_node_to_xp(int node) | 195 | static 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 | ||
1174 | static int arm_ccn_pmu_cpu_notifier(struct notifier_block *nb, | 1176 | static 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 | ||
1294 | error_pmu_register: | 1286 | error_pmu_register: |
1295 | error_set_affinity: | 1287 | error_set_affinity: |
1296 | unregister_cpu_notifier(&ccn->dt.cpu_nb); | ||
1297 | error_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 | |||
1320 | static int arm_ccn_for_each_valid_region(struct arm_ccn *ccn, | 1312 | static 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 | ||
1534 | static int __init arm_ccn_init(void) | 1526 | static 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 | ||
1544 | static void __exit arm_ccn_exit(void) | 1542 | static 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 | ||