diff --git a/src/arch/xtensa/smp/include/arch/idc.h b/src/arch/xtensa/smp/include/arch/idc.h index dc4d2b695211..4510f53e5176 100644 --- a/src/arch/xtensa/smp/include/arch/idc.h +++ b/src/arch/xtensa/smp/include/arch/idc.h @@ -45,6 +45,7 @@ #include #include #include +#include extern struct ipc *_ipc; extern void cpu_power_down_core(void); @@ -256,6 +257,9 @@ static inline void idc_cmd(struct idc_msg *msg) case iTS(IDC_MSG_COMP_CMD): idc_component_command(msg->extension); break; + case iTS(IDC_MSG_NOTIFY): + notifier_notify(); + break; default: trace_idc_error("eTc"); trace_error_value(msg->header); diff --git a/src/include/sof/idc.h b/src/include/sof/idc.h index dd3c032883e5..b407409433d0 100644 --- a/src/include/sof/idc.h +++ b/src/include/sof/idc.h @@ -94,6 +94,10 @@ #define IDC_MSG_COMP_CMD IDC_TYPE(0x4) #define IDC_MSG_COMP_CMD_EXT(x) IDC_EXTENSION(x) +/** \brief IDC notify message. */ +#define IDC_MSG_NOTIFY IDC_TYPE(0x5) +#define IDC_MSG_NOTIFY_EXT IDC_EXTENSION(0x0) + /** \brief Decodes IDC message type. */ #define iTS(x) (((x) >> IDC_TYPE_SHIFT) & IDC_TYPE_MASK) diff --git a/src/include/sof/notifier.h b/src/include/sof/notifier.h index e8de8ad71abb..57d8408775fb 100644 --- a/src/include/sof/notifier.h +++ b/src/include/sof/notifier.h @@ -41,11 +41,23 @@ struct sof; #define NOTIFIER_ID_CPU_FREQ 0 #define NOTIFIER_ID_SSP_FREQ 1 +/* notifier target core masks */ +#define NOTIFIER_TARGET_CORE_MASK(x) (1 << x) +#define NOTIFIER_TARGET_CORE_ALL_MASK 0xFFFFFFFF + struct notify { spinlock_t lock; /* notifier lock */ struct list_item list; /* list of notifiers */ }; +struct notify_data { + uint32_t id; + uint32_t message; + uint32_t target_core_mask; + uint32_t data_size; + void *data; +}; + struct notifier { uint32_t id; struct list_item list; @@ -58,7 +70,8 @@ struct notify **arch_notify_get(void); void notifier_register(struct notifier *notifier); void notifier_unregister(struct notifier *notifier); -void notifier_event(int id, int message, void *event_data); +void notifier_notify(void); +void notifier_event(struct notify_data *notify_data); void init_system_notify(struct sof *sof); diff --git a/src/lib/clk.c b/src/lib/clk.c index 34313abb5b70..ea7531cb73b7 100644 --- a/src/lib/clk.c +++ b/src/lib/clk.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -76,16 +77,20 @@ static inline uint32_t clock_get_freq(const struct freq_table *table, uint32_t clock_set_freq(int clock, uint32_t hz) { - struct clock_notify_data notify_data; + struct notify_data notify_data; + struct clock_notify_data clk_notify_data; set_frequency set_freq = NULL; const struct freq_table *freq_table = NULL; uint32_t freq_table_size = 0; - uint32_t notifier_id = 0; uint32_t idx; uint32_t flags; - notify_data.old_freq = clk_pdata->clk[clock].freq; - notify_data.old_ticks_per_msec = clk_pdata->clk[clock].ticks_per_msec; + notify_data.data_size = sizeof(clk_notify_data); + notify_data.data = &clk_notify_data; + + clk_notify_data.old_freq = clk_pdata->clk[clock].freq; + clk_notify_data.old_ticks_per_msec = + clk_pdata->clk[clock].ticks_per_msec; /* atomic context for changing clocks */ spin_lock_irq(&clk_pdata->clk[clock].lock, flags); @@ -95,13 +100,16 @@ uint32_t clock_set_freq(int clock, uint32_t hz) set_freq = &clock_platform_set_cpu_freq; freq_table = cpu_freq; freq_table_size = ARRAY_SIZE(cpu_freq); - notifier_id = NOTIFIER_ID_CPU_FREQ; + notify_data.id = NOTIFIER_ID_CPU_FREQ; + notify_data.target_core_mask = + NOTIFIER_TARGET_CORE_MASK(cpu_get_id()); break; case CLK_SSP: set_freq = &clock_platform_set_ssp_freq; freq_table = ssp_freq; freq_table_size = ARRAY_SIZE(ssp_freq); - notifier_id = NOTIFIER_ID_SSP_FREQ; + notify_data.id = NOTIFIER_ID_SSP_FREQ; + notify_data.target_core_mask = NOTIFIER_TARGET_CORE_ALL_MASK; break; default: break; @@ -109,10 +117,11 @@ uint32_t clock_set_freq(int clock, uint32_t hz) /* get nearest frequency that is >= requested Hz */ idx = clock_get_freq(freq_table, freq_table_size, hz); - notify_data.freq = freq_table[idx].freq; + clk_notify_data.freq = freq_table[idx].freq; /* tell anyone interested we are about to change freq */ - notifier_event(notifier_id, CLOCK_NOTIFY_PRE, ¬ify_data); + notify_data.message = CLOCK_NOTIFY_PRE; + notifier_event(¬ify_data); if (set_freq(freq_table[idx].enc) == 0) { /* update clock frequency */ @@ -122,7 +131,8 @@ uint32_t clock_set_freq(int clock, uint32_t hz) } /* tell anyone interested we have now changed freq */ - notifier_event(notifier_id, CLOCK_NOTIFY_POST, ¬ify_data); + notify_data.message = CLOCK_NOTIFY_POST; + notifier_event(¬ify_data); spin_unlock_irq(&clk_pdata->clk[clock].lock, flags); diff --git a/src/lib/notifier.c b/src/lib/notifier.c index e724f61b5a2e..c87363be658d 100644 --- a/src/lib/notifier.c +++ b/src/lib/notifier.c @@ -32,6 +32,11 @@ #include #include #include +#include +#include +#include + +static struct notify_data _notify_data; void notifier_register(struct notifier *notifier) { @@ -51,26 +56,53 @@ void notifier_unregister(struct notifier *notifier) spin_unlock(¬ify->lock); } -void notifier_event(int id, int message, void *event_data) +void notifier_notify(void) { struct notify *notify = *arch_notify_get(); struct list_item *wlist; struct notifier *n; - spin_lock(¬ify->lock); + if (!list_is_empty(¬ify->list)) { + dcache_invalidate_region(&_notify_data, sizeof(_notify_data)); + dcache_invalidate_region(_notify_data.data, + _notify_data.data_size); + + /* iterate through notifiers and send event to + * interested clients + */ + list_for_item(wlist, ¬ify->list) { + n = container_of(wlist, struct notifier, list); + if (n->id == _notify_data.id) + n->cb(_notify_data.message, n->cb_data, + _notify_data.data); + } + } +} - if (list_is_empty(¬ify->list)) - goto out; +void notifier_event(struct notify_data *notify_data) +{ + struct notify *notify = *arch_notify_get(); + struct idc_msg notify_msg = { IDC_MSG_NOTIFY, IDC_MSG_NOTIFY_EXT }; + int i = 0; + + spin_lock(¬ify->lock); - /* iterate through notifiers and send event to interested clients */ - list_for_item(wlist, ¬ify->list) { + _notify_data = *notify_data; + dcache_writeback_region(_notify_data.data, _notify_data.data_size); + dcache_writeback_region(&_notify_data, sizeof(_notify_data)); - n = container_of(wlist, struct notifier, list); - if (n->id == id) - n->cb(message, n->cb_data, event_data); + /* notify selected targets */ + for (i = 0; i < PLATFORM_CORE_COUNT; i++) { + if (_notify_data.target_core_mask & (1 << i)) { + if (i == cpu_get_id()) { + notifier_notify(); + } else if (cpu_is_core_enabled(i)) { + notify_msg.core = i; + idc_send_msg(¬ify_msg, IDC_BLOCKING); + } + } } -out: spin_unlock(¬ify->lock); } diff --git a/test/cmocka/src/audio/pipeline/pipeline_mocks.c b/test/cmocka/src/audio/pipeline/pipeline_mocks.c index cf6fe8d2a04c..b8450345512c 100644 --- a/test/cmocka/src/audio/pipeline/pipeline_mocks.c +++ b/test/cmocka/src/audio/pipeline/pipeline_mocks.c @@ -99,6 +99,8 @@ int arch_cpu_is_core_enabled(int id) void cpu_power_down_core(void) { } +void notifier_notify(void) { } + struct ipc_comp_dev *ipc_get_comp(struct ipc *ipc, uint32_t id) { (void)ipc; diff --git a/test/cmocka/src/audio/pipeline/pipeline_mocks.h b/test/cmocka/src/audio/pipeline/pipeline_mocks.h index dad8e11cf67c..17021e229ca7 100644 --- a/test/cmocka/src/audio/pipeline/pipeline_mocks.h +++ b/test/cmocka/src/audio/pipeline/pipeline_mocks.h @@ -46,6 +46,8 @@ void cpu_power_down_core(void); struct ipc_comp_dev *ipc_get_comp(struct ipc *ipc, uint32_t id); +void notifier_notify(void); + struct pipeline_new_setup_data { struct sof_ipc_pipe_new ipc_data; struct comp_dev *comp_data;