soc/intel_adsp: Remove interrupt masking from secondary core startup
There is some legacy code that tries to mask IDC interrupts when starting up cores. This is there because the IDC interrupt is both the system IPI when Zephyr is running (and can thus be signaled asynchronously to the code calling arch_start_cpu()) and the messaging protocol to the boot ROM on the other CPU. So the idea is that we mask interrupts after startup so nothing is confused. But that's needless in the current architecture. We maintain a synchronized cpus_active[] record that will show true/active for any CPU between the end of its SMP startup sequence and the beginning of the shutdown process in soc_halt_cpu(), and false at all other times. An IPI will never be sent to a CPU that is running in the boot ROM, because such a CPU will be flagged as inactive. Likewise a ROM startup IDC will never be sent to a CPU running Zephyr code for the converse reason. Remove all that code. Unfortunately SOF itself still needs an interrupt unmask step at CPU startup, because it's still doing its own masking (probably according to the same algorithm that we imported). Leave that in place as a minimal workaround until we get that fixed upstream. Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
This commit is contained in:
parent
29b99aa93a
commit
43d1d15da8
|
@ -226,22 +226,13 @@ void z_mp_entry(void)
|
|||
/* Unfortunately the interrupt controller doesn't understand
|
||||
* that each CPU has its own mask register (the timer has a
|
||||
* similar hook). Needed only on hardware with ROMs that
|
||||
* disable this; cAVS 2.5 starts with an unmasked hardware
|
||||
* default.
|
||||
* disable this; otherwise our own code in soc_idc_init()
|
||||
* already has it unmasked.
|
||||
*/
|
||||
if (!IS_ENABLED(CONFIG_SOC_SERIES_INTEL_CAVS_V25)) {
|
||||
CAVS_INTCTRL[start_rec.cpu].l2.clear = CAVS_L2_IDC;
|
||||
}
|
||||
|
||||
/* Unmask IDC interrupts from this core to all others. A
|
||||
* delay is needed following the write on older hardware, or
|
||||
* else the modification gets lost. Voodoo.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_SOC_SERIES_INTEL_CAVS_V15)) {
|
||||
k_busy_wait(10);
|
||||
}
|
||||
IDC[start_rec.cpu].busy_int = IDC_ALL_CORES;
|
||||
|
||||
cpus_active[start_rec.cpu] = true;
|
||||
|
||||
start_rec.fn(start_rec.arg);
|
||||
|
@ -320,9 +311,6 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz,
|
|||
|
||||
z_mp_stack_top = Z_THREAD_STACK_BUFFER(stack) + sz;
|
||||
|
||||
/* Pre-2.x cAVS delivers the IDC to ROM code, so unmask it */
|
||||
CAVS_INTCTRL[cpu_num].l2.clear = CAVS_L2_IDC;
|
||||
|
||||
/* Disable automatic power and clock gating for that CPU, so
|
||||
* it won't just go back to sleep. Note that after startup,
|
||||
* the cores are NOT power gated even if they're configured to
|
||||
|
@ -335,6 +323,20 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz,
|
|||
CAVS_SHIM.clkctl |= CAVS_CLKCTL_TCPLCG(cpu_num);
|
||||
}
|
||||
|
||||
/* Workaround. SOF seems to have some older code on pre-2.5
|
||||
* hardware that is remasking these interrupts (probably a
|
||||
* variant of the same code we inherited earlier to mask it
|
||||
* while the ROM handles the startup IDC?). Unmask
|
||||
* unconditionally while we get this figured out, it's cheap
|
||||
* and safe.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_SOF)) {
|
||||
CAVS_INTCTRL[cpu_num].l2.clear = CAVS_L2_IDC;
|
||||
for (int c = 0; c < CONFIG_MP_NUM_CPUS; c++) {
|
||||
IDC[c].busy_int |= IDC_ALL_CORES;
|
||||
}
|
||||
}
|
||||
|
||||
/* Send power-up message to the other core. Start address
|
||||
* gets passed via the IETC scratch register (only 30 bits
|
||||
* available, so it's sent shifted). The write to ITC
|
||||
|
@ -344,18 +346,6 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz,
|
|||
|
||||
IDC[curr_cpu].core[cpu_num].ietc = ietc;
|
||||
IDC[curr_cpu].core[cpu_num].itc = IDC_MSG_POWER_UP;
|
||||
|
||||
#ifndef CONFIG_SOC_SERIES_INTEL_CAVS_V25
|
||||
/* Early DSPs have a ROM that actually receives the startup
|
||||
* IDC as an interrupt, and we don't want that to be confused
|
||||
* by IPIs sent by the OS elsewhere. Mask the IDC interrupt
|
||||
* on the new core so Zephyr IPIs from existing cores won't
|
||||
* cause it to jump to ISR until the core is fully
|
||||
* initialized. Wait for the startup IDC to arrive though.
|
||||
*/
|
||||
IDC[cpu_num].busy_int &= ~IDC_ALL_CORES;
|
||||
k_busy_wait(100);
|
||||
#endif
|
||||
}
|
||||
|
||||
void arch_sched_ipi(void)
|
||||
|
@ -448,6 +438,8 @@ int soc_relaunch_cpu(int id)
|
|||
goto out;
|
||||
}
|
||||
|
||||
__ASSERT_NO_MSG(!cpus_active[id]);
|
||||
|
||||
CAVS_INTCTRL[id].l2.clear = CAVS_L2_IDC;
|
||||
z_reinit_idle_thread(id);
|
||||
z_smp_start_cpu(id);
|
||||
|
@ -482,11 +474,12 @@ int soc_halt_cpu(int id)
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* Stop sending IPIs to this core */
|
||||
cpus_active[id] = false;
|
||||
|
||||
/* Turn off the "prevent power/clock gating" bits, enabling
|
||||
* low power idle, and mask off IDC interrupts so it will not
|
||||
* be woken up by scheduler IPIs
|
||||
* low power idle
|
||||
*/
|
||||
CAVS_INTCTRL[id].l2.set = CAVS_L2_IDC;
|
||||
CAVS_SHIM.pwrctl &= ~CAVS_PWRCTL_TCPDSPPG(id);
|
||||
CAVS_SHIM.clkctl &= ~CAVS_CLKCTL_TCPLCG(id);
|
||||
|
||||
|
|
Loading…
Reference in a new issue