Skip to content

Commit 5314d67

Browse files
committed
pm_runtime: prepare secondary cores for power down in d0->d0ix flow
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>
1 parent 7d559a3 commit 5314d67

File tree

16 files changed

+191
-14
lines changed

16 files changed

+191
-14
lines changed

src/arch/host/include/arch/lib/cpu.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ static inline int arch_cpu_restore_secondary_cores(void)
3939
return 0;
4040
}
4141

42+
static inline int arch_cpu_secondary_cores_prepare_d0ix(void)
43+
{
44+
return 0;
45+
}
46+
4247
static inline void cpu_write_threadptr(int threadptr)
4348
{
4449
}

src/arch/xtensa/include/arch/lib/cpu.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,17 @@
1111
#define __ARCH_LIB_CPU_H__
1212

1313
#include <xtensa/config/core-isa.h>
14+
#include <stdint.h>
1415

1516
#if CONFIG_MULTICORE
1617

17-
void cpu_power_down_core(void);
18+
/** \brief CPU power down available flags */
19+
#define CPU_POWER_DOWN_MEMORY_ON BIT(0) /**< Power down core with memory
20+
* enabled (required in d0ix
21+
* flow)
22+
*/
23+
24+
void cpu_power_down_core(uint32_t flags);
1825

1926
void cpu_alloc_core_context(int id);
2027

@@ -28,6 +35,8 @@ int arch_cpu_enabled_cores(void);
2835

2936
int arch_cpu_restore_secondary_cores(void);
3037

38+
int arch_cpu_secondary_cores_prepare_d0ix(void);
39+
3140
#else
3241

3342
static inline int arch_cpu_enable_core(int id) { return 0; }
@@ -40,6 +49,8 @@ static inline int arch_cpu_enabled_cores(void) { return 1; }
4049

4150
static inline int arch_cpu_restore_secondary_cores(void) {return 0; }
4251

52+
static inline int arch_cpu_secondary_cores_prepare_d0ix(void) {return 0; }
53+
4354
#endif
4455

4556
static inline int arch_cpu_get_id(void)

src/arch/xtensa/lib/cpu.c

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -160,25 +160,44 @@ void cpu_alloc_core_context(int core)
160160
dcache_writeback_region(sof_get(), sizeof(*sof_get()));
161161
}
162162

163-
void cpu_power_down_core(void)
163+
void cpu_power_down_core(uint32_t flags)
164164
{
165165
arch_interrupt_global_disable();
166166

167-
idc_free(0);
167+
/* Power down with memory on is performed by secondary cores during
168+
* d0 -> d0ix before they are disabled by primary core.
169+
*/
170+
if (flags & CPU_POWER_DOWN_MEMORY_ON) {
171+
/* disable idc interrupts */
172+
idc_free(IDC_FREE_IRQ_ONLY);
173+
174+
/* disable scheduler interrupts */
175+
schedule_free(SOF_SCHEDULER_FREE_IRQ_ONLY);
176+
177+
/* data writeback/invalidate */
178+
dcache_writeback_invalidate_all();
168179

169-
schedule_free(0);
180+
/* after writeback/invalidate secondary core is prepared for
181+
* powered off - prepare_d0ix_core_mask flag can be disabled
182+
*/
183+
platform_pm_runtime_prepare_d0ix_dis(cpu_get_id());
184+
} else {
185+
idc_free(0);
170186

171-
free_system_notify();
187+
schedule_free(0);
172188

173-
/* free entire sys heap, an instance dedicated for this core */
174-
free_heap(SOF_MEM_ZONE_SYS);
189+
free_system_notify();
175190

176-
dcache_writeback_invalidate_all();
191+
/* free entire sys heap, an instance dedicated for this core */
192+
free_heap(SOF_MEM_ZONE_SYS);
177193

178-
/* Turn off stack memory for core */
179-
pm_runtime_put(CORE_MEMORY_POW, cpu_get_id());
194+
dcache_writeback_invalidate_all();
180195

181-
pm_runtime_put(PM_RUNTIME_DSP, PWRD_BY_TPLG | cpu_get_id());
196+
/* Turn off stack memory for core */
197+
pm_runtime_put(CORE_MEMORY_POW, cpu_get_id());
198+
199+
pm_runtime_put(PM_RUNTIME_DSP, PWRD_BY_TPLG | cpu_get_id());
200+
}
182201

183202
trace_point(0);
184203

@@ -214,3 +233,25 @@ int arch_cpu_restore_secondary_cores(void)
214233

215234
return 0;
216235
}
236+
237+
int arch_cpu_secondary_cores_prepare_d0ix(void)
238+
{
239+
struct idc_msg prepare_msg = { IDC_MSG_PREPARE_D0ix,
240+
IDC_MSG_PREPARE_D0ix_EXT };
241+
int ret, id;
242+
243+
for (id = 0; id < CONFIG_CORE_COUNT; id++) {
244+
if (arch_cpu_is_core_enabled(id) && id != PLATFORM_PRIMARY_CORE_ID) {
245+
prepare_msg.core = id;
246+
247+
/* send IDC prepare message to all enabled secondary
248+
* cores.
249+
*/
250+
ret = idc_send_msg(&prepare_msg, IDC_BLOCKING);
251+
if (ret < 0)
252+
return ret;
253+
}
254+
}
255+
256+
return 0;
257+
}

src/idc/idc.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <sof/lib/cpu.h>
1818
#include <sof/lib/memory.h>
1919
#include <sof/lib/notifier.h>
20+
#include <sof/lib/pm_runtime.h>
2021
#include <sof/lib/uuid.h>
2122
#include <sof/platform.h>
2223
#include <arch/lib/wait.h>
@@ -268,6 +269,16 @@ static int idc_reset(uint32_t comp_id)
268269
return ret;
269270
}
270271

272+
static void idc_prepare_d0ix(void)
273+
{
274+
/* set prepare_d0ix flag, which indicates that in the next
275+
* platform_wait_for_interrupt invocation(), core should get ready for
276+
* d0ix power down - it is required by D0->D0ix flow, when primary
277+
* core disables all secondary cores.
278+
*/
279+
platform_pm_runtime_prepare_d0ix_en(cpu_get_id());
280+
}
281+
271282
/**
272283
* \brief Executes IDC message based on type.
273284
* \param[in,out] msg Pointer to IDC message.
@@ -279,7 +290,7 @@ void idc_cmd(struct idc_msg *msg)
279290

280291
switch (type) {
281292
case iTS(IDC_MSG_POWER_DOWN):
282-
cpu_power_down_core();
293+
cpu_power_down_core(0);
283294
break;
284295
case iTS(IDC_MSG_NOTIFY):
285296
notifier_notify_remote();
@@ -299,6 +310,9 @@ void idc_cmd(struct idc_msg *msg)
299310
case iTS(IDC_MSG_RESET):
300311
ret = idc_reset(msg->extension);
301312
break;
313+
case iTS(IDC_MSG_PREPARE_D0ix):
314+
idc_prepare_d0ix();
315+
break;
302316
default:
303317
tr_err(&idc_tr, "idc_cmd(): invalid msg->header = %u",
304318
msg->header);

src/include/sof/drivers/idc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@
8888
#define IDC_MSG_RESET IDC_TYPE(0x8)
8989
#define IDC_MSG_RESET_EXT(x) IDC_EXTENSION(x)
9090

91+
/** \brief IDC prepare D0ix message. */
92+
#define IDC_MSG_PREPARE_D0ix IDC_TYPE(0x9)
93+
#define IDC_MSG_PREPARE_D0ix_EXT IDC_EXTENSION(0x0)
94+
9195
/** \brief Decodes IDC message type. */
9296
#define iTS(x) (((x) >> IDC_TYPE_SHIFT) & IDC_TYPE_MASK)
9397

src/include/sof/lib/cpu.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ static inline int cpu_restore_secondary_cores(void)
6161
return arch_cpu_restore_secondary_cores();
6262
}
6363

64+
static inline int cpu_secondary_cores_prepare_d0ix(void)
65+
{
66+
return arch_cpu_secondary_cores_prepare_d0ix();
67+
}
68+
6469
#endif
6570

6671
#endif /* __SOF_LIB_CPU_H__ */

src/ipc/ipc3/handler.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,15 @@ static int ipc_pm_gate(uint32_t header)
707707
cpu_restore_secondary_cores();
708708
#endif
709709
} else {
710+
/* before we enable pm runtime and perform D0->D0ix flow
711+
* (primary core powers off secondary cores in
712+
* platform_pg_int_handler) we have to prepare all secondary
713+
* cores data for powering off (disable interrupt, perform
714+
* cache writeback).
715+
*/
716+
#if (CONFIG_CAVS_LPS)
717+
cpu_secondary_cores_prepare_d0ix();
718+
#endif
710719
pm_runtime_enable(PM_RUNTIME_DSP, PLATFORM_PRIMARY_CORE_ID);
711720
}
712721

src/platform/apollolake/include/platform/lib/pm_runtime.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ void platform_pm_runtime_enable(uint32_t context, uint32_t index);
4848

4949
void platform_pm_runtime_disable(uint32_t context, uint32_t index);
5050

51+
void platform_pm_runtime_prepare_d0ix_en(uint32_t index);
52+
53+
void platform_pm_runtime_prepare_d0ix_dis(uint32_t index);
54+
55+
int platform_pm_runtime_prepare_d0ix_is_req(uint32_t index);
56+
5157
bool platform_pm_runtime_is_active(uint32_t context, uint32_t index);
5258

5359
/**

src/platform/cannonlake/include/platform/lib/pm_runtime.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ void platform_pm_runtime_enable(uint32_t context, uint32_t index);
4747

4848
void platform_pm_runtime_disable(uint32_t context, uint32_t index);
4949

50+
void platform_pm_runtime_prepare_d0ix_en(uint32_t index);
51+
52+
void platform_pm_runtime_prepare_d0ix_dis(uint32_t index);
53+
54+
int platform_pm_runtime_prepare_d0ix_is_req(uint32_t index);
55+
5056
bool platform_pm_runtime_is_active(uint32_t context, uint32_t index);
5157

5258
/**

src/platform/icelake/include/platform/lib/pm_runtime.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ void platform_pm_runtime_enable(uint32_t context, uint32_t index);
4747

4848
void platform_pm_runtime_disable(uint32_t context, uint32_t index);
4949

50+
void platform_pm_runtime_prepare_d0ix_en(uint32_t index);
51+
52+
void platform_pm_runtime_prepare_d0ix_dis(uint32_t index);
53+
54+
int platform_pm_runtime_prepare_d0ix_is_req(uint32_t index);
55+
5056
bool platform_pm_runtime_is_active(uint32_t context, uint32_t index);
5157

5258
/**

0 commit comments

Comments
 (0)