aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorNicolas Pitre <nicolas.pitre@linaro.org>2013-06-13 23:42:46 -0400
committerNicolas Pitre <nicolas.pitre@linaro.org>2013-08-04 15:29:13 -0400
commit38c35d4f2e408c369e3030f0717d35ad443d9223 (patch)
tree1c308ad9a20b501dd4050191ae2dd418b809e5ea /arch/arm
parentc4821c0575a3b1bf26f100230dc2938297d7043b (diff)
ARM: bL_switcher: remove assumptions between logical and physical CPUs
Up to now, the logical CPU was somehow tied to the physical CPU number within a cluster. This causes problems when forcing the boot CPU to be different from the first enumerated CPU in the device tree creating a discrepancy between logical and physical CPU numbers. Let's make the pairing completely independent from physical CPU numbers. Let's keep only those logical CPUs with same initial CPU cluster to create a uniform scheduler profile without having to modify any of the probed topology and compute capacity data. This has the potential to create a non contiguous CPU numbering space when the switcher is active with potential impact on buggy user space tools. It is however better to fix those tools rather than making the switcher code more intrusive. Signed-off-by: Nicolas Pitre <nico@linaro.org> Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/common/bL_switcher.c176
1 files changed, 104 insertions, 72 deletions
diff --git a/arch/arm/common/bL_switcher.c b/arch/arm/common/bL_switcher.c
index cec825ef392b..0e4fb3e5e99c 100644
--- a/arch/arm/common/bL_switcher.c
+++ b/arch/arm/common/bL_switcher.c
@@ -53,21 +53,19 @@ static int read_mpidr(void)
53 53
54static void bL_do_switch(void *_unused) 54static void bL_do_switch(void *_unused)
55{ 55{
56 unsigned mpidr, cpuid, clusterid, ob_cluster, ib_cluster; 56 unsigned ib_mpidr, ib_cpu, ib_cluster;
57 57
58 pr_debug("%s\n", __func__); 58 pr_debug("%s\n", __func__);
59 59
60 mpidr = read_mpidr(); 60 ib_mpidr = cpu_logical_map(smp_processor_id());
61 cpuid = MPIDR_AFFINITY_LEVEL(mpidr, 0); 61 ib_cpu = MPIDR_AFFINITY_LEVEL(ib_mpidr, 0);
62 clusterid = MPIDR_AFFINITY_LEVEL(mpidr, 1); 62 ib_cluster = MPIDR_AFFINITY_LEVEL(ib_mpidr, 1);
63 ob_cluster = clusterid;
64 ib_cluster = clusterid ^ 1;
65 63
66 /* 64 /*
67 * Our state has been saved at this point. Let's release our 65 * Our state has been saved at this point. Let's release our
68 * inbound CPU. 66 * inbound CPU.
69 */ 67 */
70 mcpm_set_entry_vector(cpuid, ib_cluster, cpu_resume); 68 mcpm_set_entry_vector(ib_cpu, ib_cluster, cpu_resume);
71 sev(); 69 sev();
72 70
73 /* 71 /*
@@ -113,6 +111,7 @@ static int bL_switchpoint(unsigned long _arg)
113 */ 111 */
114 112
115static unsigned int bL_gic_id[MAX_CPUS_PER_CLUSTER][MAX_NR_CLUSTERS]; 113static unsigned int bL_gic_id[MAX_CPUS_PER_CLUSTER][MAX_NR_CLUSTERS];
114static int bL_switcher_cpu_pairing[NR_CPUS];
116 115
117/* 116/*
118 * bL_switch_to - Switch to a specific cluster for the current CPU 117 * bL_switch_to - Switch to a specific cluster for the current CPU
@@ -123,31 +122,38 @@ static unsigned int bL_gic_id[MAX_CPUS_PER_CLUSTER][MAX_NR_CLUSTERS];
123 */ 122 */
124static int bL_switch_to(unsigned int new_cluster_id) 123static int bL_switch_to(unsigned int new_cluster_id)
125{ 124{
126 unsigned int mpidr, cpuid, clusterid, ob_cluster, ib_cluster, this_cpu; 125 unsigned int mpidr, this_cpu, that_cpu;
126 unsigned int ob_mpidr, ob_cpu, ob_cluster, ib_mpidr, ib_cpu, ib_cluster;
127 struct tick_device *tdev; 127 struct tick_device *tdev;
128 enum clock_event_mode tdev_mode; 128 enum clock_event_mode tdev_mode;
129 int ret; 129 int ret;
130 130
131 mpidr = read_mpidr(); 131 this_cpu = smp_processor_id();
132 cpuid = MPIDR_AFFINITY_LEVEL(mpidr, 0); 132 ob_mpidr = read_mpidr();
133 clusterid = MPIDR_AFFINITY_LEVEL(mpidr, 1); 133 ob_cpu = MPIDR_AFFINITY_LEVEL(ob_mpidr, 0);
134 ob_cluster = clusterid; 134 ob_cluster = MPIDR_AFFINITY_LEVEL(ob_mpidr, 1);
135 ib_cluster = clusterid ^ 1; 135 BUG_ON(cpu_logical_map(this_cpu) != ob_mpidr);
136 136
137 if (new_cluster_id == clusterid) 137 if (new_cluster_id == ob_cluster)
138 return 0; 138 return 0;
139 139
140 pr_debug("before switch: CPU %d in cluster %d\n", cpuid, clusterid); 140 that_cpu = bL_switcher_cpu_pairing[this_cpu];
141 ib_mpidr = cpu_logical_map(that_cpu);
142 ib_cpu = MPIDR_AFFINITY_LEVEL(ib_mpidr, 0);
143 ib_cluster = MPIDR_AFFINITY_LEVEL(ib_mpidr, 1);
144
145 pr_debug("before switch: CPU %d MPIDR %#x -> %#x\n",
146 this_cpu, ob_mpidr, ib_mpidr);
141 147
142 /* Close the gate for our entry vectors */ 148 /* Close the gate for our entry vectors */
143 mcpm_set_entry_vector(cpuid, ob_cluster, NULL); 149 mcpm_set_entry_vector(ob_cpu, ob_cluster, NULL);
144 mcpm_set_entry_vector(cpuid, ib_cluster, NULL); 150 mcpm_set_entry_vector(ib_cpu, ib_cluster, NULL);
145 151
146 /* 152 /*
147 * Let's wake up the inbound CPU now in case it requires some delay 153 * Let's wake up the inbound CPU now in case it requires some delay
148 * to come online, but leave it gated in our entry vector code. 154 * to come online, but leave it gated in our entry vector code.
149 */ 155 */
150 ret = mcpm_cpu_power_up(cpuid, ib_cluster); 156 ret = mcpm_cpu_power_up(ib_cpu, ib_cluster);
151 if (ret) { 157 if (ret) {
152 pr_err("%s: mcpm_cpu_power_up() returned %d\n", __func__, ret); 158 pr_err("%s: mcpm_cpu_power_up() returned %d\n", __func__, ret);
153 return ret; 159 return ret;
@@ -160,10 +166,8 @@ static int bL_switch_to(unsigned int new_cluster_id)
160 local_irq_disable(); 166 local_irq_disable();
161 local_fiq_disable(); 167 local_fiq_disable();
162 168
163 this_cpu = smp_processor_id();
164
165 /* redirect GIC's SGIs to our counterpart */ 169 /* redirect GIC's SGIs to our counterpart */
166 gic_migrate_target(bL_gic_id[cpuid][ib_cluster]); 170 gic_migrate_target(bL_gic_id[ib_cpu][ib_cluster]);
167 171
168 /* 172 /*
169 * Raise a SGI on the inbound CPU to make sure it doesn't stall 173 * Raise a SGI on the inbound CPU to make sure it doesn't stall
@@ -185,8 +189,9 @@ static int bL_switch_to(unsigned int new_cluster_id)
185 if (ret) 189 if (ret)
186 panic("%s: cpu_pm_enter() returned %d\n", __func__, ret); 190 panic("%s: cpu_pm_enter() returned %d\n", __func__, ret);
187 191
188 /* Flip the cluster in the CPU logical map for this CPU. */ 192 /* Swap the physical CPUs in the logical map for this logical CPU. */
189 cpu_logical_map(this_cpu) ^= (1 << 8); 193 cpu_logical_map(this_cpu) = ib_mpidr;
194 cpu_logical_map(that_cpu) = ob_mpidr;
190 195
191 /* Let's do the actual CPU switch. */ 196 /* Let's do the actual CPU switch. */
192 ret = cpu_suspend(0, bL_switchpoint); 197 ret = cpu_suspend(0, bL_switchpoint);
@@ -195,10 +200,8 @@ static int bL_switch_to(unsigned int new_cluster_id)
195 200
196 /* We are executing on the inbound CPU at this point */ 201 /* We are executing on the inbound CPU at this point */
197 mpidr = read_mpidr(); 202 mpidr = read_mpidr();
198 cpuid = MPIDR_AFFINITY_LEVEL(mpidr, 0); 203 pr_debug("after switch: CPU %d MPIDR %#x\n", this_cpu, mpidr);
199 clusterid = MPIDR_AFFINITY_LEVEL(mpidr, 1); 204 BUG_ON(mpidr != ib_mpidr);
200 pr_debug("after switch: CPU %d in cluster %d\n", cpuid, clusterid);
201 BUG_ON(clusterid != ib_cluster);
202 205
203 mcpm_cpu_powered_up(); 206 mcpm_cpu_powered_up();
204 207
@@ -300,7 +303,7 @@ EXPORT_SYMBOL_GPL(bL_switch_request);
300 */ 303 */
301 304
302static unsigned int bL_switcher_active; 305static unsigned int bL_switcher_active;
303static unsigned int bL_switcher_cpu_original_cluster[MAX_CPUS_PER_CLUSTER]; 306static unsigned int bL_switcher_cpu_original_cluster[NR_CPUS];
304static cpumask_t bL_switcher_removed_logical_cpus; 307static cpumask_t bL_switcher_removed_logical_cpus;
305 308
306static void bL_switcher_restore_cpus(void) 309static void bL_switcher_restore_cpus(void)
@@ -313,52 +316,86 @@ static void bL_switcher_restore_cpus(void)
313 316
314static int bL_switcher_halve_cpus(void) 317static int bL_switcher_halve_cpus(void)
315{ 318{
316 int cpu, cluster, i, ret; 319 int i, j, cluster_0, gic_id, ret;
317 cpumask_t cluster_mask[2], common_mask; 320 unsigned int cpu, cluster, mask;
318 321 cpumask_t available_cpus;
319 cpumask_clear(&bL_switcher_removed_logical_cpus);
320 cpumask_clear(&cluster_mask[0]);
321 cpumask_clear(&cluster_mask[1]);
322 322
323 /* First pass to validate what we have */
324 mask = 0;
323 for_each_online_cpu(i) { 325 for_each_online_cpu(i) {
324 cpu = cpu_logical_map(i) & 0xff; 326 cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 0);
325 cluster = (cpu_logical_map(i) >> 8) & 0xff; 327 cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 1);
326 if (cluster >= 2) { 328 if (cluster >= 2) {
327 pr_err("%s: only dual cluster systems are supported\n", __func__); 329 pr_err("%s: only dual cluster systems are supported\n", __func__);
328 return -EINVAL; 330 return -EINVAL;
329 } 331 }
330 cpumask_set_cpu(cpu, &cluster_mask[cluster]); 332 if (WARN_ON(cpu >= MAX_CPUS_PER_CLUSTER))
333 return -EINVAL;
334 mask |= (1 << cluster);
331 } 335 }
332 336 if (mask != 3) {
333 if (!cpumask_and(&common_mask, &cluster_mask[0], &cluster_mask[1])) { 337 pr_err("%s: no CPU pairing possible\n", __func__);
334 pr_err("%s: no common set of CPUs\n", __func__);
335 return -EINVAL; 338 return -EINVAL;
336 } 339 }
337 340
338 for_each_online_cpu(i) { 341 /*
339 cpu = cpu_logical_map(i) & 0xff; 342 * Now let's do the pairing. We match each CPU with another CPU
340 cluster = (cpu_logical_map(i) >> 8) & 0xff; 343 * from a different cluster. To get a uniform scheduling behavior
341 344 * without fiddling with CPU topology and compute capacity data,
342 if (cpumask_test_cpu(cpu, &common_mask)) { 345 * we'll use logical CPUs initially belonging to the same cluster.
343 /* Let's take note of the GIC ID for this CPU */ 346 */
344 int gic_id = gic_get_cpu_id(i); 347 memset(bL_switcher_cpu_pairing, -1, sizeof(bL_switcher_cpu_pairing));
345 if (gic_id < 0) { 348 cpumask_copy(&available_cpus, cpu_online_mask);
346 pr_err("%s: bad GIC ID for CPU %d\n", __func__, i); 349 cluster_0 = -1;
347 return -EINVAL; 350 for_each_cpu(i, &available_cpus) {
348 } 351 int match = -1;
349 bL_gic_id[cpu][cluster] = gic_id; 352 cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 1);
350 pr_info("GIC ID for CPU %u cluster %u is %u\n", 353 if (cluster_0 == -1)
351 cpu, cluster, gic_id); 354 cluster_0 = cluster;
352 355 if (cluster != cluster_0)
356 continue;
357 cpumask_clear_cpu(i, &available_cpus);
358 for_each_cpu(j, &available_cpus) {
359 cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(j), 1);
353 /* 360 /*
354 * We keep only those logical CPUs which number 361 * Let's remember the last match to create "odd"
355 * is equal to their physical CPU number. This is 362 * pairings on purpose in order for other code not
356 * not perfect but good enough for now. 363 * to assume any relation between physical and
364 * logical CPU numbers.
357 */ 365 */
358 if (cpu == i) { 366 if (cluster != cluster_0)
359 bL_switcher_cpu_original_cluster[cpu] = cluster; 367 match = j;
360 continue; 368 }
361 } 369 if (match != -1) {
370 bL_switcher_cpu_pairing[i] = match;
371 cpumask_clear_cpu(match, &available_cpus);
372 pr_info("CPU%d paired with CPU%d\n", i, match);
373 }
374 }
375
376 /*
377 * Now we disable the unwanted CPUs i.e. everything that has no
378 * pairing information (that includes the pairing counterparts).
379 */
380 cpumask_clear(&bL_switcher_removed_logical_cpus);
381 for_each_online_cpu(i) {
382 cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 0);
383 cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 1);
384
385 /* Let's take note of the GIC ID for this CPU */
386 gic_id = gic_get_cpu_id(i);
387 if (gic_id < 0) {
388 pr_err("%s: bad GIC ID for CPU %d\n", __func__, i);
389 bL_switcher_restore_cpus();
390 return -EINVAL;
391 }
392 bL_gic_id[cpu][cluster] = gic_id;
393 pr_info("GIC ID for CPU %u cluster %u is %u\n",
394 cpu, cluster, gic_id);
395
396 if (bL_switcher_cpu_pairing[i] != -1) {
397 bL_switcher_cpu_original_cluster[i] = cluster;
398 continue;
362 } 399 }
363 400
364 ret = cpu_down(i); 401 ret = cpu_down(i);
@@ -409,7 +446,7 @@ static int bL_switcher_enable(void)
409 446
410static void bL_switcher_disable(void) 447static void bL_switcher_disable(void)
411{ 448{
412 unsigned int cpu, cluster, i; 449 unsigned int cpu, cluster;
413 struct bL_thread *t; 450 struct bL_thread *t;
414 struct task_struct *task; 451 struct task_struct *task;
415 452
@@ -429,7 +466,6 @@ static void bL_switcher_disable(void)
429 * possibility for interference from external requests. 466 * possibility for interference from external requests.
430 */ 467 */
431 for_each_online_cpu(cpu) { 468 for_each_online_cpu(cpu) {
432 BUG_ON(cpu != (cpu_logical_map(cpu) & 0xff));
433 t = &bL_threads[cpu]; 469 t = &bL_threads[cpu];
434 task = t->task; 470 task = t->task;
435 t->task = NULL; 471 t->task = NULL;
@@ -453,14 +489,10 @@ static void bL_switcher_disable(void)
453 /* If execution gets here, we're in trouble. */ 489 /* If execution gets here, we're in trouble. */
454 pr_crit("%s: unable to restore original cluster for CPU %d\n", 490 pr_crit("%s: unable to restore original cluster for CPU %d\n",
455 __func__, cpu); 491 __func__, cpu);
456 for_each_cpu(i, &bL_switcher_removed_logical_cpus) { 492 pr_crit("%s: CPU %d can't be restored\n",
457 if ((cpu_logical_map(i) & 0xff) != cpu) 493 __func__, bL_switcher_cpu_pairing[cpu]);
458 continue; 494 cpumask_clear_cpu(bL_switcher_cpu_pairing[cpu],
459 pr_crit("%s: CPU %d can't be restored\n", 495 &bL_switcher_removed_logical_cpus);
460 __func__, i);
461 cpumask_clear_cpu(i, &bL_switcher_removed_logical_cpus);
462 break;
463 }
464 } 496 }
465 497
466 bL_switcher_restore_cpus(); 498 bL_switcher_restore_cpus();