Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fast mode task config + vendor config set #8005

Merged
merged 2 commits into from
Sep 20, 2023
Merged
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
206 changes: 204 additions & 2 deletions src/audio/kpb.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <rtos/string.h>
tobonex marked this conversation as resolved.
Show resolved Hide resolved
#include <sof/ut.h>
#include <ipc/topology.h>
#include <ipc4/module.h>
#include <ipc4/kpb.h>
#include <user/kpb.h>
#include <user/trace.h>
Expand Down Expand Up @@ -106,6 +107,8 @@ struct comp_data {
uint32_t num_of_in_channels;
uint32_t offsets[KPB_MAX_MICSEL_CHANNELS];
struct kpb_micselector_config mic_sel;
struct kpb_fmt_dev_list fmt_device_list;
struct fast_mode_task fmt;

#if CONFIG_AMS
uint32_t kpd_uuid_id;
Expand Down Expand Up @@ -141,6 +144,23 @@ static inline bool validate_host_params(struct comp_dev *dev,
size_t hb_size_req);
static inline void kpb_change_state(struct comp_data *kpb,
enum kpb_state state);
#ifdef CONFIG_IPC_MAJOR_4
/* KpbFastModeTaskModulesList Namespace */
static inline int alloc_fmt_module_list_item(struct kpb_fmt_dev_list *fmt_device_list,
struct comp_dev *mi_ptr, struct comp_dev ***item);
static int clear_fmt_modules_list(struct kpb_fmt_dev_list *fmt_device_list,
uint32_t outpin_idx);
static int prepare_fmt_modules_list(struct comp_dev *kpb_dev, uint32_t outpin_idx,
const struct kpb_task_params *modules_to_prepare);
/* FMT Namespace */
static int register_modules_list(struct fast_mode_task *fmt,
struct device_list *new_list, size_t list_idx);
static int unregister_modules_list(struct fast_mode_task *fmt,
struct device_list *list_to_remove, size_t list_idx);
/* Devicelist */
static int devicelist_push(struct device_list *devlist, struct comp_dev **dev);
static void devicelist_reset(struct device_list *devlist, bool remove_items);
#endif

static uint64_t kpb_task_deadline(void *data)
{
Expand Down Expand Up @@ -376,7 +396,8 @@ static int kpb_unbind(struct comp_dev *dev, void *data)
else
kpb->host_sink = NULL;

return 0;
/* Clear fmt config */
return clear_fmt_modules_list(&kpb->fmt_device_list, bu->extension.r.src_queue);
}

#else /* CONFIG_IPC_MAJOR_4 */
Expand Down Expand Up @@ -2378,15 +2399,196 @@ static int kpb_set_micselect(struct comp_dev *dev, const void *data,
return 0;
}

#ifdef CONFIG_IPC_MAJOR_4

static int devicelist_push(struct device_list *devlist, struct comp_dev **dev)
{
if (devlist->count != DEVICE_LIST_SIZE) {
devlist->devs[devlist->count] = dev;
devlist->count++;
return 0;
}
return -EINVAL;
}

static void devicelist_reset(struct device_list *devlist, bool remove_items)
{
/* clear items */
if (remove_items) {
for (int i = 0; i < DEVICE_LIST_SIZE; i++)
*devlist->devs[i] = NULL;
}
/* zero the pointers */
for (int i = 0; i < DEVICE_LIST_SIZE; i++)
devlist->devs[i] = NULL;

devlist->count = 0;
}

static inline int alloc_fmt_module_list_item(struct kpb_fmt_dev_list *fmt_device_list,
struct comp_dev *mi_ptr, struct comp_dev ***item)
{
/* -1 means we did not find the slot yet */
int first_empty_slot_idx = -1;

for (size_t module_slot_idx = 0; module_slot_idx < FAST_MODE_TASK_MAX_MODULES_COUNT;
++module_slot_idx){
/* check if module already added */
if (fmt_device_list->modules_list_item[module_slot_idx] == mi_ptr)
return -EINVAL;
/* finding first available empty slot */
if (first_empty_slot_idx < 0 &&
!fmt_device_list->modules_list_item[module_slot_idx])
first_empty_slot_idx = module_slot_idx;
}
/* add item to first available empty slot */
if (first_empty_slot_idx >= 0) {
fmt_device_list->modules_list_item[first_empty_slot_idx] = mi_ptr;
*item = &fmt_device_list->modules_list_item[first_empty_slot_idx];
return 0;
}
return -ENOMEM;
}

static int prepare_fmt_modules_list(struct comp_dev *kpb_dev,
uint32_t outpin_idx,
const struct kpb_task_params *modules_to_prepare)
{
int ret;
struct comp_dev *dev;
struct kpb_fmt_dev_list *fmt_device_list =
&((struct comp_data *)comp_get_drvdata(kpb_dev))->fmt_device_list;

fmt_device_list->kpb_list_item[outpin_idx] = kpb_dev;
ret = devicelist_push(&fmt_device_list->device_list[outpin_idx],
&fmt_device_list->kpb_list_item[outpin_idx]);
if (ret < 0)
return ret;

for (size_t mod_idx = 0; mod_idx < modules_to_prepare->number_of_modules; ++mod_idx) {
uint32_t comp_id = IPC4_COMP_ID(modules_to_prepare->dev_ids[mod_idx].module_id,
modules_to_prepare->dev_ids[mod_idx].instance_id);

dev = ipc4_get_comp_dev(comp_id);
if (!dev)
return -EINVAL;
tobonex marked this conversation as resolved.
Show resolved Hide resolved

struct comp_dev **new_list_item_ptr;

ret = alloc_fmt_module_list_item(fmt_device_list, dev, &new_list_item_ptr);
if (ret < 0)
return ret;
*new_list_item_ptr = dev;
ret = devicelist_push(&fmt_device_list->device_list[outpin_idx],
new_list_item_ptr);
if (ret < 0)
return ret;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

after this fmt_device_list->device_list[outpin_idx] will contain an array with the fmt_device_list->kpb_list_item[outpin_idx] as its first element and then all modules (whatever they are) from the modules_to_prepare->dev_ids array. It's still rather confusing at least to me. Maybe explain briefly somewhere what those modules are and how they're used for KPB? Or have I overlooked it somewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't read that much into the original FMT functionality code yet, but I do have some info about it though. In reference FW, executing the FMT also triggered processing of some LL modules whenever there are available DSP cycles. I'm guessing those modules are the ones provided in the IPC here.

I agree that the way the lists were (and are) handled was kind of confusing, but I'm not sure yet what can I refactor here. It's either some important logic, or just some C++'ism.

The idea for now was to implement it up to this point so that the tests related to the FMT config IPC pass. After FMT functionality actually gets implemented it will be easier to see if we can simplify the config.

return 0;
}

static int clear_fmt_modules_list(struct kpb_fmt_dev_list *fmt_device_list,
uint32_t outpin_idx)
{
if (outpin_idx >= KPB_MAX_SINK_CNT)
return -EINVAL;

devicelist_reset(&fmt_device_list->device_list[outpin_idx], true);
return 0;
}

static int unregister_modules_list(struct fast_mode_task *fmt,
struct device_list *list_to_remove, size_t list_idx)
{
if (list_to_remove == fmt->device_list[list_idx]) {
fmt->device_list[list_idx] = NULL;
return 0;
}
if (!fmt->device_list[list_idx]) {
/* Nothing to do here */
return 0;
}
return -EINVAL;
}

/* Comment from Old FW, may be outdated:
* Important: function below should be called only from within critical section
* (Goto KPB for more details)
*/
static int register_modules_list(struct fast_mode_task *fmt,
struct device_list *new_list, size_t list_idx)
{
if (list_idx >= ARRAY_SIZE(fmt->device_list))
return -EINVAL;

/* Check if slot is free */
if (!fmt->device_list[list_idx]) {
fmt->device_list[list_idx] = new_list;
return 0;
}
if (new_list == fmt->device_list[list_idx]) {
/* Already registered. */
return 0;
}
/* was ADSP_ALREADY_IN_USE */
return -EINVAL;
}

static int configure_fast_mode_task(struct comp_dev *kpb_dev, const struct kpb_task_params *cfg,
size_t pin)
{
if (pin >= KPB_MAX_SINK_CNT || pin == REALTIME_PIN_ID || !cfg)
return -EINVAL;

struct comp_data *priv_data = (struct comp_data *)comp_get_drvdata(kpb_dev);
int ret = unregister_modules_list(&priv_data->fmt,
&priv_data->fmt_device_list.device_list[pin],
pin);
if (ret)
return -EINVAL;

ret = clear_fmt_modules_list(&priv_data->fmt_device_list, pin);
if (ret)
return -EINVAL;

/* When modules count IS 0 we only need to remove modules from Fast Mode. */
if (cfg->number_of_modules > 0) {
tobonex marked this conversation as resolved.
Show resolved Hide resolved
ret = prepare_fmt_modules_list(kpb_dev, pin, cfg);
if (!ret)
ret = register_modules_list(&priv_data->fmt,
&priv_data->fmt_device_list.device_list[pin],
pin);
}
return ret;
}
#endif

static int kpb_set_large_config(struct comp_dev *dev, uint32_t param_id,
bool first_block,
bool last_block,
uint32_t data_offset,
const char *data)
{
/* We can use extended param id for both extended and standard param id */
union ipc4_extended_param_id extended_param_id;

comp_info(dev, "kpb_set_large_config()");

switch (param_id) {
extended_param_id.full = param_id;

switch (extended_param_id.part.parameter_type) {
#ifdef CONFIG_IPC_MAJOR_4
case KP_BUF_CFG_FM_MODULE: {
/* Modules count equals 0 is a special case in which we want to clear list for
* given pin. Reference FW also allowed for cfg/data to be NULL, but this is no
* longer the case.
*/
const struct kpb_task_params *cfg = (struct kpb_task_params *)data;
uint32_t outpin_id = extended_param_id.part.parameter_instance;

return configure_fast_mode_task(dev, cfg, outpin_id);
}
#endif
case KP_BUF_CLIENT_MIC_SELECT:
return kpb_set_micselect(dev, data, data_offset);
default:
Expand Down
12 changes: 12 additions & 0 deletions src/include/ipc4/kpb.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,16 @@
struct ipc4_kpb_module_cfg {
struct ipc4_base_module_cfg base_cfg;
} __packed __aligned(4);

/* For the sake of compatibility, do not change IDs, only add new ones.*/
enum ipc4_kpb_module_config_params {
tobonex marked this conversation as resolved.
Show resolved Hide resolved
/*! Configure the module ID's which would be part of the Fast mode tasks */
KP_BUF_CFG_FM_MODULE = 1,
/* Mic selector for client - sets microphone id for real time sink mic selector
* IPC4-compatible ID - please do not change the number
*/
KP_BUF_CLIENT_MIC_SELECT = 11,
Copy link
Contributor

Choose a reason for hiding this comment

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

how about 101? left more extend for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is defined as 11 in reference FW. There are some IPC commands in-between those two that are not defined in sof yet.

};

#endif

15 changes: 15 additions & 0 deletions src/include/ipc4/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
#define SOF_IPC4_DST_QUEUE_ID_BITFIELD_SIZE 3
#define SOF_IPC4_SRC_QUEUE_ID_BITFIELD_SIZE 3

/* Special large_param_id values */
#define VENDOR_CONFIG_PARAM 0xFF

enum sof_ipc4_module_type {
SOF_IPC4_MOD_INIT_INSTANCE = 0,
SOF_IPC4_MOD_CONFIG_GET = 1,
Expand All @@ -51,6 +54,18 @@ enum sof_ipc4_module_type {
SOF_IPC4_MOD_DELETE_INSTANCE = 11,
};

/*
* Structs for Vendor Config Set
*/

union ipc4_extended_param_id {
uint32_t full;
struct{
uint32_t parameter_type : 8;
uint32_t parameter_instance : 24;
} part;
} __packed __aligned(4);

/*
* Host Driver sends this message to create a new module instance.
*/
Expand Down
Loading