-
Notifications
You must be signed in to change notification settings - Fork 349
lps: restore secondary cores on wake up #4839
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
LPS functionality is limited to the primary core Signed-off-by: Adrian Bonislawski <adrian.bonislawski@intel.com> Signed-off-by: Bartosz Kokoszko <bartoszx.kokoszko@linux.intel.com>
c201cb4 to
55ade89
Compare
src/init/init.c
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be better to have a global context flag to indicate boot type (as we may want to encode more information in it too) .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea but I think we should still somehow validate all critical values in memory to make sure it is still valid to restore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so prior to core (not memory) power off, we really need to unregister our core from all these services, so that it's a clean shutdown and an automatic re-register upn reboot. This may just mean unregistering some lists and invalidating/wb the data,
10279a9 to
d77ec02
Compare
yes, we need to do more tearing down before shutting down a secondary core, I drafted a PR to showcase what I meant in the call here: |
The PR says "do not review", best to rename this so it can be reviewed. |
d77ec02 to
d2369ca
Compare
|
@lgirdwood @keyonjie @abonislawski @lyakh To sum up:
|
lgirdwood
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @bkokoszx, I think this is in the right direction, but still some opens on the clean shutdown flows.
src/init/init.c
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so prior to core (not memory) power off, we really need to unregister our core from all these services, so that it's a clean shutdown and an automatic re-register upn reboot. This may just mean unregistering some lists and invalidating/wb the data,
| err = idc_restore(); | ||
| if (err < 0) | ||
| return err; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also be able to call task_restore() and notifier_restore() here too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure about that - please look at: #4839 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, so we need to explain why this d0i3 bring up is different in the comments, i.e. each subsystem state so its obvious. Btw, what is the pipeline state on the D0i3 core ? is its stopped and resident in memory OR has it been unloaded with dynamic pipeline ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added some more comments inside secondary_core_restore() function.
The pipeline state is the same as it was before going into D0ix state (memory has not been powered off). So if before going to D0ix we send trigger_stop, it will have STOPPED state.
src/drivers/intel/cavs/idc.c
Outdated
| /* clear BUSY bits */ | ||
| for (i = 0; i < CONFIG_CORE_COUNT; i++) { | ||
| idctfc = idc_read(IPC_IDCTFC(i), core); | ||
| if (idctfc & IPC_IDCTFC_BUSY) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we need to mask all IRQs on this core ? Or do we assume that only IDC IRQs are unmasked ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure whether I understand this comment correctly. I have changed the flow in idc_free function into:
/* clear BUSY bits */
for (i = 0; i < CONFIG_CORE_COUNT; i++) {
idctfc = idc_read(IPC_IDCTFC(i), core);
if (idctfc & IPC_IDCTFC_BUSY)
idc_write(IPC_IDCTFC(i), core, idctfc);
}
if (flags & IDC_FREE_IRQ_ONLY)
return;
schedule_task_free(&idc->idc_task);
}
src/schedule/ll_schedule.c
Outdated
|
|
||
| notifier_unregister(sch, NULL, | ||
| NOTIFIER_CLK_CHANGE_ID(sch->domain->clk)); | ||
| notifier_unregister(sch, NULL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may need to invalidate lists on unregister, please look at the fix @keyonjie did for free() with caches.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lgirdwood
I think we should not unregister notifier in our scenario.
In our scenario (D0->D0ix, when we have two pipelines: one on primary core and another on secondary core), for DAI component, we register dai_dma_cb (notifier_register(dev, dd->chan, NOTIFIER_ID_DMA_COPY, dai_dma_cb, 0);) on prepare request (in dai_prepare). If we unregister notifier and free its lists before going to D0ix, we will not have dai_dma_cb registered after D0ix->D0 (we do not send prepare after D0ix, just only trigger resume). As a result it will probably cause xrun error, because we will not update dai buffers pointers.
BTW
Regarding @keyonjie 's changes - please look at:
#4718 (comment)
3c09599 to
4abda00
Compare
| trace_point(TRACE_BOOT_PLATFORM); | ||
|
|
||
| while (1) | ||
| wait_for_interrupt(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I understand: shouldn't we end up doing
schedule_task(*task_main_get(), 0, UINT64_MAX);
just like now in secondary_core_init(), then shouldn't this function be a SOF_NORETURN? As well as our main() in fact
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In our flow D0ix->D0, task_main is already added to the scheduler list, we do not have to do it one more time (in our case memory has not been powered off), so we only want to end on wait_for_interrupt() - I can add comment to the code.
| schedule_free(SOF_SCHEDULER_FREE_IRQ_ONLY); | ||
|
|
||
| /* data writeback/invalidate */ | ||
| dcache_writeback_invalidate_all(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add a comment, that after this point we aren't "polluting" any more cache lines?..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not understand what do you mean by "polluting" here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
making clean cache lines dirty (is there an official term for this?). I.e. writing to cached memory, without forcing cache write-back.
09ad076 to
808b242
Compare
lgirdwood
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like we are almost ready, to a few opens. It's a complex area so always well worth more comment and trace where we need it.
| err = idc_restore(); | ||
| if (err < 0) | ||
| return err; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, so we need to explain why this d0i3 bring up is different in the comments, i.e. each subsystem state so its obvious. Btw, what is the pipeline state on the D0i3 core ? is its stopped and resident in memory OR has it been unloaded with dynamic pipeline ?
4713ee8 to
f88674e
Compare
|
@bkokoszx the DMIC CI failures look unrelated for this PM related PR ? |
This will add missing secondary cores restore on wake up, simple pm_runtime_get(PM_RUNTIME_DSP, PLATFORM_PRIMARY_CORE_ID) in lps is not enough in multicore scenario Signed-off-by: Adrian Bonislawski <adrian.bonislawski@intel.com>
Restores idc interrupt if all is ready Signed-off-by: Adrian Bonislawski <adrian.bonislawski@intel.com>
EDF scheduler restores interrupt Signed-off-by: Adrian Bonislawski <adrian.bonislawski@intel.com>
In some multicore scenarios dsp can try to restore secondary core state if all memory is still powered up and there was no external request for a core shutdown before For example multicore case with d0ix sleep where secondary core will be put to sleep along with primary core and after wakeup there will be a possibility to restore it Signed-off-by: Adrian Bonislawski <adrian.bonislawski@intel.com> Signed-off-by: Bartosz Kokoszko <bartoszx.kokoszko@linux.intel.com>
This commit: - adds flags argument to idc_free() function; - adds IDC_FREE_IRQ_ONLY flags, which allows idc_free() to disable only interrupts. Signed-off-by: Bartosz Kokoszko <bartoszx.kokoszko@linux.intel.com>
This commit: - adds flags argument into scheduler_free function pointer in scheduler_ops struct; - adds SOF_SCHEDULER_FREE_IRQ_ONLY flag, which indicates to disable only interrupts in scheduler_free() functions. Signed-off-by: Bartosz Kokoszko <bartoszx.kokoszko@linux.intel.com>
3cb6493 to
f78a572
Compare
Primary core during going to D0i3 state disables all another cores in platform_pg_int_handler() function. Before it secondary cores should be prepared (disable interrupts, perform writeback) in order to make proper restore flow after D0i3->D0 transition. This commit adds cpu_secondary_cores_prepare_d0ix() function in ipc_pm_gate() handler, which sends idc to secondary cores with information that they should perform preparation for power down in the next platform_wait_for_interrupt() invocation. In platform_wait_for_interrupt() there is cpu_power_down_core() invocation with CPU_POWER_DOWN_MEMORY_ON (performs writeback/invalidate, disables interrupts), when proper flag is set. Signed-off-by: Bartosz Kokoszko <bartoszx.kokoszko@linux.intel.com>
f78a572 to
5314d67
Compare
|
@lgirdwood static int ipc_pm_gate(uint32_t header)
{
struct sof_ipc_pm_gate pm_gate;
IPC_COPY_CMD(pm_gate, ipc_get()->comp_data);
tr_info(&ipc_tr, "ipc: pm gate flags 0x%x", pm_gate.flags);
/* pause dma trace firstly if needed */
if (pm_gate.flags & SOF_PM_NO_TRACE)
trace_off();
if (pm_gate.flags & SOF_PM_PPG) {
pm_runtime_disable(PM_RUNTIME_DSP, PLATFORM_PRIMARY_CORE_ID);
#if (CONFIG_CAVS_LPS)
cpu_restore_secondary_cores();
#endif
} else {
/* before we enable pm runtime and perform D0->D0ix flow
* (primary core powers off secondary cores in
* platform_pg_int_handler) we have to prepare all secondary
* cores data for powering off (disable interrupt, perform
* cache writeback).
*/
#if (CONFIG_CAVS_LPS)
cpu_secondary_cores_prepare_d0ix();
#endif
pm_runtime_enable(PM_RUNTIME_DSP, PLATFORM_PRIMARY_CORE_ID);
}
/* resume dma trace if needed */
if (!(pm_gate.flags & SOF_PM_NO_TRACE))
trace_on();
return 0;
}I invoke |
|
@lgirdwood Do you require some other changes? |
Primary core disables all secondary cores in platform_pg_int_handler() function when going to D0ix state. During coming out from D0ix state (D0ix -> D0), we are not able to restore secondary cores properly. This PR add commits that allow us to enable LPS flow to be used in multicore scenario properly. This PR: