soc/intel_adsp: Keep track of started CPUs in the SOC layer

On cAVS 2.5, there is an inherent race with the IDC interrupt.  It's
used for routine IPIs during OS operation, but also for launching a
power-gated core.  Recent changes moved the unmasking of the IDC
interrupt earlier, which made it possible for early OS scheduler
behavior (e.g. adding the main thread to the run queue) to
accidentally launch the other cores into LP-SRAM that had not been
initialized.

Instead of treating this with initialization ordering, keep and
maintain a list of active CPUs and check them at runtime to be sure we
never try to IPI a CPU that isn't running yet.  We're going to need
this feature when we add live core offlining anyway.

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
This commit is contained in:
Andy Ross 2021-08-12 11:19:20 -07:00 committed by Anas Nashif
commit a71336cab3

View file

@ -86,6 +86,13 @@ static __aligned(XCHAL_DCACHE_LINESIZE) union {
static uint32_t cpu_mask; static uint32_t cpu_mask;
/* Simple array of CPUs that are active and available for an IPI. The
* IDC interrupt is ALSO used to bring a CPU out of reset, so we need
* to be absolutely sure we don't try to IPI a CPU that isn't ready to
* start, or else we'll launch it into garbage and crash the DSP.
*/
static bool cpus_active[CONFIG_MP_NUM_CPUS];
/* Tiny assembly stub for calling z_mp_entry() on the auxiliary CPUs. /* Tiny assembly stub for calling z_mp_entry() on the auxiliary CPUs.
* Mask interrupts, clear the register window state and set the stack * Mask interrupts, clear the register window state and set the stack
* pointer. This represents the minimum work required to run C code * pointer. This represents the minimum work required to run C code
@ -243,6 +250,7 @@ void z_mp_entry(void)
cavs_idc_smp_init(NULL); cavs_idc_smp_init(NULL);
#endif #endif
cpus_active[start_rec.cpu] = true;
start_rec.alive = 1; start_rec.alive = 1;
start_rec.fn(start_rec.arg); start_rec.fn(start_rec.arg);
@ -362,12 +370,11 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz,
void arch_sched_ipi(void) void arch_sched_ipi(void)
{ {
#ifdef CONFIG_SOC_SERIES_INTEL_CAVS_V25 #ifdef CONFIG_SOC_SERIES_INTEL_CAVS_V25
uint32_t prid; uint32_t curr = prid();
__asm__ volatile("rsr %0, PRID" : "=r"(prid));
for (int c = 0; c < CONFIG_MP_NUM_CPUS; c++) { for (int c = 0; c < CONFIG_MP_NUM_CPUS; c++) {
if (c != prid) { if (c != curr && cpus_active[c]) {
IDC[prid].core[c].itc = BIT(31); IDC[curr].core[c].itc = BIT(31);
} }
} }
#else #else