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:
Tomasz Lauda 2018-10-11 15:25:16 +02:00
parent cc3fb1e4b3
commit d16addfe99
7 changed files with 87 additions and 20 deletions

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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, &notify_data);
notify_data.message = CLOCK_NOTIFY_PRE;
notifier_event(&notify_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, &notify_data);
notify_data.message = CLOCK_NOTIFY_POST;
notifier_event(&notify_data);
spin_unlock_irq(&clk_pdata->clk[clock].lock, flags);

View File

@ -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(&notify->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(&notify->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, &notify->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(&notify->lock);
if (list_is_empty(&notify->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, &notify->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(&notify_msg, IDC_BLOCKING);
}
}
}
out:
spin_unlock(&notify->lock);
}

View File

@ -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;

View File

@ -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;