mirror of https://github.com/thesofproject/sof.git
notifier: support for multicore notifications
Adds support for multicore notifications: - IDC that needs to be sent to slave cores. - Flag which tells notifier, which cores should be notified. Signed-off-by: Tomasz Lauda <tomasz.lauda@linux.intel.com>
This commit is contained in:
parent
cc3fb1e4b3
commit
d16addfe99
|
@ -45,6 +45,7 @@
|
|||
#include <sof/idc.h>
|
||||
#include <sof/ipc.h>
|
||||
#include <sof/lock.h>
|
||||
#include <sof/notifier.h>
|
||||
|
||||
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);
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <sof/alloc.h>
|
||||
#include <sof/lock.h>
|
||||
#include <sof/notifier.h>
|
||||
#include <sof/cpu.h>
|
||||
#include <platform/clk.h>
|
||||
#include <platform/clk-map.h>
|
||||
#include <platform/platcfg.h>
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -32,6 +32,11 @@
|
|||
#include <sof/sof.h>
|
||||
#include <sof/list.h>
|
||||
#include <sof/alloc.h>
|
||||
#include <sof/cpu.h>
|
||||
#include <sof/idc.h>
|
||||
#include <platform/idc.h>
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (list_is_empty(¬ify->list))
|
||||
goto out;
|
||||
_notify_data = *notify_data;
|
||||
dcache_writeback_region(_notify_data.data, _notify_data.data_size);
|
||||
dcache_writeback_region(&_notify_data, sizeof(_notify_data));
|
||||
|
||||
/* 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 == 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue