/* redirect GIC's SGIs to our counterpart */
gic_migrate_target(bL_gic_id[ib_cpu][ib_cluster]);
tick_suspend_local();
ret = cpu_pm_enter();
/* we can not tolerate errors at this point */ if (ret)
panic("%s: cpu_pm_enter() returned %d\n", __func__, ret);
/* Swap the physical CPUs in the logical map for this logical CPU. */
cpu_logical_map(this_cpu) = ib_mpidr;
cpu_logical_map(that_cpu) = ob_mpidr;
/* Let's do the actual CPU switch. */
ret = cpu_suspend((unsignedlong)&handshake_ptr, bL_switchpoint); if (ret > 0)
panic("%s: cpu_suspend() returned %d\n", __func__, ret);
/* We are executing on the inbound CPU at this point */
mpidr = read_mpidr();
pr_debug("after switch: CPU %d MPIDR %#x\n", this_cpu, mpidr);
BUG_ON(mpidr != ib_mpidr);
int bL_switcher_register_notifier(struct notifier_block *nb)
{ return blocking_notifier_chain_register(&bL_activation_notifier, nb);
}
EXPORT_SYMBOL_GPL(bL_switcher_register_notifier);
int bL_switcher_unregister_notifier(struct notifier_block *nb)
{ return blocking_notifier_chain_unregister(&bL_activation_notifier, nb);
}
EXPORT_SYMBOL_GPL(bL_switcher_unregister_notifier);
staticint bL_activation_notify(unsignedlong val)
{ int ret;
ret = blocking_notifier_call_chain(&bL_activation_notifier, val, NULL); if (ret & NOTIFY_STOP_MASK)
pr_err("%s: notifier chain failed with status 0x%x\n",
__func__, ret); return notifier_to_errno(ret);
}
staticvoid bL_switcher_restore_cpus(void)
{ int i;
for_each_cpu(i, &bL_switcher_removed_logical_cpus) { struct device *cpu_dev = get_cpu_device(i); int ret = device_online(cpu_dev); if (ret)
dev_err(cpu_dev, "switcher: unable to restore CPU\n");
}
}
staticint bL_switcher_halve_cpus(void)
{ int i, j, cluster_0, gic_id, ret; unsignedint cpu, cluster, mask;
cpumask_t available_cpus;
/* First pass to validate what we have */
mask = 0;
for_each_online_cpu(i) {
cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 0);
cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 1); if (cluster >= 2) {
pr_err("%s: only dual cluster systems are supported\n", __func__); return -EINVAL;
} if (WARN_ON(cpu >= MAX_CPUS_PER_CLUSTER)) return -EINVAL;
mask |= (1 << cluster);
} if (mask != 3) {
pr_err("%s: no CPU pairing possible\n", __func__); return -EINVAL;
}
/* *Nowlet'sdothepairing.WematcheachCPUwithanotherCPU *fromadifferentcluster.Togetauniformschedulingbehavior *withoutfiddlingwithCPUtopologyandcomputecapacitydata, *we'lluselogicalCPUsinitiallybelongingtothesamecluster.
*/
memset(bL_switcher_cpu_pairing, -1, sizeof(bL_switcher_cpu_pairing));
cpumask_copy(&available_cpus, cpu_online_mask);
cluster_0 = -1;
for_each_cpu(i, &available_cpus) { int match = -1;
cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 1); if (cluster_0 == -1)
cluster_0 = cluster; if (cluster != cluster_0) continue;
cpumask_clear_cpu(i, &available_cpus);
for_each_cpu(j, &available_cpus) {
cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(j), 1); /* *Let'srememberthelastmatchtocreate"odd" *pairingsonpurposeinorderforothercodenot *toassumeanyrelationbetweenphysicaland *logicalCPUnumbers.
*/ if (cluster != cluster_0)
match = j;
} if (match != -1) {
bL_switcher_cpu_pairing[i] = match;
cpumask_clear_cpu(match, &available_cpus);
pr_info("CPU%d paired with CPU%d\n", i, match);
}
}
/* Let's take note of the GIC ID for this CPU */
gic_id = gic_get_cpu_id(i); if (gic_id < 0) {
pr_err("%s: bad GIC ID for CPU %d\n", __func__, i);
bL_switcher_restore_cpus(); return -EINVAL;
}
bL_gic_id[cpu][cluster] = gic_id;
pr_info("GIC ID for CPU %u cluster %u is %u\n",
cpu, cluster, gic_id);
if (bL_switcher_cpu_pairing[i] != -1) {
bL_switcher_cpu_original_cluster[i] = cluster; continue;
}
ret = device_offline(get_cpu_device(i)); if (ret) {
bL_switcher_restore_cpus(); return ret;
}
cpumask_set_cpu(i, &bL_switcher_removed_logical_cpus);
}
return0;
}
/* Determine the logical CPU a given physical CPU is grouped on. */ int bL_switcher_get_logical_index(u32 mpidr)
{ int cpu;
if (!bL_switcher_active) return -EUNATCH;
mpidr &= MPIDR_HWID_BITMASK;
for_each_online_cpu(cpu) { int pairing = bL_switcher_cpu_pairing[cpu]; if (pairing == -1) continue; if ((mpidr == cpu_logical_map(cpu)) ||
(mpidr == cpu_logical_map(pairing))) return cpu;
} return -EINVAL;
}
if (bL_activation_notify(BL_NOTIFY_PRE_DISABLE) != 0) {
bL_activation_notify(BL_NOTIFY_POST_ENABLE); goto out;
}
bL_switcher_active = 0;
/* *Todeactivatetheswitcher,wemustshutdowntheswitcher *threadstopreventanyotherrequestsfrombeingaccepted. *Then,ifthefinalclusterforgivenlogicalCPUisnotthe *sameastheoriginalone,we'llrecreateaswitcherthread *justforthepurposeofswitchingtheCPUbackwithoutany *possibilityforinterferencefromexternalrequests.
*/
for_each_online_cpu(cpu) {
t = &bL_threads[cpu];
task = t->task;
t->task = NULL; if (!task || IS_ERR(task)) continue;
kthread_stop(task); /* no more switch may happen on this CPU at this point */
cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(cpu), 1); if (cluster == bL_switcher_cpu_original_cluster[cpu]) continue;
init_completion(&t->started);
t->wanted_cluster = bL_switcher_cpu_original_cluster[cpu];
task = bL_switcher_thread_create(cpu, t); if (!IS_ERR(task)) {
wait_for_completion(&t->started);
kthread_stop(task);
cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(cpu), 1); if (cluster == bL_switcher_cpu_original_cluster[cpu]) continue;
} /* If execution gets here, we're in trouble. */
pr_crit("%s: unable to restore original cluster for CPU %d\n",
__func__, cpu);
pr_crit("%s: CPU %d can't be restored\n",
__func__, bL_switcher_cpu_pairing[cpu]);
cpumask_clear_cpu(bL_switcher_cpu_pairing[cpu],
&bL_switcher_removed_logical_cpus);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.