Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions src/include/sof/schedule/schedule.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,12 @@ struct schedulers {
*/
struct schedulers **arch_schedulers_get(void);

struct schedulers **arch_user_schedulers_get(void);

#if CONFIG_SOF_USERSPACE_LL
struct schedulers **arch_user_schedulers_get_for_core(int core);
#endif

/**
* Retrieves scheduler's data.
* @param type SOF_SCHEDULE_ type.
Expand Down Expand Up @@ -322,17 +328,13 @@ static inline void schedule_free(uint32_t flags)
/** See scheduler_ops::scheduler_init_context */
static inline struct k_thread *scheduler_init_context(struct task *task)
{
struct schedulers *schedulers = *arch_schedulers_get();
struct schedule_data *sch;
struct list_item *slist;

assert(schedulers);
assert(task && task->sch);
sch = task->sch;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...at some point would be good to have all these converted to

const struct scheduler_ops *ops = task->sch->ops;

if (ops->x)
    return ops->x(...);

just to reduce the number of arrows that we carry around


list_for_item(slist, &schedulers->list) {
sch = container_of(slist, struct schedule_data, list);
if (task->type == sch->type && sch->ops->scheduler_init_context)
return sch->ops->scheduler_init_context(sch->data, task);
}
if (sch->ops->scheduler_init_context)
return sch->ops->scheduler_init_context(sch->data, task);

return NULL;
}
Expand Down
45 changes: 41 additions & 4 deletions src/schedule/schedule.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,25 @@ SOF_DEFINE_REG_UUID(schedule);

DECLARE_TR_CTX(sch_tr, SOF_UUID(schedule_uuid), LOG_LEVEL_INFO);

#ifdef CONFIG_SOF_USERSPACE_LL
static inline bool scheduler_is_user(int type)
{
/*
* currently only LL managed in user-space, but longterm
* goal is to move all audio application level scheduling
* to user-space and only keep Zephyr scheduler logic in
* kernel
*/
return type == SOF_SCHEDULE_LL_TIMER;
}
#endif

int schedule_task_init(struct task *task,
const struct sof_uuid_entry *uid, uint16_t type,
uint16_t priority, enum task_state (*run)(void *data),
void *data, uint16_t core, uint32_t flags)
{
struct schedulers *schedulers = *arch_schedulers_get();
struct schedulers *schedulers;
struct schedule_data *sch = NULL;
struct list_item *slist;

Expand All @@ -36,6 +49,15 @@ int schedule_task_init(struct task *task,
return -EINVAL;
}

#ifdef CONFIG_SOF_USERSPACE_LL
if (scheduler_is_user(type))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use if (IS_ENABLED(CONFIG_SOF_USERSPACE_LL) && scheduler_is_user(type)) here?

schedulers = *arch_user_schedulers_get_for_core(core);
else
schedulers = *arch_schedulers_get();
#else
schedulers = *arch_schedulers_get();
#endif

if (!schedulers)
return -ENODEV;

Expand Down Expand Up @@ -68,15 +90,23 @@ int schedule_task_init(struct task *task,
static void scheduler_register(struct schedule_data *scheduler)
{
struct schedulers **sch = arch_schedulers_get();
struct k_heap *heap = NULL;

#ifdef CONFIG_SOF_USERSPACE_LL
if (scheduler_is_user(scheduler->type)) {
sch = arch_user_schedulers_get();
heap = sof_sys_user_heap_get();
}
#endif

if (!*sch) {
/* init schedulers list */
*sch = rzalloc(SOF_MEM_FLAG_KERNEL,
sizeof(**sch));
*sch = sof_heap_alloc(heap, 0, sizeof(**sch), 0);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this would mean, that userspace code now effectively has access to all schedulers, also kernel ones

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack. This does leave a gap with EDF currently, so this is not safe yet for production use. So in short, generic scheduler logic (Zephyr scheduling) in kernel, audio task scheduling in user-space (if SOF built for LL userspace).

if (!*sch) {
tr_err(&sch_tr, "allocation failed");
return;
}
memset(*sch, 0, sizeof(**sch));
list_init(&(*sch)->list);
}

Expand All @@ -86,16 +116,23 @@ static void scheduler_register(struct schedule_data *scheduler)
void scheduler_init(int type, const struct scheduler_ops *ops, void *data)
{
struct schedule_data *sch;
struct k_heap *heap = NULL;

#ifdef CONFIG_SOF_USERSPACE_LL
if (scheduler_is_user(type))
heap = sof_sys_user_heap_get();
#endif

if (!ops || !ops->schedule_task || !ops->schedule_task_cancel ||
!ops->schedule_task_free)
return;

sch = rzalloc(SOF_MEM_FLAG_KERNEL, sizeof(*sch));
sch = sof_heap_alloc(heap, SOF_MEM_FLAG_KERNEL, sizeof(*sch), 0);
if (!sch) {
tr_err(&sch_tr, "allocation failed");
sof_panic(SOF_IPC_PANIC_IPC);
}
memset(sch, 0, sizeof(*sch));
list_init(&sch->list);
sch->type = type;
sch->ops = ops;
Expand Down
54 changes: 53 additions & 1 deletion zephyr/schedule.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,66 @@
#include <sof/lib/cpu.h>
#include <ipc/topology.h>

static APP_SYSUSER_BSS struct schedulers *_schedulers[CONFIG_CORE_COUNT];
/* Kernel-only scheduler list — depending on how SOF is built,
* either holds all or subset of scheduler types.
* Not accessible from user-space threads.
*/
static struct schedulers *_schedulers[CONFIG_CORE_COUNT];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick, we could put a k/u in the names if we have some static objects that are always kernel or always user, just to make sure we can visualize their usage better.


#if CONFIG_SOF_USERSPACE_LL
/* User-accessible scheduler list — holds the subset of scheduler
* types that are managed in user-space
*/
static APP_SYSUSER_BSS struct schedulers *_schedulers_user[CONFIG_CORE_COUNT];
#endif

/**
* Retrieves registered schedulers.
* @return List of registered schedulers.
*/
struct schedulers **arch_schedulers_get(void)
{
#if CONFIG_SOF_USERSPACE_LL
/* user-space callers must use arch_user_schedulers_get() */
assert(!k_is_user_context());
#endif
return _schedulers + cpu_get_id();
}
EXPORT_SYMBOL(arch_schedulers_get);

/**
* Retrieves registered user schedulers for the current core.
*
* Relies on cpu_get_id(), so it may invoke privileged functions and
* must not be called from a user-space context. User-space callers
* should use arch_user_schedulers_get_for_core() instead.
*
* @return List of registered schedulers.
*/
struct schedulers **arch_user_schedulers_get(void)
{
#ifdef CONFIG_SOF_USERSPACE_LL
return _schedulers_user + cpu_get_id();
#else
return NULL;
#endif
}
EXPORT_SYMBOL(arch_user_schedulers_get);

/**
* Retrieves registered user schedulers for the given core.
*
* Unlike arch_user_schedulers_get(), this takes the core explicitly and
* is therefore safe to call from a user-space context.
*
* @return List of registered schedulers.
*/
struct schedulers **arch_user_schedulers_get_for_core(int core)
{
#ifdef CONFIG_SOF_USERSPACE_LL
return _schedulers_user + core;
#else
return NULL;
#endif
}
EXPORT_SYMBOL(arch_user_schedulers_get_for_core);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can these be made static inline which would also avoid having to export them?

Loading