On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote: > Firmware modules implement processing algorithms. Their lifecycle, > similarly to pipelines is being controlled by IPCs: initialization, > deletion and (un)binding. > > Modules can be configured at runtime - runtime parameters. This is > done > with help of LARGE_CONFIG IPCs: getter and setter. > > Signed-off-by: Amadeusz Sławiński < > amadeuszx.slawinski@xxxxxxxxxxxxxxx> > Signed-off-by: Cezary Rojewski <cezary.rojewski@xxxxxxxxx> > --- > sound/soc/intel/avs/ipc.c | 8 +- > sound/soc/intel/avs/messages.c | 262 > +++++++++++++++++++++++++++++++++ > sound/soc/intel/avs/messages.h | 53 +++++++ > 3 files changed, 322 insertions(+), 1 deletion(-) > > diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c > index c0722f8b195f..9770368a898e 100644 > --- a/sound/soc/intel/avs/ipc.c > +++ b/sound/soc/intel/avs/ipc.c > @@ -21,9 +21,15 @@ static void avs_dsp_receive_rx(struct avs_dev > *adev, u64 header) > > ipc->rx.header = header; > /* Abort copying payload if request processing was > unsuccessful. */ > - if (!msg.status) > + if (!msg.status) { > + /* update size in case of LARGE_CONFIG_GET */ > + if (msg.msg_target == AVS_MOD_MSG && > + msg.global_msg_type == AVS_MOD_LARGE_CONFIG_GET) > + ipc->rx.size = > msg.ext.large_config.data_off_size; > + > memcpy_fromio(ipc->rx.data, avs_uplink_addr(adev), > ipc->rx.size); > + } > } > > static void avs_dsp_process_notification(struct avs_dev *adev, u64 > header) > diff --git a/sound/soc/intel/avs/messages.c > b/sound/soc/intel/avs/messages.c > index de2d50f8c6b4..613c9452226d 100644 > --- a/sound/soc/intel/avs/messages.c > +++ b/sound/soc/intel/avs/messages.c > @@ -6,6 +6,7 @@ > // Amadeusz Slawinski <amadeuszx.slawinski@xxxxxxxxxxxxxxx> > // > > +#include <linux/slab.h> > #include "avs.h" > #include "messages.h" > > @@ -139,3 +140,264 @@ int avs_ipc_get_pipeline_state(struct avs_dev > *adev, u8 instance_id, > *state = reply.rsp.ext.get_ppl_state.state; > return ret; > } > + > +/* > + * avs_ipc_init_instance - Initialize module instance > + * > + * @adev: Driver context > + * @module_id: Module-type id > + * @instance_id: Unique module instance id > + * @ppl_id: Parent pipeline id > + * @core_id: DSP core to allocate module on > + * @domain: Processing domain (low latency or data processing) > + * @param: Module-type specific configuration > + * @param_size: Size of @param in bytes > + * > + * Argument verification, as well as pipeline state checks are done > by the > + * firmware. > + * > + * Note: @ppl_id and @core_id are independent of each other as > single pipeline > + * can be composed of module instances located on different DSP > cores. > + */ > +int avs_ipc_init_instance(struct avs_dev *adev, u16 module_id, u8 > instance_id, > + u8 ppl_id, u8 core_id, u8 domain, > + void *param, u32 param_size) > +{ > + union avs_module_msg msg = AVS_MODULE_REQUEST(INIT_INSTANCE); > + struct avs_ipc_msg request; > + int ret; > + > + msg.module_id = module_id; > + msg.instance_id = instance_id; > + /* firmware expects size provided in dwords */ > + msg.ext.init_instance.param_block_size = > + DIV_ROUND_UP(param_size, sizeof(u32)); > + msg.ext.init_instance.ppl_instance_id = ppl_id; > + msg.ext.init_instance.core_id = core_id; > + msg.ext.init_instance.proc_domain = domain; > + > + request.header = msg.val; > + request.data = param; > + request.size = param_size; > + > + ret = avs_dsp_send_msg(adev, &request, NULL); > + if (ret) > + avs_ipc_err(adev, &request, "init instance", ret); > + > + return ret; > +} > + > +/* > + * avs_ipc_delete_instance - Delete module instance > + * > + * @adev: Driver context > + * @module_id: Module-type id > + * @instance_id: Unique module instance id > + * > + * Argument verification, as well as pipeline state checks are done > by the > + * firmware. > + * > + * Note: only standalone modules i.e. without a parent pipeline > shall be > + * deleted using this IPC message. In all other cases, pipeline > owning the > + * modules peforms cleanup automatically when it is deleted. Can you please provide an example of such stand-alone modules? If they aren't part of any pipeline, how do they get scheduled? > + */ > +int avs_ipc_delete_instance(struct avs_dev *adev, u16 module_id, u8 > instance_id) > +{ > + union avs_module_msg msg = AVS_MODULE_REQUEST(DELETE_INSTANCE); > + struct avs_ipc_msg request = {{0}}; > + int ret; > + > + msg.module_id = module_id; > + msg.instance_id = instance_id; > + request.header = msg.val; > + > + ret = avs_dsp_send_msg(adev, &request, NULL); > + if (ret) > + avs_ipc_err(adev, &request, "delete instance", ret); > + > + return ret; > +} > + > +/* > + * avs_ipc_bind - Bind two module instances > + * > + * @adev: Driver context > + * @module_id: Source module-type id > + * @instance_id: Source module instance id > + * @dst_module_id: Sink module-type id > + * @dst_instance_id: Sink module instance id > + * @dst_queue: Sink module pin to bind @src_queue with > + * @src_queue: Source module pin to bind @dst_queue with > + */ > +int avs_ipc_bind(struct avs_dev *adev, u16 module_id, u8 > instance_id, > + u16 dst_module_id, u8 dst_instance_id, > + u8 dst_queue, u8 src_queue) > +{ > + union avs_module_msg msg = AVS_MODULE_REQUEST(BIND); > + struct avs_ipc_msg request = {{0}}; > + int ret; > + > + msg.module_id = module_id; > + msg.instance_id = instance_id; > + msg.ext.bind_unbind.dst_module_id = dst_module_id; > + msg.ext.bind_unbind.dst_instance_id = dst_instance_id; > + msg.ext.bind_unbind.dst_queue = dst_queue; > + msg.ext.bind_unbind.src_queue = src_queue; > + request.header = msg.val; > + > + ret = avs_dsp_send_msg(adev, &request, NULL); > + if (ret) > + avs_ipc_err(adev, &request, "bind modules", ret); > + > + return ret; > +} > + > +/* > + * avs_ipc_unbind - Unbind two module instances > + * > + * @adev: Driver context > + * @module_id: Source module-type id > + * @instance_id: Source module instance id > + * @dst_module_id: Sink module-type id > + * @dst_instance_id: Sink module instance id > + * @dst_queue: Sink module pin to unbind @src_queue from > + * @src_queue: Source module pin to unbind @dst_queue from > + */ Are there any rules for unbinding? For example if you have 2 modules connected to a mixer? Can you unbind the module belonging to the host pipeline that is getting stopped while the mixer is still active? > +int avs_ipc_unbind(struct avs_dev *adev, u16 module_id, u8 > instance_id, > + u16 dst_module_id, u8 dst_instance_id, > + u8 dst_queue, u8 src_queue) > +{ > + union avs_module_msg msg = AVS_MODULE_REQUEST(UNBIND); > + struct avs_ipc_msg request = {{0}}; > + int ret; > + > + msg.module_id = module_id; > + msg.instance_id = instance_id; > + msg.ext.bind_unbind.dst_module_id = dst_module_id; > + msg.ext.bind_unbind.dst_instance_id = dst_instance_id; > + msg.ext.bind_unbind.dst_queue = dst_queue; > + msg.ext.bind_unbind.src_queue = src_queue; > + request.header = msg.val; > + > + ret = avs_dsp_send_msg(adev, &request, NULL); > + if (ret) > + avs_ipc_err(adev, &request, "unbind modules", ret); > + > + return ret; > +} > + > +static int __avs_ipc_set_large_config(struct avs_dev *adev, u16 > module_id, u8 instance_id, > + u8 param_id, bool init_block, > bool final_block, > + u8 *request_data, size_t > request_size, size_t off_size) > +{ > + union avs_module_msg msg = > AVS_MODULE_REQUEST(LARGE_CONFIG_SET); > + struct avs_ipc_msg request; > + int ret; > + > + msg.module_id = module_id; > + msg.instance_id = instance_id; > + msg.ext.large_config.data_off_size = off_size; > + msg.ext.large_config.large_param_id = param_id; > + msg.ext.large_config.final_block = final_block; > + msg.ext.large_config.init_block = init_block; > + > + request.header = msg.val; > + request.data = request_data; > + request.size = request_size; > + > + ret = avs_dsp_send_msg(adev, &request, NULL); > + if (ret) > + avs_ipc_err(adev, &request, "large config set", ret); > + > + return ret; > +} > + > +int avs_ipc_set_large_config(struct avs_dev *adev, u16 module_id, > + u8 instance_id, u8 param_id, > + u8 *request, size_t request_size) > +{ > + size_t remaining, tx_size; > + bool final; > + int ret; > + > + remaining = request_size; > + tx_size = min_t(size_t, AVS_MAILBOX_SIZE, remaining); > + final = (tx_size == remaining); > + > + /* Initial request states total payload size. */ > + ret = __avs_ipc_set_large_config(adev, module_id, instance_id, > + param_id, 1, final, request, > tx_size, > + request_size); > + if (ret) > + return ret; > + > + remaining -= tx_size; > + > + /* Loop the rest only when payload exceeds mailbox's size. */ > + while (remaining) { > + size_t offset; > + > + offset = request_size - remaining; > + tx_size = min_t(size_t, AVS_MAILBOX_SIZE, remaining); > + final = (tx_size == remaining); > + > + ret = __avs_ipc_set_large_config(adev, module_id, > instance_id, > + param_id, 0, final, > + request + offset, > tx_size, > + offset); > + if (ret) > + return ret; > + > + remaining -= tx_size; > + } > + > + return 0; > +} > + > +int avs_ipc_get_large_config(struct avs_dev *adev, u16 module_id, u8 > instance_id, > + u8 param_id, u8 *request_data, size_t > request_size, > + u8 **reply_data, size_t *reply_size) > +{ > + union avs_module_msg msg = > AVS_MODULE_REQUEST(LARGE_CONFIG_GET); > + struct avs_ipc_msg request; > + struct avs_ipc_msg reply = {{0}}; > + size_t size; > + void *buf; > + int ret; > + > + reply.data = kzalloc(AVS_MAILBOX_SIZE, GFP_KERNEL); > + if (!reply.data) > + return -ENOMEM; > + > + msg.module_id = module_id; > + msg.instance_id = instance_id; > + msg.ext.large_config.data_off_size = request_size; > + msg.ext.large_config.large_param_id = param_id; > + /* final_block is always 0 on request. Updated by fw on reply. > */ > + msg.ext.large_config.final_block = 0; > + msg.ext.large_config.init_block = 1; > + > + request.header = msg.val; > + request.data = request_data; > + request.size = request_size; > + reply.size = AVS_MAILBOX_SIZE; > + > + ret = avs_dsp_send_msg(adev, &request, &reply); > + if (ret) { > + avs_ipc_err(adev, &request, "large config get", ret); > + kfree(reply.data); > + return ret; > + } How come you dont have a loop here? What if the rec'd data size if larger than the max size of IP payload? Thanks,Ranjani