// SPDX-License-Identifier: GPL-2.0-or-later /* * SMP support for pSeries machines. * * Dave Engebretsen, Peter Bergner, and * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com * * Plus various changes from other IBM teams...
*/
/* * The Primary thread of each non-boot processor was started from the OF client * interface by prom_hold_cpus and is spinning on secondary_hold_spinloop.
*/ static cpumask_var_t of_spin_mask;
/* Query where a cpu is now. Return codes #defined in plpar_wrappers.h */ int smp_query_cpu_stopped(unsignedint pcpu)
{ int cpu_status, status; int qcss_tok = rtas_function_token(RTAS_FN_QUERY_CPU_STOPPED_STATE);
if (qcss_tok == RTAS_UNKNOWN_SERVICE) {
printk_once(KERN_INFO "Firmware doesn't support query-cpu-stopped-state\n"); return QCSS_HARDWARE_ERROR;
}
/** * smp_startup_cpu() - start the given cpu * * At boot time, there is nothing to do for primary threads which were * started from Open Firmware. For anything else, call RTAS with the * appropriate start location. * * Returns: * 0 - failure * 1 - success
*/ staticinlineint smp_startup_cpu(unsignedint lcpu)
{ int status; unsignedlong start_here =
__pa(ppc_function_entry(generic_secondary_smp_init)); unsignedint pcpu; int start_cpu;
if (cpumask_test_cpu(lcpu, of_spin_mask)) /* Already started by OF and sitting in spin loop */ return 1;
pcpu = get_hard_smp_processor_id(lcpu);
/* Check to see if the CPU out of FW already for kexec */ if (smp_query_cpu_stopped(pcpu) == QCSS_NOT_STOPPED){
cpumask_set_cpu(lcpu, of_spin_mask); return 1;
}
/* * If the RTAS start-cpu token does not exist then presume the * cpu is already spinning.
*/
start_cpu = rtas_function_token(RTAS_FN_START_CPU); if (start_cpu == RTAS_UNKNOWN_SERVICE) return 1;
if (firmware_has_feature(FW_FEATURE_SPLPAR))
vpa_init(cpu);
cpumask_clear_cpu(cpu, of_spin_mask);
}
staticint smp_pSeries_kick_cpu(int nr)
{ if (nr < 0 || nr >= nr_cpu_ids) return -EINVAL;
if (!smp_startup_cpu(nr)) return -ENOENT;
/* * The processor is currently spinning, waiting for the * cpu_start field to become non-zero After we set cpu_start, * the processor will continue on to secondary_start
*/
paca_ptrs[nr]->cpu_start = 1;
/* Cause IPI as setup by the interrupt controller (xics or xive) */ staticvoid (*ic_cause_ipi)(int cpu) __ro_after_init;
/* Use msgsndp doorbells target is a sibling, else use interrupt controller */ staticvoid dbell_or_ic_cause_ipi(int cpu)
{ if (doorbell_try_core_ipi(cpu)) return;
ic_cause_ipi(cpu);
}
staticint pseries_cause_nmi_ipi(int cpu)
{ int hwcpu;
if (cpu == NMI_IPI_ALL_OTHERS) {
hwcpu = H_SIGNAL_SYS_RESET_ALL_OTHERS;
} else { if (cpu < 0) {
WARN_ONCE(true, "incorrect cpu parameter %d", cpu); return 0;
}
hwcpu = get_hard_smp_processor_id(cpu);
}
if (plpar_signal_sys_reset(hwcpu) == H_SUCCESS) return 1;
return 0;
}
static __init void pSeries_smp_probe(void)
{ if (xive_enabled())
xive_smp_probe(); else
xics_smp_probe();
/* No doorbell facility, must use the interrupt controller for IPIs */ if (!cpu_has_feature(CPU_FTR_DBELL)) return;
/* Doorbells can only be used for IPIs between SMT siblings */ if (!cpu_has_feature(CPU_FTR_SMT)) return;
check_kvm_guest();
if (is_kvm_guest()) { /* * KVM emulates doorbells by disabling FSCR[MSGP] so msgsndp * faults to the hypervisor which then reads the instruction * from guest memory, which tends to be slower than using XIVE.
*/ if (xive_enabled()) return;
/* * XICS hcalls aren't as fast, so we can use msgsndp (which * also helps exercise KVM emulation), however KVM can't * emulate secure guests because it can't read the instruction * out of their memory.
*/ if (is_secure_guest()) return;
}
/* * Under PowerVM, FSCR[MSGP] is enabled as guest vCPU siblings are * gang scheduled on the same physical core, so doorbells are always * faster than the interrupt controller, and they can be used by * secure guests.
*/
/* * Mark threads which are still spinning in hold loops * * We know prom_init will not have started them if RTAS supports * query-cpu-stopped-state.
*/ if (rtas_function_token(RTAS_FN_QUERY_CPU_STOPPED_STATE) == RTAS_UNKNOWN_SERVICE) { if (cpu_has_feature(CPU_FTR_SMT)) {
for_each_present_cpu(i) { if (cpu_thread_in_core(i) == 0)
cpumask_set_cpu(i, of_spin_mask);
}
} else
cpumask_copy(of_spin_mask, cpu_present_mask);
cpumask_clear_cpu(boot_cpuid, of_spin_mask);
}
pr_debug(" <- smp_init_pSeries()\n");
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.0 Sekunden
(vorverarbeitet)
¤
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.